humanish 0.104.3 → 0.106.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 (1407) hide show
  1. package/AGENTS.md +89 -94
  2. package/ARCHITECTURE.md +146 -0
  3. package/CHANGELOG.md +502 -0
  4. package/CONTEXT.md +51 -0
  5. package/CONTRIBUTING.md +111 -9
  6. package/README.md +213 -124
  7. package/SECURITY.md +1 -1
  8. package/TELEMETRY.md +112 -0
  9. package/dist/actors/affordance.d.ts +56 -0
  10. package/dist/actors/affordance.js +155 -0
  11. package/dist/actors/agent-session.js +42 -0
  12. package/dist/actors/codex/app-server-actor-trace.d.ts +11 -0
  13. package/dist/actors/codex/app-server-actor-trace.js +211 -0
  14. package/dist/actors/codex/app-server-client.d.ts +39 -0
  15. package/dist/actors/codex/app-server-client.js +116 -0
  16. package/dist/actors/codex/app-server-trace.d.ts +154 -0
  17. package/dist/actors/codex/app-server-trace.js +424 -0
  18. package/dist/actors/codex/app-server-ui.d.ts +40 -0
  19. package/dist/actors/codex/app-server-ui.js +328 -0
  20. package/dist/actors/codex/app-server.d.ts +44 -0
  21. package/dist/actors/codex/app-server.js +268 -0
  22. package/dist/actors/codex/qualified-versions.d.ts +45 -0
  23. package/dist/actors/codex/qualified-versions.js +87 -0
  24. package/dist/actors/codex/restricted-executable.d.ts +17 -0
  25. package/dist/actors/codex/restricted-executable.js +147 -0
  26. package/dist/actors/codex/restricted-launch.d.ts +116 -0
  27. package/dist/actors/codex/restricted-launch.js +222 -0
  28. package/dist/actors/codex/restricted-participant-policy.d.ts +46 -0
  29. package/dist/actors/codex/restricted-participant-policy.js +82 -0
  30. package/dist/actors/codex/restricted-participant.d.ts +20 -0
  31. package/dist/actors/codex/restricted-participant.js +432 -0
  32. package/dist/actors/codex/restricted-policy.d.ts +70 -0
  33. package/dist/actors/codex/restricted-policy.js +326 -0
  34. package/dist/actors/codex/restricted-session.d.ts +65 -0
  35. package/dist/actors/codex/restricted-session.js +432 -0
  36. package/dist/actors/codex/restricted-transport.d.ts +73 -0
  37. package/dist/actors/codex/restricted-transport.js +335 -0
  38. package/dist/actors/codex/restricted-turn.d.ts +62 -0
  39. package/dist/actors/codex/restricted-turn.js +284 -0
  40. package/dist/actors/computer-use/actor.d.ts +77 -0
  41. package/dist/actors/computer-use/actor.js +78 -0
  42. package/dist/actors/computer-use/admission-limit.d.ts +12 -0
  43. package/dist/actors/computer-use/admission-limit.js +19 -0
  44. package/dist/actors/computer-use/executor-error.js +48 -0
  45. package/dist/actors/computer-use/loop/actions.d.ts +26 -0
  46. package/dist/actors/computer-use/loop/actions.js +245 -0
  47. package/dist/actors/computer-use/loop/backstop.d.ts +42 -0
  48. package/dist/actors/computer-use/loop/backstop.js +202 -0
  49. package/dist/actors/computer-use/loop/debrief.d.ts +19 -0
  50. package/dist/actors/computer-use/loop/debrief.js +164 -0
  51. package/dist/actors/computer-use/loop/ending.d.ts +86 -0
  52. package/dist/actors/computer-use/loop/ending.js +316 -0
  53. package/dist/actors/computer-use/loop/observation.d.ts +55 -0
  54. package/dist/actors/computer-use/loop/observation.js +246 -0
  55. package/dist/actors/computer-use/loop/output-limit.d.ts +11 -0
  56. package/dist/actors/computer-use/loop/output-limit.js +21 -0
  57. package/dist/actors/computer-use/loop/provider-call.d.ts +19 -0
  58. package/dist/actors/computer-use/loop/provider-call.js +208 -0
  59. package/dist/actors/computer-use/loop/race.d.ts +34 -0
  60. package/dist/actors/computer-use/loop/race.js +79 -0
  61. package/dist/actors/computer-use/loop/session.d.ts +77 -0
  62. package/dist/actors/computer-use/loop/session.js +135 -0
  63. package/dist/actors/computer-use/loop/spend.d.ts +30 -0
  64. package/dist/actors/computer-use/loop/spend.js +85 -0
  65. package/dist/actors/computer-use/loop/trace.d.ts +35 -0
  66. package/dist/actors/computer-use/loop/trace.js +140 -0
  67. package/dist/actors/computer-use/loop/types.d.ts +404 -0
  68. package/dist/actors/computer-use/loop/types.js +1 -0
  69. package/dist/actors/computer-use/loop/usage.d.ts +102 -0
  70. package/dist/actors/computer-use/loop/usage.js +355 -0
  71. package/dist/actors/computer-use/loop.d.ts +11 -0
  72. package/dist/actors/computer-use/loop.js +248 -0
  73. package/dist/actors/computer-use/openai-provider.d.ts +107 -0
  74. package/dist/actors/computer-use/openai-provider.js +472 -0
  75. package/dist/actors/computer-use/openai-requests.d.ts +35 -0
  76. package/dist/actors/computer-use/openai-requests.js +74 -0
  77. package/dist/actors/computer-use/openai-wire.d.ts +67 -0
  78. package/dist/actors/computer-use/openai-wire.js +365 -0
  79. package/dist/actors/computer-use/provider-error.d.ts +27 -0
  80. package/dist/actors/computer-use/provider-error.js +86 -0
  81. package/dist/actors/computer-use/speech.js +6 -0
  82. package/dist/actors/contract.d.ts +315 -0
  83. package/dist/actors/contract.js +201 -0
  84. package/dist/actors/goal-source.js +38 -0
  85. package/dist/actors/local-agent/claude-session.d.ts +43 -0
  86. package/dist/actors/local-agent/claude-session.js +370 -0
  87. package/dist/actors/local-agent/cli.d.ts +115 -0
  88. package/dist/actors/local-agent/cli.js +413 -0
  89. package/dist/actors/local-agent/readiness.d.ts +31 -0
  90. package/dist/actors/local-agent/readiness.js +45 -0
  91. package/dist/actors/openai-endpoint.d.ts +2 -0
  92. package/dist/actors/openai-endpoint.js +2 -0
  93. package/dist/actors/output-token-limit.js +4 -0
  94. package/dist/actors/reasoning-effort.js +33 -0
  95. package/dist/actors/registry.d.ts +59 -0
  96. package/dist/actors/registry.js +89 -0
  97. package/dist/actors/scripted-browser/actor.d.ts +49 -0
  98. package/dist/actors/scripted-browser/actor.js +428 -0
  99. package/dist/actors/scripted-browser/browser-command.d.ts +1 -0
  100. package/dist/actors/scripted-browser/browser-command.js +48 -0
  101. package/dist/actors/scripted-browser/journey.d.ts +9 -0
  102. package/dist/actors/scripted-browser/journey.js +171 -0
  103. package/dist/actors/scripted-browser/steps.d.ts +60 -0
  104. package/dist/actors/scripted-browser/steps.js +384 -0
  105. package/dist/actors/scripted-browser/types.d.ts +135 -0
  106. package/dist/actors/scripted-browser/types.js +26 -0
  107. package/dist/actors/stop-cause.d.ts +9 -0
  108. package/dist/actors/stop-cause.js +42 -0
  109. package/dist/actors/stop-conditions.d.ts +40 -0
  110. package/dist/actors/stop-conditions.js +65 -0
  111. package/dist/analysis/automatic-completion.d.ts +38 -0
  112. package/dist/analysis/automatic-completion.js +90 -0
  113. package/dist/analysis/automatic-config.d.ts +41 -0
  114. package/dist/analysis/automatic-config.js +135 -0
  115. package/dist/analysis/automatic.d.ts +17 -0
  116. package/dist/analysis/automatic.js +279 -0
  117. package/dist/analysis/codex-config.d.ts +8 -0
  118. package/dist/analysis/codex-config.js +69 -0
  119. package/dist/analysis/evidence-sources.d.ts +23 -0
  120. package/dist/analysis/evidence-sources.js +251 -0
  121. package/dist/analysis/evidence.d.ts +18 -0
  122. package/dist/analysis/evidence.js +482 -0
  123. package/dist/analysis/execute.d.ts +52 -0
  124. package/dist/analysis/execute.js +504 -0
  125. package/dist/analysis/image-tokens.d.ts +1 -0
  126. package/dist/analysis/image-tokens.js +41 -0
  127. package/dist/analysis/job.d.ts +97 -0
  128. package/dist/analysis/job.js +311 -0
  129. package/dist/analysis/load.d.ts +3 -0
  130. package/dist/analysis/load.js +11 -0
  131. package/dist/analysis/provider.d.ts +57 -0
  132. package/dist/analysis/provider.js +227 -0
  133. package/dist/analysis/restricted-codex.d.ts +19 -0
  134. package/dist/analysis/restricted-codex.js +23 -0
  135. package/dist/analysis/service.d.ts +72 -0
  136. package/dist/analysis/service.js +399 -0
  137. package/dist/analysis/sharing.d.ts +11 -0
  138. package/dist/analysis/sharing.js +44 -0
  139. package/dist/analysis/store-executions.d.ts +27 -0
  140. package/dist/analysis/store-executions.js +224 -0
  141. package/dist/analysis/store.d.ts +31 -0
  142. package/dist/analysis/store.js +315 -0
  143. package/dist/analysis/types.d.ts +217 -0
  144. package/dist/analysis/types.js +12 -0
  145. package/dist/analysis/validation.d.ts +225 -0
  146. package/dist/analysis/validation.js +562 -0
  147. package/dist/browser-control/client.d.ts +18 -0
  148. package/dist/browser-control/client.js +239 -0
  149. package/dist/browser-control/dispatcher.d.ts +19 -0
  150. package/dist/browser-control/dispatcher.js +221 -0
  151. package/dist/browser-control/protocol.d.ts +492 -0
  152. package/dist/browser-control/protocol.js +360 -0
  153. package/dist/browser-control/recording-transfer.d.ts +3 -0
  154. package/dist/browser-control/recording-transfer.js +48 -0
  155. package/dist/browser-control/transport.d.ts +27 -0
  156. package/dist/browser-control/transport.js +189 -0
  157. package/dist/cli/commands/analysis-signals.d.ts +7 -0
  158. package/dist/cli/commands/analysis-signals.js +25 -0
  159. package/dist/cli/commands/analyze.d.ts +3 -0
  160. package/dist/cli/commands/analyze.js +212 -0
  161. package/dist/cli/commands/codex.d.ts +3 -0
  162. package/dist/cli/commands/codex.js +145 -0
  163. package/dist/cli/commands/comms.d.ts +3 -0
  164. package/dist/cli/commands/comms.js +225 -0
  165. package/dist/cli/commands/feedback.d.ts +3 -0
  166. package/dist/cli/commands/feedback.js +138 -0
  167. package/dist/cli/commands/lab-format.d.ts +8 -0
  168. package/dist/cli/commands/lab-format.js +105 -0
  169. package/dist/cli/commands/lab-route-computer-use.d.ts +20 -0
  170. package/dist/cli/commands/lab-route-computer-use.js +251 -0
  171. package/dist/cli/commands/lab-route-open.d.ts +27 -0
  172. package/dist/cli/commands/lab-route-open.js +37 -0
  173. package/dist/cli/commands/lab-route-preview.d.ts +20 -0
  174. package/dist/cli/commands/lab-route-preview.js +74 -0
  175. package/dist/cli/commands/lab-route-run.d.ts +17 -0
  176. package/dist/cli/commands/lab-route-run.js +31 -0
  177. package/dist/cli/commands/lab-route-scripted.d.ts +19 -0
  178. package/dist/cli/commands/lab-route-scripted.js +50 -0
  179. package/dist/cli/commands/lab-route-shared-world.d.ts +20 -0
  180. package/dist/cli/commands/lab-route-shared-world.js +135 -0
  181. package/dist/cli/commands/lab-route-terminal.d.ts +19 -0
  182. package/dist/cli/commands/lab-route-terminal.js +49 -0
  183. package/dist/cli/commands/lab-run.d.ts +9 -0
  184. package/dist/cli/commands/lab-run.js +166 -0
  185. package/dist/cli/commands/lab-scorer.d.ts +30 -0
  186. package/dist/cli/commands/lab-scorer.js +17 -0
  187. package/dist/cli/commands/lab.d.ts +3 -0
  188. package/dist/cli/commands/lab.js +193 -0
  189. package/dist/cli/commands/observe.d.ts +4 -0
  190. package/dist/cli/commands/observe.js +345 -0
  191. package/dist/cli/commands/runs.d.ts +11 -0
  192. package/dist/cli/commands/runs.js +314 -0
  193. package/dist/cli/commands/setup.d.ts +11 -0
  194. package/dist/cli/commands/setup.js +325 -0
  195. package/dist/cli/commands/tui.d.ts +32 -0
  196. package/dist/cli/commands/tui.js +305 -0
  197. package/dist/cli/commands/watch.d.ts +3 -0
  198. package/dist/cli/commands/watch.js +245 -0
  199. package/dist/cli/doctor.d.ts +39 -0
  200. package/dist/cli/doctor.js +263 -0
  201. package/dist/cli/first-run-path.d.ts +67 -0
  202. package/dist/cli/first-run-path.js +150 -0
  203. package/dist/cli/io.d.ts +85 -0
  204. package/dist/cli/io.js +232 -0
  205. package/dist/cli/observer-follow.d.ts +56 -0
  206. package/dist/cli/observer-follow.js +160 -0
  207. package/dist/cli/orientation.d.ts +30 -0
  208. package/dist/cli/orientation.js +114 -0
  209. package/dist/cli/program.d.ts +15 -0
  210. package/dist/cli/program.js +338 -0
  211. package/dist/cli/secret-prompt.js +39 -0
  212. package/dist/cli/telemetry.js +351 -0
  213. package/dist/cli.js +2 -4
  214. package/dist/comms/agentmail.d.ts +29 -0
  215. package/dist/comms/agentmail.js +568 -0
  216. package/dist/comms/capture-surface.d.ts +54 -0
  217. package/dist/comms/capture-surface.js +468 -0
  218. package/dist/comms/catch-host.d.ts +52 -0
  219. package/dist/comms/catch-host.js +192 -0
  220. package/dist/comms/connections.d.ts +20 -0
  221. package/dist/comms/connections.js +116 -0
  222. package/dist/comms/email-catch.d.ts +49 -0
  223. package/dist/comms/email-catch.js +236 -0
  224. package/dist/comms/extract.d.ts +7 -0
  225. package/dist/comms/extract.js +65 -0
  226. package/dist/comms/fake-inbox.d.ts +39 -0
  227. package/dist/comms/fake-inbox.js +136 -0
  228. package/dist/comms/images.d.ts +7 -0
  229. package/dist/comms/images.js +53 -0
  230. package/dist/comms/lease-store.d.ts +91 -0
  231. package/dist/comms/lease-store.js +600 -0
  232. package/dist/comms/providers.d.ts +30 -0
  233. package/dist/comms/providers.js +24 -0
  234. package/dist/comms/receiving-common.d.ts +17 -0
  235. package/dist/comms/receiving-common.js +82 -0
  236. package/dist/comms/receiving-evidence.d.ts +4 -0
  237. package/dist/comms/receiving-evidence.js +59 -0
  238. package/dist/comms/receiving-recovery.d.ts +22 -0
  239. package/dist/comms/receiving-recovery.js +100 -0
  240. package/dist/comms/receiving-render.d.ts +16 -0
  241. package/dist/comms/receiving-render.js +409 -0
  242. package/dist/comms/receiving-runtime.d.ts +41 -0
  243. package/dist/comms/receiving-runtime.js +66 -0
  244. package/dist/comms/receiving-surface.d.ts +8 -0
  245. package/dist/comms/receiving-surface.js +156 -0
  246. package/dist/comms/receiving-types.d.ts +122 -0
  247. package/dist/comms/receiving-types.js +3 -0
  248. package/dist/comms/receiving.d.ts +33 -0
  249. package/dist/comms/receiving.js +508 -0
  250. package/dist/comms/sandbox-catch-script.d.ts +16 -0
  251. package/dist/comms/sandbox-catch-script.js +331 -0
  252. package/dist/comms/sandbox-catch.d.ts +214 -0
  253. package/dist/comms/sandbox-catch.js +451 -0
  254. package/dist/comms/setup.d.ts +65 -0
  255. package/dist/comms/setup.js +259 -0
  256. package/dist/comms/thread-evidence.d.ts +28 -0
  257. package/dist/comms/thread-evidence.js +30 -0
  258. package/dist/comms/types.d.ts +76 -0
  259. package/dist/comms/types.js +8 -0
  260. package/dist/deprecated.d.ts +90 -0
  261. package/dist/deprecated.js +106 -0
  262. package/dist/evidence/browser-hygiene.js +42 -0
  263. package/dist/evidence/desktop-recorder.d.ts +39 -0
  264. package/dist/evidence/desktop-recorder.js +340 -0
  265. package/dist/evidence/desktop-recording-artifact.d.ts +5 -0
  266. package/dist/evidence/desktop-recording-artifact.js +53 -0
  267. package/dist/evidence/desktop-recording-types.d.ts +27 -0
  268. package/dist/evidence/desktop-recording-types.js +16 -0
  269. package/dist/evidence/encoded-text.d.ts +27 -0
  270. package/dist/evidence/encoded-text.js +243 -0
  271. package/dist/evidence/frame-signature.d.ts +17 -0
  272. package/dist/evidence/frame-signature.js +111 -0
  273. package/dist/evidence/image.d.ts +24 -0
  274. package/dist/evidence/image.js +170 -0
  275. package/dist/evidence/plain-text.d.ts +8 -0
  276. package/dist/evidence/plain-text.js +16 -0
  277. package/dist/evidence/redaction.d.ts +110 -0
  278. package/dist/evidence/redaction.js +329 -0
  279. package/dist/feedback/draft.d.ts +58 -0
  280. package/dist/feedback/draft.js +309 -0
  281. package/dist/feedback/export-bundle.d.ts +6 -0
  282. package/dist/feedback/export-bundle.js +585 -0
  283. package/dist/feedback/export.d.ts +50 -0
  284. package/dist/feedback/export.js +392 -0
  285. package/dist/feedback/feedback.d.ts +37 -0
  286. package/dist/feedback/feedback.js +282 -0
  287. package/dist/feedback/proof.d.ts +8 -0
  288. package/dist/feedback/proof.js +56 -0
  289. package/dist/guest/bootstrap.d.ts +55 -0
  290. package/dist/guest/bootstrap.js +348 -0
  291. package/dist/guest/browser-tools.d.ts +8 -0
  292. package/dist/guest/browser-tools.js +72 -0
  293. package/dist/guest/chromium-text.d.ts +62 -0
  294. package/dist/guest/chromium-text.js +386 -0
  295. package/dist/guest/desktop-executor.d.ts +57 -0
  296. package/dist/guest/desktop-executor.js +256 -0
  297. package/dist/guest/desktop-keys.d.ts +8 -0
  298. package/dist/guest/desktop-keys.js +89 -0
  299. package/dist/guest/desktop-media.d.ts +70 -0
  300. package/dist/guest/desktop-media.js +385 -0
  301. package/dist/guest/desktop-native.d.ts +14 -0
  302. package/dist/guest/desktop-native.js +156 -0
  303. package/dist/guest/media-config.d.ts +15 -0
  304. package/dist/guest/media-config.js +16 -0
  305. package/dist/guest/runtime-desktop.d.ts +45 -0
  306. package/dist/guest/runtime-desktop.js +420 -0
  307. package/dist/guest/runtime-processes.d.ts +28 -0
  308. package/dist/guest/runtime-processes.js +94 -0
  309. package/dist/guest/runtime.d.ts +31 -0
  310. package/dist/guest/runtime.js +124 -0
  311. package/dist/guest-media-worker.js +184 -48
  312. package/dist/guest-runtime-main.js +23 -10
  313. package/dist/guest-runtime-revision.js +1 -1
  314. package/dist/index.d.ts +32 -83
  315. package/dist/index.js +21 -42
  316. package/dist/keys/env-file.d.ts +15 -0
  317. package/dist/keys/env-file.js +109 -0
  318. package/dist/keys/key-resolution.d.ts +58 -0
  319. package/dist/keys/key-resolution.js +389 -0
  320. package/dist/lab/adapter-extension.d.ts +75 -0
  321. package/dist/lab/adapter-extension.js +253 -0
  322. package/dist/lab/adapter-scorer-loader.d.ts +43 -0
  323. package/dist/lab/adapter-scorer-loader.js +130 -0
  324. package/dist/lab/bag-overrides.d.ts +18 -0
  325. package/dist/lab/bag-overrides.js +121 -0
  326. package/dist/lab/composition-rules.d.ts +5 -0
  327. package/dist/lab/composition-rules.js +283 -0
  328. package/dist/lab/config.d.ts +7 -0
  329. package/dist/lab/config.js +208 -0
  330. package/dist/lab/device-presets.d.ts +97 -0
  331. package/dist/lab/device-presets.js +87 -0
  332. package/dist/lab/discover.d.ts +65 -0
  333. package/dist/lab/discover.js +422 -0
  334. package/dist/lab/doctor.d.ts +39 -0
  335. package/dist/lab/doctor.js +233 -0
  336. package/dist/lab/init-paths.d.ts +5 -0
  337. package/dist/lab/init-paths.js +89 -0
  338. package/dist/lab/init-plan.d.ts +20 -0
  339. package/dist/lab/init-plan.js +163 -0
  340. package/dist/lab/init-templates.d.ts +28 -0
  341. package/dist/lab/init-templates.js +416 -0
  342. package/dist/lab/init.d.ts +39 -0
  343. package/dist/lab/init.js +287 -0
  344. package/dist/lab/keys.d.ts +2 -0
  345. package/dist/lab/keys.js +264 -0
  346. package/dist/lab/parse/actors.d.ts +14 -0
  347. package/dist/lab/parse/actors.js +453 -0
  348. package/dist/lab/parse/comms.d.ts +12 -0
  349. package/dist/lab/parse/comms.js +246 -0
  350. package/dist/lab/parse/execution.d.ts +19 -0
  351. package/dist/lab/parse/execution.js +356 -0
  352. package/dist/lab/parse/subject-state.d.ts +30 -0
  353. package/dist/lab/parse/subject-state.js +179 -0
  354. package/dist/lab/parse/subject.d.ts +9 -0
  355. package/dist/lab/parse/subject.js +420 -0
  356. package/dist/lab/parse/values.d.ts +17 -0
  357. package/dist/lab/parse/values.js +65 -0
  358. package/dist/lab/participant-assignment.d.ts +12 -0
  359. package/dist/lab/participant-assignment.js +19 -0
  360. package/dist/lab/persona-resolve.d.ts +39 -0
  361. package/dist/lab/persona-resolve.js +118 -0
  362. package/dist/lab/persona.d.ts +39 -0
  363. package/dist/lab/persona.js +192 -0
  364. package/dist/lab/plan-base.d.ts +24 -0
  365. package/dist/lab/plan-base.js +113 -0
  366. package/dist/lab/plan-participants.d.ts +81 -0
  367. package/dist/lab/plan-participants.js +92 -0
  368. package/dist/lab/plan-types.d.ts +269 -0
  369. package/dist/lab/plan-types.js +5 -0
  370. package/dist/lab/plan.d.ts +27 -0
  371. package/dist/lab/plan.js +156 -0
  372. package/dist/lab/preflight-probes.d.ts +3 -0
  373. package/dist/lab/preflight-probes.js +312 -0
  374. package/dist/lab/preflight-result.d.ts +7 -0
  375. package/dist/lab/preflight-result.js +43 -0
  376. package/dist/lab/preflight.d.ts +95 -0
  377. package/dist/lab/preflight.js +117 -0
  378. package/dist/lab/route-inputs.d.ts +17 -0
  379. package/dist/lab/route-inputs.js +95 -0
  380. package/dist/lab/routing.d.ts +81 -0
  381. package/dist/lab/routing.js +214 -0
  382. package/dist/lab/run-lab-events.d.ts +69 -0
  383. package/dist/lab/run-lab-events.js +95 -0
  384. package/dist/lab/run-lab-options.d.ts +82 -0
  385. package/dist/lab/run-lab-options.js +399 -0
  386. package/dist/lab/summary.d.ts +60 -0
  387. package/dist/lab/summary.js +168 -0
  388. package/dist/lab/tasks.d.ts +91 -0
  389. package/dist/lab/tasks.js +139 -0
  390. package/dist/lab/types.d.ts +813 -0
  391. package/dist/lab/types.js +6 -0
  392. package/dist/lab/validation.d.ts +67 -0
  393. package/dist/lab/validation.js +387 -0
  394. package/dist/lab/warnings.d.ts +2 -0
  395. package/dist/lab/warnings.js +338 -0
  396. package/dist/observer/artifact.d.ts +23 -0
  397. package/dist/observer/artifact.js +235 -0
  398. package/dist/observer/data.d.ts +115 -0
  399. package/dist/observer/data.js +258 -0
  400. package/dist/observer/exposure.d.ts +64 -0
  401. package/dist/observer/exposure.js +143 -0
  402. package/dist/observer/http.js +50 -0
  403. package/dist/observer/library.js +190 -0
  404. package/dist/observer/listen.js +85 -0
  405. package/dist/observer/live.d.ts +9 -0
  406. package/dist/observer/live.js +25 -0
  407. package/dist/observer/pinned-files.d.ts +30 -0
  408. package/dist/observer/pinned-files.js +160 -0
  409. package/dist/observer/render.d.ts +69 -0
  410. package/dist/observer/render.js +350 -0
  411. package/dist/observer/run-inventory.d.ts +35 -0
  412. package/dist/observer/run-inventory.js +95 -0
  413. package/dist/observer/run-routes.d.ts +37 -0
  414. package/dist/observer/run-routes.js +373 -0
  415. package/dist/observer/serve.d.ts +97 -0
  416. package/dist/observer/serve.js +305 -0
  417. package/dist/observer/static.js +369 -0
  418. package/dist/observer/tunnel.js +112 -0
  419. package/dist/observer-app.html +9 -20
  420. package/dist/routes/computer-use/bundle-parts.d.ts +50 -0
  421. package/dist/routes/computer-use/bundle-parts.js +177 -0
  422. package/dist/routes/computer-use/bundle.d.ts +56 -0
  423. package/dist/routes/computer-use/bundle.js +184 -0
  424. package/dist/routes/computer-use/diagnostics.d.ts +38 -0
  425. package/dist/routes/computer-use/diagnostics.js +94 -0
  426. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +65 -0
  427. package/dist/routes/computer-use/e2b-desktop/comms.js +225 -0
  428. package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +3 -0
  429. package/dist/routes/computer-use/e2b-desktop/desktop.js +91 -0
  430. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +65 -0
  431. package/dist/routes/computer-use/e2b-desktop/fidelity.js +156 -0
  432. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +18 -0
  433. package/dist/routes/computer-use/e2b-desktop/prepare.js +198 -0
  434. package/dist/routes/computer-use/e2b-desktop/start.d.ts +14 -0
  435. package/dist/routes/computer-use/e2b-desktop/start.js +193 -0
  436. package/dist/routes/computer-use/e2b-desktop/state.d.ts +65 -0
  437. package/dist/routes/computer-use/e2b-desktop/state.js +69 -0
  438. package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +6 -0
  439. package/dist/routes/computer-use/e2b-desktop/teardown.js +152 -0
  440. package/dist/routes/computer-use/external-comms.d.ts +20 -0
  441. package/dist/routes/computer-use/external-comms.js +55 -0
  442. package/dist/routes/computer-use/fanout-bundle.d.ts +11 -0
  443. package/dist/routes/computer-use/fanout-bundle.js +274 -0
  444. package/dist/routes/computer-use/fanout-lanes.d.ts +15 -0
  445. package/dist/routes/computer-use/fanout-lanes.js +302 -0
  446. package/dist/routes/computer-use/in-process-desktop.d.ts +17 -0
  447. package/dist/routes/computer-use/in-process-desktop.js +40 -0
  448. package/dist/routes/computer-use/lanes.d.ts +35 -0
  449. package/dist/routes/computer-use/lanes.js +321 -0
  450. package/dist/routes/computer-use/legacy-lane-spec.d.ts +62 -0
  451. package/dist/routes/computer-use/legacy-lane-spec.js +39 -0
  452. package/dist/routes/computer-use/live-flush.d.ts +42 -0
  453. package/dist/routes/computer-use/live-flush.js +154 -0
  454. package/dist/routes/computer-use/local-tree-pack.d.ts +27 -0
  455. package/dist/routes/computer-use/local-tree-pack.js +47 -0
  456. package/dist/routes/computer-use/local-vm.d.ts +20 -0
  457. package/dist/routes/computer-use/local-vm.js +218 -0
  458. package/dist/routes/computer-use/participant-desktop.d.ts +63 -0
  459. package/dist/routes/computer-use/participant-desktop.js +33 -0
  460. package/dist/routes/computer-use/participant-facts.d.ts +6 -0
  461. package/dist/routes/computer-use/participant-facts.js +22 -0
  462. package/dist/routes/computer-use/participant-model.d.ts +30 -0
  463. package/dist/routes/computer-use/participant-model.js +222 -0
  464. package/dist/routes/computer-use/participant-prompt.d.ts +53 -0
  465. package/dist/routes/computer-use/participant-prompt.js +87 -0
  466. package/dist/routes/computer-use/participant-runs.d.ts +67 -0
  467. package/dist/routes/computer-use/participant-runs.js +255 -0
  468. package/dist/routes/computer-use/plan.d.ts +56 -0
  469. package/dist/routes/computer-use/plan.js +308 -0
  470. package/dist/routes/computer-use/preflight.d.ts +26 -0
  471. package/dist/routes/computer-use/preflight.js +85 -0
  472. package/dist/routes/computer-use/rerun-selection.d.ts +19 -0
  473. package/dist/routes/computer-use/rerun-selection.js +121 -0
  474. package/dist/routes/computer-use/result.d.ts +7 -0
  475. package/dist/routes/computer-use/result.js +292 -0
  476. package/dist/routes/computer-use/route.d.ts +33 -0
  477. package/dist/routes/computer-use/route.js +145 -0
  478. package/dist/routes/computer-use/run-lanes.d.ts +59 -0
  479. package/dist/routes/computer-use/run-lanes.js +135 -0
  480. package/dist/routes/computer-use/self-report.d.ts +21 -0
  481. package/dist/routes/computer-use/self-report.js +231 -0
  482. package/dist/routes/computer-use/setup.d.ts +136 -0
  483. package/dist/routes/computer-use/setup.js +371 -0
  484. package/dist/routes/computer-use/single-bundle.d.ts +97 -0
  485. package/dist/routes/computer-use/single-bundle.js +393 -0
  486. package/dist/routes/computer-use/subject-projection.d.ts +51 -0
  487. package/dist/routes/computer-use/subject-projection.js +159 -0
  488. package/dist/routes/computer-use/types.d.ts +539 -0
  489. package/dist/routes/computer-use/types.js +37 -0
  490. package/dist/routes/preview.d.ts +13 -0
  491. package/dist/routes/preview.js +36 -0
  492. package/dist/routes/scripted/bundle.d.ts +47 -0
  493. package/dist/routes/scripted/bundle.js +195 -0
  494. package/dist/routes/scripted/plan.d.ts +30 -0
  495. package/dist/routes/scripted/plan.js +95 -0
  496. package/dist/routes/scripted/result.d.ts +48 -0
  497. package/dist/routes/scripted/result.js +176 -0
  498. package/dist/routes/scripted/route.d.ts +28 -0
  499. package/dist/routes/scripted/route.js +218 -0
  500. package/dist/routes/scripted/scenario.d.ts +21 -0
  501. package/dist/routes/scripted/scenario.js +102 -0
  502. package/dist/routes/scripted/session-result.d.ts +8 -0
  503. package/dist/routes/scripted/session-result.js +60 -0
  504. package/dist/routes/scripted/setup.d.ts +45 -0
  505. package/dist/routes/scripted/setup.js +126 -0
  506. package/dist/routes/scripted/subject.d.ts +49 -0
  507. package/dist/routes/scripted/subject.js +156 -0
  508. package/dist/routes/scripted/surface-records.d.ts +26 -0
  509. package/dist/routes/scripted/surface-records.js +88 -0
  510. package/dist/routes/scripted/surface-sessions.d.ts +13 -0
  511. package/dist/routes/scripted/surface-sessions.js +40 -0
  512. package/dist/routes/scripted/types.d.ts +88 -0
  513. package/dist/routes/scripted/types.js +3 -0
  514. package/dist/routes/shared-world/bundle.d.ts +20 -0
  515. package/dist/routes/shared-world/bundle.js +446 -0
  516. package/dist/routes/shared-world/checkpoints.d.ts +25 -0
  517. package/dist/routes/shared-world/checkpoints.js +46 -0
  518. package/dist/routes/shared-world/comms.d.ts +68 -0
  519. package/dist/routes/shared-world/comms.js +176 -0
  520. package/dist/routes/shared-world/external-public.d.ts +21 -0
  521. package/dist/routes/shared-world/external-public.js +130 -0
  522. package/dist/routes/shared-world/handoff.d.ts +62 -0
  523. package/dist/routes/shared-world/handoff.js +348 -0
  524. package/dist/routes/shared-world/lobby-code.d.ts +25 -0
  525. package/dist/routes/shared-world/lobby-code.js +152 -0
  526. package/dist/routes/shared-world/plan.d.ts +27 -0
  527. package/dist/routes/shared-world/plan.js +174 -0
  528. package/dist/routes/shared-world/provenance.d.ts +27 -0
  529. package/dist/routes/shared-world/provenance.js +65 -0
  530. package/dist/routes/shared-world/provisioned.d.ts +57 -0
  531. package/dist/routes/shared-world/provisioned.js +505 -0
  532. package/dist/routes/shared-world/result.d.ts +18 -0
  533. package/dist/routes/shared-world/result.js +327 -0
  534. package/dist/routes/shared-world/route.d.ts +21 -0
  535. package/dist/routes/shared-world/route.js +277 -0
  536. package/dist/routes/shared-world/seat-records.d.ts +20 -0
  537. package/dist/routes/shared-world/seat-records.js +213 -0
  538. package/dist/routes/shared-world/seats.d.ts +38 -0
  539. package/dist/routes/shared-world/seats.js +208 -0
  540. package/dist/routes/shared-world/setup.d.ts +48 -0
  541. package/dist/routes/shared-world/setup.js +200 -0
  542. package/dist/routes/shared-world/types.d.ts +354 -0
  543. package/dist/routes/shared-world/types.js +29 -0
  544. package/dist/routes/terminal/adapter.d.ts +37 -0
  545. package/dist/routes/terminal/adapter.js +201 -0
  546. package/dist/routes/terminal/bundle.d.ts +79 -0
  547. package/dist/routes/terminal/bundle.js +305 -0
  548. package/dist/routes/terminal/credentials.d.ts +34 -0
  549. package/dist/routes/terminal/credentials.js +102 -0
  550. package/dist/routes/terminal/dry-run.d.ts +24 -0
  551. package/dist/routes/terminal/dry-run.js +157 -0
  552. package/dist/routes/terminal/encoding.js +79 -0
  553. package/dist/routes/terminal/ledger.d.ts +49 -0
  554. package/dist/routes/terminal/ledger.js +170 -0
  555. package/dist/routes/terminal/lifetime.d.ts +10 -0
  556. package/dist/routes/terminal/lifetime.js +22 -0
  557. package/dist/routes/terminal/live-finish.d.ts +31 -0
  558. package/dist/routes/terminal/live-finish.js +215 -0
  559. package/dist/routes/terminal/live-sandbox.d.ts +69 -0
  560. package/dist/routes/terminal/live-sandbox.js +452 -0
  561. package/dist/routes/terminal/persona.d.ts +20 -0
  562. package/dist/routes/terminal/persona.js +34 -0
  563. package/dist/routes/terminal/plan.d.ts +21 -0
  564. package/dist/routes/terminal/plan.js +115 -0
  565. package/dist/routes/terminal/recorder.d.ts +23 -0
  566. package/dist/routes/terminal/recorder.js +77 -0
  567. package/dist/routes/terminal/result.d.ts +47 -0
  568. package/dist/routes/terminal/result.js +114 -0
  569. package/dist/routes/terminal/route.d.ts +23 -0
  570. package/dist/routes/terminal/route.js +170 -0
  571. package/dist/routes/terminal/runtime-auth.d.ts +12 -0
  572. package/dist/routes/terminal/runtime-auth.js +23 -0
  573. package/dist/routes/terminal/runtime.d.ts +14 -0
  574. package/dist/routes/terminal/runtime.js +47 -0
  575. package/dist/routes/terminal/sandbox.d.ts +35 -0
  576. package/dist/routes/terminal/sandbox.js +126 -0
  577. package/dist/routes/terminal/session.d.ts +25 -0
  578. package/dist/routes/terminal/session.js +199 -0
  579. package/dist/routes/terminal/token-usage.d.ts +15 -0
  580. package/dist/routes/terminal/token-usage.js +93 -0
  581. package/dist/routes/terminal/trace.d.ts +40 -0
  582. package/dist/routes/terminal/trace.js +172 -0
  583. package/dist/routes/terminal/types.d.ts +342 -0
  584. package/dist/routes/terminal/types.js +31 -0
  585. package/dist/run/bundle-shape.d.ts +7 -0
  586. package/dist/run/bundle-shape.js +369 -0
  587. package/dist/run/bundle.d.ts +547 -0
  588. package/dist/run/bundle.js +44 -0
  589. package/dist/run/concurrency.js +24 -0
  590. package/dist/run/contained-output.d.ts +50 -0
  591. package/dist/run/contained-output.js +351 -0
  592. package/dist/run/cost-summary.d.ts +28 -0
  593. package/dist/run/cost-summary.js +213 -0
  594. package/dist/run/costs.js +140 -0
  595. package/dist/run/detail.d.ts +62 -0
  596. package/dist/run/detail.js +139 -0
  597. package/dist/run/dry-run-inputs.d.ts +9 -0
  598. package/dist/run/dry-run-inputs.js +90 -0
  599. package/dist/run/dry-run.d.ts +6 -0
  600. package/dist/run/dry-run.js +362 -0
  601. package/dist/run/feedback-shape.d.ts +7 -0
  602. package/dist/run/feedback-shape.js +89 -0
  603. package/dist/run/git-state.d.ts +35 -0
  604. package/dist/run/git-state.js +316 -0
  605. package/dist/run/git-workspace.d.ts +32 -0
  606. package/dist/run/git-workspace.js +450 -0
  607. package/dist/run/judge.d.ts +210 -0
  608. package/dist/run/judge.js +240 -0
  609. package/dist/run/locate.d.ts +22 -0
  610. package/dist/run/locate.js +122 -0
  611. package/dist/run/outcomes.d.ts +31 -0
  612. package/dist/run/outcomes.js +210 -0
  613. package/dist/run/participant-records.d.ts +28 -0
  614. package/dist/run/participant-records.js +63 -0
  615. package/dist/run/participant.d.ts +29 -0
  616. package/dist/run/participant.js +12 -0
  617. package/dist/run/paths.d.ts +79 -0
  618. package/dist/run/paths.js +356 -0
  619. package/dist/run/preflight-receipts.d.ts +46 -0
  620. package/dist/run/preflight-receipts.js +173 -0
  621. package/dist/run/pricing.d.ts +124 -0
  622. package/dist/run/pricing.js +298 -0
  623. package/dist/run/project.d.ts +8 -0
  624. package/dist/run/project.js +103 -0
  625. package/dist/run/projection.d.ts +184 -0
  626. package/dist/run/projection.js +356 -0
  627. package/dist/run/reclaim.d.ts +41 -0
  628. package/dist/run/reclaim.js +183 -0
  629. package/dist/run/results.d.ts +88 -0
  630. package/dist/run/results.js +3 -0
  631. package/dist/run/run-index.d.ts +107 -0
  632. package/dist/run/run-index.js +243 -0
  633. package/dist/run/run.d.ts +103 -0
  634. package/dist/run/run.js +199 -0
  635. package/dist/run/sandbox-receipts.d.ts +31 -0
  636. package/dist/run/sandbox-receipts.js +49 -0
  637. package/dist/run/shared-world-evidence.d.ts +220 -0
  638. package/dist/run/shared-world-evidence.js +49 -0
  639. package/dist/run/shared-world-shape.d.ts +26 -0
  640. package/dist/run/shared-world-shape.js +181 -0
  641. package/dist/run/stats.d.ts +82 -0
  642. package/dist/run/stats.js +258 -0
  643. package/dist/run/status.d.ts +111 -0
  644. package/dist/run/status.js +176 -0
  645. package/dist/run/stored-runs.d.ts +38 -0
  646. package/dist/run/stored-runs.js +273 -0
  647. package/dist/run/stream-shape.d.ts +4 -0
  648. package/dist/run/stream-shape.js +160 -0
  649. package/dist/run/streams.d.ts +257 -0
  650. package/dist/run/streams.js +12 -0
  651. package/dist/run/study-files.d.ts +35 -0
  652. package/dist/run/study-files.js +164 -0
  653. package/dist/run/terminal-contract.d.ts +25 -0
  654. package/dist/run/terminal-contract.js +47 -0
  655. package/dist/run/text.d.ts +2 -0
  656. package/dist/run/text.js +4 -0
  657. package/dist/run/transient-comms-secrets.js +72 -0
  658. package/dist/run/type-guards.d.ts +6 -0
  659. package/dist/run/type-guards.js +18 -0
  660. package/dist/run-lab.d.ts +110 -0
  661. package/dist/run-lab.js +148 -0
  662. package/dist/subject/clone.d.ts +37 -0
  663. package/dist/subject/clone.js +62 -0
  664. package/dist/subject/desktop-cli.d.ts +17 -0
  665. package/dist/subject/desktop-cli.js +51 -0
  666. package/dist/subject/local-tree-archive.d.ts +82 -0
  667. package/dist/subject/local-tree-archive.js +431 -0
  668. package/dist/subject/local-tree.d.ts +28 -0
  669. package/dist/subject/local-tree.js +58 -0
  670. package/dist/subject/node-bootstrap.d.ts +12 -0
  671. package/dist/subject/node-bootstrap.js +66 -0
  672. package/dist/subject/runtime.d.ts +13 -0
  673. package/dist/subject/runtime.js +50 -0
  674. package/dist/subject/serve.d.ts +39 -0
  675. package/dist/subject/serve.js +249 -0
  676. package/dist/subject/state.d.ts +23 -0
  677. package/dist/subject/state.js +58 -0
  678. package/dist/subject/steps.d.ts +37 -0
  679. package/dist/subject/steps.js +39 -0
  680. package/dist/substrates/command-failure.d.ts +23 -0
  681. package/dist/substrates/command-failure.js +45 -0
  682. package/dist/substrates/desktop-session.d.ts +41 -0
  683. package/dist/substrates/desktop-session.js +59 -0
  684. package/dist/substrates/detached.d.ts +55 -0
  685. package/dist/substrates/detached.js +139 -0
  686. package/dist/substrates/e2b/cdp-probe.d.ts +99 -0
  687. package/dist/substrates/e2b/cdp-probe.js +556 -0
  688. package/dist/substrates/e2b/desktop-browser.d.ts +81 -0
  689. package/dist/substrates/e2b/desktop-browser.js +410 -0
  690. package/dist/substrates/e2b/desktop-cdp.d.ts +77 -0
  691. package/dist/substrates/e2b/desktop-cdp.js +211 -0
  692. package/dist/substrates/e2b/desktop-executor.d.ts +92 -0
  693. package/dist/substrates/e2b/desktop-executor.js +302 -0
  694. package/dist/substrates/e2b/desktop-geometry.d.ts +83 -0
  695. package/dist/substrates/e2b/desktop-geometry.js +331 -0
  696. package/dist/substrates/e2b/desktop-media.d.ts +29 -0
  697. package/dist/substrates/e2b/desktop-media.js +151 -0
  698. package/dist/substrates/e2b/desktop-recording.d.ts +18 -0
  699. package/dist/substrates/e2b/desktop-recording.js +238 -0
  700. package/dist/substrates/e2b/desktop-resources.d.ts +11 -0
  701. package/dist/substrates/e2b/desktop-resources.js +35 -0
  702. package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +15 -0
  703. package/dist/substrates/e2b/desktop-screenshot-cleanup.js +66 -0
  704. package/dist/substrates/e2b/lifetime.d.ts +12 -0
  705. package/dist/substrates/e2b/lifetime.js +18 -0
  706. package/dist/substrates/e2b/sandbox.d.ts +102 -0
  707. package/dist/substrates/e2b/sandbox.js +202 -0
  708. package/dist/substrates/e2b/sdk.d.ts +194 -0
  709. package/dist/substrates/e2b/sdk.js +168 -0
  710. package/dist/substrates/e2b/shell.d.ts +10 -0
  711. package/dist/substrates/e2b/shell.js +61 -0
  712. package/dist/substrates/local/captured-inbox.d.ts +6 -0
  713. package/dist/substrates/local/captured-inbox.js +87 -0
  714. package/dist/substrates/local/firecracker-desktop.d.ts +25 -0
  715. package/dist/substrates/local/firecracker-desktop.js +315 -0
  716. package/dist/substrates/local/runtime-config.d.ts +6 -0
  717. package/dist/substrates/local/runtime-config.js +91 -0
  718. package/dist/substrates/local/runtime-host.d.ts +30 -0
  719. package/dist/substrates/local/runtime-host.js +143 -0
  720. package/dist/substrates/local/runtime-release.d.ts +5 -0
  721. package/dist/substrates/local/runtime-release.js +32 -0
  722. package/dist/substrates/local/runtime-ssh.d.ts +9 -0
  723. package/dist/substrates/local/runtime-ssh.js +129 -0
  724. package/dist/substrates/local/runtime.d.ts +25 -0
  725. package/dist/substrates/local/runtime.js +190 -0
  726. package/dist/substrates/shell.d.ts +44 -0
  727. package/dist/substrates/shell.js +22 -0
  728. package/dist/tui/actions.d.ts +39 -0
  729. package/dist/tui/actions.js +203 -0
  730. package/dist/tui/contract.d.ts +144 -0
  731. package/dist/tui/contract.js +52 -0
  732. package/dist/tui/launch.js +172 -0
  733. package/dist/tui/project.d.ts +10 -0
  734. package/dist/tui/project.js +17 -0
  735. package/dist/tui-app.js +125 -125
  736. package/dist/verify/actor.d.ts +27 -0
  737. package/dist/verify/actor.js +292 -0
  738. package/dist/verify/artifacts.d.ts +47 -0
  739. package/dist/verify/artifacts.js +373 -0
  740. package/dist/verify/costs.d.ts +30 -0
  741. package/dist/verify/costs.js +129 -0
  742. package/dist/verify/liveness.d.ts +7 -0
  743. package/dist/verify/liveness.js +72 -0
  744. package/dist/verify/rerun.d.ts +3 -0
  745. package/dist/verify/rerun.js +46 -0
  746. package/dist/verify/shared-world-concurrent.d.ts +11 -0
  747. package/dist/verify/shared-world-concurrent.js +346 -0
  748. package/dist/verify/shared-world.d.ts +8 -0
  749. package/dist/verify/shared-world.js +295 -0
  750. package/dist/verify/subject.d.ts +17 -0
  751. package/dist/verify/subject.js +123 -0
  752. package/dist/verify/verify.d.ts +34 -0
  753. package/dist/verify/verify.js +333 -0
  754. package/docs/README.md +67 -0
  755. package/docs/architecture/actor-contract.md +215 -174
  756. package/docs/architecture/browser-control.md +51 -37
  757. package/docs/architecture/comms-inbox.md +8 -8
  758. package/docs/architecture/desktop-recording.md +2 -2
  759. package/docs/architecture/desktop-sessions.md +33 -21
  760. package/docs/architecture/external-public-shared-world.md +80 -64
  761. package/docs/architecture/github-feedback-loop.md +40 -27
  762. package/docs/architecture/guest-desktop.md +22 -10
  763. package/docs/architecture/local-browser-runtime.md +30 -21
  764. package/docs/architecture/observer-review.md +9 -9
  765. package/docs/architecture/observer.md +53 -57
  766. package/docs/architecture/participant-media.md +3 -3
  767. package/docs/architecture/project-layout.md +33 -137
  768. package/docs/architecture/real-email-receiving.md +7 -6
  769. package/docs/architecture/restricted-codex-analysis.md +211 -25
  770. package/docs/architecture/serve.md +89 -87
  771. package/docs/architecture/state-driven-executor.md +79 -64
  772. package/docs/architecture/task-protocol-support.md +18 -18
  773. package/docs/architecture/terminal-product-lane.md +92 -86
  774. package/docs/contracts/adapter-admission.md +8 -4
  775. package/docs/contracts/adapter-fixtures.md +6 -6
  776. package/docs/contracts/core.md +22 -24
  777. package/docs/contracts/feedback.md +33 -23
  778. package/docs/contracts/policy.md +28 -31
  779. package/docs/contracts/run-bundle.md +168 -82
  780. package/docs/contracts/schemas.md +594 -379
  781. package/docs/contracts/study-analysis.md +2 -2
  782. package/docs/contracts/study-costs.md +12 -12
  783. package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +36 -0
  784. package/docs/decisions/0002-observer-is-one-self-contained-file.md +30 -0
  785. package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +35 -0
  786. package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +31 -0
  787. package/docs/decisions/README.md +16 -0
  788. package/docs/goals/current.md +22 -46
  789. package/docs/principles/actor-fidelity.md +51 -63
  790. package/docs/principles/engineering.md +81 -0
  791. package/docs/principles/invariants-and-defaults.md +48 -45
  792. package/docs/principles/self-driving-harness.md +11 -10
  793. package/docs/principles/three-roles.md +12 -13
  794. package/docs/product/automatic-analysis.md +39 -9
  795. package/docs/product/lobby-trivia-3player-external-public.md +14 -13
  796. package/docs/product/open-source-install-experience.md +34 -38
  797. package/docs/ramp/README.md +91 -213
  798. package/docs/release/open-source-readiness.md +5 -2
  799. package/docs/release/public-readiness-standard.md +1 -1
  800. package/examples/README.md +11 -0
  801. package/examples/participant/README.md +80 -0
  802. package/examples/participant/app.mjs +55 -0
  803. package/examples/participant/run.mjs +116 -0
  804. package/examples/scorer/README.md +29 -0
  805. package/examples/scorer/run.mjs +63 -0
  806. package/examples/scorer/scorer.mjs +20 -0
  807. package/package.json +61 -57
  808. package/skills/humanish/SKILL.md +112 -83
  809. package/skills/humanish/agents/openai.yaml +2 -2
  810. package/dist/actor-contract.d.ts +0 -288
  811. package/dist/actor-contract.js +0 -340
  812. package/dist/actor-contract.js.map +0 -1
  813. package/dist/actor-goal-source.js +0 -32
  814. package/dist/actor-goal-source.js.map +0 -1
  815. package/dist/actor-registry.d.ts +0 -77
  816. package/dist/actor-registry.js +0 -106
  817. package/dist/actor-registry.js.map +0 -1
  818. package/dist/actor-stop-cause.d.ts +0 -9
  819. package/dist/actor-stop-cause.js +0 -42
  820. package/dist/actor-stop-cause.js.map +0 -1
  821. package/dist/adapter-extension.d.ts +0 -76
  822. package/dist/adapter-extension.js +0 -273
  823. package/dist/adapter-extension.js.map +0 -1
  824. package/dist/adapter-scorer-loader.d.ts +0 -42
  825. package/dist/adapter-scorer-loader.js +0 -129
  826. package/dist/adapter-scorer-loader.js.map +0 -1
  827. package/dist/affordance.d.ts +0 -53
  828. package/dist/affordance.js +0 -145
  829. package/dist/affordance.js.map +0 -1
  830. package/dist/agent-session.js +0 -43
  831. package/dist/agent-session.js.map +0 -1
  832. package/dist/argv.d.ts +0 -1
  833. package/dist/argv.js +0 -8
  834. package/dist/argv.js.map +0 -1
  835. package/dist/artifact-reference.d.ts +0 -22
  836. package/dist/artifact-reference.js +0 -47
  837. package/dist/artifact-reference.js.map +0 -1
  838. package/dist/automatic-analysis-completion.d.ts +0 -25
  839. package/dist/automatic-analysis-completion.js +0 -56
  840. package/dist/automatic-analysis-completion.js.map +0 -1
  841. package/dist/automatic-analysis-config.d.ts +0 -38
  842. package/dist/automatic-analysis-config.js +0 -68
  843. package/dist/automatic-analysis-config.js.map +0 -1
  844. package/dist/automatic-study-analysis.d.ts +0 -17
  845. package/dist/automatic-study-analysis.js +0 -195
  846. package/dist/automatic-study-analysis.js.map +0 -1
  847. package/dist/browser-control-client.d.ts +0 -18
  848. package/dist/browser-control-client.js +0 -176
  849. package/dist/browser-control-client.js.map +0 -1
  850. package/dist/browser-control-dispatcher.d.ts +0 -19
  851. package/dist/browser-control-dispatcher.js +0 -147
  852. package/dist/browser-control-dispatcher.js.map +0 -1
  853. package/dist/browser-control-protocol.d.ts +0 -472
  854. package/dist/browser-control-protocol.js +0 -185
  855. package/dist/browser-control-protocol.js.map +0 -1
  856. package/dist/browser-control-recording-transfer.d.ts +0 -4
  857. package/dist/browser-control-recording-transfer.js +0 -42
  858. package/dist/browser-control-recording-transfer.js.map +0 -1
  859. package/dist/browser-control-transport.d.ts +0 -27
  860. package/dist/browser-control-transport.js +0 -177
  861. package/dist/browser-control-transport.js.map +0 -1
  862. package/dist/browser-evidence-hygiene.js +0 -43
  863. package/dist/browser-evidence-hygiene.js.map +0 -1
  864. package/dist/chrome-cdp-probe.d.ts +0 -97
  865. package/dist/chrome-cdp-probe.js +0 -536
  866. package/dist/chrome-cdp-probe.js.map +0 -1
  867. package/dist/claude-agent-sdk.d.ts +0 -94
  868. package/dist/claude-agent-sdk.js +0 -367
  869. package/dist/claude-agent-sdk.js.map +0 -1
  870. package/dist/cli.js.map +0 -1
  871. package/dist/codex-app-server-ui.d.ts +0 -39
  872. package/dist/codex-app-server-ui.js +0 -357
  873. package/dist/codex-app-server-ui.js.map +0 -1
  874. package/dist/codex-app-server.d.ts +0 -144
  875. package/dist/codex-app-server.js +0 -754
  876. package/dist/codex-app-server.js.map +0 -1
  877. package/dist/command-failure.d.ts +0 -43
  878. package/dist/command-failure.js +0 -73
  879. package/dist/command-failure.js.map +0 -1
  880. package/dist/comms-agentmail.d.ts +0 -25
  881. package/dist/comms-agentmail.js +0 -418
  882. package/dist/comms-agentmail.js.map +0 -1
  883. package/dist/comms-catch-host.d.ts +0 -52
  884. package/dist/comms-catch-host.js +0 -178
  885. package/dist/comms-catch-host.js.map +0 -1
  886. package/dist/comms-connections.d.ts +0 -52
  887. package/dist/comms-connections.js +0 -123
  888. package/dist/comms-connections.js.map +0 -1
  889. package/dist/comms-email-catch.d.ts +0 -54
  890. package/dist/comms-email-catch.js +0 -212
  891. package/dist/comms-email-catch.js.map +0 -1
  892. package/dist/comms-evidence.d.ts +0 -27
  893. package/dist/comms-evidence.js +0 -31
  894. package/dist/comms-evidence.js.map +0 -1
  895. package/dist/comms-fake-inbox.d.ts +0 -45
  896. package/dist/comms-fake-inbox.js +0 -184
  897. package/dist/comms-fake-inbox.js.map +0 -1
  898. package/dist/comms-images.d.ts +0 -7
  899. package/dist/comms-images.js +0 -39
  900. package/dist/comms-images.js.map +0 -1
  901. package/dist/comms-inbox.d.ts +0 -66
  902. package/dist/comms-inbox.js +0 -389
  903. package/dist/comms-inbox.js.map +0 -1
  904. package/dist/comms-lease-store.d.ts +0 -91
  905. package/dist/comms-lease-store.js +0 -495
  906. package/dist/comms-lease-store.js.map +0 -1
  907. package/dist/comms-receiving-evidence.d.ts +0 -46
  908. package/dist/comms-receiving-evidence.js +0 -35
  909. package/dist/comms-receiving-evidence.js.map +0 -1
  910. package/dist/comms-receiving-inbox.d.ts +0 -16
  911. package/dist/comms-receiving-inbox.js +0 -410
  912. package/dist/comms-receiving-inbox.js.map +0 -1
  913. package/dist/comms-receiving-runtime.d.ts +0 -25
  914. package/dist/comms-receiving-runtime.js +0 -45
  915. package/dist/comms-receiving-runtime.js.map +0 -1
  916. package/dist/comms-receiving-types.d.ts +0 -98
  917. package/dist/comms-receiving-types.js +0 -2
  918. package/dist/comms-receiving-types.js.map +0 -1
  919. package/dist/comms-receiving.d.ts +0 -58
  920. package/dist/comms-receiving.js +0 -554
  921. package/dist/comms-receiving.js.map +0 -1
  922. package/dist/comms-sandbox-catch.d.ts +0 -229
  923. package/dist/comms-sandbox-catch.js +0 -737
  924. package/dist/comms-sandbox-catch.js.map +0 -1
  925. package/dist/comms-setup.d.ts +0 -40
  926. package/dist/comms-setup.js +0 -121
  927. package/dist/comms-setup.js.map +0 -1
  928. package/dist/comms-types.d.ts +0 -72
  929. package/dist/comms-types.js +0 -10
  930. package/dist/comms-types.js.map +0 -1
  931. package/dist/computer-use-actor.d.ts +0 -76
  932. package/dist/computer-use-actor.js +0 -68
  933. package/dist/computer-use-actor.js.map +0 -1
  934. package/dist/computer-use.d.ts +0 -429
  935. package/dist/computer-use.js +0 -1749
  936. package/dist/computer-use.js.map +0 -1
  937. package/dist/concurrency.js +0 -27
  938. package/dist/concurrency.js.map +0 -1
  939. package/dist/concurrent-shared-world-lab.d.ts +0 -186
  940. package/dist/concurrent-shared-world-lab.js +0 -2179
  941. package/dist/concurrent-shared-world-lab.js.map +0 -1
  942. package/dist/core/git-state.d.ts +0 -33
  943. package/dist/core/git-state.js +0 -277
  944. package/dist/core/git-state.js.map +0 -1
  945. package/dist/core/git-workspace.d.ts +0 -31
  946. package/dist/core/git-workspace.js +0 -447
  947. package/dist/core/git-workspace.js.map +0 -1
  948. package/dist/core/index.d.ts +0 -4
  949. package/dist/core/index.js +0 -3
  950. package/dist/core/index.js.map +0 -1
  951. package/dist/core/run-primitives.d.ts +0 -66
  952. package/dist/core/run-primitives.js +0 -120
  953. package/dist/core/run-primitives.js.map +0 -1
  954. package/dist/cua-actor-lab.d.ts +0 -855
  955. package/dist/cua-actor-lab.js +0 -3545
  956. package/dist/cua-actor-lab.js.map +0 -1
  957. package/dist/cua-admission-limit.d.ts +0 -12
  958. package/dist/cua-admission-limit.js +0 -20
  959. package/dist/cua-admission-limit.js.map +0 -1
  960. package/dist/cua-desktop-lane.d.ts +0 -35
  961. package/dist/cua-desktop-lane.js +0 -13
  962. package/dist/cua-desktop-lane.js.map +0 -1
  963. package/dist/cua-diagnostics.d.ts +0 -38
  964. package/dist/cua-diagnostics.js +0 -68
  965. package/dist/cua-diagnostics.js.map +0 -1
  966. package/dist/cua-executor-error.js +0 -48
  967. package/dist/cua-executor-error.js.map +0 -1
  968. package/dist/cua-provider-error.d.ts +0 -16
  969. package/dist/cua-provider-error.js +0 -35
  970. package/dist/cua-provider-error.js.map +0 -1
  971. package/dist/cua-speech.js +0 -2
  972. package/dist/cua-speech.js.map +0 -1
  973. package/dist/desktop-recorder.d.ts +0 -39
  974. package/dist/desktop-recorder.js +0 -226
  975. package/dist/desktop-recorder.js.map +0 -1
  976. package/dist/desktop-recording-artifact.d.ts +0 -5
  977. package/dist/desktop-recording-artifact.js +0 -54
  978. package/dist/desktop-recording-artifact.js.map +0 -1
  979. package/dist/desktop-recording-types.d.ts +0 -24
  980. package/dist/desktop-recording-types.js +0 -14
  981. package/dist/desktop-recording-types.js.map +0 -1
  982. package/dist/desktop-session.d.ts +0 -41
  983. package/dist/desktop-session.js +0 -47
  984. package/dist/desktop-session.js.map +0 -1
  985. package/dist/device-presets.d.ts +0 -67
  986. package/dist/device-presets.js +0 -55
  987. package/dist/device-presets.js.map +0 -1
  988. package/dist/doctor-lab.d.ts +0 -38
  989. package/dist/doctor-lab.js +0 -126
  990. package/dist/doctor-lab.js.map +0 -1
  991. package/dist/e2b-cua-desktop.d.ts +0 -3
  992. package/dist/e2b-cua-desktop.js +0 -708
  993. package/dist/e2b-cua-desktop.js.map +0 -1
  994. package/dist/e2b-cua-provisioning.d.ts +0 -314
  995. package/dist/e2b-cua-provisioning.js +0 -1219
  996. package/dist/e2b-cua-provisioning.js.map +0 -1
  997. package/dist/e2b-desktop-executor.d.ts +0 -101
  998. package/dist/e2b-desktop-executor.js +0 -297
  999. package/dist/e2b-desktop-executor.js.map +0 -1
  1000. package/dist/e2b-desktop-launch.d.ts +0 -243
  1001. package/dist/e2b-desktop-launch.js +0 -234
  1002. package/dist/e2b-desktop-launch.js.map +0 -1
  1003. package/dist/e2b-desktop-media.d.ts +0 -14
  1004. package/dist/e2b-desktop-media.js +0 -58
  1005. package/dist/e2b-desktop-media.js.map +0 -1
  1006. package/dist/e2b-desktop-recording.d.ts +0 -16
  1007. package/dist/e2b-desktop-recording.js +0 -162
  1008. package/dist/e2b-desktop-recording.js.map +0 -1
  1009. package/dist/e2b-desktop-resources.d.ts +0 -11
  1010. package/dist/e2b-desktop-resources.js +0 -33
  1011. package/dist/e2b-desktop-resources.js.map +0 -1
  1012. package/dist/e2b-desktop-screenshot-cleanup.d.ts +0 -15
  1013. package/dist/e2b-desktop-screenshot-cleanup.js +0 -67
  1014. package/dist/e2b-desktop-screenshot-cleanup.js.map +0 -1
  1015. package/dist/e2b-desktop-session.d.ts +0 -7
  1016. package/dist/e2b-desktop-session.js +0 -29
  1017. package/dist/e2b-desktop-session.js.map +0 -1
  1018. package/dist/e2b-detached.d.ts +0 -53
  1019. package/dist/e2b-detached.js +0 -130
  1020. package/dist/e2b-detached.js.map +0 -1
  1021. package/dist/e2b-terminal-lab.d.ts +0 -395
  1022. package/dist/e2b-terminal-lab.js +0 -2041
  1023. package/dist/e2b-terminal-lab.js.map +0 -1
  1024. package/dist/env-file.d.ts +0 -14
  1025. package/dist/env-file.js +0 -108
  1026. package/dist/env-file.js.map +0 -1
  1027. package/dist/export-bundle.d.ts +0 -7
  1028. package/dist/export-bundle.js +0 -441
  1029. package/dist/export-bundle.js.map +0 -1
  1030. package/dist/export.d.ts +0 -49
  1031. package/dist/export.js +0 -308
  1032. package/dist/export.js.map +0 -1
  1033. package/dist/feedback-proof.d.ts +0 -8
  1034. package/dist/feedback-proof.js +0 -44
  1035. package/dist/feedback-proof.js.map +0 -1
  1036. package/dist/feedback.d.ts +0 -76
  1037. package/dist/feedback.js +0 -496
  1038. package/dist/feedback.js.map +0 -1
  1039. package/dist/first-run-path.d.ts +0 -55
  1040. package/dist/first-run-path.js +0 -136
  1041. package/dist/first-run-path.js.map +0 -1
  1042. package/dist/frame-signature.d.ts +0 -24
  1043. package/dist/frame-signature.js +0 -128
  1044. package/dist/frame-signature.js.map +0 -1
  1045. package/dist/guest-bootstrap.d.ts +0 -55
  1046. package/dist/guest-bootstrap.js +0 -285
  1047. package/dist/guest-bootstrap.js.map +0 -1
  1048. package/dist/guest-browser-tools.d.ts +0 -8
  1049. package/dist/guest-browser-tools.js +0 -66
  1050. package/dist/guest-browser-tools.js.map +0 -1
  1051. package/dist/guest-chromium-text.d.ts +0 -27
  1052. package/dist/guest-chromium-text.js +0 -281
  1053. package/dist/guest-chromium-text.js.map +0 -1
  1054. package/dist/guest-desktop-executor.d.ts +0 -22
  1055. package/dist/guest-desktop-executor.js +0 -178
  1056. package/dist/guest-desktop-executor.js.map +0 -1
  1057. package/dist/guest-desktop-media.d.ts +0 -33
  1058. package/dist/guest-desktop-media.js +0 -281
  1059. package/dist/guest-desktop-media.js.map +0 -1
  1060. package/dist/guest-desktop-native.d.ts +0 -14
  1061. package/dist/guest-desktop-native.js +0 -131
  1062. package/dist/guest-desktop-native.js.map +0 -1
  1063. package/dist/guest-media-config.d.ts +0 -15
  1064. package/dist/guest-media-config.js +0 -8
  1065. package/dist/guest-media-config.js.map +0 -1
  1066. package/dist/guest-media-worker.js.map +0 -1
  1067. package/dist/guest-runtime-desktop.d.ts +0 -42
  1068. package/dist/guest-runtime-desktop.js +0 -314
  1069. package/dist/guest-runtime-desktop.js.map +0 -1
  1070. package/dist/guest-runtime-main.js.map +0 -1
  1071. package/dist/guest-runtime-revision.js.map +0 -1
  1072. package/dist/guest-runtime.d.ts +0 -31
  1073. package/dist/guest-runtime.js +0 -99
  1074. package/dist/guest-runtime.js.map +0 -1
  1075. package/dist/image-evidence.d.ts +0 -2
  1076. package/dist/image-evidence.js +0 -47
  1077. package/dist/image-evidence.js.map +0 -1
  1078. package/dist/index.js.map +0 -1
  1079. package/dist/init-templates.d.ts +0 -25
  1080. package/dist/init-templates.js +0 -542
  1081. package/dist/init-templates.js.map +0 -1
  1082. package/dist/init.d.ts +0 -38
  1083. package/dist/init.js +0 -532
  1084. package/dist/init.js.map +0 -1
  1085. package/dist/key-resolution.d.ts +0 -67
  1086. package/dist/key-resolution.js +0 -375
  1087. package/dist/key-resolution.js.map +0 -1
  1088. package/dist/lab-app-runner.d.ts +0 -78
  1089. package/dist/lab-app-runner.js +0 -403
  1090. package/dist/lab-app-runner.js.map +0 -1
  1091. package/dist/lab-config.d.ts +0 -968
  1092. package/dist/lab-config.js +0 -2714
  1093. package/dist/lab-config.js.map +0 -1
  1094. package/dist/lab-engine.d.ts +0 -97
  1095. package/dist/lab-engine.js +0 -285
  1096. package/dist/lab-engine.js.map +0 -1
  1097. package/dist/lab-preflight.d.ts +0 -70
  1098. package/dist/lab-preflight.js +0 -388
  1099. package/dist/lab-preflight.js.map +0 -1
  1100. package/dist/lab-summary.d.ts +0 -57
  1101. package/dist/lab-summary.js +0 -126
  1102. package/dist/lab-summary.js.map +0 -1
  1103. package/dist/labs.d.ts +0 -59
  1104. package/dist/labs.js +0 -385
  1105. package/dist/labs.js.map +0 -1
  1106. package/dist/listen.js +0 -84
  1107. package/dist/listen.js.map +0 -1
  1108. package/dist/local-agent-claude-session.d.ts +0 -45
  1109. package/dist/local-agent-claude-session.js +0 -203
  1110. package/dist/local-agent-claude-session.js.map +0 -1
  1111. package/dist/local-agent-cli.d.ts +0 -121
  1112. package/dist/local-agent-cli.js +0 -427
  1113. package/dist/local-agent-cli.js.map +0 -1
  1114. package/dist/local-captured-inbox.d.ts +0 -6
  1115. package/dist/local-captured-inbox.js +0 -65
  1116. package/dist/local-captured-inbox.js.map +0 -1
  1117. package/dist/local-firecracker-desktop.d.ts +0 -23
  1118. package/dist/local-firecracker-desktop.js +0 -191
  1119. package/dist/local-firecracker-desktop.js.map +0 -1
  1120. package/dist/local-firecracker-study.d.ts +0 -9
  1121. package/dist/local-firecracker-study.js +0 -135
  1122. package/dist/local-firecracker-study.js.map +0 -1
  1123. package/dist/local-runtime-config.d.ts +0 -6
  1124. package/dist/local-runtime-config.js +0 -60
  1125. package/dist/local-runtime-config.js.map +0 -1
  1126. package/dist/local-runtime-host.d.ts +0 -31
  1127. package/dist/local-runtime-host.js +0 -128
  1128. package/dist/local-runtime-host.js.map +0 -1
  1129. package/dist/local-runtime-release.d.ts +0 -7
  1130. package/dist/local-runtime-release.js +0 -33
  1131. package/dist/local-runtime-release.js.map +0 -1
  1132. package/dist/local-runtime-ssh.d.ts +0 -27
  1133. package/dist/local-runtime-ssh.js +0 -91
  1134. package/dist/local-runtime-ssh.js.map +0 -1
  1135. package/dist/local-runtime.d.ts +0 -25
  1136. package/dist/local-runtime.js +0 -133
  1137. package/dist/local-runtime.js.map +0 -1
  1138. package/dist/observer-data.d.ts +0 -114
  1139. package/dist/observer-data.js +0 -224
  1140. package/dist/observer-data.js.map +0 -1
  1141. package/dist/observer-library.js +0 -191
  1142. package/dist/observer-library.js.map +0 -1
  1143. package/dist/observer-serve.d.ts +0 -99
  1144. package/dist/observer-serve.js +0 -284
  1145. package/dist/observer-serve.js.map +0 -1
  1146. package/dist/observer-static.js +0 -357
  1147. package/dist/observer-static.js.map +0 -1
  1148. package/dist/observer.d.ts +0 -118
  1149. package/dist/observer.js +0 -947
  1150. package/dist/observer.js.map +0 -1
  1151. package/dist/openai-responses-cu.d.ts +0 -158
  1152. package/dist/openai-responses-cu.js +0 -714
  1153. package/dist/openai-responses-cu.js.map +0 -1
  1154. package/dist/orientation.d.ts +0 -29
  1155. package/dist/orientation.js +0 -95
  1156. package/dist/orientation.js.map +0 -1
  1157. package/dist/oss-lab.d.ts +0 -55
  1158. package/dist/oss-lab.js +0 -344
  1159. package/dist/oss-lab.js.map +0 -1
  1160. package/dist/oss-meta-lab-scoring.d.ts +0 -15
  1161. package/dist/oss-meta-lab-scoring.js +0 -145
  1162. package/dist/oss-meta-lab-scoring.js.map +0 -1
  1163. package/dist/oss-meta-lab.d.ts +0 -287
  1164. package/dist/oss-meta-lab.js +0 -4551
  1165. package/dist/oss-meta-lab.js.map +0 -1
  1166. package/dist/oss-remote-telemetry.d.ts +0 -77
  1167. package/dist/oss-remote-telemetry.js +0 -403
  1168. package/dist/oss-remote-telemetry.js.map +0 -1
  1169. package/dist/output-token-limit.js +0 -5
  1170. package/dist/output-token-limit.js.map +0 -1
  1171. package/dist/participant-assignment.d.ts +0 -12
  1172. package/dist/participant-assignment.js +0 -15
  1173. package/dist/participant-assignment.js.map +0 -1
  1174. package/dist/persona-resolve.d.ts +0 -44
  1175. package/dist/persona-resolve.js +0 -109
  1176. package/dist/persona-resolve.js.map +0 -1
  1177. package/dist/persona.d.ts +0 -35
  1178. package/dist/persona.js +0 -141
  1179. package/dist/persona.js.map +0 -1
  1180. package/dist/pi-agent-core.d.ts +0 -77
  1181. package/dist/pi-agent-core.js +0 -207
  1182. package/dist/pi-agent-core.js.map +0 -1
  1183. package/dist/pricing.d.ts +0 -145
  1184. package/dist/pricing.js +0 -277
  1185. package/dist/pricing.js.map +0 -1
  1186. package/dist/program.d.ts +0 -96
  1187. package/dist/program.js +0 -4029
  1188. package/dist/program.js.map +0 -1
  1189. package/dist/reasoning-effort.js +0 -26
  1190. package/dist/reasoning-effort.js.map +0 -1
  1191. package/dist/reclaim.d.ts +0 -31
  1192. package/dist/reclaim.js +0 -90
  1193. package/dist/reclaim.js.map +0 -1
  1194. package/dist/redaction.d.ts +0 -90
  1195. package/dist/redaction.js +0 -294
  1196. package/dist/redaction.js.map +0 -1
  1197. package/dist/restricted-codex-analysis.d.ts +0 -15
  1198. package/dist/restricted-codex-analysis.js +0 -13
  1199. package/dist/restricted-codex-analysis.js.map +0 -1
  1200. package/dist/restricted-codex-participant-policy.d.ts +0 -44
  1201. package/dist/restricted-codex-participant-policy.js +0 -43
  1202. package/dist/restricted-codex-participant-policy.js.map +0 -1
  1203. package/dist/restricted-codex-participant-run.d.ts +0 -20
  1204. package/dist/restricted-codex-participant-run.js +0 -79
  1205. package/dist/restricted-codex-participant-run.js.map +0 -1
  1206. package/dist/restricted-codex-participant.d.ts +0 -20
  1207. package/dist/restricted-codex-participant.js +0 -250
  1208. package/dist/restricted-codex-participant.js.map +0 -1
  1209. package/dist/restricted-codex-policy.d.ts +0 -64
  1210. package/dist/restricted-codex-policy.js +0 -176
  1211. package/dist/restricted-codex-policy.js.map +0 -1
  1212. package/dist/restricted-codex-session.d.ts +0 -44
  1213. package/dist/restricted-codex-session.js +0 -657
  1214. package/dist/restricted-codex-session.js.map +0 -1
  1215. package/dist/restricted-codex-transport.d.ts +0 -69
  1216. package/dist/restricted-codex-transport.js +0 -296
  1217. package/dist/restricted-codex-transport.js.map +0 -1
  1218. package/dist/run-detail.d.ts +0 -61
  1219. package/dist/run-detail.js +0 -137
  1220. package/dist/run-detail.js.map +0 -1
  1221. package/dist/run-index.d.ts +0 -71
  1222. package/dist/run-index.js +0 -206
  1223. package/dist/run-index.js.map +0 -1
  1224. package/dist/run-narration-secrets.js +0 -68
  1225. package/dist/run-narration-secrets.js.map +0 -1
  1226. package/dist/run-paths.d.ts +0 -56
  1227. package/dist/run-paths.js +0 -355
  1228. package/dist/run-paths.js.map +0 -1
  1229. package/dist/run-projection.d.ts +0 -186
  1230. package/dist/run-projection.js +0 -350
  1231. package/dist/run-projection.js.map +0 -1
  1232. package/dist/run-status.d.ts +0 -139
  1233. package/dist/run-status.js +0 -218
  1234. package/dist/run-status.js.map +0 -1
  1235. package/dist/run.d.ts +0 -1255
  1236. package/dist/run.js +0 -5947
  1237. package/dist/run.js.map +0 -1
  1238. package/dist/sandbox-receipts.d.ts +0 -19
  1239. package/dist/sandbox-receipts.js +0 -51
  1240. package/dist/sandbox-receipts.js.map +0 -1
  1241. package/dist/screenshot-image.d.ts +0 -11
  1242. package/dist/screenshot-image.js +0 -26
  1243. package/dist/screenshot-image.js.map +0 -1
  1244. package/dist/scripted-browser-actor.d.ts +0 -297
  1245. package/dist/scripted-browser-actor.js +0 -1399
  1246. package/dist/scripted-browser-actor.js.map +0 -1
  1247. package/dist/scripted-browser-lab.d.ts +0 -121
  1248. package/dist/scripted-browser-lab.js +0 -852
  1249. package/dist/scripted-browser-lab.js.map +0 -1
  1250. package/dist/secret-prompt.js +0 -36
  1251. package/dist/secret-prompt.js.map +0 -1
  1252. package/dist/selected-output-paths.d.ts +0 -52
  1253. package/dist/selected-output-paths.js +0 -366
  1254. package/dist/selected-output-paths.js.map +0 -1
  1255. package/dist/serve-exposure.d.ts +0 -62
  1256. package/dist/serve-exposure.js +0 -129
  1257. package/dist/serve-exposure.js.map +0 -1
  1258. package/dist/serve-http.js +0 -45
  1259. package/dist/serve-http.js.map +0 -1
  1260. package/dist/serve-tunnel.js +0 -113
  1261. package/dist/serve-tunnel.js.map +0 -1
  1262. package/dist/shared-world-lab.d.ts +0 -269
  1263. package/dist/shared-world-lab.js +0 -1422
  1264. package/dist/shared-world-lab.js.map +0 -1
  1265. package/dist/source-archive.d.ts +0 -82
  1266. package/dist/source-archive.js +0 -408
  1267. package/dist/source-archive.js.map +0 -1
  1268. package/dist/stats.d.ts +0 -82
  1269. package/dist/stats.js +0 -219
  1270. package/dist/stats.js.map +0 -1
  1271. package/dist/stop-conditions.d.ts +0 -39
  1272. package/dist/stop-conditions.js +0 -66
  1273. package/dist/stop-conditions.js.map +0 -1
  1274. package/dist/study-analysis-codex-config.d.ts +0 -11
  1275. package/dist/study-analysis-codex-config.js +0 -34
  1276. package/dist/study-analysis-codex-config.js.map +0 -1
  1277. package/dist/study-analysis-engine.d.ts +0 -47
  1278. package/dist/study-analysis-engine.js +0 -327
  1279. package/dist/study-analysis-engine.js.map +0 -1
  1280. package/dist/study-analysis-evidence.d.ts +0 -27
  1281. package/dist/study-analysis-evidence.js +0 -660
  1282. package/dist/study-analysis-evidence.js.map +0 -1
  1283. package/dist/study-analysis-job.d.ts +0 -97
  1284. package/dist/study-analysis-job.js +0 -214
  1285. package/dist/study-analysis-job.js.map +0 -1
  1286. package/dist/study-analysis-provider.d.ts +0 -40
  1287. package/dist/study-analysis-provider.js +0 -170
  1288. package/dist/study-analysis-provider.js.map +0 -1
  1289. package/dist/study-analysis-service.d.ts +0 -59
  1290. package/dist/study-analysis-service.js +0 -257
  1291. package/dist/study-analysis-service.js.map +0 -1
  1292. package/dist/study-analysis-sharing.d.ts +0 -11
  1293. package/dist/study-analysis-sharing.js +0 -35
  1294. package/dist/study-analysis-sharing.js.map +0 -1
  1295. package/dist/study-analysis-store.d.ts +0 -47
  1296. package/dist/study-analysis-store.js +0 -493
  1297. package/dist/study-analysis-store.js.map +0 -1
  1298. package/dist/study-analysis-validation.d.ts +0 -618
  1299. package/dist/study-analysis-validation.js +0 -384
  1300. package/dist/study-analysis-validation.js.map +0 -1
  1301. package/dist/study-analysis.d.ts +0 -206
  1302. package/dist/study-analysis.js +0 -4
  1303. package/dist/study-analysis.js.map +0 -1
  1304. package/dist/study-costs.js +0 -114
  1305. package/dist/study-costs.js.map +0 -1
  1306. package/dist/subject-runtime.d.ts +0 -23
  1307. package/dist/subject-runtime.js +0 -70
  1308. package/dist/subject-runtime.js.map +0 -1
  1309. package/dist/tasks.d.ts +0 -90
  1310. package/dist/tasks.js +0 -144
  1311. package/dist/tasks.js.map +0 -1
  1312. package/dist/telemetry.js +0 -324
  1313. package/dist/telemetry.js.map +0 -1
  1314. package/dist/terminal-agent-actor.d.ts +0 -41
  1315. package/dist/terminal-agent-actor.js +0 -25
  1316. package/dist/terminal-agent-actor.js.map +0 -1
  1317. package/dist/terminal-encoding.js +0 -80
  1318. package/dist/terminal-encoding.js.map +0 -1
  1319. package/dist/terminal-node-bootstrap.d.ts +0 -4
  1320. package/dist/terminal-node-bootstrap.js +0 -58
  1321. package/dist/terminal-node-bootstrap.js.map +0 -1
  1322. package/dist/terminal-participant-activity.d.ts +0 -6
  1323. package/dist/terminal-participant-activity.js +0 -34
  1324. package/dist/terminal-participant-activity.js.map +0 -1
  1325. package/dist/terminal-runtime-auth.d.ts +0 -13
  1326. package/dist/terminal-runtime-auth.js +0 -24
  1327. package/dist/terminal-runtime-auth.js.map +0 -1
  1328. package/dist/terminal-runtime.d.ts +0 -16
  1329. package/dist/terminal-runtime.js +0 -42
  1330. package/dist/terminal-runtime.js.map +0 -1
  1331. package/dist/terminal-token-usage.d.ts +0 -15
  1332. package/dist/terminal-token-usage.js +0 -94
  1333. package/dist/terminal-token-usage.js.map +0 -1
  1334. package/dist/tui-actions.d.ts +0 -39
  1335. package/dist/tui-actions.js +0 -178
  1336. package/dist/tui-actions.js.map +0 -1
  1337. package/dist/tui-contract.d.ts +0 -141
  1338. package/dist/tui-contract.js +0 -54
  1339. package/dist/tui-contract.js.map +0 -1
  1340. package/dist/tui-launch.js +0 -167
  1341. package/dist/tui-launch.js.map +0 -1
  1342. package/dist/tui-project.d.ts +0 -9
  1343. package/dist/tui-project.js +0 -18
  1344. package/dist/tui-project.js.map +0 -1
  1345. package/docs/architecture/examples/state-driven-local-app/README.md +0 -80
  1346. package/docs/architecture/examples/state-driven-local-app/app.mjs +0 -48
  1347. package/docs/architecture/examples/state-driven-local-app/runner.mjs +0 -105
  1348. package/docs/architecture/local-codex-tui-actor.md +0 -213
  1349. package/docs/architecture/oss-lab-poc.md +0 -250
  1350. package/docs/architecture/runtime-broker-core.md +0 -30
  1351. package/docs/release/0.100.0-local-setup.md +0 -31
  1352. package/docs/release/0.100.1-participant-continuity.md +0 -20
  1353. package/docs/release/0.101.0-codex-ui-tools.md +0 -28
  1354. package/docs/release/0.102.0-participant-media.md +0 -43
  1355. package/docs/release/0.103.0-desktop-recording.md +0 -29
  1356. package/docs/release/0.103.1-analysis-capture-allocation.md +0 -18
  1357. package/docs/release/0.103.2-analysis-ending-context.md +0 -21
  1358. package/docs/release/0.104.0-local-captured-inboxes.md +0 -29
  1359. package/docs/release/0.104.1-recording-startup.md +0 -24
  1360. package/docs/release/0.104.2-recording-timestamps.md +0 -32
  1361. package/docs/release/0.104.3-local-smtp-catch.md +0 -15
  1362. package/docs/release/0.20.0-external-public-shared-world.md +0 -43
  1363. package/docs/release/0.84.0-redacted-evidence.md +0 -42
  1364. package/docs/release/0.84.1-portable-feedback.md +0 -20
  1365. package/docs/release/0.85.0-observer-review.md +0 -56
  1366. package/docs/release/0.85.1-observer-continuity.md +0 -20
  1367. package/docs/release/0.86.0-participant-evidence.md +0 -50
  1368. package/docs/release/0.86.1-task-preflight-saved-recordings.md +0 -40
  1369. package/docs/release/0.87.0-participant-endings-and-phone-review.md +0 -64
  1370. package/docs/release/0.88.0-study-diagnostics.md +0 -43
  1371. package/docs/release/0.88.1-completion-evidence-and-local-app.md +0 -79
  1372. package/docs/release/0.88.2-sequential-study-budgets.md +0 -57
  1373. package/docs/release/0.89.0-study-findings.md +0 -79
  1374. package/docs/release/0.89.1-analysis-finished-notice.md +0 -24
  1375. package/docs/release/0.90.0-automatic-analysis.md +0 -21
  1376. package/docs/release/0.91.0-analysis-quality-and-defaults.md +0 -33
  1377. package/docs/release/0.91.1-study-review-polish.md +0 -28
  1378. package/docs/release/0.92.0-grid-playback.md +0 -22
  1379. package/docs/release/0.93.0-global-playback.md +0 -26
  1380. package/docs/release/0.93.1-observer-review-controls.md +0 -24
  1381. package/docs/release/0.94.0-reliability.md +0 -48
  1382. package/docs/release/0.95.0-connections-setup.md +0 -38
  1383. package/docs/release/0.96.0-real-email-receiving.md +0 -47
  1384. package/docs/release/0.96.1-browser-navigation.md +0 -22
  1385. package/docs/release/0.97.0-codex-account-analysis.md +0 -45
  1386. package/docs/release/0.98.0-local-browser-studies.md +0 -31
  1387. package/docs/release/0.99.0-local-browser-mac.md +0 -34
  1388. package/docs/release/0.99.1-action-recovery.md +0 -19
  1389. /package/dist/{agent-session.d.ts → actors/agent-session.d.ts} +0 -0
  1390. /package/dist/{cua-executor-error.d.ts → actors/computer-use/executor-error.d.ts} +0 -0
  1391. /package/dist/{cua-speech.d.ts → actors/computer-use/speech.d.ts} +0 -0
  1392. /package/dist/{actor-goal-source.d.ts → actors/goal-source.d.ts} +0 -0
  1393. /package/dist/{output-token-limit.d.ts → actors/output-token-limit.d.ts} +0 -0
  1394. /package/dist/{reasoning-effort.d.ts → actors/reasoning-effort.d.ts} +0 -0
  1395. /package/dist/{secret-prompt.d.ts → cli/secret-prompt.d.ts} +0 -0
  1396. /package/dist/{telemetry.d.ts → cli/telemetry.d.ts} +0 -0
  1397. /package/dist/{browser-evidence-hygiene.d.ts → evidence/browser-hygiene.d.ts} +0 -0
  1398. /package/dist/{serve-http.d.ts → observer/http.d.ts} +0 -0
  1399. /package/dist/{observer-library.d.ts → observer/library.d.ts} +0 -0
  1400. /package/dist/{listen.d.ts → observer/listen.d.ts} +0 -0
  1401. /package/dist/{observer-static.d.ts → observer/static.d.ts} +0 -0
  1402. /package/dist/{serve-tunnel.d.ts → observer/tunnel.d.ts} +0 -0
  1403. /package/dist/{terminal-encoding.d.ts → routes/terminal/encoding.d.ts} +0 -0
  1404. /package/dist/{concurrency.d.ts → run/concurrency.d.ts} +0 -0
  1405. /package/dist/{study-costs.d.ts → run/costs.d.ts} +0 -0
  1406. /package/dist/{run-narration-secrets.d.ts → run/transient-comms-secrets.d.ts} +0 -0
  1407. /package/dist/{tui-launch.d.ts → tui/launch.d.ts} +0 -0
@@ -1,4551 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { randomBytes } from "node:crypto";
3
- import { lstat, mkdir, readFile, readdir, realpath, rm, stat, writeFile } from "node:fs/promises";
4
- import path from "node:path";
5
- import { feedbackProofCommands } from "./feedback-proof.js";
6
- import { runDesktopCommandOrThrow } from "./command-failure.js";
7
- import { beginRunStatus, withRunStatusScope } from "./run-status.js";
8
- import { promisify } from "node:util";
9
- import { fileURLToPath } from "node:url";
10
- import { attachObserverRuntimeStreamUrls, renderObserver } from "./observer.js";
11
- import { loadE2BDesktopModule } from "./e2b-desktop-launch.js";
12
- import { DEFAULT_OSS_REPOS, normalizeOssRepoSlugs, repoSlug, validateOssRepoSlug } from "./oss-lab.js";
13
- import { redactOssRemoteTelemetryText } from "./oss-remote-telemetry.js";
14
- import { bindExistingRunArtifactPaths, prepareExclusiveHumanishStorageDirectory, prepareReusableHumanishStorageDirectory, validatePreparedRunArtifactPaths } from "./run-paths.js";
15
- import { writeContainedOutputFile } from "./selected-output-paths.js";
16
- import { buildRunSource, PUBLIC_TARGET_CWD, REVIEW_SCHEMA, RUN_BUNDLE_SCHEMA, runDryRun } from "./run.js";
17
- import { scoreOssMetaMeaningfulUse } from "./oss-meta-lab-scoring.js";
18
- export const OSS_META_LAB_SCHEMA = "humanish.oss-meta-lab-result.v1";
19
- const execFileAsync = promisify(execFile);
20
- const moduleRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
21
- const liveRuntimeByResult = new WeakMap();
22
- const OSS_META_LAB_PROVIDER_METADATA = {
23
- mode: "oss-meta-lab",
24
- tool: "humanish"
25
- };
26
- const OSS_META_LAB_REMOTE_ENV_NAMES = [
27
- "HUMANISH_OSS_META_ACTOR_FIRST",
28
- "HUMANISH_OSS_META_ACTOR_MODEL",
29
- "HUMANISH_OSS_META_HOST_CODEX_ACTOR",
30
- "HUMANISH_OSS_META_CODEX_APP_SERVER",
31
- "HUMANISH_OSS_META_ACTOR_TIMEOUT_MS",
32
- "HUMANISH_OSS_META_REQUIRE_ACTOR"
33
- ];
34
- const OSS_META_LAB_ACTOR_AUTH_PLACEHOLDER = "CODEX_API_KEY or CODEX_ACCESS_TOKEN";
35
- const OSS_META_LAB_ACTOR_PREFLIGHT_PLACEHOLDER = "Codex actor API quota/auth preflight";
36
- const OSS_META_LAB_HOST_ACTOR_PLACEHOLDER = "host Codex actor plan";
37
- export function buildOssRepoAssignments(repos, count) {
38
- return Array.from({ length: count }, (_, index) => {
39
- const repo = repos[index % repos.length];
40
- if (!repo) {
41
- throw new Error("At least one OSS repo is required.");
42
- }
43
- return {
44
- index: index + 1,
45
- repo,
46
- scenarioId: `oss-meta-${repoSlug(repo)}`,
47
- simId: `oss-${String(index + 1).padStart(2, "0")}`,
48
- streamId: `oss-${String(index + 1).padStart(2, "0")}-desktop`
49
- };
50
- });
51
- }
52
- export function collectOssMetaLabRemoteEnv(env) {
53
- const result = {};
54
- for (const name of OSS_META_LAB_REMOTE_ENV_NAMES) {
55
- const value = env[name]?.trim();
56
- if (value) {
57
- result[name] = value;
58
- }
59
- }
60
- return result;
61
- }
62
- function githubTokenFromEnv(env) {
63
- return env.GH_TOKEN?.trim() || env.GITHUB_TOKEN?.trim() || env.GITHUB_PAT?.trim() || "";
64
- }
65
- async function createGitHubAskPassEnv(root, env) {
66
- await mkdir(root, { recursive: true });
67
- const askPassPath = path.join(root, `git-askpass-${randomBytes(4).toString("hex")}.sh`);
68
- await writeFile(askPassPath, [
69
- "#!/usr/bin/env bash",
70
- "case \"$1\" in",
71
- " *Username*) echo \"x-access-token\" ;;",
72
- " *Password*) echo \"${HUMANISH_GITHUB_TOKEN_RUNTIME:-}\" ;;",
73
- " *) echo \"\" ;;",
74
- "esac",
75
- ""
76
- ].join("\n"), { encoding: "utf8", mode: 0o700 });
77
- const token = githubTokenFromEnv(env);
78
- return {
79
- ...gitCredentialIsolatedEnv(env),
80
- GIT_ASKPASS: askPassPath,
81
- GIT_TERMINAL_PROMPT: "0",
82
- ...(token ? { HUMANISH_GITHUB_TOKEN_RUNTIME: token } : {})
83
- };
84
- }
85
- function gitEnvWithoutGitHubToken(env) {
86
- return {
87
- ...gitCredentialIsolatedEnv(env),
88
- GIT_ASKPASS: "false",
89
- SSH_ASKPASS: "false",
90
- GIT_TERMINAL_PROMPT: "0"
91
- };
92
- }
93
- function gitCredentialIsolatedEnv(env) {
94
- const isolated = { ...env };
95
- for (const key of Object.keys(isolated)) {
96
- if (key.startsWith("GIT_CONFIG_")) {
97
- delete isolated[key];
98
- }
99
- }
100
- delete isolated.GH_TOKEN;
101
- delete isolated.GITHUB_PAT;
102
- delete isolated.GITHUB_TOKEN;
103
- delete isolated.GIT_ASKPASS;
104
- delete isolated.HUMANISH_GITHUB_TOKEN_RUNTIME;
105
- delete isolated.SSH_ASKPASS;
106
- return {
107
- ...isolated,
108
- GIT_CONFIG_GLOBAL: "/dev/null",
109
- GIT_CONFIG_NOSYSTEM: "1",
110
- GIT_TERMINAL_PROMPT: "0"
111
- };
112
- }
113
- async function runGitRepoAccessProbe(execImpl, cwd, repoUrl, env, sourceEnv) {
114
- await execImpl("git", ["-c", "credential.helper=", "ls-remote", "--exit-code", repoUrl, "HEAD"], {
115
- cwd,
116
- env,
117
- maxBuffer: 256 * 1024,
118
- timeout: readPositiveInt(sourceEnv.HUMANISH_OSS_META_REPO_PREFLIGHT_TIMEOUT_MS, 45_000)
119
- });
120
- }
121
- export async function preflightOssMetaRepoAccess(args) {
122
- const execImpl = args.execFileImpl ?? execFileAsync;
123
- const tokenPresent = Boolean(githubTokenFromEnv(args.env));
124
- const rootId = `repo-access-${randomBytes(4).toString("hex")}`;
125
- const preparedRoot = await prepareExclusiveHumanishStorageDirectory(args.cwd, "tmp", rootId);
126
- const root = await pinCleanupDirectory(preparedRoot);
127
- try {
128
- await mkdir(root.physicalPath, { recursive: true });
129
- const tokenGitEnv = tokenPresent ? await createGitHubAskPassEnv(root.physicalPath, args.env) : undefined;
130
- const anonymousGitEnv = gitEnvWithoutGitHubToken(args.env);
131
- const results = [];
132
- for (const assignment of args.assignments) {
133
- const repoUrl = `https://github.com/${assignment.repo}.git`;
134
- let anonymousError;
135
- try {
136
- await runGitRepoAccessProbe(execImpl, root.physicalPath, repoUrl, anonymousGitEnv, args.env);
137
- results.push({
138
- ok: true,
139
- reason: tokenPresent
140
- ? "GitHub repo clone access preflight passed with anonymous public clone access."
141
- : "GitHub repo clone access preflight passed without token auth.",
142
- repo: assignment.repo,
143
- streamId: assignment.streamId,
144
- tokenPresent
145
- });
146
- continue;
147
- }
148
- catch (error) {
149
- anonymousError = error;
150
- }
151
- let tokenError;
152
- if (tokenGitEnv) {
153
- try {
154
- await runGitRepoAccessProbe(execImpl, root.physicalPath, repoUrl, tokenGitEnv, args.env);
155
- results.push({
156
- ok: true,
157
- reason: "GitHub repo clone access preflight passed with token auth after anonymous clone access failed.",
158
- repo: assignment.repo,
159
- streamId: assignment.streamId,
160
- tokenPresent: true
161
- });
162
- continue;
163
- }
164
- catch (error) {
165
- tokenError = error;
166
- }
167
- }
168
- results.push({
169
- ok: false,
170
- reason: repoAccessFailureReason({
171
- anonymousError,
172
- redactRepoName: args.redactRepoNames === true,
173
- repo: assignment.repo,
174
- tokenError,
175
- tokenPresent
176
- }),
177
- repo: assignment.repo,
178
- streamId: assignment.streamId,
179
- tokenPresent
180
- });
181
- }
182
- return results;
183
- }
184
- finally {
185
- if (await validatePinnedCleanupDirectory(root).catch(() => false)) {
186
- await rm(root.physicalPath, { recursive: true, force: true }).catch(() => undefined);
187
- }
188
- }
189
- }
190
- async function pinCleanupDirectory(directoryInput) {
191
- const physicalPath = await realpath(path.resolve(directoryInput));
192
- const stats = await lstat(physicalPath, { bigint: true });
193
- if (stats.isSymbolicLink() || !stats.isDirectory()) {
194
- throw new Error("OSS meta-lab cleanup roots must be physical directories.");
195
- }
196
- return Object.freeze({ birthtimeNs: stats.birthtimeNs, dev: stats.dev, ino: stats.ino, physicalPath });
197
- }
198
- async function validatePinnedCleanupDirectory(directory) {
199
- const stats = await lstat(directory.physicalPath, { bigint: true });
200
- return !stats.isSymbolicLink()
201
- && stats.isDirectory()
202
- && stats.birthtimeNs === directory.birthtimeNs
203
- && stats.dev === directory.dev
204
- && stats.ino === directory.ino
205
- && await realpath(directory.physicalPath) === directory.physicalPath;
206
- }
207
- export async function preflightOssMetaActorApiKey(args) {
208
- const apiKey = args.env.CODEX_API_KEY?.trim() || args.env.OPENAI_API_KEY?.trim();
209
- if (!apiKey) {
210
- return {
211
- ok: true,
212
- reason: "No API-key actor auth present; preflight skipped."
213
- };
214
- }
215
- const fetchImpl = args.fetchImpl ?? fetch;
216
- const model = args.env.HUMANISH_OSS_META_ACTOR_PREFLIGHT_MODEL?.trim() || "gpt-4.1-mini";
217
- try {
218
- const response = await fetchImpl("https://api.openai.com/v1/responses", {
219
- method: "POST",
220
- headers: {
221
- Authorization: `Bearer ${apiKey}`,
222
- "Content-Type": "application/json"
223
- },
224
- body: JSON.stringify({
225
- input: "Return a JSON object exactly like {\"status\":\"passed\"}. This is an actor auth preflight.",
226
- max_output_tokens: 32,
227
- model,
228
- text: {
229
- format: {
230
- type: "json_object"
231
- }
232
- }
233
- })
234
- });
235
- if (response.ok) {
236
- return {
237
- ok: true,
238
- reason: `OpenAI actor API-key preflight passed for ${model}.`,
239
- status: response.status
240
- };
241
- }
242
- const body = await response.text().catch(() => "");
243
- return {
244
- ok: false,
245
- reason: compactError(`OpenAI actor API-key preflight failed with HTTP ${response.status}: ${body}`),
246
- status: response.status
247
- };
248
- }
249
- catch (error) {
250
- return {
251
- ok: false,
252
- reason: compactError(error)
253
- };
254
- }
255
- }
256
- function hostCodexActorRequested(env) {
257
- return env.HUMANISH_OSS_META_HOST_CODEX_ACTOR === "1";
258
- }
259
- function codexAppServerModeRequested(env, explicit = false) {
260
- return explicit || env.HUMANISH_OSS_META_CODEX_APP_SERVER === "1";
261
- }
262
- function remoteActorAuthRequested(env) {
263
- return env.HUMANISH_OSS_META_ACTOR_FIRST === "1" || env.HUMANISH_OSS_META_REQUIRE_ACTOR === "1";
264
- }
265
- function actorRequired(env) {
266
- return env.HUMANISH_OSS_META_REQUIRE_ACTOR === "1";
267
- }
268
- async function createHostActorPlans(_args) {
269
- throw new Error("Host actor planning is disabled until live OSS meta-lab execution has an isolated credential boundary.");
270
- }
271
- function repoAccessFailureReason(args) {
272
- const anonymous = sanitizeRepoAccessError(args.anonymousError, args.repo, args.redactRepoName);
273
- const token = args.tokenError
274
- ? ` Token auth also failed: ${sanitizeRepoAccessError(args.tokenError, args.repo, args.redactRepoName)}`
275
- : "";
276
- const authHint = args.tokenPresent
277
- ? "A GitHub token was present, but `git ls-remote` could not read the repo with token or anonymous access. Check token repo access and scopes."
278
- : "No GitHub token was present. Public repos should pass unauthenticated; private repos need GH_TOKEN, GITHUB_TOKEN, or GITHUB_PAT with read access.";
279
- return `${authHint} Anonymous access failed: ${anonymous}${token}`.replace(/\s+/g, " ").trim().slice(0, 420);
280
- }
281
- function sanitizeRepoAccessError(error, repo, redactRepoName) {
282
- let message = compactError(error)
283
- .replace(/github_pat_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]")
284
- .replace(/\bHUMANISH_GITHUB_TOKEN_RUNTIME=[^\s]+/g, "HUMANISH_GITHUB_TOKEN_RUNTIME=[redacted-github-token]");
285
- if (redactRepoName) {
286
- message = message
287
- .replaceAll(`https://github.com/${repo}.git`, "https://github.com/[redacted-authorized-repo].git")
288
- .replaceAll(`github.com/${repo}.git`, "github.com/[redacted-authorized-repo].git")
289
- .replaceAll(repo, "[redacted-authorized-repo]");
290
- }
291
- return message;
292
- }
293
- function blockedLiveDesktopsForRepoAccess(args) {
294
- const checkedAt = new Date().toISOString();
295
- const preflightByStream = new Map(args.preflight.map((result) => [result.streamId, result]));
296
- const failedCount = args.preflight.filter((result) => !result.ok).length;
297
- return args.assignments.map((assignment) => {
298
- const repoLabel = args.redactRepoNames ? repoArtifactLabel(assignment) : assignment.repo;
299
- const preflight = preflightByStream.get(assignment.streamId);
300
- const reason = preflight?.ok
301
- ? `GitHub repo clone access preflight passed for ${repoLabel}, but live launch was skipped because ${failedCount} assigned repo${failedCount === 1 ? "" : "s"} failed preflight.`
302
- : preflight?.reason ?? `GitHub repo clone access preflight did not run for ${repoLabel}.`;
303
- return {
304
- completion: {
305
- actorStatus: "blocked",
306
- appReason: reason,
307
- appStatus: "blocked",
308
- checkedAt,
309
- logTail: reason,
310
- nestedObserverPresent: false,
311
- nestedVerifyPassed: false,
312
- reason,
313
- status: "blocked",
314
- visualReason: "No headed desktop was launched before repo clone access was proven.",
315
- visualStatus: "not_started",
316
- visualWindowCount: 0
317
- },
318
- repo: repoLabel,
319
- simId: assignment.simId,
320
- streamId: assignment.streamId
321
- };
322
- });
323
- }
324
- export function normalizeHostActorRecommendedProof(value) {
325
- const proof = cleanHostActorText(value, "");
326
- if (!/\bhumanish\s+run\b/.test(proof)) {
327
- return "Start the target app on a loopback URL, then run `humanish run --app-url http://127.0.0.1:<port> --sims 2`.";
328
- }
329
- if (/\s--(?:browser|viewport|persona|scenario)\b/.test(proof)) {
330
- return "Start the target app on a loopback URL, then run `humanish run --app-url http://127.0.0.1:<port> --sims 2`.";
331
- }
332
- return proof;
333
- }
334
- function cleanHostActorText(value, fallback) {
335
- const text = String(typeof value === "string" ? value : fallback)
336
- .replace(/sk-[A-Za-z0-9_-]{20,}/g, "[redacted-openai-key]")
337
- .replace(/e2b_[A-Za-z0-9_-]{12,}/g, "[redacted-e2b-key]")
338
- .replace(/gh[pousr]_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]")
339
- .replace(/github_pat_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]")
340
- .replace(/\s+/g, " ")
341
- .trim()
342
- .slice(0, 500);
343
- return text || fallback;
344
- }
345
- /**
346
- * Wrapped so a DIRECT library caller gets the same status-record lifetime the CLI does: returning
347
- * from this function finalizes any record the run opened, whichever of its fail-closed exits it
348
- * took. `runLab` establishes a scope too and nesting is harmless — the inner scope owns what it
349
- * opened. Without this a test or an adopter calling the backend directly leaves the 5s cadence
350
- * ticking into a directory something else is deleting, which surfaces as an unrelated ENOTEMPTY.
351
- */
352
- export async function runOssMetaLab(options) {
353
- return withRunStatusScope(() => runOssMetaLabInScope(options));
354
- }
355
- async function runOssMetaLabInScope(options) {
356
- const cwd = path.resolve(options.cwd);
357
- const dryRun = options.dryRun === true;
358
- const liveRequested = !dryRun;
359
- const warnings = [];
360
- const repos = normalizeOssRepoSlugs(options.repos);
361
- const count = options.count ?? DEFAULT_OSS_REPOS.length;
362
- if (!Number.isInteger(count) || count < 1) {
363
- return {
364
- schema: OSS_META_LAB_SCHEMA,
365
- ok: false,
366
- assignments: [],
367
- cwd,
368
- dryRun,
369
- error: {
370
- code: "HUMANISH_INVALID_OSS_COUNT",
371
- message: "--count must be a positive integer."
372
- },
373
- liveRequested,
374
- repos,
375
- sandboxes: [],
376
- warnings
377
- };
378
- }
379
- const invalid = repos.find((repo) => !validateOssRepoSlug(repo));
380
- if (invalid) {
381
- return {
382
- schema: OSS_META_LAB_SCHEMA,
383
- ok: false,
384
- assignments: [],
385
- count,
386
- cwd,
387
- dryRun,
388
- error: {
389
- code: "HUMANISH_INVALID_OSS_REPO",
390
- message: `Only GitHub owner/repo slugs are supported: ${invalid}`
391
- },
392
- liveRequested,
393
- repos,
394
- sandboxes: [],
395
- warnings
396
- };
397
- }
398
- const redactRepoNames = options.redactRepoNames ?? (liveRequested && (Boolean(githubTokenFromEnv(process.env)) || Boolean(options.repos?.length)));
399
- const assignments = buildOssRepoAssignments(repos, count);
400
- const publicAssignments = redactAssignments(assignments, redactRepoNames);
401
- const publicRepos = redactRepoNames ? publicAssignments.map((assignment) => assignment.repo) : repos;
402
- if (liveRequested) {
403
- return {
404
- schema: OSS_META_LAB_SCHEMA,
405
- ok: false,
406
- assignments: publicAssignments,
407
- count,
408
- cwd,
409
- dryRun,
410
- error: {
411
- code: "HUMANISH_OSS_META_LIVE_ISOLATION_REQUIRED",
412
- message: "Live OSS meta-lab execution is unavailable because repository-derived instructions require an isolated credential boundary. Use --dry-run."
413
- },
414
- liveRequested,
415
- repos: publicRepos,
416
- sandboxes: [],
417
- warnings
418
- };
419
- }
420
- const codexAppServerMode = codexAppServerModeRequested(process.env, options.codexAppServer === true);
421
- const hostActorMode = liveRequested && hostCodexActorRequested(process.env);
422
- const missingKeys = missingLiveKeys(process.env);
423
- const runId = options.runId ?? makeMetaRunId();
424
- const physicalCwd = await realpath(cwd);
425
- const runResult = await runDryRun({
426
- cwd: physicalCwd,
427
- ...(options.lab === undefined ? {} : { lab: options.lab }),
428
- dryRun: true,
429
- runId,
430
- simCount: count
431
- });
432
- if (!runResult.ok || !runResult.runId) {
433
- return {
434
- schema: OSS_META_LAB_SCHEMA,
435
- ok: false,
436
- assignments: publicAssignments,
437
- count,
438
- cwd,
439
- dryRun,
440
- error: {
441
- code: "HUMANISH_META_RUN_FAILED",
442
- message: runResult.error?.message ?? "Failed to create OSS meta-lab run bundle."
443
- },
444
- liveRequested,
445
- repos: publicRepos,
446
- sandboxes: [],
447
- warnings: [...warnings, ...runResult.warnings]
448
- };
449
- }
450
- const preparedRunPaths = await bindExistingRunArtifactPaths(physicalCwd, runId);
451
- // The dry-run route created (and finalized) this run dir; the meta lab now keeps working in it
452
- // for minutes. Re-open the status record so a watcher sees a LIVE run rather than a finished one
453
- // (#455) — the same file, honestly re-stated.
454
- const runStatus = beginRunStatus(preparedRunPaths, {
455
- runId,
456
- mode: dryRun ? "dry-run" : "live",
457
- ...(options.lab === undefined ? {} : { lab: options.lab })
458
- });
459
- const artifactRoot = preparedRunPaths;
460
- const createdAt = new Date().toISOString();
461
- const source = await buildRunSource({
462
- capturedAt: createdAt,
463
- cwd: physicalCwd,
464
- humanishSource: "present",
465
- packageName: "humanish"
466
- });
467
- const persistScreenshots = liveRequested;
468
- let liveDesktops = [];
469
- let substrateMissingKeys = [...missingKeys];
470
- const initialBundle = buildMetaBundle({
471
- assignments,
472
- createdAt,
473
- cwd,
474
- dryRun,
475
- liveDesktops,
476
- liveRequested,
477
- missingKeys: substrateMissingKeys,
478
- redactRepoNames,
479
- runId,
480
- source
481
- });
482
- await writeMetaBundleArtifacts(artifactRoot, initialBundle);
483
- let observer = await renderObserver(physicalCwd, runId, { open: false });
484
- if (observer.ok && options.onObserverReady) {
485
- await options.onObserverReady(observer);
486
- await validatePreparedRunArtifactPaths(preparedRunPaths);
487
- }
488
- const shouldPreflightRepoAccess = liveRequested
489
- && missingKeys.length === 0
490
- && process.env.HUMANISH_OSS_META_SKIP_REPO_ACCESS_PREFLIGHT !== "1"
491
- && (Boolean(githubTokenFromEnv(process.env)) || Boolean(options.repos?.length));
492
- const repoAccessPreflight = shouldPreflightRepoAccess
493
- ? await preflightOssMetaRepoAccess({
494
- assignments,
495
- cwd,
496
- env: process.env,
497
- redactRepoNames
498
- })
499
- : [];
500
- const repoAccessPreflightBlocked = repoAccessPreflight.some((result) => !result.ok);
501
- if (repoAccessPreflight.length > 0) {
502
- const passed = repoAccessPreflight.filter((result) => result.ok).length;
503
- warnings.push(`GitHub repo clone access preflight passed ${passed}/${repoAccessPreflight.length} assigned repo${repoAccessPreflight.length === 1 ? "" : "s"}.`);
504
- for (const failed of repoAccessPreflight.filter((result) => !result.ok)) {
505
- const assignment = assignments.find((candidate) => candidate.streamId === failed.streamId);
506
- const repoLabel = assignment && redactRepoNames ? repoArtifactLabel(assignment) : failed.repo;
507
- warnings.push(`${repoLabel}: ${failed.reason}`);
508
- }
509
- }
510
- const hostActorPlanResults = hostActorMode && missingKeys.length === 0 && !repoAccessPreflightBlocked
511
- ? await createHostActorPlans({
512
- assignments,
513
- cwd,
514
- redactRepoNames,
515
- runId
516
- })
517
- : [];
518
- const hostActorPlansByStream = new Map(hostActorPlanResults.flatMap((result) => result.plan?.status === "passed" ? [[result.streamId, result]] : []));
519
- if (hostActorPlanResults.length > 0) {
520
- const passed = hostActorPlanResults.filter((result) => result.plan?.status === "passed").length;
521
- warnings.push(`Host Codex actor authored ${passed}/${hostActorPlanResults.length} public-safe Humanish plan${hostActorPlanResults.length === 1 ? "" : "s"}.`);
522
- for (const failed of hostActorPlanResults.filter((result) => result.plan?.status !== "passed")) {
523
- warnings.push(`Host Codex actor plan failed for ${redactRepoNames ? "[redacted-authorized-repo]" : failed.repo}: ${failed.error ?? failed.plan?.summary ?? "unknown failure"}`);
524
- }
525
- }
526
- const hostActorPlanBlocked = hostActorMode
527
- && actorRequired(process.env)
528
- && hostActorPlanResults.length > 0
529
- && hostActorPlanResults.some((result) => result.plan?.status !== "passed");
530
- const actorAuthPreflight = liveRequested
531
- && missingKeys.length === 0
532
- && !hostActorMode
533
- && actorRequired(process.env)
534
- && process.env.HUMANISH_OSS_META_SKIP_ACTOR_PREFLIGHT !== "1"
535
- ? await preflightOssMetaActorApiKey({ env: process.env })
536
- : undefined;
537
- const actorAuthPreflightBlocked = actorAuthPreflight !== undefined && !actorAuthPreflight.ok;
538
- substrateMissingKeys = [
539
- ...missingKeys,
540
- ...(hostActorPlanBlocked ? [OSS_META_LAB_HOST_ACTOR_PLACEHOLDER] : []),
541
- ...(actorAuthPreflightBlocked ? [OSS_META_LAB_ACTOR_PREFLIGHT_PLACEHOLDER] : [])
542
- ];
543
- if (actorAuthPreflight) {
544
- warnings.push(actorAuthPreflight.ok
545
- ? actorAuthPreflight.reason
546
- : `Remote Codex actor API-key preflight blocked live launch: ${actorAuthPreflight.reason}`);
547
- }
548
- let localPackage;
549
- if (liveRequested && missingKeys.length === 0 && !repoAccessPreflightBlocked && !hostActorPlanBlocked && !actorAuthPreflightBlocked) {
550
- try {
551
- localPackage = await packLocalHumanishPackage(cwd, runId);
552
- warnings.push(`Packed local humanish package for sandbox install (${localPackage.fileName}).`);
553
- }
554
- catch (error) {
555
- warnings.push(`Local humanish package pack failed; sandbox bootstrap will try public npm fallback. ${compactError(error)}`);
556
- }
557
- }
558
- if (liveRequested && missingKeys.length === 0 && !repoAccessPreflightBlocked && !hostActorPlanBlocked && !actorAuthPreflightBlocked) {
559
- try {
560
- liveDesktops = await launchLiveDesktops(assignments, {
561
- codexAppServerMode,
562
- cwd,
563
- hostActorPlansByStream,
564
- ...(localPackage ? { localPackage } : {}),
565
- redactRepoNames
566
- });
567
- const completionSummary = await pollLiveDesktopCompletions(liveDesktops, {
568
- ...(options.completionTimeoutMs === undefined
569
- ? {}
570
- : {
571
- timeoutMs: options.completionTimeoutMs,
572
- timeoutReason: "attached watch mode serves the Observer immediately after desktop streams are created"
573
- })
574
- });
575
- warnings.push(...completionSummary.warnings);
576
- }
577
- catch (error) {
578
- warnings.push(compactError(error));
579
- liveDesktops = assignments.map((assignment) => {
580
- const hostActorPlanResult = hostActorPlanResults.find((result) => result.streamId === assignment.streamId);
581
- return {
582
- error: compactError(error),
583
- ...(hostActorPlanResult?.plan ? { hostActorPlan: hostActorPlanResult.plan } : {}),
584
- ...(hostActorPlanResult?.artifactPath ? { hostActorPlanPath: hostActorPlanResult.artifactPath } : {}),
585
- repo: redactRepoNames ? repoArtifactLabel(assignment) : assignment.repo,
586
- simId: assignment.simId,
587
- streamId: assignment.streamId
588
- };
589
- });
590
- }
591
- }
592
- else if (repoAccessPreflightBlocked) {
593
- liveDesktops = blockedLiveDesktopsForRepoAccess({
594
- assignments,
595
- preflight: repoAccessPreflight,
596
- redactRepoNames
597
- });
598
- warnings.push("Live E2B launch skipped because GitHub repo clone access preflight failed.");
599
- }
600
- else if (hostActorPlanBlocked) {
601
- warnings.push("Live E2B launch skipped because required host Codex actor plan evidence did not pass preflight.");
602
- }
603
- else if (actorAuthPreflightBlocked) {
604
- warnings.push("Live E2B launch skipped because required Codex actor API-key quota/auth preflight failed.");
605
- }
606
- const liveDesktopCount = liveDesktops.filter((desktop) => desktop.url).length;
607
- const failedLiveDesktopCount = liveDesktops.filter((desktop) => desktop.error).length;
608
- const startedBootstrapCount = liveDesktops.filter((desktop) => desktop.bootstrap?.status === "started").length;
609
- const terminalCompletionCount = liveDesktops.filter((desktop) => isTerminalCompletion(desktop.completion)).length;
610
- const runningAppCount = liveDesktops.filter((desktop) => desktop.completion?.appStatus === "running").length;
611
- const visibleDesktopCount = liveDesktops.filter((desktop) => desktop.completion?.visualStatus === "visible").length;
612
- if (liveDesktops.length > 0) {
613
- warnings.push(`Launched ${liveDesktopCount}/${liveDesktops.length} live E2B desktop stream${liveDesktops.length === 1 ? "" : "s"}.`);
614
- if (startedBootstrapCount > 0) {
615
- warnings.push(`Started ${startedBootstrapCount}/${liveDesktops.length} visible bootstrap terminal${liveDesktops.length === 1 ? "" : "s"} for target app startup, nested Humanish setup, and ${codexAppServerMode ? "Codex app-server client surface" : "Codex actor attempt"}.`);
616
- if (terminalCompletionCount > 0) {
617
- warnings.push(`Classified ${terminalCompletionCount}/${startedBootstrapCount} bootstrap terminal state${startedBootstrapCount === 1 ? "" : "s"} from remote public-safe evidence.`);
618
- warnings.push(`Detected ${runningAppCount}/${terminalCompletionCount} target app HTTP-ready surface${terminalCompletionCount === 1 ? "" : "s"} from remote public-safe evidence.`);
619
- warnings.push(`Detected ${visibleDesktopCount}/${terminalCompletionCount} headed desktop visual layout${terminalCompletionCount === 1 ? "" : "s"} from remote public-safe evidence.`);
620
- }
621
- }
622
- else {
623
- warnings.push(codexAppServerMode
624
- ? "Codex app-server client surfacing and nested Humanish execution remain the next substrate slice behind these live desktops."
625
- : "Codex TUI injection and nested Humanish execution remain the next substrate slice behind these live desktops.");
626
- }
627
- }
628
- if (failedLiveDesktopCount > 0) {
629
- warnings.push(`${failedLiveDesktopCount} E2B desktop launch${failedLiveDesktopCount === 1 ? "" : "es"} failed; see stream events in the Observer.`);
630
- }
631
- if (persistScreenshots) {
632
- const screenshotSummary = await captureLiveDesktopScreenshots(artifactRoot, liveDesktops, { redactRepoNames });
633
- warnings.push(...screenshotSummary.warnings);
634
- }
635
- const actorEvidenceSummary = await writeActorEvidenceArtifacts(artifactRoot, liveDesktops, {
636
- assignments,
637
- redactRepoNames
638
- });
639
- warnings.push(...actorEvidenceSummary.warnings);
640
- const bundle = buildMetaBundle({
641
- assignments,
642
- createdAt,
643
- cwd,
644
- dryRun,
645
- liveDesktops,
646
- liveRequested,
647
- missingKeys: substrateMissingKeys,
648
- redactRepoNames,
649
- runId,
650
- source
651
- });
652
- await writeMetaBundleArtifacts(artifactRoot, bundle);
653
- await runStatus.finish({
654
- ...(bundle.review?.verdict === undefined ? {} : { verdict: bundle.review.verdict })
655
- });
656
- const finalObserver = await renderObserver(physicalCwd, runId, { open: options.open === true });
657
- Object.assign(observer, finalObserver);
658
- if (observer.ok) {
659
- attachObserverRuntimeStreamUrls(observer, liveDesktops
660
- .filter((desktop) => desktop.url)
661
- .map((desktop) => ({
662
- streamId: desktop.streamId,
663
- url: desktop.url
664
- })));
665
- }
666
- const outcome = classifyMetaLabOutcome({
667
- dryRun,
668
- liveDesktops,
669
- liveRequested,
670
- missingKeys: substrateMissingKeys
671
- });
672
- const result = {
673
- schema: OSS_META_LAB_SCHEMA,
674
- ok: observer.ok && outcome.ok,
675
- assignments: publicAssignments,
676
- count,
677
- cwd,
678
- dryRun,
679
- ...(observer.ok && outcome.ok
680
- ? {}
681
- : {
682
- error: {
683
- code: "HUMANISH_META_RUN_FAILED",
684
- message: observer.ok ? outcome.reason : observer.error?.message ?? "OSS meta-lab Observer failed."
685
- }
686
- }),
687
- liveRequested,
688
- observer,
689
- repos: publicRepos,
690
- runId,
691
- sandboxes: liveDesktops.map((desktop) => formatLiveDesktopForResult(desktop, redactRepoNames)),
692
- warnings: [...warnings, ...observer.warnings]
693
- };
694
- if (observer.ok && liveDesktops.some((desktop) => desktop.desktop && desktop.bootstrap?.status === "started")) {
695
- liveRuntimeByResult.set(result, {
696
- artifactRoot,
697
- assignments,
698
- createdAt,
699
- cwd,
700
- dryRun,
701
- liveDesktops,
702
- liveRequested,
703
- missingKeys: substrateMissingKeys,
704
- persistScreenshots,
705
- physicalCwd,
706
- redactRepoNames,
707
- runId,
708
- source,
709
- startedAt: Date.now()
710
- });
711
- }
712
- return result;
713
- }
714
- async function writeMetaBundleArtifacts(artifactRoot, bundle) {
715
- const publicBundle = publicSafeOssMetaBundle(bundle);
716
- await writeJson(artifactRoot, "run.json", publicBundle);
717
- await writeJson(artifactRoot, "review.json", publicBundle.review);
718
- await writeContainedOutputFile(artifactRoot, "review.md", renderMetaReviewMarkdown(publicBundle), "utf8");
719
- await writeContainedOutputFile(artifactRoot, "events.ndjson", `${publicBundle.events.map((event) => JSON.stringify(event)).join("\n")}\n`, "utf8");
720
- }
721
- export function publicSafeOssMetaBundle(bundle) {
722
- return {
723
- ...bundle,
724
- cwd: PUBLIC_TARGET_CWD,
725
- streams: bundle.streams.map(publicSafeMetaStream)
726
- };
727
- }
728
- function publicSafeMetaStream(stream) {
729
- return {
730
- ...stream,
731
- artifacts: uniqueStreamArtifacts(stream.artifacts.filter((artifact) => isLocalEvidenceArtifactPath(artifact.path))),
732
- ...(stream.terminal ? {
733
- terminal: {
734
- ...stream.terminal,
735
- tail: sanitizeRemoteLog(stream.terminal.tail)
736
- }
737
- } : {}),
738
- ...(stream.ui ? { ui: publicSafeMetaStreamUi(stream.ui) } : {})
739
- };
740
- }
741
- function publicSafeMetaStreamUi(ui) {
742
- const { nestedObserverPath: rawNestedObserverPath, nestedObserverUrl: _rawNestedObserverUrl, ...rest } = ui;
743
- const nestedObserverPath = rawNestedObserverPath && isLocalEvidenceArtifactPath(rawNestedObserverPath)
744
- ? rawNestedObserverPath
745
- : undefined;
746
- return {
747
- ...rest,
748
- ...(nestedObserverPath === undefined ? {} : { nestedObserverPath })
749
- };
750
- }
751
- export function startOssMetaLabLiveRefresh(result, options = {}) {
752
- const runtime = liveRuntimeByResult.get(result);
753
- if (!runtime) {
754
- return null;
755
- }
756
- const intervalMs = options.intervalMs ?? readPositiveInt(process.env.HUMANISH_OSS_META_WATCH_REFRESH_MS, 5_000);
757
- const screenshotIntervalMs = options.screenshotIntervalMs ?? readPositiveInt(process.env.HUMANISH_OSS_META_SCREENSHOT_REFRESH_MS, 15_000);
758
- const timeoutMs = options.timeoutMs ?? readNonNegativeInt(process.env.HUMANISH_OSS_META_COMPLETION_TIMEOUT_MS, 240_000);
759
- const deadline = timeoutMs === 0 ? null : runtime.startedAt + timeoutMs;
760
- let lastScreenshotAt = 0;
761
- let timer = null;
762
- let stopped = false;
763
- let running = false;
764
- const tick = async () => {
765
- if (stopped || running) {
766
- return;
767
- }
768
- running = true;
769
- try {
770
- const now = Date.now();
771
- const timedOut = deadline !== null && now >= deadline;
772
- const shouldCaptureScreenshot = runtime.persistScreenshots
773
- && (timedOut || lastScreenshotAt === 0 || now - lastScreenshotAt >= screenshotIntervalMs);
774
- await refreshOssMetaLabLiveRuntime(runtime, {
775
- captureScreenshots: shouldCaptureScreenshot,
776
- timedOut,
777
- timeoutMs
778
- });
779
- result.sandboxes = runtime.liveDesktops.map((desktop) => formatLiveDesktopForResult(desktop, runtime.redactRepoNames));
780
- const outcome = classifyMetaLabOutcome({
781
- dryRun: runtime.dryRun,
782
- liveDesktops: runtime.liveDesktops,
783
- liveRequested: runtime.liveRequested,
784
- missingKeys: runtime.missingKeys
785
- });
786
- result.ok = result.observer?.ok === true && outcome.ok;
787
- if (result.ok) {
788
- delete result.error;
789
- }
790
- else {
791
- result.error = {
792
- code: "HUMANISH_META_RUN_FAILED",
793
- message: outcome.reason
794
- };
795
- }
796
- if (shouldCaptureScreenshot) {
797
- lastScreenshotAt = now;
798
- }
799
- if (runtime.liveDesktops.every((desktop) => isTerminalCompletion(desktop.completion))) {
800
- if (timer) {
801
- clearInterval(timer);
802
- timer = null;
803
- }
804
- }
805
- }
806
- catch {
807
- // Attached watch is best-effort telemetry. Keep serving the last verified
808
- // bundle instead of crashing the user's observer process.
809
- }
810
- finally {
811
- running = false;
812
- }
813
- };
814
- void tick();
815
- timer = setInterval(() => {
816
- void tick();
817
- }, intervalMs);
818
- const stop = async () => {
819
- stopped = true;
820
- if (timer) {
821
- clearInterval(timer);
822
- timer = null;
823
- }
824
- while (running) {
825
- await wait(100);
826
- }
827
- };
828
- return {
829
- async cleanup() {
830
- await stop();
831
- return cleanupOssMetaLabLiveDesktops(runtime.liveDesktops);
832
- },
833
- async stop() {
834
- await stop();
835
- }
836
- };
837
- }
838
- function cleanupOssMetaLabLiveDesktops(liveDesktops, options = {}) {
839
- const ids = [...new Set(liveDesktops.flatMap((entry) => entry.desktop?.sandboxId ? [entry.desktop.sandboxId] : []))];
840
- return killOssMetaLabProviderSandboxIds(ids, {
841
- ...(options.killSandbox === undefined ? {} : { killSandbox: options.killSandbox }),
842
- ...(options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs }),
843
- skipped: liveDesktops.length - ids.length
844
- });
845
- }
846
- export async function cleanupStaleOssMetaLabSandboxes(options = {}) {
847
- return cleanupOssMetaLabSandboxesAndProviderMatches({ sandboxes: [] }, options);
848
- }
849
- export async function cleanupOssMetaLabSandboxesAndProviderMatches(result, options = {}) {
850
- const requestTimeoutMs = options.requestTimeoutMs ?? readPositiveInt(process.env.HUMANISH_E2B_REQUEST_TIMEOUT_MS, 60_000);
851
- const listed = await listOssMetaLabProviderSandboxIds({
852
- ...(options.listSandboxes === undefined ? {} : { listSandboxes: options.listSandboxes }),
853
- requestTimeoutMs
854
- });
855
- const cleanup = await killOssMetaLabProviderSandboxIds(listed.ids, {
856
- ...(options.killSandbox === undefined ? {} : { killSandbox: options.killSandbox }),
857
- redactIds: true,
858
- requestTimeoutMs,
859
- skipped: listed.skipped
860
- });
861
- const remaining = listed.errors.length > 0 || cleanup.errors.length > 0
862
- ? undefined
863
- : (await listOssMetaLabProviderSandboxIds({
864
- ...(options.listSandboxes === undefined ? {} : { listSandboxes: options.listSandboxes }),
865
- requestTimeoutMs
866
- })).ids.length;
867
- return {
868
- killed: cleanup.killed,
869
- matched: listed.ids.length,
870
- ...(remaining === undefined ? {} : { remaining }),
871
- skipped: result.sandboxes.length + cleanup.skipped,
872
- errors: [
873
- ...(result.sandboxes.length > 0
874
- ? ["Stored OSS meta-lab sandbox IDs were not used; cleanup requires verified provider metadata."]
875
- : []),
876
- ...listed.errors,
877
- ...cleanup.errors
878
- ]
879
- };
880
- }
881
- async function listOssMetaLabProviderSandboxIds(options) {
882
- let listSandboxes = options.listSandboxes;
883
- if (!listSandboxes) {
884
- // humanish never enumerates an operator's E2B account by default (see
885
- // docs/principles/invariants-and-defaults.md). Account-wide Sandbox.list discovery exists
886
- // ONLY for a maintainer's explicit orphan sweep of a crashed
887
- // prior process (`humanish lab cleanup oss`) and requires this opt-in, set deliberately by the
888
- // maintainer running it against their own account -- never a default, never for a shared key.
889
- if (process.env.HUMANISH_OSS_META_ALLOW_PROVIDER_LIST !== "1") {
890
- return {
891
- ids: [],
892
- skipped: 0,
893
- errors: ["Provider-wide Sandbox.list discovery is disabled by default (humanish never enumerates an E2B account); set HUMANISH_OSS_META_ALLOW_PROVIDER_LIST=1 to opt in for a maintainer-run orphan sweep."]
894
- };
895
- }
896
- const e2bApiKey = process.env.E2B_API_KEY;
897
- if (!e2bApiKey) {
898
- return {
899
- ids: [],
900
- skipped: 0,
901
- errors: ["E2B_API_KEY is not present; provider metadata cleanup readback skipped."]
902
- };
903
- }
904
- const desktopModule = await loadE2BDesktopModule();
905
- if (!desktopModule.Sandbox.list) {
906
- return {
907
- ids: [],
908
- skipped: 0,
909
- errors: ["Installed @e2b/desktop SDK does not expose Sandbox.list; provider metadata cleanup readback skipped."]
910
- };
911
- }
912
- listSandboxes = async (request) => {
913
- const paginator = desktopModule.Sandbox.list?.({
914
- metadata: request.metadata,
915
- requestTimeoutMs: request.requestTimeoutMs
916
- });
917
- const sandboxes = [];
918
- if (!paginator) {
919
- return sandboxes;
920
- }
921
- while (true) {
922
- sandboxes.push(...await paginator.nextItems({ requestTimeoutMs: request.requestTimeoutMs }));
923
- if (!paginator.hasNext) {
924
- return sandboxes;
925
- }
926
- }
927
- };
928
- }
929
- try {
930
- const sandboxes = await listSandboxes({
931
- metadata: { ...OSS_META_LAB_PROVIDER_METADATA },
932
- requestTimeoutMs: options.requestTimeoutMs
933
- });
934
- let skipped = 0;
935
- const ids = sandboxes.flatMap((sandbox) => {
936
- const id = sandboxProviderId(sandbox);
937
- if (!id || !isCleanupEligibleOssMetaLabSandbox(sandbox)) {
938
- skipped += 1;
939
- return [];
940
- }
941
- return [id];
942
- });
943
- return { ids: [...new Set(ids)], skipped, errors: [] };
944
- }
945
- catch (error) {
946
- return {
947
- ids: [],
948
- skipped: 0,
949
- errors: [`provider metadata cleanup readback failed: ${compactError(error)}`]
950
- };
951
- }
952
- }
953
- function sandboxProviderId(sandbox) {
954
- for (const value of [sandbox.sandboxId, sandbox.sandboxID, sandbox.id]) {
955
- if (typeof value === "string" && value.trim()) {
956
- return value;
957
- }
958
- }
959
- return null;
960
- }
961
- function isCleanupEligibleOssMetaLabSandbox(sandbox) {
962
- const metadata = sandbox.metadata;
963
- if (!metadata || metadata.tool !== OSS_META_LAB_PROVIDER_METADATA.tool || metadata.mode !== OSS_META_LAB_PROVIDER_METADATA.mode) {
964
- return false;
965
- }
966
- const state = typeof sandbox.state === "string" ? sandbox.state.toLowerCase() : "";
967
- return !["closed", "killed", "paused", "terminated"].includes(state);
968
- }
969
- export async function cleanupOssMetaLabSandboxes(result, _options = {}) {
970
- return {
971
- killed: 0,
972
- skipped: result.sandboxes.length,
973
- errors: result.sandboxes.some((sandbox) => sandbox.sandboxId)
974
- ? ["Stored OSS meta-lab sandbox IDs cannot authorize provider mutation; use the explicit metadata-verified orphan sweep."]
975
- : []
976
- };
977
- }
978
- async function killOssMetaLabProviderSandboxIds(idsInput, options = {}) {
979
- const ids = [...new Set(idsInput.filter((id) => id.trim()))];
980
- const skipped = options.skipped ?? 0;
981
- if (ids.length === 0) {
982
- return { killed: 0, skipped, errors: [] };
983
- }
984
- const requestTimeoutMs = options.requestTimeoutMs ?? readPositiveInt(process.env.HUMANISH_E2B_REQUEST_TIMEOUT_MS, 60_000);
985
- let killSandbox = options.killSandbox;
986
- if (!killSandbox) {
987
- const e2bApiKey = process.env.E2B_API_KEY;
988
- if (!e2bApiKey) {
989
- return {
990
- killed: 0,
991
- skipped: skipped + ids.length,
992
- errors: ["E2B_API_KEY is not present; remote sandbox cleanup skipped."]
993
- };
994
- }
995
- const desktopModule = await loadE2BDesktopModule();
996
- if (!desktopModule.Sandbox.kill) {
997
- return {
998
- killed: 0,
999
- skipped: skipped + ids.length,
1000
- errors: ["Installed @e2b/desktop SDK does not expose Sandbox.kill; remote sandbox cleanup skipped."]
1001
- };
1002
- }
1003
- killSandbox = async (sandboxId, timeout) => desktopModule.Sandbox.kill?.(sandboxId, { requestTimeoutMs: timeout });
1004
- }
1005
- let killed = 0;
1006
- const errors = [];
1007
- for (const id of ids) {
1008
- try {
1009
- await killSandbox(id, requestTimeoutMs);
1010
- killed += 1;
1011
- }
1012
- catch (error) {
1013
- const errorText = compactError(error);
1014
- errors.push(`${options.redactIds ? "[provider-runtime]" : id}: ${options.redactIds ? errorText.replaceAll(id, "[provider-runtime]") : errorText}`);
1015
- }
1016
- }
1017
- return { killed, skipped, errors };
1018
- }
1019
- export function buildOssMetaBundleFixture(args) {
1020
- return buildMetaBundle({
1021
- assignments: args.assignments,
1022
- createdAt: args.createdAt,
1023
- cwd: args.cwd,
1024
- dryRun: args.dryRun,
1025
- liveDesktops: args.lanes,
1026
- liveRequested: args.liveRequested,
1027
- missingKeys: args.missingKeys,
1028
- redactRepoNames: args.redactRepoNames === true,
1029
- runId: args.runId
1030
- });
1031
- }
1032
- export function buildOssMetaBootstrapScriptFixture() {
1033
- const [assignment] = buildOssRepoAssignments(["maciekt07/TodoApp"], 1);
1034
- if (!assignment) {
1035
- throw new Error("Missing OSS meta-lab fixture assignment.");
1036
- }
1037
- return buildRemoteBootstrapScript({
1038
- assignment,
1039
- appDir: "/home/user/maciekt07-todoapp",
1040
- completionPath: "/home/user/.humanish-oss-lab/maciekt07-todoapp/completion.json",
1041
- displayRepo: "maciekt07/TodoApp",
1042
- logPath: "/home/user/.humanish-oss-lab/maciekt07-todoapp/bootstrap.log",
1043
- nestedObserverPath: "/home/user/maciekt07-todoapp/.humanish/runs/nested-maciekt07-todoapp/observer/index.html",
1044
- remoteHostActorPlanPath: "/home/user/.humanish-oss-lab/maciekt07-todoapp/host-actor-plan.json",
1045
- stateDir: "/home/user/.humanish-oss-lab/maciekt07-todoapp",
1046
- token: "maciekt07-todoapp"
1047
- });
1048
- }
1049
- function syntheticOssMetaRunSource(createdAt) {
1050
- return {
1051
- packageName: "humanish",
1052
- humanishSource: "present",
1053
- git: {
1054
- schema: "humanish.git-state.v1",
1055
- status: "clean",
1056
- capturedAt: createdAt,
1057
- head: {
1058
- shortSha: null,
1059
- refState: "unknown"
1060
- },
1061
- changes: {
1062
- staged: 0,
1063
- unstaged: 0,
1064
- untracked: 0,
1065
- total: 0
1066
- },
1067
- note: "public-safe synthetic OSS meta-lab fixture"
1068
- }
1069
- };
1070
- }
1071
- function buildMetaBundle(args) {
1072
- const simulations = [];
1073
- const streams = [];
1074
- const events = [
1075
- {
1076
- id: "event-000",
1077
- at: args.createdAt,
1078
- level: "info",
1079
- type: "oss-meta.contract.created",
1080
- message: "Created public-safe OSS meta-lab Observer-of-Observers contract."
1081
- }
1082
- ];
1083
- for (const assignment of args.assignments) {
1084
- const prompt = buildCodexBootstrapPrompt(assignment, args.redactRepoNames);
1085
- const rawLiveDesktop = args.liveDesktops.find((desktop) => desktop.streamId === assignment.streamId);
1086
- const liveDesktop = rawLiveDesktop && args.redactRepoNames
1087
- ? redactLiveDesktopRepoMentions(rawLiveDesktop, assignment.repo)
1088
- : rawLiveDesktop;
1089
- const repoLabel = args.redactRepoNames ? repoArtifactLabel(assignment) : assignment.repo;
1090
- const scenarioId = args.redactRepoNames ? `oss-meta-${repoLabel}` : assignment.scenarioId;
1091
- const status = statusForMeta(args, liveDesktop);
1092
- const completion = liveDesktop?.completion;
1093
- const screenshot = liveDesktop?.screenshot;
1094
- const terminalTail = terminalTailForMeta(prompt, liveDesktop);
1095
- const liveStreamPresent = Boolean(liveDesktop?.url);
1096
- const appServerMode = liveDesktop?.bootstrap?.codexMode === "app-server-client";
1097
- simulations.push({
1098
- id: assignment.simId,
1099
- index: assignment.index,
1100
- personaId: `codex-oss-operator-${String(assignment.index).padStart(2, "0")}`,
1101
- scenarioId,
1102
- status,
1103
- streamKind: "browser",
1104
- mode: "browser-sim",
1105
- progress: progressForMeta(status, liveDesktop),
1106
- currentStep: currentStepForMeta(args, assignment, liveDesktop),
1107
- summary: completion
1108
- ? `Headed E2B desktop lane assigned to ${repoLabel}; ${completion.reason}`
1109
- : liveDesktop?.bootstrap?.status === "started"
1110
- ? `Headed E2B desktop lane assigned to ${repoLabel}; bootstrap terminal launched to set up Humanish and open the nested Observer${appServerMode ? " plus Codex app-server client surface" : ""}.`
1111
- : `Headed E2B desktop lane assigned to ${repoLabel}; remote bootstrap should set up Humanish and open a nested Observer inside that desktop.`,
1112
- streamIds: [assignment.streamId],
1113
- startedAt: args.createdAt,
1114
- updatedAt: args.createdAt
1115
- });
1116
- const artifacts = uniqueStreamArtifacts([
1117
- { label: "run bundle", path: "run.json", kind: "bundle" },
1118
- { label: "review", path: "review.md", kind: "review" },
1119
- { label: "events", path: "events.ndjson", kind: "events" },
1120
- ...(completion?.appServerActorEvidence?.tracePath ? [{ label: "codex app-server trace", path: completion.appServerActorEvidence.tracePath, kind: "trace" }] : []),
1121
- ...(completion?.appServerActorEvidence?.eventsPath ? [{ label: "codex app-server events", path: completion.appServerActorEvidence.eventsPath, kind: "events" }] : []),
1122
- ...(completion?.appServerActorEvidence?.transcriptPath ? [{ label: "codex app-server transcript", path: completion.appServerActorEvidence.transcriptPath, kind: "log" }] : []),
1123
- ...(liveDesktop?.actorEvidence?.actorLastMessageTailPath ? [{ label: "actor last-message tail", path: liveDesktop.actorEvidence.actorLastMessageTailPath, kind: "log" }] : []),
1124
- ...(liveDesktop?.actorEvidence?.actorLogTailPath ? [{ label: "actor log tail", path: liveDesktop.actorEvidence.actorLogTailPath, kind: "log" }] : []),
1125
- ...(liveDesktop?.actorEvidence?.appServerTracePath ? [{ label: "codex app-server trace", path: liveDesktop.actorEvidence.appServerTracePath, kind: "trace" }] : []),
1126
- ...(liveDesktop?.actorEvidence?.appServerEventsPath ? [{ label: "codex app-server events", path: liveDesktop.actorEvidence.appServerEventsPath, kind: "events" }] : []),
1127
- ...(liveDesktop?.actorEvidence?.appServerTranscriptPath ? [{ label: "codex app-server transcript", path: liveDesktop.actorEvidence.appServerTranscriptPath, kind: "log" }] : []),
1128
- ...(liveDesktop?.actorEvidence?.nestedEvidencePath ? [{ label: "nested Humanish proof", path: liveDesktop.actorEvidence.nestedEvidencePath, kind: "trace" }] : []),
1129
- ...(liveDesktop?.actorEvidence?.setupQualityPath ? [{ label: "setup quality", path: liveDesktop.actorEvidence.setupQualityPath, kind: "filesystem" }] : []),
1130
- ...(liveDesktop?.hostActorPlanPath ? [{ label: "host Codex actor plan", path: liveDesktop.hostActorPlanPath, kind: "trace" }] : []),
1131
- ...(screenshot ? [{ label: "desktop screenshot", path: screenshot.path, kind: "screenshot" }] : [])
1132
- ]);
1133
- const stream = {
1134
- id: assignment.streamId,
1135
- simId: assignment.simId,
1136
- kind: "browser",
1137
- label: `E2B desktop - ${repoLabel}`,
1138
- status,
1139
- transport: liveStreamPresent ? "sse" : screenshot ? "snapshot" : status === "contract_proof_only" ? "snapshot" : "sse",
1140
- updatedAt: args.createdAt,
1141
- embed: {
1142
- kind: screenshot ? "screenshot" : "placeholder",
1143
- ...(screenshot ? { url: screenshot.observerUrl } : {}),
1144
- title: `E2B desktop ${assignment.index}`
1145
- },
1146
- desktopGeometry: {
1147
- screen: { requested: { width: 1440, height: 960 } }
1148
- },
1149
- terminal: {
1150
- title: `${appServerMode ? "Codex app-server" : "Codex"} bootstrap - ${repoLabel}`,
1151
- format: "plain",
1152
- stdin: liveDesktop?.bootstrap ? "sent" : "planned",
1153
- tail: terminalTail
1154
- },
1155
- ui: {
1156
- route: completion?.appUrl ?? `e2b://desktop/${repoLabel}`,
1157
- intent: appServerMode
1158
- ? "Watch the headed desktop where the bootstrap clones the repo, starts the target app, sets up Humanish, opens the nested Observer, and opens a Codex app-server client surface."
1159
- : "Watch the headed desktop where the bootstrap clones the repo, starts the target app, sets up Humanish, opens the nested Observer, and attempts a Codex actor.",
1160
- ...(completion?.actorStatus ? { actorStatus: completion.actorStatus } : {}),
1161
- ...(completion?.appStatus ? { appStatus: completion.appStatus } : {}),
1162
- ...(completion?.appUrl ? { appUrl: completion.appUrl } : {}),
1163
- ...(liveDesktop?.actorEvidence?.nestedEvidencePath ? { nestedObserverPath: liveDesktop.actorEvidence.nestedEvidencePath } : {}),
1164
- ...(screenshot ? { screenshotUrl: screenshot.observerUrl } : {}),
1165
- ...(completion?.visualStatus ? { visualStatus: completion.visualStatus } : {}),
1166
- state: completion
1167
- ? [
1168
- completion.reason,
1169
- completion.appStatus ? `app=${completion.appStatus}` : "",
1170
- completion.actorStatus ? `actor=${completion.actorStatus}` : "",
1171
- completion.visualStatus ? `visual=${completion.visualStatus}` : ""
1172
- ].filter(Boolean).join(" | ")
1173
- : liveDesktop?.bootstrap?.status === "started"
1174
- ? "bootstrap terminal launched; target app and nested Observer setup running"
1175
- : liveStreamPresent ? "live E2B desktop stream present; stream URL is runtime-only" : args.dryRun ? "contract desktop" : "headed E2B desktop"
1176
- },
1177
- ...(completion ? { completion: completionForStream(completion, appServerMode) } : {}),
1178
- artifacts
1179
- };
1180
- if (appServerMode) {
1181
- stream.codex = codexMetadataForMetaStream(liveDesktop, completion);
1182
- }
1183
- streams.push(stream);
1184
- events.push({
1185
- id: `event-${String(assignment.index).padStart(3, "0")}-assigned`,
1186
- at: args.createdAt,
1187
- level: "info",
1188
- type: "oss-meta.repo.assigned",
1189
- message: `Assigned ${repoLabel} to Codex desktop lane ${assignment.index}.`,
1190
- simId: assignment.simId,
1191
- streamId: assignment.streamId
1192
- }, {
1193
- id: `event-${String(assignment.index).padStart(3, "0")}-prompt`,
1194
- at: args.createdAt,
1195
- level: "info",
1196
- type: "oss-meta.codex.prompt.ready",
1197
- message: appServerMode
1198
- ? "Codex app-server client hook is available in the stream logs tab."
1199
- : "Codex bootstrap prompt is available in the stream logs tab.",
1200
- simId: assignment.simId,
1201
- streamId: assignment.streamId
1202
- });
1203
- if (liveStreamPresent && liveDesktop) {
1204
- events.push({
1205
- id: `event-${String(assignment.index).padStart(3, "0")}-stream`,
1206
- at: args.createdAt,
1207
- level: "info",
1208
- type: "oss-meta.e2b.stream.started",
1209
- message: `Live E2B desktop stream started for ${repoLabel}; auth URL is runtime-only and not persisted in run artifacts.`,
1210
- simId: assignment.simId,
1211
- streamId: assignment.streamId
1212
- });
1213
- if (liveDesktop.bootstrap?.status === "started") {
1214
- events.push({
1215
- id: `event-${String(assignment.index).padStart(3, "0")}-bootstrap-started`,
1216
- at: args.createdAt,
1217
- level: "info",
1218
- type: "oss-meta.bootstrap.started",
1219
- message: `Visible bootstrap terminal launched for ${repoLabel}.`,
1220
- simId: assignment.simId,
1221
- streamId: assignment.streamId
1222
- });
1223
- if (completion) {
1224
- events.push({
1225
- id: `event-${String(assignment.index).padStart(3, "0")}-bootstrap-${completion.status}`,
1226
- at: completion.checkedAt,
1227
- level: eventLevelForCompletion(completion.status),
1228
- type: `oss-meta.bootstrap.${completion.status}`,
1229
- message: `${repoLabel}: ${completion.reason}`,
1230
- simId: assignment.simId,
1231
- streamId: assignment.streamId
1232
- });
1233
- if (completion.nestedStepTraceSummary) {
1234
- events.push({
1235
- id: `event-${String(assignment.index).padStart(3, "0")}-nested-step-trace`,
1236
- at: completion.checkedAt,
1237
- level: completion.nestedStepTraceSummary.status === "passed" ? "info" : "warn",
1238
- type: "oss-meta.nested.step_trace.summary",
1239
- message: `${repoLabel}: Nested browser trace summary captured ${completion.nestedStepTraceSummary.counts.passedSteps}/${completion.nestedStepTraceSummary.counts.totalSteps} steps across ${completion.nestedStepTraceSummary.counts.surfaces} surface(s).`,
1240
- simId: assignment.simId,
1241
- streamId: assignment.streamId
1242
- });
1243
- }
1244
- }
1245
- }
1246
- else if (liveDesktop.bootstrap?.status === "failed") {
1247
- events.push({
1248
- id: `event-${String(assignment.index).padStart(3, "0")}-bootstrap-failed`,
1249
- at: args.createdAt,
1250
- level: "error",
1251
- type: "oss-meta.bootstrap.failed",
1252
- message: `Bootstrap launcher failed for ${repoLabel}.`,
1253
- simId: assignment.simId,
1254
- streamId: assignment.streamId
1255
- });
1256
- }
1257
- }
1258
- else if (completion) {
1259
- events.push({
1260
- id: `event-${String(assignment.index).padStart(3, "0")}-completion-${completion.status}`,
1261
- at: completion.checkedAt,
1262
- level: eventLevelForCompletion(completion.status),
1263
- type: `oss-meta.bootstrap.${completion.status}`,
1264
- message: `${repoLabel}: ${completion.reason}`,
1265
- simId: assignment.simId,
1266
- streamId: assignment.streamId
1267
- });
1268
- if (completion.nestedStepTraceSummary) {
1269
- events.push({
1270
- id: `event-${String(assignment.index).padStart(3, "0")}-nested-step-trace`,
1271
- at: completion.checkedAt,
1272
- level: completion.nestedStepTraceSummary.status === "passed" ? "info" : "warn",
1273
- type: "oss-meta.nested.step_trace.summary",
1274
- message: `${repoLabel}: Nested browser trace summary captured ${completion.nestedStepTraceSummary.counts.passedSteps}/${completion.nestedStepTraceSummary.counts.totalSteps} steps across ${completion.nestedStepTraceSummary.counts.surfaces} surface(s).`,
1275
- simId: assignment.simId,
1276
- streamId: assignment.streamId
1277
- });
1278
- }
1279
- }
1280
- else if (liveDesktop?.error) {
1281
- events.push({
1282
- id: `event-${String(assignment.index).padStart(3, "0")}-stream-error`,
1283
- at: args.createdAt,
1284
- level: "error",
1285
- type: "oss-meta.e2b.stream.failed",
1286
- message: `E2B desktop stream failed for ${repoLabel}: ${liveDesktop.error}`,
1287
- simId: assignment.simId,
1288
- streamId: assignment.streamId
1289
- });
1290
- }
1291
- }
1292
- if (args.liveRequested && args.missingKeys.length > 0) {
1293
- events.push({
1294
- id: "event-live-keys-blocked",
1295
- at: args.createdAt,
1296
- level: "warn",
1297
- type: "oss-meta.live.keys_missing",
1298
- message: `Live launch is blocked until ${args.missingKeys.join(", ")} are present.`
1299
- });
1300
- }
1301
- if (args.liveRequested && args.liveDesktops.length === 0) {
1302
- events.push({
1303
- id: "event-live-substrate-planned",
1304
- at: args.createdAt,
1305
- level: "warn",
1306
- type: "oss-meta.live.substrate_planned",
1307
- message: args.missingKeys.length > 0
1308
- ? "E2B desktop launch is waiting on required environment variables."
1309
- : "Codex TUI injection and nested Humanish execution are planned behind this Observer contract."
1310
- });
1311
- }
1312
- if (args.liveDesktops.some((desktop) => desktop.url)) {
1313
- events.push({
1314
- id: "event-live-substrate-started",
1315
- at: args.createdAt,
1316
- level: "info",
1317
- type: "oss-meta.live.substrate_started",
1318
- message: args.liveDesktops.some((desktop) => desktop.bootstrap?.status === "started")
1319
- ? "E2B desktop streams are connected and bootstrap terminals are launched."
1320
- : "E2B desktop streams are connected; Codex TUI injection is still pending."
1321
- });
1322
- }
1323
- const review = createMetaReview(args);
1324
- const feedbackCandidates = buildMetaFeedbackCandidates({
1325
- assignments: args.assignments,
1326
- liveDesktops: args.liveDesktops,
1327
- redactRepoNames: args.redactRepoNames,
1328
- runId: args.runId
1329
- });
1330
- return {
1331
- schema: RUN_BUNDLE_SCHEMA,
1332
- runId: args.runId,
1333
- mode: args.dryRun ? "dry-run" : "live",
1334
- simCount: args.assignments.length,
1335
- createdAt: args.createdAt,
1336
- cwd: args.cwd,
1337
- artifactRoot: path.join(".humanish", "runs", args.runId),
1338
- source: args.source ?? syntheticOssMetaRunSource(args.createdAt),
1339
- persona: {
1340
- id: "oss-meta-codex-tui-operators",
1341
- name: "Codex TUI OSS Setup Operators",
1342
- source: "lab:oss:meta",
1343
- sourceDigest: "public-safe"
1344
- },
1345
- scenario: {
1346
- id: "oss-meta-observer-of-observers",
1347
- title: "OSS Observer-of-Observers Meta-Lab",
1348
- goal: "Launch headed E2B desktops where Codex agents clone authorized GitHub repos, set up Humanish, run nested Humanish proof commands, attempt Codex TUI, and keep each nested Observer visible.",
1349
- source: "lab:oss:meta",
1350
- sourceDigest: "public-safe"
1351
- },
1352
- lifecycle: [
1353
- {
1354
- at: args.createdAt,
1355
- event: "oss-meta.run.created",
1356
- message: `Created OSS meta-lab run with ${args.assignments.length} headed desktop lane${args.assignments.length === 1 ? "" : "s"}.`
1357
- },
1358
- {
1359
- at: args.createdAt,
1360
- event: "oss-meta.repos.assigned",
1361
- message: `Assigned repos: ${args.assignments.map((assignment) => args.redactRepoNames ? repoArtifactLabel(assignment) : assignment.repo).join(", ")}.`
1362
- },
1363
- {
1364
- at: args.createdAt,
1365
- event: "oss-meta.observer.ready",
1366
- message: "Top-level Observer is ready to watch nested Humanish Observers."
1367
- }
1368
- ],
1369
- simulations,
1370
- streams,
1371
- events,
1372
- redaction: {
1373
- status: "passed",
1374
- notes: "OSS meta-lab artifacts contain GitHub slugs and redacted/synthetic bootstrap evidence only."
1375
- },
1376
- artifacts: {
1377
- run: "run.json",
1378
- reviewJson: "review.json",
1379
- reviewMarkdown: "review.md",
1380
- observerData: "observer/observer-data.json",
1381
- events: "events.ndjson"
1382
- },
1383
- review,
1384
- feedbackCandidates
1385
- };
1386
- }
1387
- function uniqueStreamArtifacts(artifacts) {
1388
- const seen = new Set();
1389
- const unique = [];
1390
- for (const artifact of artifacts) {
1391
- const key = `${artifact.kind}:${artifact.path}`;
1392
- if (seen.has(key))
1393
- continue;
1394
- seen.add(key);
1395
- unique.push(artifact);
1396
- }
1397
- return unique;
1398
- }
1399
- function codexMetadataForMetaStream(liveDesktop, completion) {
1400
- const trace = completion?.appServerActorEvidence?.traceJson;
1401
- const traceRecord = isRecord(trace) ? trace : undefined;
1402
- const counts = isRecord(traceRecord?.counts) ? traceRecord.counts : undefined;
1403
- const eventCount = typeof counts?.envelopes === "number" ? counts.envelopes : undefined;
1404
- return {
1405
- provider: "codex-app-server",
1406
- state: codexStateForMeta(completion),
1407
- contract: "Codex app-server JSON-RPC actor telemetry projected from redacted event envelopes, trace summary, transcript tail, and filesystem setup evidence.",
1408
- ...(eventCount === undefined ? {} : { eventCount }),
1409
- ...(liveDesktop?.actorEvidence?.appServerTracePath ? { tracePath: liveDesktop.actorEvidence.appServerTracePath } : {}),
1410
- ...(typeof traceRecord?.threadId === "string" && traceRecord.threadId.trim() ? { threadId: traceRecord.threadId } : {}),
1411
- ...(typeof traceRecord?.turnId === "string" && traceRecord.turnId.trim() ? { turnId: traceRecord.turnId } : {}),
1412
- ...(typeof traceRecord?.sessionId === "string" && traceRecord.sessionId.trim() ? { sessionId: traceRecord.sessionId } : {}),
1413
- ...(typeof traceRecord?.model === "string" && traceRecord.model.trim() ? { model: traceRecord.model } : {})
1414
- };
1415
- }
1416
- function codexStateForMeta(completion) {
1417
- if (!completion)
1418
- return "connecting";
1419
- if (completion.actorStatus === "passed")
1420
- return "completed";
1421
- if (completion.actorStatus === "running")
1422
- return "running";
1423
- if (completion.actorStatus === "timed_out" || completion.status === "timed_out")
1424
- return "timed_out";
1425
- if (completion.actorStatus === "blocked" || completion.status === "blocked")
1426
- return "blocked";
1427
- if (completion.actorStatus === "failed" || completion.status === "failed")
1428
- return "failed";
1429
- return completion.status === "running" ? "running" : "watching";
1430
- }
1431
- function statusForMeta(args, liveDesktop) {
1432
- if (args.dryRun)
1433
- return "contract_proof_only";
1434
- if (liveDesktop?.completion?.status === "passed" && liveDesktop.completion.appStatus !== "running")
1435
- return "blocked";
1436
- if (liveDesktop?.completion?.status === "passed" && liveDesktop.completion.visualStatus !== "visible")
1437
- return "blocked";
1438
- if (liveDesktop?.completion?.status === "passed"
1439
- && liveDesktop.bootstrap?.codexMode === "app-server-client"
1440
- && liveDesktop.completion.actorStatus !== "passed")
1441
- return "blocked";
1442
- if (liveDesktop?.completion?.status === "passed")
1443
- return "passed";
1444
- if (liveDesktop?.completion?.status === "failed")
1445
- return "failed";
1446
- if (liveDesktop?.completion?.status === "blocked")
1447
- return "blocked";
1448
- if (liveDesktop?.completion?.status === "timed_out")
1449
- return "timed_out";
1450
- if (liveDesktop?.bootstrap?.status === "failed")
1451
- return "failed";
1452
- if (liveDesktop?.url)
1453
- return "running";
1454
- if (liveDesktop?.error)
1455
- return "failed";
1456
- if (args.missingKeys.length > 0)
1457
- return "blocked";
1458
- return "preparing";
1459
- }
1460
- function progressForMeta(status, liveDesktop) {
1461
- if (status === "contract_proof_only")
1462
- return 100;
1463
- if (status === "passed")
1464
- return 100;
1465
- if (status === "timed_out")
1466
- return 100;
1467
- if (status === "failed" && liveDesktop?.completion)
1468
- return 100;
1469
- if (status === "blocked")
1470
- return 18;
1471
- if (status === "failed")
1472
- return 8;
1473
- if (liveDesktop?.completion?.appStatus === "running")
1474
- return 86;
1475
- if (liveDesktop?.bootstrap?.status === "started")
1476
- return 74;
1477
- if (liveDesktop?.url)
1478
- return 58;
1479
- return 34;
1480
- }
1481
- function currentStepForMeta(args, assignment, liveDesktop) {
1482
- const repoLabel = args.redactRepoNames ? repoArtifactLabel(assignment) : assignment.repo;
1483
- if (args.dryRun) {
1484
- return `Contract ready for ${repoLabel}; no E2B desktop launched.`;
1485
- }
1486
- if (liveDesktop?.completion) {
1487
- return liveDesktop.completion.reason;
1488
- }
1489
- if (liveDesktop?.bootstrap?.status === "started") {
1490
- return liveDesktop.bootstrap.codexMode === "app-server-client"
1491
- ? `Bootstrap terminal launched for ${repoLabel}; Codex app-server actor, Humanish setup, target app, and nested Observer run inside the desktop.`
1492
- : `Bootstrap terminal launched for ${repoLabel}; Codex TUI attempt, Humanish setup, and nested Observer run inside the desktop.`;
1493
- }
1494
- if (liveDesktop?.bootstrap?.status === "failed") {
1495
- return `Bootstrap launcher failed for ${repoLabel}.`;
1496
- }
1497
- if (liveDesktop?.url) {
1498
- return `Live E2B desktop connected for ${repoLabel}; Codex TUI injection pending.`;
1499
- }
1500
- if (liveDesktop?.error) {
1501
- return `E2B desktop launch failed for ${repoLabel}.`;
1502
- }
1503
- if (args.missingKeys.length > 0) {
1504
- return `Waiting for ${args.missingKeys.join(", ")} before launching ${repoLabel}.`;
1505
- }
1506
- return `Ready to launch E2B desktop and run Codex actor setup for ${repoLabel}.`;
1507
- }
1508
- function createMetaReview(args) {
1509
- const started = args.liveDesktops.filter((desktop) => desktop.bootstrap?.status === "started");
1510
- const terminalCompletions = args.liveDesktops.filter((desktop) => isTerminalCompletion(desktop.completion));
1511
- const appRunning = args.liveDesktops.filter((desktop) => desktop.completion?.appStatus === "running");
1512
- const visualVisible = args.liveDesktops.filter((desktop) => desktop.completion?.visualStatus === "visible");
1513
- const nestedLiveProof = args.liveDesktops.some((desktop) => desktop.completion?.nestedVerifyPassed === true
1514
- && /\bhumanish run live\b/.test(desktop.completion.logTail ?? ""));
1515
- const outcome = classifyMetaLabOutcome(args);
1516
- const gaps = [
1517
- nestedLiveProof && appRunning.length > 0 && visualVisible.length > 0
1518
- ? "Target app browser surfaces, nested Observer windows, and nested Humanish live app-url proof are visible inside headed desktops."
1519
- : appRunning.length > 0 && visualVisible.length > 0
1520
- ? "Target app browser surfaces and nested Observer windows are visible inside headed desktops; nested Humanish live proof is still missing."
1521
- : appRunning.length > 0
1522
- ? "Target app surfaces responded over HTTP, but headed desktop browser-window visibility was not detected for every lane."
1523
- : started.length > 0 && terminalCompletions.length === started.length
1524
- ? "OSS lane terminal states are classified from public-safe remote bootstrap evidence, but target app HTTP readiness was not detected."
1525
- : args.liveDesktops.some((desktop) => desktop.bootstrap?.status === "started")
1526
- ? "Visible E2B bootstrap terminals are launched and run nested Humanish setup plus target app startup; completion is watched in the desktop stream until remote evidence is polled back."
1527
- : "Nested Humanish Observer evidence is represented as a lane contract until Codex TUI injection and nested Humanish execution land.",
1528
- nestedLiveProof
1529
- ? "Nested Humanish proof reached live app-url mode with desktop/mobile browser persona evidence; richer app-specific journey manifests remain the next adapter slice."
1530
- : "Nested Humanish proof did not reach live app-url mode; target app startup or browser evidence is still missing.",
1531
- "The top-level run does not clone, modify, commit, push, or file issues in target repos.",
1532
- "Public runs may record GitHub owner/repo slugs; token-backed maintainer/private runs redact repo labels in durable artifacts by default."
1533
- ];
1534
- if (args.liveRequested && args.missingKeys.length > 0) {
1535
- gaps.unshift(`Live launch is blocked until ${args.missingKeys.join(", ")} are available in environment.`);
1536
- }
1537
- if (args.liveDesktops.some((desktop) => desktop.url) && !args.liveDesktops.some((desktop) => desktop.bootstrap?.status === "started")) {
1538
- gaps.unshift("Live E2B desktop streams are connected, but Codex TUI injection and nested Humanish execution are not yet automated.");
1539
- }
1540
- return {
1541
- schema: REVIEW_SCHEMA,
1542
- verdict: outcome.verdict,
1543
- summary: outcome.verdict === "fail" || outcome.verdict === "timed_out" || outcome.verdict === "blocked"
1544
- ? outcome.reason
1545
- : args.dryRun
1546
- ? "OSS meta-lab dry-run rendered the Observer-of-Observers contract without provider spend."
1547
- : terminalCompletions.length > 0
1548
- ? `OSS meta-lab launched live E2B desktop streams, classified ${terminalCompletions.length}/${started.length || terminalCompletions.length} bootstrap terminal state${terminalCompletions.length === 1 ? "" : "s"} from public-safe remote evidence, detected ${appRunning.length}/${terminalCompletions.length} target app HTTP-ready surface${terminalCompletions.length === 1 ? "" : "s"}, and detected ${visualVisible.length}/${terminalCompletions.length} headed desktop visual layout${terminalCompletions.length === 1 ? "" : "s"}.`
1549
- : args.liveDesktops.some((desktop) => desktop.bootstrap?.status === "started")
1550
- ? "OSS meta-lab launched live E2B desktop streams, injected visible bootstrap terminals, and started target app plus nested Humanish setup inside each desktop."
1551
- : args.liveDesktops.some((desktop) => desktop.url)
1552
- ? "OSS meta-lab launched live E2B desktop streams and rendered them in the top-level Observer."
1553
- : "OSS meta-lab rendered the live headed-desktop control surface and marked the missing substrate truth in-lane.",
1554
- gaps
1555
- };
1556
- }
1557
- function classifyMetaLabOutcome(args) {
1558
- if (args.dryRun) {
1559
- return {
1560
- ok: true,
1561
- reason: "OSS meta-lab dry-run rendered the Observer-of-Observers contract without provider spend.",
1562
- verdict: "contract_proof_only"
1563
- };
1564
- }
1565
- if (args.liveRequested && args.missingKeys.length > 0) {
1566
- return {
1567
- ok: true,
1568
- reason: `Live launch is blocked until ${args.missingKeys.join(", ")} are available in environment.`,
1569
- verdict: "blocked"
1570
- };
1571
- }
1572
- const launchFailures = args.liveDesktops.filter((desktop) => desktop.error || desktop.bootstrap?.status === "failed");
1573
- if (launchFailures.length > 0) {
1574
- return {
1575
- ok: false,
1576
- reason: `OSS meta-lab failed ${launchFailures.length}/${args.liveDesktops.length} live desktop or bootstrap launch${launchFailures.length === 1 ? "" : "es"}.`,
1577
- verdict: "fail"
1578
- };
1579
- }
1580
- const failedCompletions = args.liveDesktops.filter((desktop) => desktop.completion?.status === "failed");
1581
- if (failedCompletions.length > 0) {
1582
- return {
1583
- ok: false,
1584
- reason: `OSS meta-lab classified ${failedCompletions.length}/${args.liveDesktops.length} bootstrap terminal state${failedCompletions.length === 1 ? "" : "s"} as failed from public-safe remote evidence.`,
1585
- verdict: "fail"
1586
- };
1587
- }
1588
- const timedOutCompletions = args.liveDesktops.filter((desktop) => desktop.completion?.status === "timed_out");
1589
- if (timedOutCompletions.length > 0) {
1590
- return {
1591
- ok: false,
1592
- reason: `OSS meta-lab timed out waiting for ${timedOutCompletions.length}/${args.liveDesktops.length} bootstrap completion marker${timedOutCompletions.length === 1 ? "" : "s"}.`,
1593
- verdict: "timed_out"
1594
- };
1595
- }
1596
- const blockedCompletions = args.liveDesktops.filter((desktop) => desktop.completion?.status === "blocked");
1597
- if (blockedCompletions.length > 0) {
1598
- return {
1599
- ok: false,
1600
- reason: `OSS meta-lab classified ${blockedCompletions.length}/${args.liveDesktops.length} bootstrap terminal state${blockedCompletions.length === 1 ? "" : "s"} as blocked from public-safe remote evidence.`,
1601
- verdict: "blocked"
1602
- };
1603
- }
1604
- const completedWithMissingApp = args.liveDesktops.filter((desktop) => desktop.completion?.status === "passed"
1605
- && desktop.completion.appStatus !== "running");
1606
- if (completedWithMissingApp.length > 0) {
1607
- return {
1608
- ok: false,
1609
- reason: `OSS meta-lab completed nested Humanish setup but did not detect ${completedWithMissingApp.length}/${args.liveDesktops.length} target app HTTP-ready surface${completedWithMissingApp.length === 1 ? "" : "s"}.`,
1610
- verdict: "blocked"
1611
- };
1612
- }
1613
- const completedWithMissingVisual = args.liveDesktops.filter((desktop) => desktop.completion?.status === "passed"
1614
- && desktop.completion.visualStatus !== "visible");
1615
- if (completedWithMissingVisual.length > 0) {
1616
- return {
1617
- ok: false,
1618
- reason: `OSS meta-lab completed nested Humanish setup but did not detect ${completedWithMissingVisual.length}/${args.liveDesktops.length} headed desktop visual layout${completedWithMissingVisual.length === 1 ? "" : "s"}.`,
1619
- verdict: "blocked"
1620
- };
1621
- }
1622
- const completedWithMissingAppServerActor = args.liveDesktops.filter((desktop) => desktop.bootstrap?.codexMode === "app-server-client"
1623
- && desktop.completion?.status === "passed"
1624
- && desktop.completion.actorStatus !== "passed");
1625
- if (completedWithMissingAppServerActor.length > 0) {
1626
- return {
1627
- ok: false,
1628
- reason: `OSS meta-lab completed nested Humanish setup but did not capture passed Codex app-server actor evidence for ${completedWithMissingAppServerActor.length}/${args.liveDesktops.length} headed desktop lane${completedWithMissingAppServerActor.length === 1 ? "" : "s"}.`,
1629
- verdict: "blocked"
1630
- };
1631
- }
1632
- if (args.liveDesktops.length > 0 && args.liveDesktops.every((desktop) => desktop.completion?.status === "passed")) {
1633
- return {
1634
- ok: true,
1635
- reason: `OSS meta-lab passed ${args.liveDesktops.length}/${args.liveDesktops.length} bootstrap terminal states with target app HTTP readiness and headed desktop visual layout detected from public-safe remote evidence.`,
1636
- verdict: "pass"
1637
- };
1638
- }
1639
- return {
1640
- ok: true,
1641
- reason: "OSS meta-lab rendered the live headed-desktop control surface and marked the missing substrate truth in-lane.",
1642
- verdict: "contract_proof_only"
1643
- };
1644
- }
1645
- function terminalTailForMeta(prompt, liveDesktop) {
1646
- if (!liveDesktop?.completion) {
1647
- return liveDesktop?.bootstrap?.tail ?? prompt;
1648
- }
1649
- const lines = [
1650
- `Remote bootstrap ${liveDesktop.completion.status}: ${liveDesktop.completion.reason}`,
1651
- `checked_at: ${liveDesktop.completion.checkedAt}`,
1652
- ...(liveDesktop.completion.appStatus === undefined ? [] : [`app_status: ${liveDesktop.completion.appStatus}`]),
1653
- ...(liveDesktop.completion.appUrl === undefined ? [] : [`app_url: ${liveDesktop.completion.appUrl}`]),
1654
- ...(liveDesktop.completion.appReason === undefined ? [] : [`app_reason: ${liveDesktop.completion.appReason}`]),
1655
- ...(liveDesktop.completion.actorStatus === undefined ? [] : [`actor_status: ${liveDesktop.completion.actorStatus}`]),
1656
- ...(liveDesktop.completion.exitCode === undefined ? [] : [`exit_code: ${liveDesktop.completion.exitCode}`]),
1657
- ...(liveDesktop.completion.nestedVerifyPassed === undefined ? [] : [`nested_verify_passed: ${liveDesktop.completion.nestedVerifyPassed ? "true" : "false"}`]),
1658
- ...(liveDesktop.completion.nestedObserverPresent === undefined ? [] : [`nested_observer_present: ${liveDesktop.completion.nestedObserverPresent ? "true" : "false"}`]),
1659
- ...(liveDesktop.completion.visualStatus === undefined ? [] : [`visual_status: ${liveDesktop.completion.visualStatus}`]),
1660
- ...(liveDesktop.completion.visualWindowCount === undefined ? [] : [`visual_window_count: ${liveDesktop.completion.visualWindowCount}`]),
1661
- ...(liveDesktop.completion.visualReason === undefined ? [] : [`visual_reason: ${liveDesktop.completion.visualReason}`]),
1662
- ...(liveDesktop.completion.setupQuality === undefined ? [] : [
1663
- `setup_quality: ${liveDesktop.completion.setupQuality.status}`,
1664
- `setup_summary: ${liveDesktop.completion.setupQuality.summary}`,
1665
- ...(liveDesktop.completion.setupQuality.studyQuality === undefined ? [] : [
1666
- `study_quality: ${liveDesktop.completion.setupQuality.studyQuality.rating}`,
1667
- `study_summary: ${liveDesktop.completion.setupQuality.studyQuality.summary}`
1668
- ])
1669
- ]),
1670
- "",
1671
- "public-safe actor last message tail:",
1672
- liveDesktop.completion.actorLastMessageTail?.trim() || "(no actor last-message captured)",
1673
- "",
1674
- "public-safe actor log tail:",
1675
- liveDesktop.completion.actorLogTail?.trim() || "(no actor log tail captured)",
1676
- "",
1677
- "public-safe bootstrap log tail:",
1678
- liveDesktop.completion.logTail?.trim() || "(no log tail captured)"
1679
- ];
1680
- return lines.join("\n").trim();
1681
- }
1682
- function completionForStream(completion, appServerMode = false) {
1683
- const effectiveStatus = appServerMode && completion.status === "passed" && completion.actorStatus !== "passed"
1684
- ? "blocked"
1685
- : completion.status;
1686
- const effectiveReason = effectiveStatus === "blocked" && completion.status === "passed" && completion.actorStatus !== "passed"
1687
- ? "Codex app-server mode requires passed app-server actor evidence; actor evidence did not reach passed."
1688
- : completion.reason;
1689
- const meaningfulUse = scoreOssMetaMeaningfulUse({
1690
- ...(completion.actorLastMessageTail === undefined ? {} : { actorLastMessageTail: completion.actorLastMessageTail }),
1691
- ...(completion.actorLogTail === undefined ? {} : { actorLogTail: completion.actorLogTail }),
1692
- actorRequired: appServerMode,
1693
- ...(completion.actorStatus === undefined ? {} : { actorStatus: completion.actorStatus }),
1694
- ...(completion.appStatus === undefined ? {} : { appStatus: completion.appStatus }),
1695
- ...(completion.appUrl === undefined ? {} : { appUrl: completion.appUrl }),
1696
- ...(completion.nestedObserverPresent === undefined ? {} : { nestedObserverPresent: completion.nestedObserverPresent }),
1697
- ...(completion.nestedVerifyPassed === undefined ? {} : { nestedVerifyPassed: completion.nestedVerifyPassed }),
1698
- ...(completion.setupQuality === undefined ? {} : { setupQuality: completion.setupQuality }),
1699
- status: effectiveStatus,
1700
- ...(completion.visualStatus === undefined ? {} : { visualStatus: completion.visualStatus })
1701
- });
1702
- return {
1703
- ...(completion.actorLogPath === undefined ? {} : { actorLogPath: completion.actorLogPath }),
1704
- ...(completion.actorLogTail === undefined ? {} : { actorLogTail: completion.actorLogTail }),
1705
- ...(completion.actorLastMessageTail === undefined ? {} : { actorLastMessageTail: completion.actorLastMessageTail }),
1706
- ...(completion.actorPid === undefined ? {} : { actorPid: completion.actorPid }),
1707
- ...(completion.actorStatus === undefined ? {} : { actorStatus: completion.actorStatus }),
1708
- ...(completion.appLogPath === undefined ? {} : { appLogPath: completion.appLogPath }),
1709
- ...(completion.appPid === undefined ? {} : { appPid: completion.appPid }),
1710
- ...(completion.appReason === undefined ? {} : { appReason: completion.appReason }),
1711
- ...(completion.appStatus === undefined ? {} : { appStatus: completion.appStatus }),
1712
- ...(completion.appUrl === undefined ? {} : { appUrl: completion.appUrl }),
1713
- checkedAt: completion.checkedAt,
1714
- ...(completion.exitCode === undefined ? {} : { exitCode: completion.exitCode }),
1715
- ...(completion.logTail === undefined ? {} : { logTail: completion.logTail }),
1716
- ...(completion.nestedObserverPresent === undefined ? {} : { nestedObserverPresent: completion.nestedObserverPresent }),
1717
- ...(completion.nestedVerifyPassed === undefined ? {} : { nestedVerifyPassed: completion.nestedVerifyPassed }),
1718
- reason: effectiveReason,
1719
- status: effectiveStatus,
1720
- meaningfulUse,
1721
- ...(completion.visualReason === undefined ? {} : { visualReason: completion.visualReason }),
1722
- ...(completion.visualStatus === undefined ? {} : { visualStatus: completion.visualStatus }),
1723
- ...(completion.visualWindowCount === undefined ? {} : { visualWindowCount: completion.visualWindowCount })
1724
- };
1725
- }
1726
- function buildMetaFeedbackCandidates(args) {
1727
- const candidates = [];
1728
- for (const assignment of args.assignments) {
1729
- const desktop = args.liveDesktops.find((lane) => lane.streamId === assignment.streamId);
1730
- if (!desktop) {
1731
- continue;
1732
- }
1733
- const repoLabel = args.redactRepoNames ? repoArtifactLabel(assignment) : assignment.repo;
1734
- const scenarioId = args.redactRepoNames ? `oss-meta-${repoLabel}` : assignment.scenarioId;
1735
- const baseEvidence = feedbackEvidenceForDesktop(desktop);
1736
- const setupQualityPath = desktop.actorEvidence?.setupQualityPath;
1737
- const failedSetupChecks = desktop.completion?.setupQuality?.checks.filter((check) => !check.ok) ?? [];
1738
- const studyQuality = desktop.completion?.setupQuality?.studyQuality;
1739
- if (setupQualityPath && failedSetupChecks.length > 0) {
1740
- candidates.push({
1741
- schema: "humanish.feedback-candidate.v1",
1742
- id: `setup-quality-${safeArtifactToken(assignment.streamId)}`,
1743
- run_id: args.runId,
1744
- stream_id: assignment.streamId,
1745
- adapter_id: "oss-meta-lab",
1746
- scenario_id: scenarioId,
1747
- persona_id: `codex-oss-operator-${String(assignment.index).padStart(2, "0")}`,
1748
- actor: "codex-tui",
1749
- substrate: "e2b-desktop",
1750
- failure_owner: "actor",
1751
- summary: `Generated Humanish setup for ${repoLabel} needs review`,
1752
- expected: "The setup actor should create committed Humanish source files, useful personas/scenarios, a package script, and a .humanish/ runtime ignore without preserving private state.",
1753
- actual: failedSetupChecks.map((check) => `${check.label}: ${check.detail}`).join(" "),
1754
- evidence: [
1755
- {
1756
- path: setupQualityPath,
1757
- kind: "filesystem",
1758
- note: "Setup-quality snapshot with tree, checks, package scripts, and allowlisted previews."
1759
- },
1760
- ...baseEvidence
1761
- ],
1762
- redaction: {
1763
- status: "passed",
1764
- notes: "Feedback candidate references local public-safe run artifacts only."
1765
- },
1766
- idempotency_key: `humanish:${args.runId}:${assignment.streamId}:setup-quality`,
1767
- proposed_next_state: "setup-quality-review",
1768
- acceptance_proof: [
1769
- feedbackProofCommands(args.runId).verify,
1770
- feedbackProofCommands(args.runId).watch
1771
- ]
1772
- });
1773
- }
1774
- const actorText = `${desktop.completion?.actorLastMessageTail ?? ""}\n${desktop.completion?.actorLogTail ?? ""}`;
1775
- if (hasAppUrlProofBlocker(actorText)) {
1776
- candidates.push({
1777
- schema: "humanish.feedback-candidate.v1",
1778
- id: `published-cli-app-url-${safeArtifactToken(assignment.streamId)}`,
1779
- run_id: args.runId,
1780
- stream_id: assignment.streamId,
1781
- adapter_id: "oss-meta-lab",
1782
- scenario_id: scenarioId,
1783
- persona_id: `codex-oss-operator-${String(assignment.index).padStart(2, "0")}`,
1784
- actor: "codex-tui",
1785
- substrate: "e2b-desktop",
1786
- failure_owner: "harness",
1787
- summary: "Published Humanish install path blocked app-url proof",
1788
- expected: "A fresh npm-installed Humanish CLI should support the app-url live proof path documented for agents.",
1789
- actual: "The actor evidence reports that the installed CLI did not accept or expose the app-url proof option.",
1790
- evidence: baseEvidence,
1791
- redaction: {
1792
- status: "passed",
1793
- notes: "Actor evidence was redacted before persistence."
1794
- },
1795
- idempotency_key: `humanish:${args.runId}:${assignment.streamId}:published-cli-app-url`,
1796
- proposed_next_state: "adapter-hardening",
1797
- acceptance_proof: [
1798
- "npm view humanish version",
1799
- "npx --yes --package humanish humanish run --help | grep -- --app-url",
1800
- feedbackProofCommands(args.runId).verify
1801
- ]
1802
- });
1803
- }
1804
- if (setupQualityPath && studyQuality && (studyQuality.rating === "none" || studyQuality.rating === "ceremonial")) {
1805
- candidates.push({
1806
- schema: "humanish.feedback-candidate.v1",
1807
- id: `study-quality-${safeArtifactToken(assignment.streamId)}`,
1808
- run_id: args.runId,
1809
- stream_id: assignment.streamId,
1810
- adapter_id: "oss-meta-lab",
1811
- scenario_id: scenarioId,
1812
- persona_id: `codex-oss-operator-${String(assignment.index).padStart(2, "0")}`,
1813
- actor: "codex-tui",
1814
- substrate: "e2b-desktop",
1815
- failure_owner: "actor",
1816
- summary: `Generated Humanish setup for ${repoLabel} was ${studyQuality.rating}`,
1817
- expected: "The setup actor should turn Humanish init into an app-aware user-study plan with customized coverage, personas, scenarios, app-url proof, and public-safe feedback.",
1818
- actual: studyQuality.summary,
1819
- evidence: [
1820
- {
1821
- path: setupQualityPath,
1822
- kind: "filesystem",
1823
- note: "Setup-quality snapshot includes study-quality checks and public-safe structural signals."
1824
- },
1825
- ...baseEvidence
1826
- ],
1827
- redaction: {
1828
- status: "passed",
1829
- notes: "Study-quality feedback candidate references local public-safe artifacts only."
1830
- },
1831
- idempotency_key: `humanish:${args.runId}:${assignment.streamId}:study-quality`,
1832
- proposed_next_state: "study-quality-review",
1833
- acceptance_proof: [
1834
- feedbackProofCommands(args.runId).verify,
1835
- feedbackProofCommands(args.runId).watch,
1836
- "Study-quality rating is useful or high_leverage, or the remaining ceremonial state is explicitly explained."
1837
- ]
1838
- });
1839
- }
1840
- }
1841
- return candidates.slice(0, 20);
1842
- }
1843
- function feedbackEvidenceForDesktop(desktop) {
1844
- const evidence = [];
1845
- if (desktop.actorEvidence?.actorLastMessageTailPath) {
1846
- evidence.push({
1847
- path: desktop.actorEvidence.actorLastMessageTailPath,
1848
- kind: "log",
1849
- note: "Public-safe actor last-message tail."
1850
- });
1851
- }
1852
- if (desktop.actorEvidence?.actorLogTailPath) {
1853
- evidence.push({
1854
- path: desktop.actorEvidence.actorLogTailPath,
1855
- kind: "log",
1856
- note: "Public-safe actor log tail."
1857
- });
1858
- }
1859
- if (desktop.screenshot?.path) {
1860
- evidence.push({
1861
- path: desktop.screenshot.path,
1862
- kind: "screenshot",
1863
- note: "Headed desktop screenshot fallback."
1864
- });
1865
- }
1866
- if (desktop.hostActorPlanPath) {
1867
- evidence.push({
1868
- path: desktop.hostActorPlanPath,
1869
- kind: "trace",
1870
- note: "Host-authored public-safe actor plan."
1871
- });
1872
- }
1873
- return evidence;
1874
- }
1875
- function eventLevelForCompletion(status) {
1876
- if (status === "passed")
1877
- return "info";
1878
- if (status === "running")
1879
- return "info";
1880
- if (status === "blocked" || status === "timed_out")
1881
- return "warn";
1882
- return "error";
1883
- }
1884
- function isTerminalCompletion(completion) {
1885
- return completion !== undefined && completion.status !== "running";
1886
- }
1887
- function buildCodexBootstrapPrompt(assignment, redactRepoName = false) {
1888
- const repoLabel = redactRepoName ? "[redacted-authorized-repo]" : `https://github.com/${assignment.repo}.git`;
1889
- return [
1890
- `# Humanish OSS Meta-Lab Actor ${assignment.index}`,
1891
- "",
1892
- "You are running inside a disposable headed E2B desktop with a visible terminal and browser.",
1893
- "Public-safety hard rails: use only authorized repo contents; never print keys; never commit, push, file issues, or preserve private artifacts.",
1894
- "",
1895
- `Target repo: ${repoLabel}`,
1896
- "",
1897
- "Mission:",
1898
- "1. Clone the target repo into a clean disposable workspace.",
1899
- "2. Inspect the package manager, dev scripts, README, and app shape.",
1900
- "3. Get the repo into a local runnable dev mode if feasible.",
1901
- "4. Discover the Humanish skill path and try installing it with `npx skills add danielgwilson/humanish --skill humanish`.",
1902
- "5. Install Humanish as a dev dependency with the package manager the repo already uses. The package is `humanish`; the binary is `humanish`.",
1903
- "6. Run `npx --no-install humanish init --yes` or the package-manager equivalent. Do not run bare `npx humanish` unless you have confirmed it resolves the local `humanish` binary.",
1904
- "7. Replace starter coverage files with an app-aware `humanish/coverage-map.md` and `humanish/coverage-matrix.md` that name real screens, roles, states, happy paths, and at least one sad/friction path discovered from the repo/app.",
1905
- "8. Author at least two public-safe, app-specific Humanish personas and two desktop/mobile browser scenarios. Avoid generic `first-run-smoke` only; each scenario should name a target journey, route/state, expected evidence, and a failure/friction check.",
1906
- "9. Run `npx --no-install humanish run --help` and verify `--app-url` is available. If the local binary is missing, install `humanish`; one-shot fallback is `npx --yes --package humanish@latest humanish run --help`.",
1907
- "10. If the app is running locally, run `npx --no-install humanish run --app-url <loopback-url> --sims 2`; do not use `humanish watch --sims` as app behavior proof.",
1908
- "11. After `run --app-url`, render or open the nested Humanish Observer with `npx --no-install humanish watch --run latest --detach --no-open --json` and keep it visible.",
1909
- "12. Final summary must be public-safe and include: personas/scenarios created, product journeys covered, one observed friction/improvement or `none observed`, and evidence paths. Do not stop at install/init proof.",
1910
- "13. Record public-safe blockers and evidence paths only.",
1911
- "",
1912
- "Expected nested outcome: the top-level Humanish Observer shows this desktop, and this desktop shows its own nested Humanish Observer."
1913
- ].join("\n");
1914
- }
1915
- function renderMetaReviewMarkdown(bundle) {
1916
- return `# Humanish OSS Meta-Lab Review
1917
-
1918
- Run: ${bundle.runId}
1919
-
1920
- Verdict: ${bundle.review.verdict}
1921
-
1922
- ${bundle.review.summary}
1923
-
1924
- ## Public-Safety
1925
-
1926
- - Redaction: ${bundle.redaction.status}
1927
- - Notes: ${bundle.redaction.notes}
1928
-
1929
- ## Assigned Repos
1930
-
1931
- ${bundle.streams.map((stream) => `- ${stream.label}: ${stream.simId}`).join("\n")}
1932
-
1933
- ## Gaps
1934
-
1935
- ${bundle.review.gaps.map((gap) => `- ${gap}`).join("\n")}
1936
- `;
1937
- }
1938
- async function launchLiveDesktops(assignments, options = {}) {
1939
- const e2bApiKey = process.env.E2B_API_KEY;
1940
- if (!e2bApiKey) {
1941
- return [];
1942
- }
1943
- const desktopModule = await loadE2BDesktopModule();
1944
- const timeoutMs = readPositiveInt(process.env.HUMANISH_E2B_TIMEOUT_MS, 60 * 60 * 1000);
1945
- const requestTimeoutMs = readPositiveInt(process.env.HUMANISH_E2B_REQUEST_TIMEOUT_MS, 60_000);
1946
- return Promise.all(assignments.map(async (assignment) => {
1947
- const repoLabel = options.redactRepoNames ? repoArtifactLabel(assignment) : assignment.repo;
1948
- const hostActorPlanResult = options.hostActorPlansByStream?.get(assignment.streamId);
1949
- // Retain the provider object in process memory so attached cleanup can use a trusted handle.
1950
- // Durable result IDs are evidence only and never authorize provider mutation.
1951
- let desktop;
1952
- try {
1953
- desktop = await desktopModule.Sandbox.create({
1954
- apiKey: e2bApiKey,
1955
- requestTimeoutMs,
1956
- timeoutMs,
1957
- metadata: {
1958
- ...OSS_META_LAB_PROVIDER_METADATA,
1959
- repo: repoLabel,
1960
- simId: assignment.simId
1961
- },
1962
- envs: {
1963
- ...collectOssMetaLabRemoteEnv(process.env),
1964
- ...(options.codexAppServerMode ? { HUMANISH_OSS_META_CODEX_APP_SERVER: "1" } : {})
1965
- },
1966
- resolution: [1440, 960],
1967
- dpi: 96,
1968
- lifecycle: {
1969
- onTimeout: "kill"
1970
- }
1971
- });
1972
- const bootstrap = await startOssBootstrap(desktop, assignment, options.localPackage, requestTimeoutMs, {
1973
- ...(options.codexAppServerMode === undefined ? {} : { codexAppServerMode: options.codexAppServerMode }),
1974
- ...(hostActorPlanResult === undefined ? {} : { hostActorPlanResult }),
1975
- repoLabel,
1976
- token: options.redactRepoNames ? repoLabel : repoSlug(assignment.repo)
1977
- });
1978
- await desktop.wait(750).catch(() => undefined);
1979
- await desktop.stream.start({ requireAuth: true });
1980
- const authKey = desktop.stream.getAuthKey();
1981
- const url = desktop.stream.getUrl({
1982
- authKey,
1983
- autoConnect: true,
1984
- viewOnly: true,
1985
- resize: "scale"
1986
- });
1987
- return {
1988
- bootstrap,
1989
- desktop,
1990
- ...(hostActorPlanResult?.plan ? { hostActorPlan: hostActorPlanResult.plan } : {}),
1991
- ...(hostActorPlanResult?.artifactPath ? { hostActorPlanPath: hostActorPlanResult.artifactPath } : {}),
1992
- repo: repoLabel,
1993
- sandboxId: desktop.sandboxId,
1994
- simId: assignment.simId,
1995
- streamId: assignment.streamId,
1996
- url
1997
- };
1998
- }
1999
- catch (error) {
2000
- return {
2001
- error: compactError(error),
2002
- ...(desktop ? { desktop } : {}),
2003
- ...(hostActorPlanResult?.plan ? { hostActorPlan: hostActorPlanResult.plan } : {}),
2004
- ...(hostActorPlanResult?.artifactPath ? { hostActorPlanPath: hostActorPlanResult.artifactPath } : {}),
2005
- repo: repoLabel,
2006
- // Keep the id as public-safe lifecycle evidence only. Cleanup authority comes from the
2007
- // in-memory provider object above or a separately verified provider-metadata sweep.
2008
- ...(desktop?.sandboxId ? { sandboxId: desktop.sandboxId } : {}),
2009
- simId: assignment.simId,
2010
- streamId: assignment.streamId
2011
- };
2012
- }
2013
- }));
2014
- }
2015
- async function pollLiveDesktopCompletions(liveDesktops, options = {}) {
2016
- const pollable = liveDesktops.filter((desktop) => desktop.desktop
2017
- && desktop.bootstrap?.status === "started"
2018
- && desktop.bootstrap.completionPath);
2019
- if (pollable.length === 0) {
2020
- return { warnings: [] };
2021
- }
2022
- const timeoutMs = options.timeoutMs ?? readNonNegativeInt(process.env.HUMANISH_OSS_META_COMPLETION_TIMEOUT_MS, 240_000);
2023
- const intervalMs = readPositiveInt(process.env.HUMANISH_OSS_META_COMPLETION_INTERVAL_MS, 5_000);
2024
- const requestTimeoutMs = readPositiveInt(process.env.HUMANISH_E2B_REQUEST_TIMEOUT_MS, 60_000);
2025
- const warnings = [];
2026
- if (timeoutMs === 0) {
2027
- warnings.push(`Initial OSS meta-lab completion wait skipped because ${options.timeoutReason ?? "HUMANISH_OSS_META_COMPLETION_TIMEOUT_MS=0"}; attached watch continues polling while the Observer is open.`);
2028
- return { warnings };
2029
- }
2030
- const deadline = Date.now() + timeoutMs;
2031
- while (Date.now() <= deadline) {
2032
- await Promise.all(pollable.map(async (desktop) => {
2033
- if (isTerminalCompletion(desktop.completion) || !desktop.desktop || !desktop.bootstrap?.completionPath) {
2034
- return;
2035
- }
2036
- const completion = await readRemoteCompletion(desktop.desktop, desktop.bootstrap, requestTimeoutMs);
2037
- if (completion) {
2038
- desktop.completion = completion;
2039
- }
2040
- }));
2041
- if (pollable.every((desktop) => isTerminalCompletion(desktop.completion))) {
2042
- return { warnings };
2043
- }
2044
- await wait(Math.min(intervalMs, Math.max(0, deadline - Date.now())));
2045
- }
2046
- await Promise.all(pollable.map(async (desktop) => {
2047
- if (isTerminalCompletion(desktop.completion) || !desktop.desktop || !desktop.bootstrap) {
2048
- return;
2049
- }
2050
- desktop.completion = {
2051
- checkedAt: new Date().toISOString(),
2052
- logTail: await readRemoteLogTail(desktop.desktop, desktop.bootstrap, requestTimeoutMs),
2053
- reason: `Timed out waiting ${timeoutMs}ms for remote bootstrap completion marker.`,
2054
- status: "timed_out"
2055
- };
2056
- }));
2057
- warnings.push(`Timed out waiting for ${pollable.filter((desktop) => desktop.completion?.status === "timed_out").length}/${pollable.length} OSS meta-lab bootstrap completion marker${pollable.length === 1 ? "" : "s"}.`);
2058
- return { warnings };
2059
- }
2060
- async function refreshOssMetaLabLiveRuntime(runtime, options) {
2061
- await refreshLiveDesktopProgress(runtime.liveDesktops, {
2062
- timedOut: options.timedOut,
2063
- timeoutMs: options.timeoutMs
2064
- });
2065
- if (options.captureScreenshots) {
2066
- await captureLiveDesktopScreenshots(runtime.artifactRoot, runtime.liveDesktops);
2067
- }
2068
- await writeActorEvidenceArtifacts(runtime.artifactRoot, runtime.liveDesktops, {
2069
- assignments: runtime.assignments,
2070
- redactRepoNames: runtime.redactRepoNames
2071
- });
2072
- const bundle = buildMetaBundle({
2073
- assignments: runtime.assignments,
2074
- createdAt: runtime.createdAt,
2075
- cwd: runtime.cwd,
2076
- dryRun: runtime.dryRun,
2077
- liveDesktops: runtime.liveDesktops,
2078
- liveRequested: runtime.liveRequested,
2079
- missingKeys: runtime.missingKeys,
2080
- redactRepoNames: runtime.redactRepoNames,
2081
- runId: runtime.runId,
2082
- source: runtime.source
2083
- });
2084
- await writeMetaBundleArtifacts(runtime.artifactRoot, bundle);
2085
- await renderObserver(runtime.physicalCwd, runtime.runId, { open: false });
2086
- }
2087
- async function refreshLiveDesktopProgress(liveDesktops, options) {
2088
- const requestTimeoutMs = readPositiveInt(process.env.HUMANISH_E2B_REQUEST_TIMEOUT_MS, 60_000);
2089
- await Promise.all(liveDesktops.map(async (desktop) => {
2090
- if (!desktop.desktop || desktop.bootstrap?.status !== "started") {
2091
- return;
2092
- }
2093
- if (isTerminalCompletion(desktop.completion)) {
2094
- return;
2095
- }
2096
- const completion = await readRemoteCompletion(desktop.desktop, desktop.bootstrap, requestTimeoutMs);
2097
- if (completion) {
2098
- desktop.completion = completion;
2099
- return;
2100
- }
2101
- const logTail = await readRemoteLogTail(desktop.desktop, desktop.bootstrap, requestTimeoutMs);
2102
- desktop.completion = {
2103
- checkedAt: new Date().toISOString(),
2104
- logTail,
2105
- reason: options.timedOut
2106
- ? `Timed out waiting ${options.timeoutMs}ms for remote bootstrap completion marker.`
2107
- : logTail
2108
- ? "Remote bootstrap is running; latest public-safe log tail is available."
2109
- : "Remote bootstrap is running; waiting for first public-safe log output.",
2110
- status: options.timedOut ? "timed_out" : "running"
2111
- };
2112
- }));
2113
- }
2114
- async function readRemoteCompletion(desktop, bootstrap, requestTimeoutMs) {
2115
- if (!bootstrap.completionPath) {
2116
- return null;
2117
- }
2118
- const command = `if [ -f ${shellQuote(bootstrap.completionPath)} ]; then cat ${shellQuote(bootstrap.completionPath)}; else exit 3; fi`;
2119
- const result = await desktop.commands.run(`bash -lc ${shellQuote(command)}`, {
2120
- requestTimeoutMs,
2121
- timeoutMs: 30_000
2122
- }).catch(() => null);
2123
- if (!result || (result.exitCode && result.exitCode !== 0) || !result.stdout) {
2124
- return null;
2125
- }
2126
- return parseRemoteCompletion(result.stdout);
2127
- }
2128
- async function readRemoteLogTail(desktop, bootstrap, requestTimeoutMs) {
2129
- if (!bootstrap.logPath) {
2130
- return "";
2131
- }
2132
- const command = `tail -n 80 ${shellQuote(bootstrap.logPath)} 2>/dev/null || true`;
2133
- const result = await desktop.commands.run(`bash -lc ${shellQuote(command)}`, {
2134
- requestTimeoutMs,
2135
- timeoutMs: 30_000
2136
- }).catch(() => null);
2137
- return sanitizeRemoteLog(result?.stdout ?? "");
2138
- }
2139
- async function captureLiveDesktopScreenshots(artifactRoot, liveDesktops, options = { redactRepoNames: false }) {
2140
- const candidates = liveDesktops.filter((desktop) => desktop.desktop && desktop.url);
2141
- if (candidates.length === 0) {
2142
- return { warnings: [] };
2143
- }
2144
- const warnings = [];
2145
- await Promise.all(candidates.map(async (desktop) => {
2146
- if (!desktop.desktop) {
2147
- return;
2148
- }
2149
- try {
2150
- await arrangeLiveDesktopForScreenshot(desktop.desktop, desktop.bootstrap?.terminalTitle, readPositiveInt(process.env.HUMANISH_E2B_REQUEST_TIMEOUT_MS, 60_000));
2151
- await desktop.desktop.wait(readPositiveInt(process.env.HUMANISH_OSS_META_SCREENSHOT_SETTLE_MS, 2_500)).catch(() => undefined);
2152
- const bytes = await desktop.desktop.screenshot("bytes");
2153
- const fileName = `${safeArtifactToken(desktop.streamId)}.png`;
2154
- await writeContainedOutputFile(artifactRoot, path.join("screenshots", fileName), Buffer.from(bytes));
2155
- desktop.screenshot = {
2156
- capturedAt: new Date().toISOString(),
2157
- observerUrl: `../screenshots/${fileName}`,
2158
- path: path.join("screenshots", fileName)
2159
- };
2160
- }
2161
- catch (error) {
2162
- const laneLabel = options.redactRepoNames ? desktop.streamId : desktop.repo;
2163
- warnings.push(`Screenshot capture failed for ${laneLabel}: ${compactError(error)}`);
2164
- }
2165
- }));
2166
- const capturedCount = liveDesktops.filter((desktop) => desktop.screenshot).length;
2167
- if (capturedCount > 0) {
2168
- warnings.push(options.redactRepoNames
2169
- ? `Captured ${capturedCount}/${candidates.length} local-only redacted E2B desktop screenshot fallback${candidates.length === 1 ? "" : "s"}; do not publish private screenshots.`
2170
- : `Captured ${capturedCount}/${candidates.length} E2B desktop screenshot fallback${candidates.length === 1 ? "" : "s"}.`);
2171
- }
2172
- return { warnings };
2173
- }
2174
- async function writeActorEvidenceArtifacts(artifactRoot, liveDesktops, options) {
2175
- const candidates = liveDesktops.filter((desktop) => desktop.completion?.actorLastMessageTail
2176
- || desktop.completion?.actorLogTail
2177
- || desktop.completion?.appServerActorEvidence
2178
- || desktop.completion?.nestedObserverPresent !== undefined
2179
- || desktop.completion?.nestedStepTraceSummary !== undefined
2180
- || desktop.completion?.nestedVerifyPassed !== undefined
2181
- || desktop.completion?.setupQuality);
2182
- if (candidates.length === 0) {
2183
- return { warnings: [] };
2184
- }
2185
- let written = 0;
2186
- for (const desktop of candidates) {
2187
- const assignment = options.assignments.find((candidate) => candidate.streamId === desktop.streamId);
2188
- const repoForRedaction = options.redactRepoNames ? assignment?.repo : undefined;
2189
- const baseName = safeArtifactToken(desktop.streamId);
2190
- const actorEvidence = {};
2191
- if (desktop.completion?.actorLastMessageTail) {
2192
- const relativePath = path.join("actor-evidence", `${baseName}-actor-last-message-tail.txt`);
2193
- await writeContainedOutputFile(artifactRoot, relativePath, renderPublicSafeActorEvidenceText("actor-last-message", desktop.streamId, desktop.completion.actorLastMessageTail, {
2194
- providerRuntimeId: options.redactRepoNames ? desktop.sandboxId : undefined,
2195
- repo: repoForRedaction
2196
- }), "utf8");
2197
- actorEvidence.actorLastMessageTailPath = relativePath;
2198
- written += 1;
2199
- }
2200
- if (desktop.completion?.actorLogTail) {
2201
- const relativePath = path.join("actor-evidence", `${baseName}-actor-log-tail.txt`);
2202
- await writeContainedOutputFile(artifactRoot, relativePath, renderPublicSafeActorEvidenceText("actor-log", desktop.streamId, desktop.completion.actorLogTail, {
2203
- providerRuntimeId: options.redactRepoNames ? desktop.sandboxId : undefined,
2204
- repo: repoForRedaction
2205
- }), "utf8");
2206
- actorEvidence.actorLogTailPath = relativePath;
2207
- written += 1;
2208
- }
2209
- if (desktop.completion?.setupQuality) {
2210
- const relativePath = path.join("setup-quality", `${baseName}-setup-quality.json`);
2211
- const snapshot = options.redactRepoNames
2212
- ? redactSetupQualityRepoMentions(suppressSetupQualityPreviews(desktop.completion.setupQuality), repoForRedaction)
2213
- : desktop.completion.setupQuality;
2214
- await writeJson(artifactRoot, relativePath, snapshot);
2215
- actorEvidence.setupQualityPath = relativePath;
2216
- written += 1;
2217
- }
2218
- if (desktop.completion && (desktop.completion.nestedObserverPresent !== undefined
2219
- || desktop.completion.nestedStepTraceSummary !== undefined
2220
- || desktop.completion.nestedVerifyPassed !== undefined)) {
2221
- const relativePath = path.join("nested-evidence", `${baseName}-nested-proof.json`);
2222
- await writeJson(artifactRoot, relativePath, {
2223
- schema: "humanish.oss-meta-nested-proof.v1",
2224
- streamId: desktop.streamId,
2225
- redaction: {
2226
- status: "passed",
2227
- notes: "Nested proof summary contains booleans and redacted local artifact pointers only; remote sandbox paths are intentionally omitted."
2228
- },
2229
- status: desktop.completion.status,
2230
- reason: desktop.completion.reason,
2231
- checkedAt: desktop.completion.checkedAt,
2232
- nestedObserverPresent: desktop.completion.nestedObserverPresent === true,
2233
- nestedVerifyPassed: desktop.completion.nestedVerifyPassed === true,
2234
- ...(desktop.completion.nestedStepTraceSummary ? { stepTraceSummary: desktop.completion.nestedStepTraceSummary } : {}),
2235
- appStatus: desktop.completion.appStatus ?? "unknown",
2236
- actorStatus: desktop.completion.actorStatus ?? "unknown"
2237
- });
2238
- actorEvidence.nestedEvidencePath = relativePath;
2239
- written += 1;
2240
- }
2241
- if (desktop.completion?.appServerActorEvidence) {
2242
- const evidence = desktop.completion.appServerActorEvidence;
2243
- const tracePath = path.join("codex-app-server", `${baseName}-summary.json`);
2244
- const eventsPath = path.join("codex-app-server", `${baseName}-events.ndjson`);
2245
- const transcriptPath = path.join("codex-app-server", `${baseName}-transcript.txt`);
2246
- await writeJson(artifactRoot, tracePath, isRecord(evidence.traceJson)
2247
- ? evidence.traceJson
2248
- : {
2249
- schema: "humanish.codex-app-server-trace.missing.v1",
2250
- redaction: { status: "passed" },
2251
- status: evidence.status ?? "unknown",
2252
- reason: evidence.reason ?? "Remote app-server trace JSON was not captured.",
2253
- traceText: evidence.traceText ?? ""
2254
- });
2255
- await writeContainedOutputFile(artifactRoot, eventsPath, evidence.eventsText ?? "No app-server event envelope tail captured.\n", "utf8");
2256
- await writeContainedOutputFile(artifactRoot, transcriptPath, evidence.transcriptText ?? "No app-server transcript tail captured.\n", "utf8");
2257
- evidence.tracePath = tracePath;
2258
- evidence.eventsPath = eventsPath;
2259
- evidence.transcriptPath = transcriptPath;
2260
- actorEvidence.appServerTracePath = tracePath;
2261
- actorEvidence.appServerEventsPath = eventsPath;
2262
- actorEvidence.appServerTranscriptPath = transcriptPath;
2263
- written += 3;
2264
- }
2265
- desktop.actorEvidence = actorEvidence;
2266
- }
2267
- return {
2268
- warnings: [
2269
- `Persisted ${written} public-safe local actor evidence artifact${written === 1 ? "" : "s"}.`
2270
- ]
2271
- };
2272
- }
2273
- function suppressSetupQualityPreviews(snapshot) {
2274
- return {
2275
- ...snapshot,
2276
- summary: sanitizeSetupQualityText(snapshot.summary),
2277
- checks: snapshot.checks.map((check) => ({
2278
- ...check,
2279
- label: sanitizeSetupQualityText(check.label),
2280
- detail: sanitizeSetupQualityText(check.detail)
2281
- })),
2282
- ...(snapshot.studyQuality ? { studyQuality: sanitizeStudyQualitySnapshot(snapshot.studyQuality) } : {}),
2283
- previews: [],
2284
- redaction: {
2285
- status: "passed",
2286
- rawPreviews: "suppressed",
2287
- notes: "Raw file previews are suppressed for token-backed/private OSS meta-lab runs."
2288
- }
2289
- };
2290
- }
2291
- function renderPublicSafeActorEvidenceText(kind, streamId, text, redaction) {
2292
- const sanitized = sanitizeRemoteLog(redactPrivateActorEvidence(text, redaction));
2293
- return [
2294
- `schema: humanish.oss-meta-actor-evidence.v1`,
2295
- `kind: ${kind}`,
2296
- `stream: ${streamId}`,
2297
- `redaction: passed`,
2298
- "",
2299
- sanitized || "(no actor evidence captured)"
2300
- ].join("\n").trimEnd() + "\n";
2301
- }
2302
- function redactLiveDesktopRepoMentions(desktop, repo) {
2303
- return {
2304
- ...desktop,
2305
- ...(desktop.bootstrap
2306
- ? {
2307
- bootstrap: {
2308
- ...desktop.bootstrap,
2309
- tail: redactPrivateRuntimeMentions(desktop.bootstrap.tail, { providerRuntimeId: desktop.sandboxId, repo })
2310
- }
2311
- }
2312
- : {}),
2313
- ...(desktop.completion
2314
- ? { completion: redactCompletionRepoMentions(desktop.completion, repo, desktop.sandboxId) }
2315
- : {})
2316
- };
2317
- }
2318
- function redactCompletionRepoMentions(completion, repo, providerRuntimeId) {
2319
- const redaction = { providerRuntimeId, repo };
2320
- return {
2321
- ...completion,
2322
- ...(completion.actorLogTail === undefined ? {} : { actorLogTail: redactPrivateActorEvidence(completion.actorLogTail, redaction) }),
2323
- ...(completion.actorLastMessageTail === undefined ? {} : { actorLastMessageTail: redactPrivateActorEvidence(completion.actorLastMessageTail, redaction) }),
2324
- ...(completion.appServerActorEvidence === undefined ? {} : { appServerActorEvidence: redactAppServerActorEvidence(completion.appServerActorEvidence, redaction) }),
2325
- ...(completion.appReason === undefined ? {} : { appReason: redactPrivateRuntimeMentions(completion.appReason, redaction) }),
2326
- ...(completion.logTail === undefined ? {} : { logTail: redactPrivateRuntimeMentions(completion.logTail, redaction) }),
2327
- ...(completion.nestedStepTraceSummary === undefined ? {} : { nestedStepTraceSummary: redactNestedStepTraceSummary(completion.nestedStepTraceSummary, redaction) }),
2328
- reason: redactPrivateRuntimeMentions(completion.reason, redaction),
2329
- ...(completion.setupQuality === undefined ? {} : { setupQuality: redactSetupQualityRepoMentions(completion.setupQuality, repo) }),
2330
- ...(completion.visualReason === undefined ? {} : { visualReason: redactPrivateRuntimeMentions(completion.visualReason, redaction) })
2331
- };
2332
- }
2333
- function redactNestedStepTraceSummary(summary, redaction) {
2334
- return normalizeNestedStepTraceSummary(redactJsonValue(summary, redaction)) ?? summary;
2335
- }
2336
- function redactAppServerActorEvidence(evidence, redaction) {
2337
- return {
2338
- ...evidence,
2339
- ...(evidence.eventsText === undefined ? {} : { eventsText: redactPrivateActorEvidence(evidence.eventsText, redaction) }),
2340
- ...(evidence.reason === undefined ? {} : { reason: redactPrivateRuntimeMentions(evidence.reason, redaction) }),
2341
- ...(evidence.status === undefined ? {} : { status: redactPrivateRuntimeMentions(evidence.status, redaction) }),
2342
- ...(evidence.traceJson === undefined ? {} : { traceJson: redactJsonValue(evidence.traceJson, redaction) }),
2343
- ...(evidence.traceText === undefined ? {} : { traceText: redactPrivateActorEvidence(evidence.traceText, redaction) }),
2344
- ...(evidence.transcriptText === undefined ? {} : { transcriptText: redactPrivateActorEvidence(evidence.transcriptText, redaction) })
2345
- };
2346
- }
2347
- function redactJsonValue(value, redaction) {
2348
- try {
2349
- return JSON.parse(redactPrivateActorEvidence(JSON.stringify(value), redaction));
2350
- }
2351
- catch {
2352
- return value;
2353
- }
2354
- }
2355
- function redactPrivateActorEvidence(text, redaction) {
2356
- const redacted = redactPrivateRuntimeMentions(text, redaction);
2357
- return redaction?.repo ? stripSourceDiffBlocks(redacted) : redacted;
2358
- }
2359
- function stripSourceDiffBlocks(text) {
2360
- const lines = text.split(/\r?\n/);
2361
- const output = [];
2362
- let inDiff = false;
2363
- let emittedMarker = false;
2364
- for (const line of lines) {
2365
- if (/^diff --git\b/.test(line)) {
2366
- if (!emittedMarker) {
2367
- output.push("[redacted-source-diff]");
2368
- emittedMarker = true;
2369
- }
2370
- inDiff = true;
2371
- continue;
2372
- }
2373
- if (inDiff) {
2374
- if (/^(tokens used|Installed\b|Humanish\b|Created personas:|Created browser scenarios:|Product journeys covered:|Observed friction|Evidence paths:|Verification:|If you want\b)/.test(line)) {
2375
- inDiff = false;
2376
- }
2377
- else {
2378
- continue;
2379
- }
2380
- }
2381
- output.push(line);
2382
- }
2383
- return output.join("\n");
2384
- }
2385
- function redactSetupQualityRepoMentions(snapshot, repo) {
2386
- if (!repo) {
2387
- return snapshot;
2388
- }
2389
- return JSON.parse(JSON.stringify(snapshot, (_key, value) => typeof value === "string" ? redactRepoMentions(value, repo) : value));
2390
- }
2391
- function redactRepoMentions(text, repo) {
2392
- const [owner, name] = repo.split("/");
2393
- if (!owner || !name) {
2394
- return text;
2395
- }
2396
- const replacement = "[redacted-authorized-repo]";
2397
- let redacted = text
2398
- .replace(new RegExp(`https://github\\.com/${escapeRegExp(owner)}/${escapeRegExp(name)}(?:\\.git)?`, "gi"), replacement)
2399
- .replace(new RegExp(`git@github\\.com:${escapeRegExp(owner)}/${escapeRegExp(name)}(?:\\.git)?`, "gi"), replacement)
2400
- .replace(new RegExp(`\\b${escapeRegExp(owner)}/${escapeRegExp(name)}\\b`, "gi"), replacement);
2401
- if (name.length >= 4 && !isCommonRepoBasename(name)) {
2402
- redacted = redacted.replace(new RegExp(`\\b${escapeRegExp(name)}\\b`, "gi"), replacement);
2403
- }
2404
- return redacted;
2405
- }
2406
- function redactPrivateRuntimeMentions(text, redaction) {
2407
- let redacted = text;
2408
- if (redaction?.repo) {
2409
- redacted = redactRepoMentions(redacted, redaction.repo);
2410
- }
2411
- if (redaction?.providerRuntimeId) {
2412
- redacted = redacted.replace(new RegExp(escapeRegExp(redaction.providerRuntimeId), "g"), "[redacted-provider-runtime-id]");
2413
- }
2414
- return redacted;
2415
- }
2416
- function isCommonRepoBasename(value) {
2417
- return new Set(["app", "web", "api", "cli", "repo", "site", "docs", "main", "next", "demo", "test"]).has(value.toLowerCase());
2418
- }
2419
- function escapeRegExp(value) {
2420
- return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2421
- }
2422
- function hasAppUrlProofBlocker(text) {
2423
- const normalized = normalizeActorEvidenceForPattern(text);
2424
- const blocker = "(?:unknown option|unsupported|not available|does\\s+\\W*not\\W*(?:support|expose|accept)|did\\s+\\W*not\\W*(?:support|expose|accept)|doesnt\\s+(?:support|expose|accept)|didnt\\s+(?:support|expose|accept))";
2425
- const appUrl = "(?:--app-url|run\\s+--app-url|app-url\\s+proof)";
2426
- return new RegExp(`${blocker}[\\s\\S]{0,220}${appUrl}|${appUrl}[\\s\\S]{0,220}${blocker}`, "i").test(normalized);
2427
- }
2428
- function normalizeActorEvidenceForPattern(text) {
2429
- return text
2430
- .replace(/[*_`~[\](){}<>]/g, " ")
2431
- .replace(/\s+/g, " ")
2432
- .trim();
2433
- }
2434
- async function arrangeLiveDesktopForScreenshot(desktop, terminalTitle, requestTimeoutMs) {
2435
- const command = buildRemoteScreenshotArrangeCommand(terminalTitle);
2436
- await desktop.commands.run(`bash -lc ${shellQuote(command)}`, {
2437
- requestTimeoutMs,
2438
- timeoutMs: 15_000
2439
- }).catch(() => undefined);
2440
- }
2441
- function parseRemoteCompletion(payload) {
2442
- try {
2443
- const parsed = JSON.parse(payload);
2444
- const status = normalizeCompletionStatus(parsed.status);
2445
- if (!status) {
2446
- return null;
2447
- }
2448
- const nestedVerifyPassed = parsed.nestedVerifyStatus === "passed"
2449
- ? true
2450
- : parsed.nestedVerifyStatus === "failed" ? false : undefined;
2451
- const appStatus = normalizeAppStatus(parsed.appStatus);
2452
- const actorStatus = normalizeActorStatus(parsed.actorStatus);
2453
- const visualStatus = normalizeVisualStatus(parsed.visualStatus);
2454
- const appServerActorEvidence = normalizeAppServerActorEvidence(parsed.appServerActorEvidence);
2455
- const nestedStepTraceSummary = normalizeNestedStepTraceSummary(parsed.nestedStepTraceSummary);
2456
- return {
2457
- ...(typeof parsed.actorLogPath === "string" && parsed.actorLogPath.trim() ? { actorLogPath: sanitizeRemoteLog(parsed.actorLogPath) } : {}),
2458
- ...(typeof parsed.actorLogTail === "string" && parsed.actorLogTail.trim() ? { actorLogTail: sanitizeRemoteLog(parsed.actorLogTail) } : {}),
2459
- ...(typeof parsed.actorLastMessageTail === "string" && parsed.actorLastMessageTail.trim() ? { actorLastMessageTail: sanitizeRemoteLog(parsed.actorLastMessageTail) } : {}),
2460
- ...(typeof parsed.actorPid === "number" && Number.isFinite(parsed.actorPid) ? { actorPid: parsed.actorPid } : {}),
2461
- ...(actorStatus ? { actorStatus } : {}),
2462
- ...(appServerActorEvidence ? { appServerActorEvidence } : {}),
2463
- ...(typeof parsed.appLogPath === "string" && parsed.appLogPath.trim() ? { appLogPath: sanitizeRemoteLog(parsed.appLogPath) } : {}),
2464
- ...(typeof parsed.appPid === "number" && Number.isFinite(parsed.appPid) ? { appPid: parsed.appPid } : {}),
2465
- ...(typeof parsed.appReason === "string" && parsed.appReason.trim() ? { appReason: sanitizeRemoteLog(parsed.appReason).replace(/\s+/g, " ").slice(0, 240) } : {}),
2466
- ...(appStatus ? { appStatus } : {}),
2467
- ...(typeof parsed.appUrl === "string" && parsed.appUrl.trim() ? { appUrl: sanitizeRemoteLog(parsed.appUrl).replace(/\s+/g, " ").slice(0, 240) } : {}),
2468
- checkedAt: typeof parsed.completedAt === "string" ? parsed.completedAt : new Date().toISOString(),
2469
- ...(typeof parsed.exitCode === "number" ? { exitCode: parsed.exitCode } : {}),
2470
- ...(typeof parsed.logTail === "string" ? { logTail: sanitizeRemoteLog(parsed.logTail) } : {}),
2471
- ...(typeof parsed.nestedObserverPresent === "boolean" ? { nestedObserverPresent: parsed.nestedObserverPresent } : {}),
2472
- ...(nestedStepTraceSummary ? { nestedStepTraceSummary } : {}),
2473
- ...(nestedVerifyPassed === undefined ? {} : { nestedVerifyPassed }),
2474
- reason: typeof parsed.reason === "string" && parsed.reason.trim()
2475
- ? sanitizeRemoteLog(parsed.reason).replace(/\s+/g, " ").slice(0, 240)
2476
- : defaultReasonForCompletion(status),
2477
- ...(isRunSetupQualitySnapshot(parsed.setupQuality) ? { setupQuality: sanitizeSetupQualitySnapshot(parsed.setupQuality) } : {}),
2478
- status,
2479
- ...(typeof parsed.visualReason === "string" && parsed.visualReason.trim() ? { visualReason: sanitizeRemoteLog(parsed.visualReason).replace(/\s+/g, " ").slice(0, 240) } : {}),
2480
- ...(visualStatus ? { visualStatus } : {}),
2481
- ...(typeof parsed.visualWindowCount === "number" && Number.isFinite(parsed.visualWindowCount) ? { visualWindowCount: parsed.visualWindowCount } : {})
2482
- };
2483
- }
2484
- catch {
2485
- return null;
2486
- }
2487
- }
2488
- function normalizeAppStatus(value) {
2489
- return value === "not_started"
2490
- || value === "running"
2491
- || value === "blocked"
2492
- || value === "failed"
2493
- || value === "missing"
2494
- || value === "unknown"
2495
- ? value
2496
- : null;
2497
- }
2498
- function normalizeVisualStatus(value) {
2499
- return value === "not_started"
2500
- || value === "visible"
2501
- || value === "blocked"
2502
- || value === "unknown"
2503
- ? value
2504
- : null;
2505
- }
2506
- function normalizeActorStatus(value) {
2507
- return value === "not_started"
2508
- || value === "running"
2509
- || value === "passed"
2510
- || value === "failed"
2511
- || value === "blocked"
2512
- || value === "timed_out"
2513
- || value === "suspended"
2514
- || value === "unknown"
2515
- ? value
2516
- : null;
2517
- }
2518
- function normalizeNestedStepTraceSummary(value) {
2519
- if (!isRecord(value) || !Array.isArray(value.surfaces)) {
2520
- return null;
2521
- }
2522
- const surfaces = value.surfaces
2523
- .slice(0, 8)
2524
- .filter((surface) => isRecord(surface))
2525
- .map((surface) => {
2526
- const steps = Array.isArray(surface.steps)
2527
- ? surface.steps
2528
- .slice(0, 20)
2529
- .filter((step) => isRecord(step))
2530
- .map((step) => {
2531
- const status = normalizeNestedStepStatus(step.status);
2532
- const assertionStatuses = Array.isArray(step.assertionStatuses)
2533
- ? step.assertionStatuses
2534
- .map((statusValue) => publicSafeSummaryToken(statusValue, "assertion"))
2535
- .filter(Boolean)
2536
- .slice(0, 12)
2537
- : undefined;
2538
- return {
2539
- action: publicSafeSummaryToken(step.action, "action"),
2540
- ...(assertionStatuses && assertionStatuses.length > 0 ? { assertionStatuses } : {}),
2541
- id: publicSafeSummaryToken(step.id, "step"),
2542
- ...(typeof step.label === "string" && step.label.trim() ? { label: sanitizeNestedTraceText(step.label, 140) } : {}),
2543
- reason: sanitizeNestedTraceText(step.reason, 240),
2544
- status
2545
- };
2546
- })
2547
- : [];
2548
- return {
2549
- id: publicSafeSummaryToken(surface.id, "surface"),
2550
- ...(typeof surface.label === "string" && surface.label.trim() ? { label: sanitizeNestedTraceText(surface.label, 140) } : {}),
2551
- ok: surface.ok === true,
2552
- reason: sanitizeNestedTraceText(surface.reason, 240),
2553
- steps
2554
- };
2555
- })
2556
- .filter((surface) => surface.steps.length > 0);
2557
- if (surfaces.length === 0) {
2558
- return null;
2559
- }
2560
- const totalSteps = surfaces.reduce((total, surface) => total + surface.steps.length, 0);
2561
- const passedSteps = surfaces.reduce((total, surface) => total + surface.steps.filter((step) => step.status === "passed").length, 0);
2562
- const blockedSteps = surfaces.reduce((total, surface) => total + surface.steps.filter((step) => step.status === "blocked").length, 0);
2563
- const scenario = isRecord(value.scenario)
2564
- ? {
2565
- id: publicSafeSummaryToken(value.scenario.id, "scenario"),
2566
- ...(typeof value.scenario.source === "string" && isSafeRepoRelativePath(value.scenario.source) ? { source: sanitizeSetupQualityPath(value.scenario.source) } : {}),
2567
- ...(typeof value.scenario.sourceDigest === "string" && value.scenario.sourceDigest.trim() ? { sourceDigest: publicSafeSummaryToken(value.scenario.sourceDigest, "digest") } : {}),
2568
- ...(typeof value.scenario.stepCount === "number" && Number.isFinite(value.scenario.stepCount) ? { stepCount: Math.max(0, Math.round(value.scenario.stepCount)) } : {}),
2569
- ...(typeof value.scenario.title === "string" && value.scenario.title.trim() ? { title: sanitizeNestedTraceText(value.scenario.title, 140) } : {})
2570
- }
2571
- : undefined;
2572
- return {
2573
- schema: "humanish.oss-meta-nested-step-trace-summary.v1",
2574
- redaction: {
2575
- status: "passed",
2576
- notes: "Nested browser trace summary stores counts and redacted step metadata only; URLs, auth streams, remote paths, screenshots, and raw DOM text are omitted."
2577
- },
2578
- counts: {
2579
- blockedSteps,
2580
- passedSteps,
2581
- surfaces: surfaces.length,
2582
- totalSteps,
2583
- traces: surfaces.length
2584
- },
2585
- ...(scenario ? { scenario } : {}),
2586
- status: blockedSteps > 0 ? "blocked" : passedSteps === totalSteps ? "passed" : "unknown",
2587
- surfaces
2588
- };
2589
- }
2590
- function normalizeNestedStepStatus(value) {
2591
- return value === "passed" || value === "blocked" ? value : "unknown";
2592
- }
2593
- function publicSafeSummaryToken(value, fallback) {
2594
- const token = sanitizeSetupQualityText(value)
2595
- .toLowerCase()
2596
- .replace(/[^a-z0-9_.-]+/g, "-")
2597
- .replace(/^-+|-+$/g, "")
2598
- .slice(0, 80);
2599
- return token || fallback;
2600
- }
2601
- function sanitizeNestedTraceText(value, maxLength) {
2602
- return sanitizeSetupQualityText(value)
2603
- .replace(/https?:\/\/\S+/gi, "[redacted-url]")
2604
- .replace(/(?:^|\s)\/(?:home|tmp|var|Users)\/\S+/g, " [redacted-path]")
2605
- .replace(/\s+/g, " ")
2606
- .trim()
2607
- .slice(0, maxLength);
2608
- }
2609
- function normalizeAppServerActorEvidence(value) {
2610
- if (!isRecord(value)) {
2611
- return null;
2612
- }
2613
- const tracePath = safeRelativeArtifactPath(typeof value.tracePath === "string" ? value.tracePath : "");
2614
- const eventsPath = safeRelativeArtifactPath(typeof value.eventsPath === "string" ? value.eventsPath : "");
2615
- const transcriptPath = safeRelativeArtifactPath(typeof value.transcriptPath === "string" ? value.transcriptPath : "");
2616
- if (!tracePath || !eventsPath || !transcriptPath) {
2617
- return null;
2618
- }
2619
- return {
2620
- eventsPath,
2621
- ...(typeof value.eventsText === "string" && value.eventsText.trim() ? { eventsText: sanitizeRemoteLog(value.eventsText) } : {}),
2622
- ...(typeof value.reason === "string" && value.reason.trim() ? { reason: sanitizeRemoteLog(value.reason).replace(/\s+/g, " ").slice(0, 240) } : {}),
2623
- ...(typeof value.status === "string" && value.status.trim() ? { status: sanitizeRemoteLog(value.status).replace(/\s+/g, " ").slice(0, 80) } : {}),
2624
- ...(isRecord(value.traceJson) ? { traceJson: value.traceJson } : {}),
2625
- tracePath,
2626
- ...(typeof value.traceText === "string" && value.traceText.trim() ? { traceText: sanitizeRemoteLog(value.traceText) } : {}),
2627
- transcriptPath,
2628
- ...(typeof value.transcriptText === "string" && value.transcriptText.trim() ? { transcriptText: sanitizeRemoteLog(value.transcriptText) } : {})
2629
- };
2630
- }
2631
- function safeRelativeArtifactPath(value) {
2632
- const normalized = value.replace(/\\/g, "/").replace(/^\.\/+/, "");
2633
- if (!normalized || normalized.startsWith("/") || normalized.startsWith("../") || normalized.includes("://") || normalized.split("/").includes("..")) {
2634
- return "";
2635
- }
2636
- return normalized;
2637
- }
2638
- function normalizeCompletionStatus(value) {
2639
- return value === "running"
2640
- || value === "passed"
2641
- || value === "failed"
2642
- || value === "blocked"
2643
- || value === "timed_out"
2644
- ? value
2645
- : null;
2646
- }
2647
- function defaultReasonForCompletion(status) {
2648
- switch (status) {
2649
- case "passed":
2650
- return "Remote bootstrap completed successfully.";
2651
- case "failed":
2652
- return "Remote bootstrap failed.";
2653
- case "blocked":
2654
- return "Remote bootstrap is blocked.";
2655
- case "timed_out":
2656
- return "Remote bootstrap completion timed out.";
2657
- case "running":
2658
- return "Remote bootstrap is still running.";
2659
- }
2660
- }
2661
- function isRunSetupQualitySnapshot(value) {
2662
- if (!isRecord(value) || value.schema !== "humanish.setup-quality.v1") {
2663
- return false;
2664
- }
2665
- return Array.isArray(value.checks)
2666
- && Array.isArray(value.tree)
2667
- && Array.isArray(value.previews)
2668
- && isRecord(value.humanish)
2669
- && isRecord(value.packageScripts)
2670
- && typeof value.generatedAt === "string"
2671
- && typeof value.summary === "string"
2672
- && (value.status === "passed" || value.status === "needs_review" || value.status === "blocked");
2673
- }
2674
- function sanitizeSetupQualitySnapshot(snapshot) {
2675
- const safeTree = snapshot.tree
2676
- .filter((entry) => isSafeRepoRelativePath(entry.path) && (entry.type === "file" || entry.type === "directory"))
2677
- .slice(0, 240)
2678
- .map((entry) => ({
2679
- path: sanitizeSetupQualityPath(entry.path),
2680
- type: entry.type,
2681
- ...(typeof entry.sizeBytes === "number" && Number.isFinite(entry.sizeBytes) ? { sizeBytes: Math.max(0, Math.round(entry.sizeBytes)) } : {})
2682
- }));
2683
- const safePreviews = snapshot.previews
2684
- .filter((preview) => isSafeRepoRelativePath(preview.path))
2685
- .slice(0, 20)
2686
- .map((preview) => ({
2687
- path: sanitizeSetupQualityPath(preview.path),
2688
- language: sanitizePreviewLanguage(preview.language),
2689
- truncated: preview.truncated === true,
2690
- text: sanitizeSetupQualityText(preview.text).slice(0, 8_000)
2691
- }));
2692
- const safeScripts = {};
2693
- for (const [key, value] of Object.entries(snapshot.packageScripts)) {
2694
- const safeKey = sanitizeSetupQualityText(key).replace(/[^a-zA-Z0-9:_-]/g, "").slice(0, 80);
2695
- if (!safeKey || typeof value !== "string") {
2696
- continue;
2697
- }
2698
- safeScripts[safeKey] = sanitizeSetupQualityText(value).slice(0, 300);
2699
- }
2700
- return {
2701
- schema: "humanish.setup-quality.v1",
2702
- generatedAt: sanitizeSetupQualityText(snapshot.generatedAt).slice(0, 80) || new Date().toISOString(),
2703
- redaction: {
2704
- status: "passed",
2705
- rawPreviews: snapshot.redaction?.rawPreviews === "suppressed" ? "suppressed" : "included",
2706
- notes: sanitizeSetupQualityText(snapshot.redaction?.notes ?? "Remote setup snapshot was redacted before persistence.").slice(0, 240)
2707
- },
2708
- summary: sanitizeSetupQualityText(snapshot.summary).slice(0, 320),
2709
- status: snapshot.status,
2710
- checks: snapshot.checks
2711
- .filter((check) => isRecord(check) && typeof check.id === "string" && typeof check.label === "string" && typeof check.detail === "string")
2712
- .slice(0, 40)
2713
- .map((check) => ({
2714
- id: sanitizeSetupQualityText(check.id).replace(/[^a-zA-Z0-9:_-]/g, "").slice(0, 80) || "check",
2715
- label: sanitizeSetupQualityText(check.label).slice(0, 140),
2716
- ok: check.ok === true,
2717
- detail: sanitizeSetupQualityText(check.detail).slice(0, 320)
2718
- })),
2719
- tree: safeTree,
2720
- previews: safePreviews,
2721
- ...(snapshot.studyQuality ? { studyQuality: sanitizeStudyQualitySnapshot(snapshot.studyQuality) } : {}),
2722
- packageScripts: safeScripts,
2723
- humanish: {
2724
- configPresent: snapshot.humanish.configPresent === true,
2725
- personaCount: typeof snapshot.humanish.personaCount === "number" && Number.isFinite(snapshot.humanish.personaCount) ? Math.max(0, Math.round(snapshot.humanish.personaCount)) : 0,
2726
- scenarioCount: typeof snapshot.humanish.scenarioCount === "number" && Number.isFinite(snapshot.humanish.scenarioCount) ? Math.max(0, Math.round(snapshot.humanish.scenarioCount)) : 0,
2727
- packageScriptPresent: snapshot.humanish.packageScriptPresent === true,
2728
- gitignoreContainsRuntimeIgnore: snapshot.humanish.gitignoreContainsRuntimeIgnore === true
2729
- }
2730
- };
2731
- }
2732
- function sanitizeStudyQualitySnapshot(studyQuality) {
2733
- const rating = studyQuality.rating === "none"
2734
- || studyQuality.rating === "ceremonial"
2735
- || studyQuality.rating === "useful"
2736
- || studyQuality.rating === "high_leverage"
2737
- ? studyQuality.rating
2738
- : "none";
2739
- return {
2740
- schema: "humanish.study-quality.v1",
2741
- rating,
2742
- summary: sanitizeSetupQualityText(studyQuality.summary).slice(0, 320),
2743
- checks: Array.isArray(studyQuality.checks)
2744
- ? studyQuality.checks
2745
- .filter((check) => isRecord(check) && typeof check.id === "string" && typeof check.label === "string" && typeof check.detail === "string")
2746
- .slice(0, 20)
2747
- .map((check) => ({
2748
- id: sanitizeSetupQualityText(check.id).replace(/[^a-zA-Z0-9:_-]/g, "").slice(0, 80) || "study-check",
2749
- label: sanitizeSetupQualityText(check.label).slice(0, 140),
2750
- ok: check.ok === true,
2751
- detail: sanitizeSetupQualityText(check.detail).slice(0, 320)
2752
- }))
2753
- : [],
2754
- signals: {
2755
- appUrlProofBlocked: studyQuality.signals?.appUrlProofBlocked === true,
2756
- appUrlProofMentioned: studyQuality.signals?.appUrlProofMentioned === true,
2757
- actorInsightCaptured: studyQuality.signals?.actorInsightCaptured === true,
2758
- coverageCustomized: studyQuality.signals?.coverageCustomized === true,
2759
- personaCustomized: studyQuality.signals?.personaCustomized === true,
2760
- scenarioCustomized: studyQuality.signals?.scenarioCustomized === true
2761
- }
2762
- };
2763
- }
2764
- function sanitizePreviewLanguage(value) {
2765
- return value === "json" || value === "yaml" || value === "typescript" || value === "markdown" || value === "text"
2766
- ? value
2767
- : "text";
2768
- }
2769
- function sanitizeSetupQualityPath(value) {
2770
- return value.replace(/\\/g, "/").replace(/^\.\/+/, "").slice(0, 240);
2771
- }
2772
- function sanitizeSetupQualityText(value) {
2773
- return redactOssRemoteTelemetryText(String(value ?? ""))
2774
- .replace(/\0/g, "")
2775
- .replace(/https?:\/\/[^/\s]*e2b[^)\s]+/gi, "[redacted-e2b-url]")
2776
- .trim();
2777
- }
2778
- function isSafeRepoRelativePath(value) {
2779
- if (typeof value !== "string" || !value.trim()) {
2780
- return false;
2781
- }
2782
- const normalized = value.replace(/\\/g, "/").replace(/^\.\/+/, "");
2783
- return !path.isAbsolute(normalized)
2784
- && !normalized.includes("://")
2785
- && !normalized.startsWith("../")
2786
- && !normalized.split("/").includes("..")
2787
- && !normalized.split("/").some((segment) => /^(?:\.env(?:\..*)?|\.npmrc|\.git|node_modules|dist|build|\.next)$/.test(segment));
2788
- }
2789
- function isLocalEvidenceArtifactPath(value) {
2790
- return isSafeRepoRelativePath(value);
2791
- }
2792
- function isRecord(value) {
2793
- return typeof value === "object" && value !== null && !Array.isArray(value);
2794
- }
2795
- function sanitizeRemoteLog(value) {
2796
- return redactOssRemoteTelemetryText(value)
2797
- .split(/\r?\n/)
2798
- .slice(-80)
2799
- .join("\n")
2800
- .trim();
2801
- }
2802
- async function startOssBootstrap(desktop, assignment, localPackage, requestTimeoutMs, display = {
2803
- repoLabel: assignment.repo,
2804
- token: repoSlug(assignment.repo)
2805
- }) {
2806
- const token = display.token;
2807
- const appDir = `/home/user/${token}`;
2808
- const stateDir = `/home/user/.humanish-oss-lab/${token}`;
2809
- const remotePackagePath = `/tmp/${localPackage?.fileName ?? "humanish.tgz"}`;
2810
- const remoteHostActorPlanPath = `${stateDir}/host-actor-plan.json`;
2811
- const bootstrapPath = `${stateDir}/bootstrap.sh`;
2812
- const launcherPath = `${stateDir}/launch-terminal.sh`;
2813
- const logPath = `${stateDir}/bootstrap.log`;
2814
- const completionPath = `${stateDir}/completion.json`;
2815
- const nestedObserverPath = `${appDir}/.humanish/runs/nested-${token}/observer/index.html`;
2816
- const title = `Humanish ${assignment.index} ${display.repoLabel}`;
2817
- const codexMode = codexAppServerModeRequested(process.env, display.codexAppServerMode === true) ? "app-server-client" : "tui-attempted";
2818
- const baseTail = [
2819
- `repo: ${display.repoLabel}`,
2820
- `project: ${appDir}`,
2821
- `sandbox: ${desktop.sandboxId}`,
2822
- `remote package: ${localPackage ? remotePackagePath : "npm:humanish fallback"}`,
2823
- `bootstrap: ${bootstrapPath}`,
2824
- `completion: ${completionPath}`,
2825
- `log: ${logPath}`,
2826
- `nested observer: ${nestedObserverPath}`
2827
- ].join("\n");
2828
- try {
2829
- await runDesktopCommand(desktop, `mkdir -p ${shellQuote(stateDir)}`, {
2830
- requestTimeoutMs,
2831
- timeoutMs: 30_000
2832
- });
2833
- if (localPackage) {
2834
- const packageBytes = await readFile(localPackage.path);
2835
- await desktop.files.write(remotePackagePath, toArrayBuffer(packageBytes), {
2836
- requestTimeoutMs,
2837
- useOctetStream: true
2838
- });
2839
- }
2840
- if (display.hostActorPlanResult?.plan) {
2841
- await desktop.files.write(remoteHostActorPlanPath, `${JSON.stringify(display.hostActorPlanResult.plan, null, 2)}\n`, {
2842
- requestTimeoutMs
2843
- });
2844
- }
2845
- const bootstrapScript = buildRemoteBootstrapScript({
2846
- assignment,
2847
- appDir,
2848
- completionPath,
2849
- displayRepo: display.repoLabel,
2850
- logPath,
2851
- nestedObserverPath,
2852
- ...(display.hostActorPlanResult?.plan ? { remoteHostActorPlanPath } : {}),
2853
- stateDir,
2854
- token,
2855
- ...(localPackage ? { remotePackagePath } : {})
2856
- });
2857
- const launcherScript = buildRemoteLauncherScript({
2858
- bootstrapPath,
2859
- launcherPath,
2860
- logPath,
2861
- title
2862
- });
2863
- await desktop.files.write(bootstrapPath, bootstrapScript, { requestTimeoutMs });
2864
- await desktop.files.write(launcherPath, launcherScript, { requestTimeoutMs });
2865
- await runDesktopCommand(desktop, `chmod +x ${shellQuote(bootstrapPath)} ${shellQuote(launcherPath)}`, {
2866
- requestTimeoutMs,
2867
- timeoutMs: 30_000
2868
- });
2869
- await runDesktopCommand(desktop, `bash ${shellQuote(launcherPath)}`, {
2870
- requestTimeoutMs,
2871
- timeoutMs: 30_000
2872
- });
2873
- await desktop.wait(1200).catch(() => undefined);
2874
- await runDesktopCommand(desktop, buildRemoteFocusCommand(title), {
2875
- requestTimeoutMs,
2876
- timeoutMs: 10_000
2877
- }).catch(() => undefined);
2878
- return {
2879
- codexMode,
2880
- completionPath,
2881
- launcherPath,
2882
- logPath,
2883
- humanishPackageUploaded: Boolean(localPackage),
2884
- nestedObserverPath,
2885
- status: "started",
2886
- tail: [
2887
- "Visible E2B bootstrap terminal launched.",
2888
- codexMode === "app-server-client"
2889
- ? "The terminal clones the authorized repo, installs this local humanish package tarball when available, runs nested Humanish proof commands, opens the nested Observer, and opens the Codex app-server client surface in Chrome when configured."
2890
- : "The terminal clones the authorized repo, installs this local humanish package tarball when available, runs nested Humanish proof commands, attempts Codex TUI, then opens the nested Observer in Chrome.",
2891
- baseTail
2892
- ].join("\n"),
2893
- terminalTitle: title
2894
- };
2895
- }
2896
- catch (error) {
2897
- return {
2898
- codexMode,
2899
- completionPath,
2900
- launcherPath,
2901
- logPath,
2902
- humanishPackageUploaded: Boolean(localPackage),
2903
- nestedObserverPath,
2904
- status: "failed",
2905
- tail: [
2906
- "Bootstrap launcher failed before the remote terminal could start.",
2907
- baseTail,
2908
- `error: ${compactError(error)}`
2909
- ].join("\n"),
2910
- terminalTitle: title
2911
- };
2912
- }
2913
- }
2914
- function buildRemoteBootstrapScript(args) {
2915
- const repoUrl = `https://github.com/${args.assignment.repo}.git`;
2916
- const runId = `nested-${args.token}`;
2917
- return `#!/usr/bin/env bash
2918
- set -Eeuo pipefail
2919
- export TERM=xterm-256color
2920
- export HUMANISH_PUBLIC_SAFE=1
2921
- HUMANISH_PRIVATE_CODEX_API_KEY="\${HUMANISH_CODEX_API_KEY:-}"
2922
- HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN="\${HUMANISH_CODEX_ACCESS_TOKEN:-}"
2923
- HUMANISH_PRIVATE_CODEX_APP_SERVER_URL="\${HUMANISH_CODEX_APP_SERVER_URL:-}"
2924
- HUMANISH_PRIVATE_GITHUB_TOKEN="\${HUMANISH_GITHUB_TOKEN:-}"
2925
- unset HUMANISH_CODEX_API_KEY HUMANISH_CODEX_ACCESS_TOKEN HUMANISH_CODEX_APP_SERVER_URL HUMANISH_GITHUB_TOKEN
2926
- unset OPENAI_API_KEY CODEX_API_KEY CODEX_ACCESS_TOKEN E2B_API_KEY GH_TOKEN GITHUB_TOKEN
2927
- STATE_DIR=${shellQuote(args.stateDir)}
2928
- ROOT_DIR="$STATE_DIR"
2929
- APP_DIR=${shellQuote(args.appDir)}
2930
- LOG_PATH=${shellQuote(args.logPath)}
2931
- COMPLETION_PATH=${shellQuote(args.completionPath)}
2932
- NESTED_OBSERVER=${shellQuote(args.nestedObserverPath)}
2933
- REMOTE_PACKAGE=${args.remotePackagePath ? shellQuote(args.remotePackagePath) : "''"}
2934
- HOST_ACTOR_PLAN=${args.remoteHostActorPlanPath ? shellQuote(args.remoteHostActorPlanPath) : "''"}
2935
- APP_LOG_PATH="$ROOT_DIR/app.log"
2936
- ACTOR_LOG_PATH="$ROOT_DIR/actor.log"
2937
- ACTOR_LAST_MESSAGE_PATH="$ROOT_DIR/actor-last-message.txt"
2938
- CODEX_APP_SERVER_ROOT_PATH="$ROOT_DIR/codex-app-server"
2939
- CODEX_APP_SERVER_STATE_PATH="$CODEX_APP_SERVER_ROOT_PATH/state.json"
2940
- CODEX_APP_SERVER_LOG_PATH="$CODEX_APP_SERVER_ROOT_PATH/ui.log"
2941
- CODEX_APP_SERVER_PROMPT_PATH="$ROOT_DIR/codex-app-server-prompt.txt"
2942
- CODEX_APP_SERVER_PORT="\${HUMANISH_OSS_META_CODEX_APP_SERVER_PORT:-45137}"
2943
- CODEX_APP_SERVER_UI_URL=""
2944
- STREAM_ID=${shellQuote(args.assignment.streamId)}
2945
- TERMINAL_TITLE=${shellQuote(`Humanish ${args.assignment.index} ${args.displayRepo}`)}
2946
- mkdir -p "$ROOT_DIR"
2947
- touch "$LOG_PATH"
2948
- exec > >(tee -a "$LOG_PATH") 2>&1
2949
- NESTED_VERIFY_STATUS=not_run
2950
- APP_STATUS=not_started
2951
- APP_REASON="Target app startup has not started."
2952
- APP_URL=""
2953
- APP_PID=""
2954
- ACTOR_STATUS=not_started
2955
- ACTOR_PID=""
2956
- VISUAL_STATUS=not_started
2957
- VISUAL_REASON="Browser windows have not been arranged."
2958
- VISUAL_WINDOW_COUNT=0
2959
- CODEX_APP_SERVER_CLIENT_OPENED=0
2960
-
2961
- write_completion() {
2962
- local status="$1"
2963
- local reason="$2"
2964
- local exit_code="$3"
2965
- local nested_observer_present=false
2966
- if [[ -f "$NESTED_OBSERVER" ]]; then
2967
- nested_observer_present=true
2968
- fi
2969
-
2970
- node - "$COMPLETION_PATH" "$LOG_PATH" "$APP_DIR" "$status" "$reason" "$exit_code" "$nested_observer_present" "$NESTED_OBSERVER" "$NESTED_VERIFY_STATUS" "$APP_STATUS" "$APP_REASON" "$APP_URL" "$APP_PID" "$APP_LOG_PATH" "$ACTOR_STATUS" "$ACTOR_PID" "$ACTOR_LOG_PATH" "$ACTOR_LAST_MESSAGE_PATH" "$VISUAL_STATUS" "$VISUAL_REASON" "$VISUAL_WINDOW_COUNT" "$STREAM_ID" "$CODEX_APP_SERVER_STATE_PATH" "$CODEX_APP_SERVER_ROOT_PATH" <<'NODE' || true
2971
- const fs = require("node:fs");
2972
- const path = require("node:path");
2973
- const [
2974
- completionPath,
2975
- logPath,
2976
- appDir,
2977
- status,
2978
- reason,
2979
- exitCode,
2980
- nestedObserverPresent,
2981
- nestedObserverPath,
2982
- nestedVerifyStatus,
2983
- appStatus,
2984
- appReason,
2985
- appUrl,
2986
- appPid,
2987
- appLogPath,
2988
- actorStatus,
2989
- actorPid,
2990
- actorLogPath,
2991
- actorLastMessagePath,
2992
- visualStatus,
2993
- visualReason,
2994
- visualWindowCount,
2995
- streamId,
2996
- codexAppServerStatePath,
2997
- codexAppServerRootPath
2998
- ] = process.argv.slice(2);
2999
- const tailFile = (filePath, lines = 80) => fs.existsSync(filePath)
3000
- ? fs.readFileSync(filePath, "utf8").split(/\\r?\\n/).slice(-lines).join("\\n")
3001
- : "";
3002
- const redactText = (value) => String(value || "")
3003
- .replace(/sk-(?:proj-)?[A-Za-z0-9_-]{20,}/g, "[redacted-openai-key]")
3004
- .replace(/e2b_[A-Za-z0-9_-]{12,}/g, "[redacted-e2b-key]")
3005
- .replace(/(?:gh[pousr]_[A-Za-z0-9_]{12,}|github_pat_[A-Za-z0-9_]{12,})/g, "[redacted-github-token]")
3006
- .replace(/\\bBearer\\s+[A-Za-z0-9._~+/=-]{12,}\\b/gi, "Bearer [redacted-token]")
3007
- .replace(/https?:\\/\\/[^/\\s]*e2b[^)\\s]+/gi, "[redacted-e2b-url]");
3008
- const redactedTail = redactText(tailFile(logPath, 80));
3009
- const actorLogTail = redactText(tailFile(actorLogPath, 80));
3010
- const actorLastMessageTail = redactText(tailFile(actorLastMessagePath, 40));
3011
- const numberOrNull = (value) => /^\\d+$/.test(String(value || "")) ? Number(value) : null;
3012
- const cleanText = (value) => redactText(value)
3013
- .replace(/\\s+/g, " ")
3014
- .trim()
3015
- .slice(0, 240);
3016
- const safeRel = (value) => {
3017
- const normalized = String(value || "").replace(/\\\\/g, "/").replace(/^\\.\\/+/, "");
3018
- if (!normalized || normalized.startsWith("../") || normalized.includes("://") || normalized.split("/").includes("..")) return "";
3019
- return normalized;
3020
- };
3021
- const languageFor = (rel) => {
3022
- if (rel.endsWith(".json")) return "json";
3023
- if (rel.endsWith(".yaml") || rel.endsWith(".yml")) return "yaml";
3024
- if (rel.endsWith(".ts") || rel.endsWith(".tsx")) return "typescript";
3025
- if (rel.endsWith(".md") || rel.endsWith(".markdown")) return "markdown";
3026
- return "text";
3027
- };
3028
- const shouldPreview = (rel) => rel === "package.json"
3029
- || rel === ".gitignore"
3030
- || rel === "humanish/config.ts"
3031
- || rel === "humanish/coverage-map.md"
3032
- || rel === "humanish/coverage-matrix.md"
3033
- || rel.startsWith("humanish/personas/")
3034
- || rel.startsWith("humanish/scenarios/");
3035
- const ignoredSegments = new Set([".git", "node_modules", ".humanish", "dist", "build", ".next", "coverage", ".turbo", ".cache"]);
3036
- const readTextLimited = (filePath, maxBytes = 12000) => {
3037
- try {
3038
- const buffer = fs.readFileSync(filePath);
3039
- return redactText(buffer.slice(0, maxBytes).toString("utf8")).replace(/\\0/g, "");
3040
- } catch {
3041
- return "";
3042
- }
3043
- };
3044
- const countFilesUnder = (root, prefix) => {
3045
- try {
3046
- return fs.readdirSync(path.join(root, prefix), { withFileTypes: true }).filter((entry) => entry.isFile()).length;
3047
- } catch {
3048
- return 0;
3049
- }
3050
- };
3051
- const buildSetupQuality = (root) => {
3052
- const tree = [];
3053
- const previews = [];
3054
- const walk = (dir, depth) => {
3055
- if (depth > 4 || tree.length >= 240) return;
3056
- let entries = [];
3057
- try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
3058
- entries.sort((a, b) => a.name.localeCompare(b.name));
3059
- for (const entry of entries) {
3060
- if (tree.length >= 240) break;
3061
- if (ignoredSegments.has(entry.name)) continue;
3062
- const absolute = path.join(dir, entry.name);
3063
- const rel = safeRel(path.relative(root, absolute));
3064
- if (!rel) continue;
3065
- if (entry.isDirectory()) {
3066
- tree.push({ path: rel, type: "directory" });
3067
- walk(absolute, depth + 1);
3068
- continue;
3069
- }
3070
- if (!entry.isFile()) continue;
3071
- const stats = fs.statSync(absolute);
3072
- tree.push({ path: rel, type: "file", sizeBytes: stats.size });
3073
- if (shouldPreview(rel) && previews.length < 20) {
3074
- const text = readTextLimited(absolute);
3075
- previews.push({ path: rel, language: languageFor(rel), truncated: stats.size > 12000 || text.length >= 8000, text: text.slice(0, 8000) });
3076
- }
3077
- }
3078
- };
3079
- const packageJsonPath = path.join(root, "package.json");
3080
- let packageScripts = {};
3081
- if (fs.existsSync(packageJsonPath)) {
3082
- try {
3083
- const parsedPackage = JSON.parse(readTextLimited(packageJsonPath, 20000));
3084
- if (parsedPackage && typeof parsedPackage.scripts === "object" && parsedPackage.scripts) {
3085
- packageScripts = Object.fromEntries(Object.entries(parsedPackage.scripts).filter(([, value]) => typeof value === "string"));
3086
- }
3087
- } catch {}
3088
- }
3089
- walk(root, 0);
3090
- const readRel = (rel) => readTextLimited(path.join(root, rel), 20000);
3091
- const listFilesUnder = (prefix) => {
3092
- const absoluteRoot = path.join(root, prefix);
3093
- const files = [];
3094
- const visit = (dir, depth) => {
3095
- if (depth > 2 || files.length >= 40) return;
3096
- let entries = [];
3097
- try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; }
3098
- entries.sort((a, b) => a.name.localeCompare(b.name));
3099
- for (const entry of entries) {
3100
- const absolute = path.join(dir, entry.name);
3101
- const rel = safeRel(path.relative(root, absolute));
3102
- if (!rel) continue;
3103
- if (entry.isDirectory()) visit(absolute, depth + 1);
3104
- else if (entry.isFile()) files.push(rel);
3105
- }
3106
- };
3107
- visit(absoluteRoot, 0);
3108
- return files;
3109
- };
3110
- const coverageMapText = readRel("humanish/coverage-map.md");
3111
- const coverageMatrixText = readRel("humanish/coverage-matrix.md");
3112
- const personaFiles = listFilesUnder(path.join("humanish", "personas"));
3113
- const scenarioFiles = listFilesUnder(path.join("humanish", "scenarios"));
3114
- const personaText = personaFiles.map((rel) => readRel(rel)).join("\\n");
3115
- const scenarioText = scenarioFiles.map((rel) => readRel(rel)).join("\\n");
3116
- const configText = readRel("humanish/config.ts");
3117
- const defaultPersonaFiles = new Set(["humanish/personas/synthetic-new-user.yaml", "humanish/personas/skeptical-power-user.yaml"]);
3118
- const defaultScenarioFiles = new Set(["humanish/scenarios/first-run-smoke.yaml", "humanish/scenarios/onboarding-regression.yaml"]);
3119
- const personaEntries = personaFiles.map((rel) => ({ rel, text: readRel(rel) }));
3120
- const scenarioEntries = scenarioFiles.map((rel) => ({ rel, text: readRel(rel) }));
3121
- const coverageCustomized = (
3122
- Boolean(coverageMapText.trim())
3123
- && !/Current starter coverage is intentionally minimal/i.test(coverageMapText)
3124
- && /\\b(screen|route|role|state|path|flow|journey|surface|happy|sad|friction)\\b/i.test(coverageMapText)
3125
- ) || (
3126
- Boolean(coverageMatrixText.trim())
3127
- && !/\\bstarter\\b/i.test(coverageMatrixText)
3128
- && /\\b(screen|route|role|state|path|flow|journey|surface|happy|sad|friction)\\b/i.test(coverageMatrixText)
3129
- );
3130
- const personaCustomizedCount = personaEntries.filter(({ rel, text }) => !defaultPersonaFiles.has(rel)
3131
- || (Boolean(text.trim())
3132
- && !/privacy-safe first-time user evaluating the app|prefers clear affordances over novelty|starter persona/i.test(text)
3133
- && /\\b(role|workflow|creator|operator|admin|guest|player|customer|seller|designer|developer|founder|marketer|power user|novice|skeptical|accessibility|persona|job-to-be-done)\\b/i.test(text))).length;
3134
- const scenarioCustomizedCount = scenarioEntries.filter(({ rel, text }) => !defaultScenarioFiles.has(rel)
3135
- || (Boolean(text.trim())
3136
- && !/Reach the first meaningful product state|Exercise onboarding friction|starter scenario/i.test(text)
3137
- && /\\b(route|screen|journey|state|happy|sad|friction|error|empty|mobile|desktop|evidence|expectation|selector|upload|preview|pricing|auth|settings|checkout|workflow)\\b/i.test(text))).length;
3138
- const personaCustomized = personaCustomizedCount >= Math.min(2, personaFiles.length || 2);
3139
- const scenarioCustomized = scenarioCustomizedCount >= Math.min(2, scenarioFiles.length || 2);
3140
- const actorEvidenceText = [actorLogTail, actorLastMessageTail, redactedTail, scenarioText, configText].join("\\n");
3141
- const actorEvidenceNormalized = actorEvidenceText.replace(/[*_\`~[\\](){}<>]/g, " ").replace(/\\s+/g, " ").trim();
3142
- const appUrlProofBlocked = /(?:unknown option|unsupported|not available|does\\s+\\W*not\\W*(?:support|expose|accept)|did\\s+\\W*not\\W*(?:support|expose|accept)|doesnt\\s+(?:support|expose|accept)|didnt\\s+(?:support|expose|accept))[\\s\\S]{0,220}(?:--app-url|run\\s+--app-url|app-url\\s+proof)|(?:--app-url|run\\s+--app-url|app-url\\s+proof)[\\s\\S]{0,220}(?:unknown option|unsupported|not available|does\\s+\\W*not\\W*(?:support|expose|accept)|did\\s+\\W*not\\W*(?:support|expose|accept)|doesnt\\s+(?:support|expose|accept)|didnt\\s+(?:support|expose|accept))/i.test(actorEvidenceNormalized);
3143
- const appUrlProofMentioned = !appUrlProofBlocked && (
3144
- nestedVerifyStatus === "passed"
3145
- || /(?:humanish\\s+run[\\s\\S]{0,160}--app-url|--app-url[\\s\\S]{0,160}humanish\\s+run)/i.test(actorEvidenceText)
3146
- );
3147
- const actorInsightCaptured = /\\b(observed|found|friction|improvement|issue|gap|confusing|blocked|recommend|none observed|feedback|useful improvement|next harness upgrade)\\b/i.test(actorEvidenceNormalized);
3148
- const gitignore = readTextLimited(path.join(root, ".gitignore"), 20000);
3149
- const configPresent = fs.existsSync(path.join(root, "humanish", "config.ts"));
3150
- const personaCount = countFilesUnder(root, path.join("humanish", "personas"));
3151
- const scenarioCount = countFilesUnder(root, path.join("humanish", "scenarios"));
3152
- const packageScriptPresent = Object.entries(packageScripts).some(([key, value]) => key.includes("humanish") || String(value).includes("humanish"));
3153
- const gitignoreContainsRuntimeIgnore = /(^|\\n)\\s*\\.humanish\\/?\\s*(\\n|$)/.test(gitignore);
3154
- const checks = [
3155
- { id: "humanish-config", label: "Humanish config", ok: configPresent, detail: configPresent ? "humanish/config.ts exists." : "humanish/config.ts was not created." },
3156
- { id: "personas", label: "Personas", ok: personaCount > 0, detail: personaCount + " persona file(s) detected." },
3157
- { id: "scenarios", label: "Scenarios", ok: scenarioCount > 0, detail: scenarioCount + " scenario file(s) detected." },
3158
- { id: "package-script", label: "Package script", ok: packageScriptPresent, detail: packageScriptPresent ? "package.json exposes a Humanish script." : "package.json does not expose a Humanish script." },
3159
- { id: "runtime-ignore", label: "Runtime ignore", ok: gitignoreContainsRuntimeIgnore, detail: gitignoreContainsRuntimeIgnore ? ".gitignore ignores .humanish/." : ".gitignore does not ignore .humanish/." }
3160
- ];
3161
- const studyChecks = [
3162
- { id: "coverage-customized", label: "Coverage customized", ok: coverageCustomized, detail: coverageCustomized ? "Coverage map or matrix appears app-aware." : "Coverage map/matrix still appears starter-level or absent." },
3163
- { id: "personas-customized", label: "Personas customized", ok: personaCustomized, detail: personaCustomized ? "Personas appear app-specific or non-starter." : "Personas appear generic starter-level." },
3164
- { id: "scenarios-customized", label: "Scenarios customized", ok: scenarioCustomized, detail: scenarioCustomized ? "Scenarios appear app-specific or non-starter." : "Scenarios appear generic starter-level." },
3165
- { id: "app-url-proof", label: "App-url proof", ok: appUrlProofMentioned, detail: appUrlProofMentioned ? "Actor/setup evidence references app-url proof." : appUrlProofBlocked ? "Actor evidence reports that app-url proof was blocked." : "No app-url proof signal detected." },
3166
- { id: "actor-insight", label: "Actor insight", ok: actorInsightCaptured, detail: actorInsightCaptured ? "Actor evidence mentions feedback, friction, coverage, or observed product behavior." : "Actor evidence does not capture product feedback or coverage insight." }
3167
- ];
3168
- const studySignalCount = studyChecks.filter((check) => check.ok).length;
3169
- const usefulStudy = coverageCustomized && personaCustomized && scenarioCustomized;
3170
- const concreteStudyInsight = actorInsightCaptured || appUrlProofBlocked;
3171
- const studyRating = !configPresent || personaCount === 0 || scenarioCount === 0
3172
- ? "none"
3173
- : usefulStudy && concreteStudyInsight && (appUrlProofMentioned || appUrlProofBlocked)
3174
- ? "high_leverage"
3175
- : usefulStudy
3176
- ? "useful"
3177
- : "ceremonial";
3178
- const failed = checks.filter((check) => !check.ok);
3179
- return {
3180
- schema: "humanish.setup-quality.v1",
3181
- generatedAt: new Date().toISOString(),
3182
- redaction: {
3183
- status: "passed",
3184
- rawPreviews: "included",
3185
- notes: "Only allowlisted setup files are previewed; generated state, browser profiles, secrets, .git, node_modules, and .humanish are excluded."
3186
- },
3187
- summary: failed.length === 0 ? "Humanish setup evidence looks complete." : failed.length + " setup-quality gap(s) need review.",
3188
- status: failed.length === 0 ? "passed" : "needs_review",
3189
- checks,
3190
- tree,
3191
- previews,
3192
- studyQuality: {
3193
- schema: "humanish.study-quality.v1",
3194
- rating: studyRating,
3195
- summary: "Study-quality rating " + studyRating + " from " + studySignalCount + "/5 app-specific leverage signals" + (appUrlProofBlocked ? "; app-url proof path was blocked by actor evidence." : "."),
3196
- checks: studyChecks,
3197
- signals: {
3198
- appUrlProofBlocked,
3199
- appUrlProofMentioned,
3200
- actorInsightCaptured,
3201
- coverageCustomized,
3202
- personaCustomized,
3203
- scenarioCustomized
3204
- }
3205
- },
3206
- packageScripts,
3207
- humanish: { configPresent, personaCount, scenarioCount, packageScriptPresent, gitignoreContainsRuntimeIgnore }
3208
- };
3209
- };
3210
- const setupQuality = buildSetupQuality(appDir);
3211
- const safeToken = (value) => String(value || "stream").replace(/[^a-zA-Z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 120) || "stream";
3212
- const appServerActorEvidence = (() => {
3213
- if (!fs.existsSync(codexAppServerStatePath)) return null;
3214
- try {
3215
- const state = JSON.parse(fs.readFileSync(codexAppServerStatePath, "utf8"));
3216
- const result = state && typeof state === "object" ? state.result || {} : {};
3217
- const readArtifact = (relativePath, maxBytes = 120000) => {
3218
- if (!relativePath || String(relativePath).includes("..") || String(relativePath).includes("://")) return "";
3219
- return readTextLimited(path.join(codexAppServerRootPath, String(relativePath)), maxBytes);
3220
- };
3221
- const readJsonArtifact = (relativePath) => {
3222
- if (!relativePath || String(relativePath).includes("..") || String(relativePath).includes("://")) return null;
3223
- try {
3224
- return JSON.parse(fs.readFileSync(path.join(codexAppServerRootPath, String(relativePath)), "utf8"));
3225
- } catch {
3226
- return null;
3227
- }
3228
- };
3229
- const compactList = (items, mapper, limit = 8) => Array.isArray(items)
3230
- ? items.slice(-limit).map(mapper).filter(Boolean)
3231
- : undefined;
3232
- const projectTraceJson = (value) => {
3233
- if (!value || typeof value !== "object") return null;
3234
- const messages = compactList(value.messages, (message) => message && typeof message === "object" ? {
3235
- ...(message.itemId ? { itemId: cleanText(message.itemId) } : {}),
3236
- ...(message.text ? { text: cleanText(message.text).slice(0, 4000) } : {})
3237
- } : null, 10);
3238
- const commands = compactList(value.commands, (command) => command && typeof command === "object" ? {
3239
- ...(command.itemId ? { itemId: cleanText(command.itemId) } : {}),
3240
- ...(command.command ? { command: cleanText(command.command).slice(0, 2000) } : {}),
3241
- ...(command.cwd ? { cwd: cleanText(command.cwd).slice(0, 500) } : {}),
3242
- ...(command.status ? { status: cleanText(command.status).slice(0, 80) } : {}),
3243
- ...(Number.isFinite(command.exitCode) ? { exitCode: command.exitCode } : {}),
3244
- ...(command.outputTail ? { outputTail: cleanText(command.outputTail).slice(-4000) } : {})
3245
- } : null, 12);
3246
- const fileChanges = compactList(value.fileChanges, (change) => change && typeof change === "object" ? {
3247
- ...(change.itemId ? { itemId: cleanText(change.itemId) } : {}),
3248
- ...(change.status ? { status: cleanText(change.status).slice(0, 80) } : {}),
3249
- ...(Number.isFinite(change.changeCount) ? { changeCount: change.changeCount } : {}),
3250
- ...(change.outputTail ? { outputTail: cleanText(change.outputTail).slice(-2000) } : {})
3251
- } : null, 8);
3252
- return {
3253
- schema: "humanish.codex-app-server-trace.projected.v1",
3254
- sourceSchema: cleanText(value.schema || ""),
3255
- redaction: value.redaction && typeof value.redaction === "object" ? value.redaction : { status: "passed" },
3256
- status: cleanText(value.status || result.status || state.status || ""),
3257
- reason: cleanText(value.reason || result.reason || state.reason || ""),
3258
- ...(value.counts && typeof value.counts === "object" ? { counts: value.counts } : {}),
3259
- ...(messages && messages.length ? { messages } : {}),
3260
- ...(commands && commands.length ? { commands } : {}),
3261
- ...(fileChanges && fileChanges.length ? { fileChanges } : {}),
3262
- ...(value.tokenUsage && typeof value.tokenUsage === "object" ? { tokenUsage: value.tokenUsage } : {}),
3263
- ...(value.threadId ? { threadId: cleanText(value.threadId) } : {}),
3264
- ...(value.turnId ? { turnId: cleanText(value.turnId) } : {}),
3265
- ...(value.sessionId ? { sessionId: cleanText(value.sessionId) } : {}),
3266
- ...(value.completedAt ? { completedAt: cleanText(value.completedAt) } : {}),
3267
- ...(Number.isFinite(value.durationMs) ? { durationMs: value.durationMs } : {})
3268
- };
3269
- };
3270
- const rawTraceJson = readJsonArtifact(result.tracePath);
3271
- const traceJson = projectTraceJson(rawTraceJson);
3272
- const traceText = traceJson ? "" : readArtifact(result.tracePath, 160000);
3273
- const token = safeToken(streamId);
3274
- return {
3275
- eventsPath: path.join("codex-app-server", token + "-events.ndjson"),
3276
- eventsText: readArtifact(result.eventsPath, 120000),
3277
- reason: cleanText(state.reason || result.reason || ""),
3278
- status: cleanText(state.status || result.status || ""),
3279
- tracePath: path.join("codex-app-server", token + "-summary.json"),
3280
- ...(traceJson ? { traceJson } : { traceText }),
3281
- transcriptPath: path.join("codex-app-server", token + "-transcript.txt"),
3282
- transcriptText: readArtifact(result.transcriptPath, 80000)
3283
- };
3284
- } catch {
3285
- return null;
3286
- }
3287
- })();
3288
- const nestedStepTraceSummary = (() => {
3289
- try {
3290
- const runRoot = path.dirname(path.dirname(String(nestedObserverPath || "")));
3291
- const tracesDir = path.join(runRoot, "traces");
3292
- if (!fs.existsSync(tracesDir)) return null;
3293
- const traceNames = fs.readdirSync(tracesDir)
3294
- .filter((name) => name.endsWith(".json"))
3295
- .sort()
3296
- .slice(0, 8);
3297
- if (!traceNames.length) return null;
3298
- const surfaceSummaries = [];
3299
- let scenario = null;
3300
- for (const name of traceNames) {
3301
- let trace = null;
3302
- try {
3303
- trace = JSON.parse(fs.readFileSync(path.join(tracesDir, name), "utf8"));
3304
- } catch {
3305
- continue;
3306
- }
3307
- if (!trace || typeof trace !== "object" || !Array.isArray(trace.steps)) continue;
3308
- if (!scenario && trace.scenario && typeof trace.scenario === "object") {
3309
- scenario = {
3310
- id: cleanText(trace.scenario.id || "scenario"),
3311
- ...(trace.scenario.source ? { source: safeRel(trace.scenario.source) } : {}),
3312
- ...(trace.scenario.sourceDigest ? { sourceDigest: cleanText(trace.scenario.sourceDigest) } : {}),
3313
- ...(Number.isFinite(trace.scenario.stepCount) ? { stepCount: trace.scenario.stepCount } : {}),
3314
- ...(trace.scenario.title ? { title: cleanText(trace.scenario.title) } : {})
3315
- };
3316
- }
3317
- const steps = trace.steps.slice(0, 20).map((step) => {
3318
- const assertions = Array.isArray(step.assertions)
3319
- ? step.assertions.slice(0, 12).map((assertion) => cleanText((assertion.id || "assertion") + ":" + (assertion.status || "unknown")))
3320
- : [];
3321
- return {
3322
- action: cleanText(step.action || "action"),
3323
- ...(assertions.length ? { assertionStatuses: assertions } : {}),
3324
- id: cleanText(step.id || "step"),
3325
- ...(step.label ? { label: cleanText(step.label) } : {}),
3326
- reason: cleanText(step.reason || ""),
3327
- status: step.status === "passed" || step.status === "blocked" ? step.status : "unknown"
3328
- };
3329
- });
3330
- if (!steps.length) continue;
3331
- surfaceSummaries.push({
3332
- id: cleanText(trace.surface && trace.surface.id ? trace.surface.id : path.basename(name, ".json")),
3333
- ...(trace.surface && trace.surface.label ? { label: cleanText(trace.surface.label) } : {}),
3334
- ok: trace.ok === true,
3335
- reason: cleanText(trace.reason || ""),
3336
- steps
3337
- });
3338
- }
3339
- if (!surfaceSummaries.length) return null;
3340
- const totalSteps = surfaceSummaries.reduce((total, surface) => total + surface.steps.length, 0);
3341
- const passedSteps = surfaceSummaries.reduce((total, surface) => total + surface.steps.filter((step) => step.status === "passed").length, 0);
3342
- const blockedSteps = surfaceSummaries.reduce((total, surface) => total + surface.steps.filter((step) => step.status === "blocked").length, 0);
3343
- return {
3344
- schema: "humanish.oss-meta-nested-step-trace-summary.v1",
3345
- redaction: {
3346
- status: "passed",
3347
- notes: "Projected inside disposable sandbox from nested Humanish trace JSON; URLs, screenshots, and remote paths are omitted."
3348
- },
3349
- counts: {
3350
- blockedSteps,
3351
- passedSteps,
3352
- surfaces: surfaceSummaries.length,
3353
- totalSteps,
3354
- traces: traceNames.length
3355
- },
3356
- ...(scenario ? { scenario } : {}),
3357
- status: blockedSteps > 0 ? "blocked" : passedSteps === totalSteps ? "passed" : "unknown",
3358
- surfaces: surfaceSummaries
3359
- };
3360
- } catch {
3361
- return null;
3362
- }
3363
- })();
3364
- fs.writeFileSync(completionPath, JSON.stringify({
3365
- schema: "humanish.oss-meta-bootstrap-completion.v1",
3366
- status,
3367
- reason,
3368
- exitCode: Number(exitCode),
3369
- appStatus,
3370
- appReason: cleanText(appReason),
3371
- appUrl: cleanText(appUrl),
3372
- appPid: numberOrNull(appPid),
3373
- appLogPath: cleanText(appLogPath),
3374
- actorStatus,
3375
- actorPid: numberOrNull(actorPid),
3376
- actorLogPath: cleanText(actorLogPath),
3377
- actorLogTail,
3378
- actorLastMessageTail,
3379
- ...(appServerActorEvidence ? { appServerActorEvidence } : {}),
3380
- nestedObserverPresent: nestedObserverPresent === "true",
3381
- ...(nestedStepTraceSummary ? { nestedStepTraceSummary } : {}),
3382
- nestedVerifyStatus,
3383
- setupQuality,
3384
- visualStatus,
3385
- visualReason: cleanText(visualReason),
3386
- visualWindowCount: numberOrNull(visualWindowCount),
3387
- logTail: redactedTail,
3388
- completedAt: new Date().toISOString()
3389
- }, null, 2) + "\\n");
3390
- NODE
3391
- }
3392
-
3393
- finish() {
3394
- local exit_code="$?"
3395
- trap - EXIT
3396
- if [[ "$exit_code" -ne 0 ]]; then
3397
- write_completion "failed" "Bootstrap exited before nested Humanish proof completed." "$exit_code"
3398
- elif [[ "$NESTED_VERIFY_STATUS" != "passed" ]]; then
3399
- write_completion "failed" "Nested Humanish verification did not pass." "$exit_code"
3400
- elif [[ "$APP_STATUS" != "running" ]]; then
3401
- write_completion "blocked" "Nested Humanish proof completed, but the target app surface was not proven running." "$exit_code"
3402
- elif [[ "$VISUAL_STATUS" != "visible" ]]; then
3403
- write_completion "blocked" "Nested Humanish proof completed, but headed desktop visual layout was not proven visible." "$exit_code"
3404
- elif [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" == "1" && "$ACTOR_STATUS" != "passed" ]]; then
3405
- write_completion "blocked" "Codex app-server mode requires passed Codex app-server actor evidence." "$exit_code"
3406
- elif [[ "\${HUMANISH_OSS_META_REQUIRE_ACTOR:-0}" == "1" && "$ACTOR_STATUS" != "passed" ]]; then
3407
- write_completion "blocked" "Required Codex actor evidence did not reach a passed terminal status." "$exit_code"
3408
- else
3409
- write_completion "passed" "Target app surface, nested Humanish proof, and nested Observer were checked." "$exit_code"
3410
- fi
3411
- exit "$exit_code"
3412
- }
3413
- trap finish EXIT
3414
-
3415
- echo "== humanish oss meta-lab bootstrap =="
3416
- echo "repo=${args.displayRepo}"
3417
- echo "public_safe=1"
3418
- echo "provider_secrets=isolated"
3419
- echo "github_token=$([[ -n "$HUMANISH_PRIVATE_GITHUB_TOKEN" ]] && echo available-for-clone || echo absent)"
3420
- echo "codex_actor_auth=$([[ -n "$HUMANISH_PRIVATE_CODEX_API_KEY$HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN" ]] && echo available-for-actor || echo absent)"
3421
- echo "codex_app_server_mode=\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}"
3422
- echo "codex_app_server_client=$([[ -n "$HUMANISH_PRIVATE_CODEX_APP_SERVER_URL" ]] && echo available || echo placeholder)"
3423
- echo "host_actor_plan=$([[ -f "$HOST_ACTOR_PLAN" ]] && echo available || echo absent)"
3424
- echo
3425
-
3426
- need() {
3427
- if ! command -v "$1" >/dev/null 2>&1; then
3428
- echo "missing command: $1"
3429
- return 1
3430
- fi
3431
- }
3432
-
3433
- ensure_node() {
3434
- local major=0
3435
- if command -v node >/dev/null 2>&1; then
3436
- major="$(node -e 'console.log(Number(process.versions.node.split(".")[0]))' 2>/dev/null || echo 0)"
3437
- fi
3438
-
3439
- if command -v node >/dev/null 2>&1 && command -v npm >/dev/null 2>&1 && [[ "$major" -ge 20 ]]; then
3440
- return 0
3441
- fi
3442
-
3443
- echo "node_or_npm=missing_or_too_old"
3444
- if command -v apt-get >/dev/null 2>&1 && command -v sudo >/dev/null 2>&1; then
3445
- echo "installing nodejs/npm via nodesource"
3446
- sudo -n apt-get update
3447
- sudo -n apt-get install -y ca-certificates curl gnupg
3448
- curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
3449
- sudo -n apt-get install -y nodejs
3450
- fi
3451
- }
3452
-
3453
- need git
3454
- ensure_node
3455
- need node
3456
- need npm
3457
-
3458
- wait_for_http() {
3459
- local url="$1"
3460
- local timeout_ms="$2"
3461
- local interval_ms="$3"
3462
- node - "$url" "$timeout_ms" "$interval_ms" <<'NODE'
3463
- const [url, timeoutArg, intervalArg] = process.argv.slice(2);
3464
- const timeoutMs = Number(timeoutArg);
3465
- const intervalMs = Number(intervalArg);
3466
- const startedAt = Date.now();
3467
-
3468
- async function probe() {
3469
- const controller = new AbortController();
3470
- const timer = setTimeout(() => controller.abort(), Math.min(intervalMs, 5_000));
3471
- try {
3472
- const response = await fetch(url, { signal: controller.signal });
3473
- return response.status < 500;
3474
- } catch {
3475
- return false;
3476
- } finally {
3477
- clearTimeout(timer);
3478
- }
3479
- }
3480
-
3481
- while (Date.now() - startedAt <= timeoutMs) {
3482
- if (await probe()) process.exit(0);
3483
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
3484
- }
3485
- process.exit(1);
3486
- NODE
3487
- }
3488
-
3489
- wait_for_any_http() {
3490
- local timeout_ms="$1"
3491
- local interval_ms="$2"
3492
- shift 2
3493
- node - "$timeout_ms" "$interval_ms" "$@" <<'NODE'
3494
- const [timeoutArg, intervalArg, ...urls] = process.argv.slice(2);
3495
- const timeoutMs = Number(timeoutArg);
3496
- const intervalMs = Number(intervalArg);
3497
- const startedAt = Date.now();
3498
-
3499
- async function probe(url) {
3500
- const controller = new AbortController();
3501
- const timer = setTimeout(() => controller.abort(), Math.min(intervalMs, 5_000));
3502
- try {
3503
- const response = await fetch(url, { signal: controller.signal });
3504
- return response.status < 500;
3505
- } catch {
3506
- return false;
3507
- } finally {
3508
- clearTimeout(timer);
3509
- }
3510
- }
3511
-
3512
- while (Date.now() - startedAt <= timeoutMs) {
3513
- for (const url of urls) {
3514
- if (await probe(url)) {
3515
- console.log(url);
3516
- process.exit(0);
3517
- }
3518
- }
3519
- await new Promise((resolve) => setTimeout(resolve, intervalMs));
3520
- }
3521
- process.exit(1);
3522
- NODE
3523
- }
3524
-
3525
- open_browser_url() {
3526
- local url="$1"
3527
- local profile="$2"
3528
- local x="$3"
3529
- local y="$4"
3530
- local width="$5"
3531
- local height="$6"
3532
- if command -v google-chrome >/dev/null 2>&1; then
3533
- nohup google-chrome --new-window --no-first-run --no-default-browser-check --disable-default-apps --user-data-dir="$ROOT_DIR/chrome-$profile" --window-position="$x,$y" --window-size="$width,$height" "$url" >/dev/null 2>&1 &
3534
- elif command -v firefox >/dev/null 2>&1; then
3535
- nohup firefox --width "$width" --height "$height" "$url" >/dev/null 2>&1 &
3536
- else
3537
- echo "browser_open=skipped profile=$profile url=$url"
3538
- fi
3539
- }
3540
-
3541
- open_nested_observer() {
3542
- local label="$1"
3543
- echo
3544
- echo "== $label =="
3545
- if [[ -f "$NESTED_OBSERVER" ]]; then
3546
- open_browser_url "file://$NESTED_OBSERVER" nested-observer 760 0 680 940
3547
- else
3548
- echo "Nested observer missing: $NESTED_OBSERVER"
3549
- fi
3550
- }
3551
-
3552
- open_codex_app_server_client() {
3553
- if [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" != "1" ]]; then
3554
- return 0
3555
- fi
3556
- if [[ "$CODEX_APP_SERVER_CLIENT_OPENED" == "1" ]]; then
3557
- return 0
3558
- fi
3559
-
3560
- echo
3561
- echo "== codex app-server client surface =="
3562
- local client_url="\${CODEX_APP_SERVER_UI_URL:-$HUMANISH_PRIVATE_CODEX_APP_SERVER_URL}"
3563
- if [[ -z "$client_url" ]]; then
3564
- ACTOR_STATUS=blocked
3565
- echo "codex_app_server_client=blocked reason=no real app-server UI URL available"
3566
- return 1
3567
- fi
3568
- echo "codex_app_server_client=provided"
3569
- open_browser_url "$client_url" codex-app-server 430 520 330 420
3570
- CODEX_APP_SERVER_CLIENT_OPENED=1
3571
- }
3572
-
3573
- arrange_lab_windows() {
3574
- echo
3575
- echo "== visual desktop layout =="
3576
- VISUAL_STATUS=unknown
3577
- VISUAL_REASON="Window manager proof was not collected."
3578
- VISUAL_WINDOW_COUNT=0
3579
- local expected_chrome_windows=2
3580
- if [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" == "1" ]]; then
3581
- expected_chrome_windows=3
3582
- fi
3583
- if ! command -v xdotool >/dev/null 2>&1; then
3584
- VISUAL_STATUS=unknown
3585
- VISUAL_REASON="xdotool is unavailable; cannot prove headed browser window visibility."
3586
- echo "visual_status=$VISUAL_STATUS reason=$VISUAL_REASON"
3587
- return 0
3588
- fi
3589
-
3590
- local chrome_windows=()
3591
- local observer_window=""
3592
- for attempt in $(seq 1 40); do
3593
- mapfile -t chrome_windows < <(xdotool search --onlyvisible --class google-chrome 2>/dev/null || true)
3594
- observer_window="$(xdotool search --onlyvisible --name "Humanish Observer" 2>/dev/null | tail -n 1 || true)"
3595
- VISUAL_WINDOW_COUNT="\${#chrome_windows[@]}"
3596
- if [[ "$VISUAL_WINDOW_COUNT" -ge "$expected_chrome_windows" && -n "$observer_window" ]]; then
3597
- break
3598
- fi
3599
- sleep 0.25
3600
- done
3601
-
3602
- if [[ -n "$observer_window" ]]; then
3603
- xdotool windowsize "$observer_window" 680 933 >/dev/null 2>&1 || true
3604
- xdotool windowmove "$observer_window" 760 27 >/dev/null 2>&1 || true
3605
- fi
3606
-
3607
- local slot=0
3608
- local win
3609
- for win in "\${chrome_windows[@]}"; do
3610
- if [[ -n "$observer_window" && "$win" == "$observer_window" ]]; then
3611
- continue
3612
- fi
3613
- if [[ "$slot" -eq 0 ]]; then
3614
- xdotool windowsize "$win" 760 493 >/dev/null 2>&1 || true
3615
- xdotool windowmove "$win" 0 27 >/dev/null 2>&1 || true
3616
- elif [[ "$slot" -eq 1 ]]; then
3617
- xdotool windowsize "$win" 430 420 >/dev/null 2>&1 || true
3618
- xdotool windowmove "$win" 0 520 >/dev/null 2>&1 || true
3619
- else
3620
- xdotool windowsize "$win" 330 420 >/dev/null 2>&1 || true
3621
- xdotool windowmove "$win" 430 520 >/dev/null 2>&1 || true
3622
- fi
3623
- slot=$((slot + 1))
3624
- done
3625
-
3626
- local terminal_window
3627
- terminal_window="$(xdotool search --onlyvisible --name "$TERMINAL_TITLE" 2>/dev/null | head -n 1 || true)"
3628
- if [[ -n "$terminal_window" ]]; then
3629
- xdotool windowlower "$terminal_window" >/dev/null 2>&1 || xdotool windowminimize "$terminal_window" >/dev/null 2>&1 || true
3630
- fi
3631
- if [[ -n "$observer_window" ]]; then
3632
- xdotool windowactivate "$observer_window" >/dev/null 2>&1 || true
3633
- fi
3634
-
3635
- mapfile -t chrome_windows < <(xdotool search --onlyvisible --class google-chrome 2>/dev/null || true)
3636
- VISUAL_WINDOW_COUNT="\${#chrome_windows[@]}"
3637
- if [[ "$VISUAL_WINDOW_COUNT" -ge "$expected_chrome_windows" && -n "$observer_window" ]]; then
3638
- VISUAL_STATUS=visible
3639
- if [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" == "1" ]]; then
3640
- VISUAL_REASON="Detected $VISUAL_WINDOW_COUNT visible Chrome windows including target app, nested Observer, and Codex app-server client surface."
3641
- else
3642
- VISUAL_REASON="Detected $VISUAL_WINDOW_COUNT visible Chrome windows including nested Observer; app and Observer windows arranged for screenshot."
3643
- fi
3644
- else
3645
- VISUAL_STATUS=blocked
3646
- if [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" == "1" ]]; then
3647
- VISUAL_REASON="Expected target app, nested Observer, and Codex app-server client browser windows, detected $VISUAL_WINDOW_COUNT visible Chrome window(s)."
3648
- else
3649
- VISUAL_REASON="Expected app and nested Observer browser windows, detected $VISUAL_WINDOW_COUNT visible Chrome window(s)."
3650
- fi
3651
- fi
3652
- echo "visual_status=$VISUAL_STATUS window_count=$VISUAL_WINDOW_COUNT reason=$VISUAL_REASON"
3653
- }
3654
-
3655
- detect_app_plan() {
3656
- node <<'NODE'
3657
- const fs = require("node:fs");
3658
- const shell = (value) => "'" + String(value).replace(/'/g, "'\\"'\\"'") + "'";
3659
- const emit = (key, value) => console.log(key + "=" + shell(value));
3660
-
3661
- if (!fs.existsSync("package.json")) {
3662
- console.log("APP_PLAN_OK='0'");
3663
- emit("APP_PM", "npm");
3664
- emit("APP_PLAN_REASON", "package.json not found");
3665
- process.exit(0);
3666
- }
3667
-
3668
- let pkg;
3669
- try {
3670
- pkg = JSON.parse(fs.readFileSync("package.json", "utf8"));
3671
- } catch {
3672
- console.log("APP_PLAN_OK='0'");
3673
- emit("APP_PM", "npm");
3674
- emit("APP_PLAN_REASON", "package.json could not be parsed");
3675
- process.exit(0);
3676
- }
3677
-
3678
- const scripts = pkg.scripts && typeof pkg.scripts === "object" ? pkg.scripts : {};
3679
- const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
3680
- const lockfiles = fs.readdirSync(".").filter((name) => /^(pnpm-lock\\.yaml|yarn\\.lock|bun\\.lockb?|package-lock\\.json|npm-shrinkwrap\\.json)$/.test(name));
3681
- const packageManagerHint = typeof pkg.packageManager === "string" ? pkg.packageManager : "";
3682
- let pm = "npm";
3683
- if (packageManagerHint.startsWith("pnpm@") || lockfiles.includes("pnpm-lock.yaml")) pm = "pnpm";
3684
- else if (packageManagerHint.startsWith("yarn@") || lockfiles.includes("yarn.lock")) pm = "yarn";
3685
- else if (packageManagerHint.startsWith("bun@") || lockfiles.includes("bun.lock") || lockfiles.includes("bun.lockb")) pm = "bun";
3686
-
3687
- const names = ["dev", "start", "serve", "preview"];
3688
- const entries = names
3689
- .map((name) => ({ name, command: typeof scripts[name] === "string" ? scripts[name].trim() : "" }))
3690
- .filter((entry) => entry.command && /^[A-Za-z0-9:_-]+$/.test(entry.name));
3691
-
3692
- if (!entries.length) {
3693
- console.log("APP_PLAN_OK='0'");
3694
- emit("APP_PM", pm);
3695
- emit("APP_PLAN_REASON", "no dev/start/serve/preview script found");
3696
- process.exit(0);
3697
- }
3698
-
3699
- const pickByCommand = (pattern) => entries.find((entry) => pattern.test(entry.command));
3700
- let picked = null;
3701
- let framework = "generic";
3702
- if ((picked = pickByCommand(/\\bnext\\s+(dev|start)\\b/)) || deps.next) framework = "next";
3703
- if (!picked && (picked = pickByCommand(/\\bvite(\\s|$)/))) framework = "vite";
3704
- if (!picked && deps.vite) { picked = entries.find((entry) => entry.name === "dev") || entries[0]; framework = "vite"; }
3705
- if (!picked && deps.next) picked = entries.find((entry) => entry.name === "dev" || entry.name === "start") || entries[0];
3706
- if (!picked && (picked = pickByCommand(/\\bastro\\s+dev\\b/))) framework = "vite";
3707
- if (!picked) picked = entries.find((entry) => entry.name === "dev") || entries.find((entry) => entry.name === "start") || entries[0];
3708
-
3709
- const command = picked.command;
3710
- const portFromCommand = /(?:^|\\s)(?:--port|-p)\\s+([0-9]{2,5})(?:\\s|$)/.exec(command)?.[1]
3711
- || /(?:^|\\s)PORT=([0-9]{2,5})(?:\\s|$)/.exec(command)?.[1];
3712
- const defaultPort = framework === "vite" ? "5173" : "3000";
3713
-
3714
- console.log("APP_PLAN_OK='1'");
3715
- emit("APP_PM", pm);
3716
- emit("APP_SCRIPT", picked.name);
3717
- emit("APP_FRAMEWORK", framework);
3718
- emit("APP_PORT", portFromCommand || defaultPort);
3719
- emit("APP_PLAN_REASON", "selected " + picked.name + " script for " + framework + " app startup");
3720
- NODE
3721
- }
3722
-
3723
- ensure_package_manager() {
3724
- local pm="$1"
3725
- mkdir -p "$ROOT_DIR/npm-global"
3726
- export NPM_CONFIG_PREFIX="$ROOT_DIR/npm-global"
3727
- export PATH="$NPM_CONFIG_PREFIX/bin:$PATH"
3728
- if command -v "$pm" >/dev/null 2>&1; then
3729
- return 0
3730
- fi
3731
- if command -v corepack >/dev/null 2>&1; then
3732
- corepack enable >/dev/null 2>&1 || true
3733
- if [[ "$pm" == "pnpm" ]]; then
3734
- corepack prepare pnpm@latest --activate >/dev/null 2>&1 || true
3735
- elif [[ "$pm" == "yarn" ]]; then
3736
- corepack prepare yarn@stable --activate >/dev/null 2>&1 || true
3737
- fi
3738
- fi
3739
- if command -v "$pm" >/dev/null 2>&1; then
3740
- return 0
3741
- fi
3742
- case "$pm" in
3743
- pnpm) npm i -g pnpm --no-audit --no-fund --prefix "$NPM_CONFIG_PREFIX" ;;
3744
- yarn) npm i -g yarn --no-audit --no-fund --prefix "$NPM_CONFIG_PREFIX" ;;
3745
- bun) npm i -g bun --no-audit --no-fund --prefix "$NPM_CONFIG_PREFIX" ;;
3746
- npm) command -v npm >/dev/null 2>&1 ;;
3747
- *) return 1 ;;
3748
- esac
3749
- }
3750
-
3751
- install_project_dependencies() {
3752
- local pm="$1"
3753
- if [[ "$pm" == "pnpm" ]]; then
3754
- pnpm config set verify-deps-before-run false --location project >/dev/null 2>&1 || true
3755
- pnpm config set dangerously-allow-all-builds true --location project >/dev/null 2>&1 || true
3756
- fi
3757
- if [[ -d node_modules ]]; then
3758
- echo "dependencies=present"
3759
- return 0
3760
- fi
3761
- echo "dependencies=installing manager=$pm"
3762
- case "$pm" in
3763
- pnpm)
3764
- echo "pnpm_build_scripts=allowed disposable_e2b_lab=1"
3765
- if [[ -f pnpm-lock.yaml ]]; then pnpm install --frozen-lockfile --dangerously-allow-all-builds || pnpm install --dangerously-allow-all-builds; else pnpm install --dangerously-allow-all-builds; fi
3766
- ;;
3767
- yarn)
3768
- if [[ -f yarn.lock ]]; then yarn install --frozen-lockfile --ignore-scripts || yarn install --ignore-scripts; else yarn install --ignore-scripts; fi
3769
- ;;
3770
- bun)
3771
- bun install
3772
- ;;
3773
- npm)
3774
- if [[ -f package-lock.json || -f npm-shrinkwrap.json ]]; then npm ci --ignore-scripts --no-audit --no-fund || npm install --ignore-scripts --no-audit --no-fund; else npm install --ignore-scripts --no-audit --no-fund; fi
3775
- ;;
3776
- *) return 1 ;;
3777
- esac
3778
- }
3779
-
3780
- install_humanish_cli() {
3781
- echo
3782
- echo "== installing humanish =="
3783
- local plan_output
3784
- plan_output="$(detect_app_plan)"
3785
- eval "$plan_output"
3786
- local pm="\${APP_PM:-npm}"
3787
- if ! ensure_package_manager "$pm"; then
3788
- echo "humanish_install=blocked package_manager=$pm"
3789
- return 1
3790
- fi
3791
- local spec="humanish"
3792
- if [[ -n "$REMOTE_PACKAGE" && -f "$REMOTE_PACKAGE" ]]; then
3793
- spec="$REMOTE_PACKAGE"
3794
- fi
3795
-
3796
- case "$pm" in
3797
- pnpm)
3798
- if pnpm root -w >/dev/null 2>&1; then
3799
- PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false npm_config_verify_deps_before_run=false pnpm add --save-dev --workspace-root "$spec" --ignore-scripts
3800
- else
3801
- PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false npm_config_verify_deps_before_run=false pnpm add --save-dev "$spec" --ignore-scripts
3802
- fi
3803
- ;;
3804
- yarn)
3805
- YARN_ENABLE_SCRIPTS=0 yarn add -D "$spec"
3806
- ;;
3807
- bun)
3808
- bun add -d "$spec"
3809
- ;;
3810
- npm)
3811
- npm i -D "$spec" --ignore-scripts --no-audit --no-fund
3812
- ;;
3813
- *)
3814
- return 1
3815
- ;;
3816
- esac
3817
- }
3818
-
3819
- apply_host_actor_plan() {
3820
- if [[ "\${HUMANISH_OSS_META_HOST_CODEX_ACTOR:-0}" != "1" ]]; then
3821
- return 0
3822
- fi
3823
-
3824
- echo
3825
- echo "== host codex actor plan =="
3826
- if [[ ! -f "$HOST_ACTOR_PLAN" ]]; then
3827
- ACTOR_STATUS=blocked
3828
- echo "host_actor_plan=missing"
3829
- return 1
3830
- fi
3831
-
3832
- node - "$HOST_ACTOR_PLAN" <<'NODE'
3833
- const fs = require("node:fs");
3834
- const path = require("node:path");
3835
- const [planPath] = process.argv.slice(2);
3836
- const plan = JSON.parse(fs.readFileSync(planPath, "utf8"));
3837
- if (plan.schema !== "humanish.oss-host-actor-plan.v1" || plan.status !== "passed") {
3838
- throw new Error("host actor plan is not passed");
3839
- }
3840
- const clean = (value, fallback) => String(value || fallback)
3841
- .replace(/sk-[A-Za-z0-9_-]{20,}/g, "[redacted-openai-key]")
3842
- .replace(/e2b_[A-Za-z0-9_-]{12,}/g, "[redacted-e2b-key]")
3843
- .replace(/gh[pousr]_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]")
3844
- .replace(/github_pat_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]")
3845
- .replace(/\\s+/g, " ")
3846
- .trim()
3847
- .slice(0, 300);
3848
- const token = (value, fallback) => clean(value, fallback).toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || fallback;
3849
- const yamlScalar = (value) => clean(value, "").replace(/"/g, "\\\\\"");
3850
- const yamlList = (values) => (Array.isArray(values) && values.length ? values : ["public_safe"]).map((value) => " - " + yamlScalar(value)).join("\\n");
3851
- fs.mkdirSync("humanish/personas", { recursive: true });
3852
- fs.mkdirSync("humanish/scenarios", { recursive: true });
3853
- const personas = Array.isArray(plan.personas) ? plan.personas.slice(0, 2) : [];
3854
- const scenarios = Array.isArray(plan.scenarios) ? plan.scenarios.slice(0, 2) : [];
3855
- if (!personas.length || !scenarios.length) {
3856
- throw new Error("host actor plan lacks personas or scenarios");
3857
- }
3858
- for (const persona of personas) {
3859
- const id = token(persona.id, "host-codex-persona");
3860
- fs.writeFileSync(path.join("humanish/personas", id + ".yaml"), [
3861
- "schema: humanish.persona.v1",
3862
- "id: " + id,
3863
- "name: " + yamlScalar(persona.name || "Host Codex Persona"),
3864
- "summary: " + yamlScalar(persona.intent || "Public-safe host Codex actor persona."),
3865
- "traits:",
3866
- yamlList(persona.traits),
3867
- "constraints:",
3868
- " - Do not use real personal data.",
3869
- " - Do not use production accounts.",
3870
- " - Treat all credentials as env var names only.",
3871
- " - Source: local Codex host actor plan applied inside disposable E2B."
3872
- ].join("\\n") + "\\n");
3873
- }
3874
- for (const scenario of scenarios) {
3875
- const id = token(scenario.id, "host-codex-scenario");
3876
- const personaId = token(personas[0].id, "host-codex-persona");
3877
- fs.writeFileSync(path.join("humanish/scenarios", id + ".yaml"), [
3878
- "schema: humanish.scenario.v1",
3879
- "id: " + id,
3880
- "title: " + yamlScalar(scenario.title || "Host Codex Scenario"),
3881
- "persona: " + personaId,
3882
- "goal: " + yamlScalar(scenario.goal || "Exercise the app through a public-safe browser flow."),
3883
- "mode: browser",
3884
- "steps:",
3885
- ...(Array.isArray(scenario.steps) && scenario.steps.length ? scenario.steps : ["Open the app", "Reach a meaningful state"]).slice(0, 8).map((step, index) => [
3886
- " - name: Step " + String(index + 1),
3887
- " expectation: " + yamlScalar(step)
3888
- ].join("\\n"))
3889
- ].join("\\n") + "\\n");
3890
- }
3891
- console.log("host_actor_plan=applied personas=" + personas.length + " scenarios=" + scenarios.length);
3892
- console.log("host_actor_recommended_proof=" + clean(plan.recommendedProof, "humanish run --app-url <loopback-url> --sims 2"));
3893
- NODE
3894
- local apply_exit=$?
3895
- if [[ "$apply_exit" -eq 0 ]]; then
3896
- ACTOR_STATUS=blocked
3897
- echo "actor_status=$ACTOR_STATUS source=host-codex-plan reason=remote-actor-not-run"
3898
- else
3899
- ACTOR_STATUS=failed
3900
- echo "actor_status=$ACTOR_STATUS source=host-codex-plan exit=$apply_exit"
3901
- fi
3902
- return "$apply_exit"
3903
- }
3904
-
3905
- start_codex_app_server_actor_attempt() {
3906
- echo "Codex app-server mode requested."
3907
- mkdir -p "$CODEX_APP_SERVER_ROOT_PATH"
3908
- cat > "$CODEX_APP_SERVER_PROMPT_PATH" <<'PROMPT'
3909
- You are a Humanish meta-lab actor running through Codex app-server in a disposable authorized repo clone.
3910
-
3911
- Goal: make Humanish useful for this app, then run at least one meaningful public-safe user-test proof.
3912
-
3913
- Work requirements:
3914
- - Inspect package.json, README, routes/components where lightweight, and the running app URL from APP_URL.
3915
- - Improve Humanish setup beyond ceremonial init: app-aware coverage map/matrix, at least two app-specific synthetic personas, and at least two meaningful browser scenarios covering desktop/mobile or happy/friction states.
3916
- - Do not leave only starter persona/scenario filenames, ids, or names. Write app-specific persona and scenario files with app-specific ids, names, goals, selectors, and expectations.
3917
- - Use committed humanish/ source files for personas/scenarios. Keep runtime output under ignored .humanish/.
3918
- - Run at least one meaningful Humanish proof against the running app URL when available: npx --no-install humanish run --app-url "$APP_URL" --sims 2.
3919
- - Render or refresh the nested Observer with npx --no-install humanish watch --run latest --detach --no-open when feasible.
3920
- - Finish with concise public-safe feedback: what user journey was tested, what evidence path proves it, and one useful product or Humanish harness improvement.
3921
-
3922
- Safety:
3923
- - Do not print secrets, environment values, raw private source, or private screenshots.
3924
- - Do not commit, push, file issues, or mutate remotes.
3925
- - Do not run provider-spend-heavy commands beyond the bounded Humanish/Codex proof.
3926
- PROMPT
3927
-
3928
- local timeout_ms="\${HUMANISH_OSS_META_ACTOR_TIMEOUT_MS:-480000}"
3929
- local command
3930
- command="APP_URL=$(printf '%q' "$APP_URL") HUMANISH_PRIVATE_CODEX_API_KEY=$(printf '%q' "$HUMANISH_PRIVATE_CODEX_API_KEY") HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN=$(printf '%q' "$HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN") npx --no-install humanish codex app-server --cwd $(printf '%q' "$APP_DIR") --run-root $(printf '%q' "$CODEX_APP_SERVER_ROOT_PATH") --state-file $(printf '%q' "$CODEX_APP_SERVER_STATE_PATH") --prompt-file $(printf '%q' "$CODEX_APP_SERVER_PROMPT_PATH") --timeout-ms $(printf '%q' "$timeout_ms") --port $(printf '%q' "$CODEX_APP_SERVER_PORT") --sandbox danger-full-access --actor-command 'npx -y @openai/codex@latest app-server --listen stdio://' --keep-open"
3931
- nohup bash -lc "$command" > "$CODEX_APP_SERVER_LOG_PATH" 2>&1 &
3932
- ACTOR_PID=$!
3933
- ACTOR_STATUS=running
3934
- CODEX_APP_SERVER_UI_URL="http://127.0.0.1:$CODEX_APP_SERVER_PORT/"
3935
- echo "actor_status=$ACTOR_STATUS source=codex-app-server pid=$ACTOR_PID log=$CODEX_APP_SERVER_LOG_PATH state=$CODEX_APP_SERVER_STATE_PATH"
3936
- echo "codex_app_server_trace=codex-app-server/summary.json"
3937
- echo "codex_app_server_events=codex-app-server/events.ndjson"
3938
- echo "codex_app_server_transcript=codex-app-server/transcript.txt"
3939
- wait_for_http "$CODEX_APP_SERVER_UI_URL" 60000 500 || true
3940
- open_codex_app_server_client || true
3941
- }
3942
-
3943
- write_app_specific_browser_scenario() {
3944
- if [[ "$APP_STATUS" != "running" || -z "$APP_URL" ]]; then
3945
- return 0
3946
- fi
3947
-
3948
- node - "$APP_DIR" "$APP_URL" <<'NODE' || true
3949
- const fs = require("node:fs");
3950
- const path = require("node:path");
3951
- const [appDir, appUrl] = process.argv.slice(2);
3952
- const clean = (value, fallback = "") => String(value || fallback)
3953
- .replace(/sk-(?:proj-)?[A-Za-z0-9_-]{20,}/g, "[redacted-openai-key]")
3954
- .replace(/e2b_[A-Za-z0-9_-]{12,}/g, "[redacted-e2b-key]")
3955
- .replace(/(?:gh[pousr]_[A-Za-z0-9_]{12,}|github_pat_[A-Za-z0-9_]{12,})/g, "[redacted-github-token]")
3956
- .replace(/https?:\\/\\/[^\\s]+/g, "[redacted-url]")
3957
- .replace(/\\s+/g, " ")
3958
- .trim()
3959
- .slice(0, 160);
3960
- const yamlScalar = (value) => clean(value, "").replace(/'/g, "''");
3961
- const token = (value, fallback) => clean(value, fallback).toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80) || fallback;
3962
- const visibleTextFromHtml = (html) => clean(html
3963
- .replace(/<script[\\s\\S]*?<\\/script>/gi, " ")
3964
- .replace(/<style[\\s\\S]*?<\\/style>/gi, " ")
3965
- .replace(/<[^>]+>/g, " "), "");
3966
- const titleFromHtml = (html) => {
3967
- const match = html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i);
3968
- return clean(match ? match[1] : "", "");
3969
- };
3970
- (async () => {
3971
- try {
3972
- const response = await fetch(appUrl);
3973
- const html = await response.text();
3974
- const title = titleFromHtml(html);
3975
- const bodyText = visibleTextFromHtml(html);
3976
- const expectedText = clean(bodyText.split(/[.!?\\n]/).find((part) => clean(part, "").length >= 4) || title, "");
3977
- const scenarioId = token(title || "app-surface-browser", "app-surface-browser");
3978
- const scenarioPath = path.join(appDir, "humanish", "scenarios", "app-surface-browser.yaml");
3979
- fs.mkdirSync(path.dirname(scenarioPath), { recursive: true });
3980
- const lines = [
3981
- "schema: humanish.scenario.v1",
3982
- "id: " + scenarioId,
3983
- "title: App surface browser proof",
3984
- "persona: synthetic-new-user",
3985
- "goal: Prove the running app exposes a public-safe browser surface for synthetic users.",
3986
- "mode: browser",
3987
- "browser:",
3988
- " startPath: /",
3989
- " steps:",
3990
- " - id: app-surface-load",
3991
- " label: Load the running app surface",
3992
- " action: goto",
3993
- " path: /",
3994
- " expect:",
3995
- " selectorVisible: body",
3996
- ...(expectedText ? [
3997
- " text: '" + yamlScalar(expectedText) + "'"
3998
- ] : []),
3999
- " - id: app-surface-ready",
4000
- " label: Confirm the browser can observe the app body",
4001
- " action: waitForSelector",
4002
- " selector: body"
4003
- ];
4004
- fs.writeFileSync(scenarioPath, lines.join("\\n") + "\\n");
4005
- console.log("browser_scenario=authored path=humanish/scenarios/app-surface-browser.yaml expected_text=" + (expectedText ? "present" : "absent"));
4006
- } catch (error) {
4007
- console.log("browser_scenario=skipped reason=" + clean(error && error.message ? error.message : error, "unknown"));
4008
- }
4009
- })();
4010
- NODE
4011
- }
4012
-
4013
- start_target_app_surface() {
4014
- echo
4015
- echo "== target app surface =="
4016
- local plan_output
4017
- plan_output="$(detect_app_plan)"
4018
- eval "$plan_output"
4019
- if [[ "\${APP_PLAN_OK:-0}" != "1" ]]; then
4020
- APP_STATUS=missing
4021
- APP_REASON="\${APP_PLAN_REASON:-no runnable app script detected}"
4022
- echo "app_status=$APP_STATUS reason=$APP_REASON"
4023
- return 0
4024
- fi
4025
-
4026
- if ! ensure_package_manager "$APP_PM"; then
4027
- APP_STATUS=blocked
4028
- APP_REASON="package manager $APP_PM is unavailable"
4029
- echo "app_status=$APP_STATUS reason=$APP_REASON"
4030
- return 0
4031
- fi
4032
-
4033
- if ! install_project_dependencies "$APP_PM"; then
4034
- APP_STATUS=blocked
4035
- APP_REASON="dependency install failed before app startup"
4036
- echo "app_status=$APP_STATUS reason=$APP_REASON"
4037
- return 0
4038
- fi
4039
-
4040
- local app_url_candidates=("http://localhost:$APP_PORT" "http://127.0.0.1:$APP_PORT" "http://[::1]:$APP_PORT")
4041
- APP_URL="\${app_url_candidates[0]}"
4042
- local start_command
4043
- local command_prefix="HOST=0.0.0.0 PORT=$APP_PORT"
4044
- local script_arg_separator="--"
4045
- if [[ "$APP_PM" == "pnpm" ]]; then
4046
- command_prefix="PNPM_CONFIG_VERIFY_DEPS_BEFORE_RUN=false npm_config_verify_deps_before_run=false $command_prefix"
4047
- script_arg_separator=""
4048
- fi
4049
- case "$APP_FRAMEWORK" in
4050
- next)
4051
- start_command="$command_prefix $APP_PM run $APP_SCRIPT $script_arg_separator --hostname 0.0.0.0 --port $APP_PORT"
4052
- ;;
4053
- vite)
4054
- start_command="$command_prefix $APP_PM run $APP_SCRIPT $script_arg_separator --host 0.0.0.0 --port $APP_PORT"
4055
- ;;
4056
- *)
4057
- start_command="$command_prefix $APP_PM run $APP_SCRIPT"
4058
- ;;
4059
- esac
4060
-
4061
- echo "app_plan=$APP_PLAN_REASON"
4062
- echo "app_url_candidates=\${app_url_candidates[*]}"
4063
- echo "app_command=$start_command"
4064
- nohup bash -lc "$start_command" > "$APP_LOG_PATH" 2>&1 &
4065
- APP_PID=$!
4066
-
4067
- local ready_url=""
4068
- if ready_url="$(wait_for_any_http 120000 1000 "\${app_url_candidates[@]}")"; then
4069
- APP_URL="$ready_url"
4070
- APP_STATUS=running
4071
- APP_REASON="target app responded at $APP_URL"
4072
- open_browser_url "$APP_URL" app-desktop 0 0 760 520
4073
- open_browser_url "$APP_URL" app-compact 0 520 430 420
4074
- write_app_specific_browser_scenario || true
4075
- else
4076
- APP_STATUS=blocked
4077
- APP_REASON="target app did not become HTTP-ready at $APP_URL"
4078
- tail -n 40 "$APP_LOG_PATH" || true
4079
- fi
4080
- echo "app_status=$APP_STATUS reason=$APP_REASON pid=$APP_PID"
4081
- }
4082
-
4083
- start_actor_attempt() {
4084
- echo
4085
- echo "== codex actor attempt =="
4086
- if [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" == "1" ]]; then
4087
- start_codex_app_server_actor_attempt
4088
- return 0
4089
- fi
4090
-
4091
- local actor_script="$ROOT_DIR/actor-run.sh"
4092
- cat > "$actor_script" <<ACTOR
4093
- #!/usr/bin/env bash
4094
- set +e
4095
- APP_DIR="$APP_DIR"
4096
- if [[ "\${HUMANISH_OSS_META_ACTOR_FIRST:-0}" == "1" ]]; then
4097
- PROMPT='You are a Humanish meta-lab actor running in a disposable public-safe repo clone. Your goal is useful product-specific user-study setup, not ceremonial install proof. Inspect package.json, README, routes, scripts, and the running app shape. Install humanish as a dev dependency with the repo package manager if needed; package=humanish, binary=humanish. Run npx --no-install humanish init --yes if Humanish is not initialized. Replace starter humanish/coverage-map.md and humanish/coverage-matrix.md with app-aware screens, roles, states, happy paths, and at least one sad/friction path. Author at least two public-safe app-specific personas and two desktop/mobile browser scenarios; avoid generic first-run-smoke only. Start the local app if feasible. Run npx --no-install humanish run --help and verify --app-url is available. If the local binary is missing, install humanish; one-shot fallback is npx --yes --package humanish@latest humanish run --help. If the app is running locally, run npx --no-install humanish run --app-url <loopback-url> --sims 2; do not use humanish watch --sims as app behavior proof. After run --app-url, render or open the nested Humanish Observer with npx --no-install humanish watch --run latest --detach --no-open --json if feasible. Final summary must include personas/scenarios created, product journeys covered, one observed friction/improvement or none observed, and evidence paths. Do not stop at install/init proof. Do not wait on long-running watchers after rendering proof. Do not print secrets, do not commit, do not push, and do not file issues.'
4098
- else
4099
- PROMPT='You are a Humanish meta-lab actor. Inspect this repo, inspect the running app and Humanish artifacts already generated here, and draft the best next public-safe personas and desktop/mobile browser scenarios for human users of this app. Once the draft is written, exit successfully. Do not wait on long-running watchers. Do not print secrets, do not commit, do not push, and do not file issues.'
4100
- fi
4101
- printf -v app_dir_q '%q' "\\$APP_DIR"
4102
- printf -v prompt_q '%q' "\\$PROMPT"
4103
- printf -v actor_message_q '%q' "$ACTOR_LAST_MESSAGE_PATH"
4104
- ACTOR_MODEL="\${HUMANISH_OSS_META_ACTOR_MODEL:-gpt-5.4-mini}"
4105
- ACTOR_TIMEOUT_MS="\${HUMANISH_OSS_META_ACTOR_TIMEOUT_MS:-480000}"
4106
- ACTOR_TIMEOUT_SECONDS=\\$(( (ACTOR_TIMEOUT_MS + 999) / 1000 ))
4107
- printf -v actor_model_q '%q' "\\$ACTOR_MODEL"
4108
- CODEX_COMMAND="npx -y @openai/codex@latest exec --ephemeral --ignore-user-config --skip-git-repo-check -m \\$actor_model_q -C \\$app_dir_q --dangerously-bypass-approvals-and-sandbox --output-last-message \\$actor_message_q \\$prompt_q"
4109
- if [[ -n "\${HUMANISH_PRIVATE_CODEX_API_KEY:-}" && -n "\${HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN:-}" ]]; then
4110
- CODEX_API_KEY="\\$HUMANISH_PRIVATE_CODEX_API_KEY" CODEX_ACCESS_TOKEN="\\$HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN" timeout "\\$ACTOR_TIMEOUT_SECONDS" bash -lc "\\$CODEX_COMMAND"
4111
- elif [[ -n "\${HUMANISH_PRIVATE_CODEX_API_KEY:-}" ]]; then
4112
- CODEX_API_KEY="\\$HUMANISH_PRIVATE_CODEX_API_KEY" timeout "\\$ACTOR_TIMEOUT_SECONDS" bash -lc "\\$CODEX_COMMAND"
4113
- elif [[ -n "\${HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN:-}" ]]; then
4114
- CODEX_ACCESS_TOKEN="\\$HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN" timeout "\\$ACTOR_TIMEOUT_SECONDS" bash -lc "\\$CODEX_COMMAND"
4115
- else
4116
- timeout "\\$ACTOR_TIMEOUT_SECONDS" bash -lc "\\$CODEX_COMMAND"
4117
- fi
4118
- code=\\$?
4119
- echo "actor_exit=\\$code"
4120
- exit "\\$code"
4121
- ACTOR
4122
- chmod +x "$actor_script"
4123
- HUMANISH_PRIVATE_CODEX_API_KEY="$HUMANISH_PRIVATE_CODEX_API_KEY" HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN="$HUMANISH_PRIVATE_CODEX_ACCESS_TOKEN" nohup bash "$actor_script" > "$ACTOR_LOG_PATH" 2>&1 &
4124
- ACTOR_PID=$!
4125
- ACTOR_STATUS=running
4126
- echo "actor_status=$ACTOR_STATUS pid=$ACTOR_PID log=$ACTOR_LOG_PATH"
4127
- }
4128
-
4129
- wait_for_actor_attempt_if_required() {
4130
- if [[ "\${HUMANISH_OSS_META_REQUIRE_ACTOR:-0}" != "1" && "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" != "1" ]]; then
4131
- return 0
4132
- fi
4133
-
4134
- echo
4135
- echo "== required codex actor readback =="
4136
- if [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" == "1" ]]; then
4137
- local timeout_ms="\${HUMANISH_OSS_META_ACTOR_TIMEOUT_MS:-480000}"
4138
- local started_ms
4139
- started_ms="$(date +%s%3N)"
4140
- local next_heartbeat_ms=$((started_ms + 15000))
4141
- while true; do
4142
- local status_line
4143
- status_line="$(node - "$CODEX_APP_SERVER_STATE_PATH" <<'NODE' 2>/dev/null || true
4144
- const fs = require("node:fs");
4145
- const [statePath] = process.argv.slice(2);
4146
- if (!fs.existsSync(statePath)) process.exit(2);
4147
- const state = JSON.parse(fs.readFileSync(statePath, "utf8"));
4148
- console.log(String(state.status || "unknown"));
4149
- NODE
4150
- )"
4151
- if [[ "$status_line" != "starting" && "$status_line" != "running" && "$status_line" != "unknown" && -n "$status_line" ]]; then
4152
- ACTOR_STATUS="$status_line"
4153
- break
4154
- fi
4155
- local now_ms
4156
- now_ms="$(date +%s%3N)"
4157
- if [[ "$now_ms" -ge "$next_heartbeat_ms" ]]; then
4158
- echo "actor_status=running source=codex-app-server elapsed_ms=$((now_ms - started_ms)) state=$CODEX_APP_SERVER_STATE_PATH log=$CODEX_APP_SERVER_LOG_PATH"
4159
- echo "actor_log_tail_begin"
4160
- tail -n 20 "$CODEX_APP_SERVER_LOG_PATH" || true
4161
- echo "actor_log_tail_end"
4162
- next_heartbeat_ms=$((now_ms + 15000))
4163
- fi
4164
- if [[ $((now_ms - started_ms)) -ge "$timeout_ms" ]]; then
4165
- ACTOR_STATUS=timed_out
4166
- echo "actor_status=$ACTOR_STATUS timeout_ms=$timeout_ms state=$CODEX_APP_SERVER_STATE_PATH log=$CODEX_APP_SERVER_LOG_PATH"
4167
- return 1
4168
- fi
4169
- sleep 1
4170
- done
4171
- echo "actor_status=$ACTOR_STATUS source=codex-app-server state=$CODEX_APP_SERVER_STATE_PATH log=$CODEX_APP_SERVER_LOG_PATH"
4172
- echo "actor_log_tail_begin"
4173
- tail -n 80 "$CODEX_APP_SERVER_LOG_PATH" || true
4174
- echo "actor_log_tail_end"
4175
- if [[ -f "$CODEX_APP_SERVER_ROOT_PATH/codex-app-server/summary.json" ]]; then
4176
- node - "$CODEX_APP_SERVER_ROOT_PATH/codex-app-server/summary.json" "$ACTOR_LAST_MESSAGE_PATH" <<'NODE' || true
4177
- const fs = require("node:fs");
4178
- const [summaryPath, outPath] = process.argv.slice(2);
4179
- const summary = JSON.parse(fs.readFileSync(summaryPath, "utf8"));
4180
- const messages = Array.isArray(summary.messages) ? summary.messages : [];
4181
- const text = messages
4182
- .slice(-4)
4183
- .map((message) => typeof message?.text === "string" ? message.text : "")
4184
- .filter(Boolean)
4185
- .join("\\n\\n")
4186
- .slice(-12000);
4187
- fs.writeFileSync(outPath, text || "No final Codex app-server agent message captured.\\n");
4188
- NODE
4189
- elif [[ -f "$CODEX_APP_SERVER_ROOT_PATH/codex-app-server/transcript.txt" ]]; then
4190
- tail -n 80 "$CODEX_APP_SERVER_ROOT_PATH/codex-app-server/transcript.txt" > "$ACTOR_LAST_MESSAGE_PATH" || true
4191
- fi
4192
- [[ "$ACTOR_STATUS" == "passed" ]]
4193
- return $?
4194
- fi
4195
-
4196
- if [[ -z "$ACTOR_PID" ]]; then
4197
- ACTOR_STATUS=blocked
4198
- echo "actor_status=$ACTOR_STATUS reason=no actor process was started"
4199
- return 1
4200
- fi
4201
-
4202
- local timeout_ms="\${HUMANISH_OSS_META_ACTOR_TIMEOUT_MS:-480000}"
4203
- local started_ms
4204
- started_ms="$(date +%s%3N)"
4205
- while kill -0 "$ACTOR_PID" >/dev/null 2>&1; do
4206
- local now_ms
4207
- now_ms="$(date +%s%3N)"
4208
- if [[ $((now_ms - started_ms)) -ge "$timeout_ms" ]]; then
4209
- ACTOR_STATUS=timed_out
4210
- kill "$ACTOR_PID" >/dev/null 2>&1 || true
4211
- echo "actor_status=$ACTOR_STATUS timeout_ms=$timeout_ms log=$ACTOR_LOG_PATH"
4212
- return 1
4213
- fi
4214
- sleep 1
4215
- done
4216
-
4217
- local actor_exit=0
4218
- wait "$ACTOR_PID" || actor_exit=$?
4219
- if [[ "$actor_exit" -eq 0 ]]; then
4220
- ACTOR_STATUS=passed
4221
- else
4222
- ACTOR_STATUS=failed
4223
- fi
4224
- echo "actor_status=$ACTOR_STATUS exit=$actor_exit log=$ACTOR_LOG_PATH"
4225
- echo "actor_log_tail_begin"
4226
- tail -n 80 "$ACTOR_LOG_PATH" || true
4227
- echo "actor_log_tail_end"
4228
- [[ "$actor_exit" -eq 0 ]]
4229
- }
4230
-
4231
- rm -rf "$APP_DIR"
4232
- ASKPASS="$ROOT_DIR/git-askpass.sh"
4233
- cat > "$ASKPASS" <<'ASKPASS'
4234
- #!/usr/bin/env bash
4235
- case "$1" in
4236
- *Username*) echo "x-access-token" ;;
4237
- *Password*) echo "\${HUMANISH_GITHUB_TOKEN_RUNTIME:-}" ;;
4238
- *) echo "" ;;
4239
- esac
4240
- ASKPASS
4241
- chmod 700 "$ASKPASS"
4242
- clone_repo() {
4243
- local repo_url=${shellQuote(repoUrl)}
4244
- if GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 GIT_ASKPASS=false SSH_ASKPASS=false GIT_TERMINAL_PROMPT=0 git -c credential.helper= clone --depth=1 "$repo_url" "$APP_DIR"; then
4245
- echo "clone_auth=anonymous"
4246
- return 0
4247
- fi
4248
- echo "clone_auth=anonymous_failed retry=token_clone"
4249
- rm -rf "$APP_DIR"
4250
-
4251
- if [[ -n "$HUMANISH_PRIVATE_GITHUB_TOKEN" ]]; then
4252
- if GIT_CONFIG_GLOBAL=/dev/null GIT_CONFIG_NOSYSTEM=1 GIT_ASKPASS="$ASKPASS" GIT_TERMINAL_PROMPT=0 HUMANISH_GITHUB_TOKEN_RUNTIME="$HUMANISH_PRIVATE_GITHUB_TOKEN" git -c credential.helper= clone --depth=1 "$repo_url" "$APP_DIR"; then
4253
- echo "clone_auth=token"
4254
- return 0
4255
- fi
4256
- echo "clone_auth=token_failed"
4257
- rm -rf "$APP_DIR"
4258
- fi
4259
-
4260
- return 1
4261
- }
4262
- clone_repo
4263
- cd "$APP_DIR"
4264
- echo
4265
- echo "== repo fingerprint =="
4266
- git rev-parse --short HEAD || true
4267
- node --version || true
4268
- npm --version || true
4269
-
4270
- echo
4271
- echo "== humanish skill discovery =="
4272
- if npx -y skills add danielgwilson/humanish --skill humanish --list >/tmp/humanish-skill-list.txt 2>&1; then
4273
- echo "skill_discovery=listed"
4274
- elif npx -y skills add danielgwilson/humanish --skill humanish >/tmp/humanish-skill-install.txt 2>&1; then
4275
- echo "skill_install=attempted"
4276
- else
4277
- echo "skill_install=blocked"
4278
- tail -n 20 /tmp/humanish-skill-list.txt /tmp/humanish-skill-install.txt 2>/dev/null || true
4279
- fi
4280
-
4281
- echo
4282
- if [[ "\${HUMANISH_OSS_META_ACTOR_FIRST:-0}" == "1" && "\${HUMANISH_OSS_META_HOST_CODEX_ACTOR:-0}" != "1" && "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" != "1" ]]; then
4283
- start_actor_attempt
4284
- wait_for_actor_attempt_if_required || true
4285
- fi
4286
-
4287
- echo
4288
- install_humanish_cli
4289
-
4290
- echo
4291
- echo "== humanish init =="
4292
- npx --no-install humanish init --yes
4293
- apply_host_actor_plan || true
4294
-
4295
- start_target_app_surface
4296
-
4297
- if [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" == "1" && "\${HUMANISH_OSS_META_HOST_CODEX_ACTOR:-0}" != "1" ]]; then
4298
- start_actor_attempt
4299
- wait_for_actor_attempt_if_required || true
4300
- fi
4301
-
4302
- echo
4303
- echo "== nested humanish proof =="
4304
- if [[ "$APP_STATUS" == "running" && -n "$APP_URL" ]]; then
4305
- npx --no-install humanish run --app-url "$APP_URL" --sims 2 --run-id ${shellQuote(runId)}
4306
- else
4307
- echo "app_not_running_for_browser_proof=$APP_REASON"
4308
- npx --no-install humanish run --dry-run --run-id ${shellQuote(runId)}
4309
- fi
4310
- if npx --no-install humanish verify --run latest; then
4311
- NESTED_VERIFY_STATUS=passed
4312
- else
4313
- NESTED_VERIFY_STATUS=failed
4314
- exit 1
4315
- fi
4316
- npx --no-install humanish watch --run latest --detach --no-open
4317
- open_nested_observer "opening nested observer"
4318
- open_codex_app_server_client
4319
- arrange_lab_windows
4320
- if [[ "\${HUMANISH_OSS_META_ACTOR_FIRST:-0}" != "1" && "\${HUMANISH_OSS_META_HOST_CODEX_ACTOR:-0}" != "1" && "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" != "1" ]]; then
4321
- start_actor_attempt
4322
- wait_for_actor_attempt_if_required || true
4323
- fi
4324
-
4325
- echo
4326
- echo "== bootstrap complete =="
4327
- echo "app_status=$APP_STATUS"
4328
- echo "app_url=$APP_URL"
4329
- echo "actor_status=$ACTOR_STATUS"
4330
- echo "nested_observer=$NESTED_OBSERVER"
4331
- `;
4332
- }
4333
- function buildRemoteLauncherScript(args) {
4334
- const terminalCommand = `bash -lc ${shellQuote(`${args.bootstrapPath}; echo; echo 'Humanish bootstrap finished. Leave this terminal open for review.'; exec bash`)}`;
4335
- return `#!/usr/bin/env bash
4336
- set -u
4337
- BOOTSTRAP=${shellQuote(args.bootstrapPath)}
4338
- LOG_PATH=${shellQuote(args.logPath)}
4339
- TITLE=${shellQuote(args.title)}
4340
- echo "launching visible terminal for $BOOTSTRAP" >> "$LOG_PATH"
4341
- if command -v xfce4-terminal >/dev/null 2>&1; then
4342
- nohup xfce4-terminal --hold --title "$TITLE" --command ${shellQuote(terminalCommand)} >> "$LOG_PATH" 2>&1 &
4343
- elif command -v xterm >/dev/null 2>&1; then
4344
- nohup xterm -T "$TITLE" -e ${shellQuote(terminalCommand)} >> "$LOG_PATH" 2>&1 &
4345
- else
4346
- echo "No GUI terminal found; running bootstrap headless." >> "$LOG_PATH"
4347
- nohup bash "$BOOTSTRAP" >> "$LOG_PATH" 2>&1 &
4348
- fi
4349
- `;
4350
- }
4351
- function buildRemoteFocusCommand(title) {
4352
- return `TITLE=${shellQuote(title)}
4353
- for attempt in $(seq 1 20); do
4354
- if command -v wmctrl >/dev/null 2>&1; then
4355
- wmctrl -a "$TITLE" >/dev/null 2>&1 && exit 0
4356
- fi
4357
- if command -v xdotool >/dev/null 2>&1; then
4358
- WIN="$(xdotool search --name "$TITLE" 2>/dev/null | head -n 1 || true)"
4359
- if [[ -n "$WIN" ]]; then
4360
- xdotool windowactivate "$WIN" >/dev/null 2>&1 && exit 0
4361
- fi
4362
- fi
4363
- sleep 0.25
4364
- done
4365
- exit 0`;
4366
- }
4367
- function buildRemoteScreenshotArrangeCommand(terminalTitle) {
4368
- return `TERMINAL_TITLE=${shellQuote(terminalTitle ?? "")}
4369
- EXPECTED_CHROME_WINDOWS=2
4370
- if [[ "\${HUMANISH_OSS_META_CODEX_APP_SERVER:-0}" == "1" ]]; then
4371
- EXPECTED_CHROME_WINDOWS=3
4372
- fi
4373
- if ! command -v xdotool >/dev/null 2>&1; then
4374
- exit 0
4375
- fi
4376
- for attempt in $(seq 1 24); do
4377
- CHROME_COUNT="$(xdotool search --onlyvisible --class google-chrome 2>/dev/null | wc -l | tr -d ' ')"
4378
- OBSERVER_WINDOW="$(xdotool search --onlyvisible --name "Humanish Observer" 2>/dev/null | tail -n 1 || true)"
4379
- if [[ "$CHROME_COUNT" -ge "$EXPECTED_CHROME_WINDOWS" && -n "$OBSERVER_WINDOW" ]]; then
4380
- break
4381
- fi
4382
- sleep 0.25
4383
- done
4384
- OBSERVER_WINDOW="$(xdotool search --onlyvisible --name "Humanish Observer" 2>/dev/null | tail -n 1 || true)"
4385
- if [[ -n "$OBSERVER_WINDOW" ]]; then
4386
- xdotool windowsize "$OBSERVER_WINDOW" 680 933 >/dev/null 2>&1 || true
4387
- xdotool windowmove "$OBSERVER_WINDOW" 760 27 >/dev/null 2>&1 || true
4388
- fi
4389
- slot=0
4390
- while IFS= read -r win; do
4391
- [[ -z "$win" ]] && continue
4392
- if [[ -n "$OBSERVER_WINDOW" && "$win" == "$OBSERVER_WINDOW" ]]; then
4393
- continue
4394
- fi
4395
- if [[ "$slot" -eq 0 ]]; then
4396
- xdotool windowsize "$win" 760 493 >/dev/null 2>&1 || true
4397
- xdotool windowmove "$win" 0 27 >/dev/null 2>&1 || true
4398
- elif [[ "$slot" -eq 1 ]]; then
4399
- xdotool windowsize "$win" 430 420 >/dev/null 2>&1 || true
4400
- xdotool windowmove "$win" 0 520 >/dev/null 2>&1 || true
4401
- else
4402
- xdotool windowsize "$win" 330 420 >/dev/null 2>&1 || true
4403
- xdotool windowmove "$win" 430 520 >/dev/null 2>&1 || true
4404
- fi
4405
- slot=$((slot + 1))
4406
- done < <(xdotool search --onlyvisible --class google-chrome 2>/dev/null || true)
4407
- if [[ -n "$TERMINAL_TITLE" ]]; then
4408
- TERMINAL_WINDOW="$(xdotool search --onlyvisible --name "$TERMINAL_TITLE" 2>/dev/null | head -n 1 || true)"
4409
- if [[ -n "$TERMINAL_WINDOW" ]]; then
4410
- xdotool windowlower "$TERMINAL_WINDOW" >/dev/null 2>&1 || xdotool windowminimize "$TERMINAL_WINDOW" >/dev/null 2>&1 || true
4411
- fi
4412
- fi
4413
- if [[ -n "$OBSERVER_WINDOW" ]]; then
4414
- xdotool windowactivate "$OBSERVER_WINDOW" >/dev/null 2>&1 || true
4415
- fi
4416
- exit 0`;
4417
- }
4418
- async function runDesktopCommand(desktop, command, options) {
4419
- const result = await runDesktopCommandOrThrow(() => desktop.commands.run(`bash -lc ${shellQuote(command)}`, options),
4420
- // The real Sandbox throws CommandExitError on a non-zero exit, so recover the
4421
- // exit code + output tail from the throw and preserve the formatted error.
4422
- ({ exitCode, stderrTail }) => new Error(`Remote command failed with exit code ${exitCode ?? "unknown"}.\noutput=${stderrTail}`));
4423
- if (result.exitCode && result.exitCode !== 0) {
4424
- throw new Error([
4425
- `Remote command failed with exit code ${result.exitCode}.`,
4426
- `stdout=${result.stdout ?? ""}`,
4427
- `stderr=${result.stderr ?? ""}`
4428
- ].join("\n"));
4429
- }
4430
- return result;
4431
- }
4432
- async function packLocalHumanishPackage(cwd, runId) {
4433
- const packageRoot = moduleRoot;
4434
- await prepareReusableHumanishStorageDirectory(cwd, "tmp", "oss-meta", runId);
4435
- const packDir = await prepareReusableHumanishStorageDirectory(cwd, "tmp", "oss-meta", runId, "package");
4436
- await execFileAsync("pnpm", ["build"], {
4437
- cwd: packageRoot,
4438
- env: process.env,
4439
- maxBuffer: 10 * 1024 * 1024
4440
- });
4441
- await execFileAsync("npm", ["pack", "--pack-destination", packDir], {
4442
- cwd: packageRoot,
4443
- env: process.env,
4444
- maxBuffer: 10 * 1024 * 1024
4445
- });
4446
- const files = await readdir(packDir);
4447
- const fileName = files.find((file) => /^humanish-.*\.tgz$/.test(file));
4448
- if (!fileName) {
4449
- throw new Error("npm pack did not produce a humanish tarball.");
4450
- }
4451
- const archivePath = path.join(packDir, fileName);
4452
- const archiveStat = await stat(archivePath);
4453
- return {
4454
- fileName,
4455
- path: archivePath,
4456
- sizeBytes: archiveStat.size
4457
- };
4458
- }
4459
- function toArrayBuffer(buffer) {
4460
- const copy = new ArrayBuffer(buffer.byteLength);
4461
- new Uint8Array(copy).set(buffer);
4462
- return copy;
4463
- }
4464
- function shellQuote(value) {
4465
- if (value.length === 0) {
4466
- return "''";
4467
- }
4468
- return `'${value.replaceAll("'", "'\"'\"'")}'`;
4469
- }
4470
- function formatLiveDesktopForResult(desktop, redactRepoNames) {
4471
- return {
4472
- ...(desktop.completion?.actorStatus ? { actorStatus: desktop.completion.actorStatus } : {}),
4473
- ...(desktop.completion?.appStatus ? { appStatus: desktop.completion.appStatus } : {}),
4474
- ...(desktop.bootstrap ? { bootstrapStatus: desktop.bootstrap.status } : {}),
4475
- ...(desktop.completion ? { completionReason: desktop.completion.reason, completionStatus: desktop.completion.status } : {}),
4476
- repo: desktop.repo,
4477
- ...(desktop.screenshot ? { screenshotPresent: true } : {}),
4478
- ...(!redactRepoNames && desktop.sandboxId ? { sandboxId: desktop.sandboxId } : {}),
4479
- streamId: desktop.streamId,
4480
- urlPresent: Boolean(desktop.url),
4481
- ...(desktop.completion?.visualStatus ? { visualStatus: desktop.completion.visualStatus } : {}),
4482
- ...(desktop.completion?.visualWindowCount === undefined ? {} : { visualWindowCount: desktop.completion.visualWindowCount })
4483
- };
4484
- }
4485
- function missingLiveKeys(env) {
4486
- const missing = ["E2B_API_KEY"].filter((name) => !env[name]?.trim());
4487
- const actorAuthRequested = remoteActorAuthRequested(env);
4488
- const actorAuthPresent = Boolean(env.CODEX_API_KEY?.trim() || env.CODEX_ACCESS_TOKEN?.trim() || env.OPENAI_API_KEY?.trim());
4489
- if (actorAuthRequested && !hostCodexActorRequested(env) && !actorAuthPresent) {
4490
- missing.push(OSS_META_LAB_ACTOR_AUTH_PLACEHOLDER);
4491
- }
4492
- return missing;
4493
- }
4494
- function readPositiveInt(value, fallback) {
4495
- if (!value || !/^\d+$/.test(value)) {
4496
- return fallback;
4497
- }
4498
- const parsed = Number.parseInt(value, 10);
4499
- return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
4500
- }
4501
- function readNonNegativeInt(value, fallback) {
4502
- if (!value || !/^\d+$/.test(value)) {
4503
- return fallback;
4504
- }
4505
- const parsed = Number.parseInt(value, 10);
4506
- return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : fallback;
4507
- }
4508
- async function wait(ms) {
4509
- if (ms <= 0) {
4510
- return;
4511
- }
4512
- await new Promise((resolve) => setTimeout(resolve, ms));
4513
- }
4514
- function compactError(error) {
4515
- const message = error instanceof Error ? error.message : String(error);
4516
- return message
4517
- .replace(/sk-[A-Za-z0-9_-]{20,}/g, "[redacted-openai-key]")
4518
- .replace(/e2b_[A-Za-z0-9_-]{12,}/g, "[redacted-e2b-key]")
4519
- .replace(/gh[pousr]_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]")
4520
- .replace(/github_pat_[A-Za-z0-9_]{12,}/g, "[redacted-github-token]")
4521
- .replace(/https?:\/\/[^/\s]*e2b[^)\s]+/gi, "[redacted-e2b-url]")
4522
- .replace(/\s+/g, " ")
4523
- .slice(0, 240);
4524
- }
4525
- function makeMetaRunId() {
4526
- const stamp = new Date().toISOString().replace(/[:.]/g, "-");
4527
- return `oss-meta-${stamp}-${randomBytes(4).toString("hex")}`;
4528
- }
4529
- function repoArtifactLabel(assignment) {
4530
- return `repo-${String(assignment.index).padStart(2, "0")}`;
4531
- }
4532
- function redactAssignments(assignments, redactRepoNames) {
4533
- if (!redactRepoNames) {
4534
- return assignments;
4535
- }
4536
- return assignments.map((assignment) => ({
4537
- ...assignment,
4538
- repo: repoArtifactLabel(assignment),
4539
- scenarioId: `oss-meta-${repoArtifactLabel(assignment)}`
4540
- }));
4541
- }
4542
- function safeArtifactToken(value) {
4543
- const token = value.toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
4544
- return token || "artifact";
4545
- }
4546
- async function writeJson(artifactRoot, relativePath, value) {
4547
- await writeContainedOutputFile(artifactRoot, relativePath, `${JSON.stringify(value, null, 2)}\n`, "utf8");
4548
- }
4549
- // E2B desktop interfaces + the optional-peer loader now live in ./e2b-desktop-launch.js
4550
- // (shared with the computer-use actor lane) and are imported at the top of this file.
4551
- //# sourceMappingURL=oss-meta-lab.js.map