humanish 0.105.0 → 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.
- package/AGENTS.md +89 -94
- package/ARCHITECTURE.md +146 -0
- package/CHANGELOG.md +502 -0
- package/CONTEXT.md +51 -0
- package/CONTRIBUTING.md +111 -9
- package/README.md +213 -124
- package/SECURITY.md +1 -1
- package/TELEMETRY.md +112 -0
- package/dist/actors/affordance.d.ts +56 -0
- package/dist/actors/affordance.js +155 -0
- package/dist/actors/agent-session.js +42 -0
- package/dist/actors/codex/app-server-actor-trace.d.ts +11 -0
- package/dist/actors/codex/app-server-actor-trace.js +211 -0
- package/dist/actors/codex/app-server-client.d.ts +39 -0
- package/dist/actors/codex/app-server-client.js +116 -0
- package/dist/actors/codex/app-server-trace.d.ts +154 -0
- package/dist/actors/codex/app-server-trace.js +424 -0
- package/dist/actors/codex/app-server-ui.d.ts +40 -0
- package/dist/actors/codex/app-server-ui.js +328 -0
- package/dist/actors/codex/app-server.d.ts +44 -0
- package/dist/actors/codex/app-server.js +268 -0
- package/dist/actors/codex/qualified-versions.d.ts +45 -0
- package/dist/actors/codex/qualified-versions.js +87 -0
- package/dist/actors/codex/restricted-executable.d.ts +17 -0
- package/dist/actors/codex/restricted-executable.js +147 -0
- package/dist/actors/codex/restricted-launch.d.ts +116 -0
- package/dist/actors/codex/restricted-launch.js +222 -0
- package/dist/actors/codex/restricted-participant-policy.d.ts +46 -0
- package/dist/actors/codex/restricted-participant-policy.js +82 -0
- package/dist/actors/codex/restricted-participant.d.ts +20 -0
- package/dist/actors/codex/restricted-participant.js +432 -0
- package/dist/actors/codex/restricted-policy.d.ts +70 -0
- package/dist/actors/codex/restricted-policy.js +326 -0
- package/dist/actors/codex/restricted-session.d.ts +65 -0
- package/dist/actors/codex/restricted-session.js +432 -0
- package/dist/actors/codex/restricted-transport.d.ts +73 -0
- package/dist/actors/codex/restricted-transport.js +335 -0
- package/dist/actors/codex/restricted-turn.d.ts +62 -0
- package/dist/actors/codex/restricted-turn.js +284 -0
- package/dist/actors/computer-use/actor.d.ts +77 -0
- package/dist/actors/computer-use/actor.js +78 -0
- package/dist/actors/computer-use/admission-limit.d.ts +12 -0
- package/dist/actors/computer-use/admission-limit.js +19 -0
- package/dist/actors/computer-use/executor-error.js +48 -0
- package/dist/actors/computer-use/loop/actions.d.ts +26 -0
- package/dist/actors/computer-use/loop/actions.js +245 -0
- package/dist/actors/computer-use/loop/backstop.d.ts +42 -0
- package/dist/actors/computer-use/loop/backstop.js +202 -0
- package/dist/actors/computer-use/loop/debrief.d.ts +19 -0
- package/dist/actors/computer-use/loop/debrief.js +164 -0
- package/dist/actors/computer-use/loop/ending.d.ts +86 -0
- package/dist/actors/computer-use/loop/ending.js +316 -0
- package/dist/actors/computer-use/loop/observation.d.ts +55 -0
- package/dist/actors/computer-use/loop/observation.js +246 -0
- package/dist/actors/computer-use/loop/output-limit.d.ts +11 -0
- package/dist/actors/computer-use/loop/output-limit.js +21 -0
- package/dist/actors/computer-use/loop/provider-call.d.ts +19 -0
- package/dist/actors/computer-use/loop/provider-call.js +208 -0
- package/dist/actors/computer-use/loop/race.d.ts +34 -0
- package/dist/actors/computer-use/loop/race.js +79 -0
- package/dist/actors/computer-use/loop/session.d.ts +77 -0
- package/dist/actors/computer-use/loop/session.js +135 -0
- package/dist/actors/computer-use/loop/spend.d.ts +30 -0
- package/dist/actors/computer-use/loop/spend.js +85 -0
- package/dist/actors/computer-use/loop/trace.d.ts +35 -0
- package/dist/actors/computer-use/loop/trace.js +140 -0
- package/dist/actors/computer-use/loop/types.d.ts +404 -0
- package/dist/actors/computer-use/loop/types.js +1 -0
- package/dist/actors/computer-use/loop/usage.d.ts +102 -0
- package/dist/actors/computer-use/loop/usage.js +355 -0
- package/dist/actors/computer-use/loop.d.ts +11 -0
- package/dist/actors/computer-use/loop.js +248 -0
- package/dist/actors/computer-use/openai-provider.d.ts +107 -0
- package/dist/actors/computer-use/openai-provider.js +472 -0
- package/dist/actors/computer-use/openai-requests.d.ts +35 -0
- package/dist/actors/computer-use/openai-requests.js +74 -0
- package/dist/actors/computer-use/openai-wire.d.ts +67 -0
- package/dist/actors/computer-use/openai-wire.js +365 -0
- package/dist/actors/computer-use/provider-error.d.ts +27 -0
- package/dist/actors/computer-use/provider-error.js +86 -0
- package/dist/actors/computer-use/speech.js +6 -0
- package/dist/actors/contract.d.ts +315 -0
- package/dist/actors/contract.js +201 -0
- package/dist/actors/goal-source.js +38 -0
- package/dist/actors/local-agent/claude-session.d.ts +43 -0
- package/dist/actors/local-agent/claude-session.js +370 -0
- package/dist/actors/local-agent/cli.d.ts +115 -0
- package/dist/actors/local-agent/cli.js +413 -0
- package/dist/actors/local-agent/readiness.d.ts +31 -0
- package/dist/actors/local-agent/readiness.js +45 -0
- package/dist/actors/openai-endpoint.d.ts +2 -0
- package/dist/actors/openai-endpoint.js +2 -0
- package/dist/actors/output-token-limit.js +4 -0
- package/dist/actors/reasoning-effort.js +33 -0
- package/dist/actors/registry.d.ts +59 -0
- package/dist/actors/registry.js +89 -0
- package/dist/actors/scripted-browser/actor.d.ts +49 -0
- package/dist/actors/scripted-browser/actor.js +428 -0
- package/dist/actors/scripted-browser/browser-command.d.ts +1 -0
- package/dist/actors/scripted-browser/browser-command.js +48 -0
- package/dist/actors/scripted-browser/journey.d.ts +9 -0
- package/dist/actors/scripted-browser/journey.js +171 -0
- package/dist/actors/scripted-browser/steps.d.ts +60 -0
- package/dist/actors/scripted-browser/steps.js +384 -0
- package/dist/actors/scripted-browser/types.d.ts +135 -0
- package/dist/actors/scripted-browser/types.js +26 -0
- package/dist/actors/stop-cause.d.ts +9 -0
- package/dist/actors/stop-cause.js +42 -0
- package/dist/actors/stop-conditions.d.ts +40 -0
- package/dist/actors/stop-conditions.js +65 -0
- package/dist/analysis/automatic-completion.d.ts +38 -0
- package/dist/analysis/automatic-completion.js +90 -0
- package/dist/analysis/automatic-config.d.ts +41 -0
- package/dist/analysis/automatic-config.js +135 -0
- package/dist/analysis/automatic.d.ts +17 -0
- package/dist/analysis/automatic.js +279 -0
- package/dist/analysis/codex-config.d.ts +8 -0
- package/dist/analysis/codex-config.js +69 -0
- package/dist/analysis/evidence-sources.d.ts +23 -0
- package/dist/analysis/evidence-sources.js +251 -0
- package/dist/analysis/evidence.d.ts +18 -0
- package/dist/analysis/evidence.js +482 -0
- package/dist/analysis/execute.d.ts +52 -0
- package/dist/analysis/execute.js +504 -0
- package/dist/analysis/image-tokens.d.ts +1 -0
- package/dist/analysis/image-tokens.js +41 -0
- package/dist/analysis/job.d.ts +97 -0
- package/dist/analysis/job.js +311 -0
- package/dist/analysis/load.d.ts +3 -0
- package/dist/analysis/load.js +11 -0
- package/dist/analysis/provider.d.ts +57 -0
- package/dist/analysis/provider.js +227 -0
- package/dist/analysis/restricted-codex.d.ts +19 -0
- package/dist/analysis/restricted-codex.js +23 -0
- package/dist/analysis/service.d.ts +72 -0
- package/dist/analysis/service.js +399 -0
- package/dist/analysis/sharing.d.ts +11 -0
- package/dist/analysis/sharing.js +44 -0
- package/dist/analysis/store-executions.d.ts +27 -0
- package/dist/analysis/store-executions.js +224 -0
- package/dist/analysis/store.d.ts +31 -0
- package/dist/analysis/store.js +315 -0
- package/dist/analysis/types.d.ts +217 -0
- package/dist/analysis/types.js +12 -0
- package/dist/analysis/validation.d.ts +225 -0
- package/dist/analysis/validation.js +562 -0
- package/dist/browser-control/client.d.ts +18 -0
- package/dist/browser-control/client.js +239 -0
- package/dist/browser-control/dispatcher.d.ts +19 -0
- package/dist/browser-control/dispatcher.js +221 -0
- package/dist/browser-control/protocol.d.ts +492 -0
- package/dist/browser-control/protocol.js +360 -0
- package/dist/browser-control/recording-transfer.d.ts +3 -0
- package/dist/browser-control/recording-transfer.js +48 -0
- package/dist/browser-control/transport.d.ts +27 -0
- package/dist/browser-control/transport.js +189 -0
- package/dist/cli/commands/analysis-signals.d.ts +7 -0
- package/dist/cli/commands/analysis-signals.js +25 -0
- package/dist/cli/commands/analyze.d.ts +3 -0
- package/dist/cli/commands/analyze.js +212 -0
- package/dist/cli/commands/codex.d.ts +3 -0
- package/dist/cli/commands/codex.js +145 -0
- package/dist/cli/commands/comms.d.ts +3 -0
- package/dist/cli/commands/comms.js +225 -0
- package/dist/cli/commands/feedback.d.ts +3 -0
- package/dist/cli/commands/feedback.js +138 -0
- package/dist/cli/commands/lab-format.d.ts +8 -0
- package/dist/cli/commands/lab-format.js +105 -0
- package/dist/cli/commands/lab-route-computer-use.d.ts +20 -0
- package/dist/cli/commands/lab-route-computer-use.js +251 -0
- package/dist/cli/commands/lab-route-open.d.ts +27 -0
- package/dist/cli/commands/lab-route-open.js +37 -0
- package/dist/cli/commands/lab-route-preview.d.ts +20 -0
- package/dist/cli/commands/lab-route-preview.js +74 -0
- package/dist/cli/commands/lab-route-run.d.ts +17 -0
- package/dist/cli/commands/lab-route-run.js +31 -0
- package/dist/cli/commands/lab-route-scripted.d.ts +19 -0
- package/dist/cli/commands/lab-route-scripted.js +50 -0
- package/dist/cli/commands/lab-route-shared-world.d.ts +20 -0
- package/dist/cli/commands/lab-route-shared-world.js +135 -0
- package/dist/cli/commands/lab-route-terminal.d.ts +19 -0
- package/dist/cli/commands/lab-route-terminal.js +49 -0
- package/dist/cli/commands/lab-run.d.ts +9 -0
- package/dist/cli/commands/lab-run.js +166 -0
- package/dist/cli/commands/lab-scorer.d.ts +30 -0
- package/dist/cli/commands/lab-scorer.js +17 -0
- package/dist/cli/commands/lab.d.ts +3 -0
- package/dist/cli/commands/lab.js +193 -0
- package/dist/cli/commands/observe.d.ts +4 -0
- package/dist/cli/commands/observe.js +345 -0
- package/dist/cli/commands/runs.d.ts +11 -0
- package/dist/cli/commands/runs.js +314 -0
- package/dist/cli/commands/setup.d.ts +11 -0
- package/dist/cli/commands/setup.js +325 -0
- package/dist/cli/commands/tui.d.ts +32 -0
- package/dist/cli/commands/tui.js +305 -0
- package/dist/cli/commands/watch.d.ts +3 -0
- package/dist/cli/commands/watch.js +245 -0
- package/dist/cli/doctor.d.ts +39 -0
- package/dist/cli/doctor.js +263 -0
- package/dist/cli/first-run-path.d.ts +67 -0
- package/dist/cli/first-run-path.js +150 -0
- package/dist/cli/io.d.ts +85 -0
- package/dist/cli/io.js +232 -0
- package/dist/cli/observer-follow.d.ts +56 -0
- package/dist/cli/observer-follow.js +160 -0
- package/dist/cli/orientation.d.ts +30 -0
- package/dist/cli/orientation.js +114 -0
- package/dist/cli/program.d.ts +15 -0
- package/dist/cli/program.js +338 -0
- package/dist/cli/secret-prompt.js +39 -0
- package/dist/cli/telemetry.js +351 -0
- package/dist/cli.js +2 -4
- package/dist/comms/agentmail.d.ts +29 -0
- package/dist/comms/agentmail.js +568 -0
- package/dist/comms/capture-surface.d.ts +54 -0
- package/dist/comms/capture-surface.js +468 -0
- package/dist/comms/catch-host.d.ts +52 -0
- package/dist/comms/catch-host.js +192 -0
- package/dist/comms/connections.d.ts +20 -0
- package/dist/comms/connections.js +116 -0
- package/dist/comms/email-catch.d.ts +49 -0
- package/dist/comms/email-catch.js +236 -0
- package/dist/comms/extract.d.ts +7 -0
- package/dist/comms/extract.js +65 -0
- package/dist/comms/fake-inbox.d.ts +39 -0
- package/dist/comms/fake-inbox.js +136 -0
- package/dist/comms/images.d.ts +7 -0
- package/dist/comms/images.js +53 -0
- package/dist/comms/lease-store.d.ts +91 -0
- package/dist/comms/lease-store.js +600 -0
- package/dist/comms/providers.d.ts +30 -0
- package/dist/comms/providers.js +24 -0
- package/dist/comms/receiving-common.d.ts +17 -0
- package/dist/comms/receiving-common.js +82 -0
- package/dist/comms/receiving-evidence.d.ts +4 -0
- package/dist/comms/receiving-evidence.js +59 -0
- package/dist/comms/receiving-recovery.d.ts +22 -0
- package/dist/comms/receiving-recovery.js +100 -0
- package/dist/comms/receiving-render.d.ts +16 -0
- package/dist/comms/receiving-render.js +409 -0
- package/dist/comms/receiving-runtime.d.ts +41 -0
- package/dist/comms/receiving-runtime.js +66 -0
- package/dist/comms/receiving-surface.d.ts +8 -0
- package/dist/comms/receiving-surface.js +156 -0
- package/dist/comms/receiving-types.d.ts +122 -0
- package/dist/comms/receiving-types.js +3 -0
- package/dist/comms/receiving.d.ts +33 -0
- package/dist/comms/receiving.js +508 -0
- package/dist/comms/sandbox-catch-script.d.ts +16 -0
- package/dist/comms/sandbox-catch-script.js +331 -0
- package/dist/comms/sandbox-catch.d.ts +214 -0
- package/dist/comms/sandbox-catch.js +451 -0
- package/dist/comms/setup.d.ts +65 -0
- package/dist/comms/setup.js +259 -0
- package/dist/comms/thread-evidence.d.ts +28 -0
- package/dist/comms/thread-evidence.js +30 -0
- package/dist/comms/types.d.ts +76 -0
- package/dist/comms/types.js +8 -0
- package/dist/deprecated.d.ts +90 -0
- package/dist/deprecated.js +106 -0
- package/dist/evidence/browser-hygiene.js +42 -0
- package/dist/evidence/desktop-recorder.d.ts +39 -0
- package/dist/evidence/desktop-recorder.js +340 -0
- package/dist/evidence/desktop-recording-artifact.d.ts +5 -0
- package/dist/evidence/desktop-recording-artifact.js +53 -0
- package/dist/evidence/desktop-recording-types.d.ts +27 -0
- package/dist/evidence/desktop-recording-types.js +16 -0
- package/dist/evidence/encoded-text.d.ts +27 -0
- package/dist/evidence/encoded-text.js +243 -0
- package/dist/evidence/frame-signature.d.ts +17 -0
- package/dist/evidence/frame-signature.js +111 -0
- package/dist/evidence/image.d.ts +24 -0
- package/dist/evidence/image.js +170 -0
- package/dist/evidence/plain-text.d.ts +8 -0
- package/dist/evidence/plain-text.js +16 -0
- package/dist/evidence/redaction.d.ts +110 -0
- package/dist/evidence/redaction.js +329 -0
- package/dist/feedback/draft.d.ts +58 -0
- package/dist/feedback/draft.js +309 -0
- package/dist/feedback/export-bundle.d.ts +6 -0
- package/dist/feedback/export-bundle.js +585 -0
- package/dist/feedback/export.d.ts +50 -0
- package/dist/feedback/export.js +392 -0
- package/dist/feedback/feedback.d.ts +37 -0
- package/dist/feedback/feedback.js +282 -0
- package/dist/feedback/proof.d.ts +8 -0
- package/dist/feedback/proof.js +56 -0
- package/dist/guest/bootstrap.d.ts +55 -0
- package/dist/guest/bootstrap.js +348 -0
- package/dist/guest/browser-tools.d.ts +8 -0
- package/dist/guest/browser-tools.js +72 -0
- package/dist/guest/chromium-text.d.ts +62 -0
- package/dist/guest/chromium-text.js +386 -0
- package/dist/guest/desktop-executor.d.ts +57 -0
- package/dist/guest/desktop-executor.js +256 -0
- package/dist/guest/desktop-keys.d.ts +8 -0
- package/dist/guest/desktop-keys.js +89 -0
- package/dist/guest/desktop-media.d.ts +70 -0
- package/dist/guest/desktop-media.js +385 -0
- package/dist/guest/desktop-native.d.ts +14 -0
- package/dist/guest/desktop-native.js +156 -0
- package/dist/guest/media-config.d.ts +15 -0
- package/dist/guest/media-config.js +16 -0
- package/dist/guest/runtime-desktop.d.ts +45 -0
- package/dist/guest/runtime-desktop.js +420 -0
- package/dist/guest/runtime-processes.d.ts +28 -0
- package/dist/guest/runtime-processes.js +94 -0
- package/dist/guest/runtime.d.ts +31 -0
- package/dist/guest/runtime.js +124 -0
- package/dist/guest-media-worker.js +184 -48
- package/dist/guest-runtime-main.js +23 -10
- package/dist/guest-runtime-revision.js +1 -1
- package/dist/index.d.ts +32 -83
- package/dist/index.js +21 -42
- package/dist/keys/env-file.d.ts +15 -0
- package/dist/keys/env-file.js +109 -0
- package/dist/keys/key-resolution.d.ts +58 -0
- package/dist/keys/key-resolution.js +389 -0
- package/dist/lab/adapter-extension.d.ts +75 -0
- package/dist/lab/adapter-extension.js +253 -0
- package/dist/lab/adapter-scorer-loader.d.ts +43 -0
- package/dist/lab/adapter-scorer-loader.js +130 -0
- package/dist/lab/bag-overrides.d.ts +18 -0
- package/dist/lab/bag-overrides.js +121 -0
- package/dist/lab/composition-rules.d.ts +5 -0
- package/dist/lab/composition-rules.js +283 -0
- package/dist/lab/config.d.ts +7 -0
- package/dist/lab/config.js +208 -0
- package/dist/lab/device-presets.d.ts +97 -0
- package/dist/lab/device-presets.js +87 -0
- package/dist/lab/discover.d.ts +65 -0
- package/dist/lab/discover.js +422 -0
- package/dist/lab/doctor.d.ts +39 -0
- package/dist/lab/doctor.js +233 -0
- package/dist/lab/init-paths.d.ts +5 -0
- package/dist/lab/init-paths.js +89 -0
- package/dist/lab/init-plan.d.ts +20 -0
- package/dist/lab/init-plan.js +163 -0
- package/dist/lab/init-templates.d.ts +28 -0
- package/dist/lab/init-templates.js +416 -0
- package/dist/lab/init.d.ts +39 -0
- package/dist/lab/init.js +287 -0
- package/dist/lab/keys.d.ts +2 -0
- package/dist/lab/keys.js +264 -0
- package/dist/lab/parse/actors.d.ts +14 -0
- package/dist/lab/parse/actors.js +453 -0
- package/dist/lab/parse/comms.d.ts +12 -0
- package/dist/lab/parse/comms.js +246 -0
- package/dist/lab/parse/execution.d.ts +19 -0
- package/dist/lab/parse/execution.js +356 -0
- package/dist/lab/parse/subject-state.d.ts +30 -0
- package/dist/lab/parse/subject-state.js +179 -0
- package/dist/lab/parse/subject.d.ts +9 -0
- package/dist/lab/parse/subject.js +420 -0
- package/dist/lab/parse/values.d.ts +17 -0
- package/dist/lab/parse/values.js +65 -0
- package/dist/lab/participant-assignment.d.ts +12 -0
- package/dist/lab/participant-assignment.js +19 -0
- package/dist/lab/persona-resolve.d.ts +39 -0
- package/dist/lab/persona-resolve.js +118 -0
- package/dist/lab/persona.d.ts +39 -0
- package/dist/lab/persona.js +192 -0
- package/dist/lab/plan-base.d.ts +24 -0
- package/dist/lab/plan-base.js +113 -0
- package/dist/lab/plan-participants.d.ts +81 -0
- package/dist/lab/plan-participants.js +92 -0
- package/dist/lab/plan-types.d.ts +269 -0
- package/dist/lab/plan-types.js +5 -0
- package/dist/lab/plan.d.ts +27 -0
- package/dist/lab/plan.js +156 -0
- package/dist/lab/preflight-probes.d.ts +3 -0
- package/dist/lab/preflight-probes.js +312 -0
- package/dist/lab/preflight-result.d.ts +7 -0
- package/dist/lab/preflight-result.js +43 -0
- package/dist/lab/preflight.d.ts +95 -0
- package/dist/lab/preflight.js +117 -0
- package/dist/lab/route-inputs.d.ts +17 -0
- package/dist/lab/route-inputs.js +95 -0
- package/dist/lab/routing.d.ts +81 -0
- package/dist/lab/routing.js +214 -0
- package/dist/lab/run-lab-events.d.ts +69 -0
- package/dist/lab/run-lab-events.js +95 -0
- package/dist/lab/run-lab-options.d.ts +82 -0
- package/dist/lab/run-lab-options.js +399 -0
- package/dist/lab/summary.d.ts +60 -0
- package/dist/lab/summary.js +168 -0
- package/dist/lab/tasks.d.ts +91 -0
- package/dist/lab/tasks.js +139 -0
- package/dist/lab/types.d.ts +813 -0
- package/dist/lab/types.js +6 -0
- package/dist/lab/validation.d.ts +67 -0
- package/dist/lab/validation.js +387 -0
- package/dist/lab/warnings.d.ts +2 -0
- package/dist/lab/warnings.js +338 -0
- package/dist/observer/artifact.d.ts +23 -0
- package/dist/observer/artifact.js +235 -0
- package/dist/observer/data.d.ts +115 -0
- package/dist/observer/data.js +258 -0
- package/dist/observer/exposure.d.ts +64 -0
- package/dist/observer/exposure.js +143 -0
- package/dist/observer/http.js +50 -0
- package/dist/observer/library.js +190 -0
- package/dist/observer/listen.js +85 -0
- package/dist/observer/live.d.ts +9 -0
- package/dist/observer/live.js +25 -0
- package/dist/observer/pinned-files.d.ts +30 -0
- package/dist/observer/pinned-files.js +160 -0
- package/dist/observer/render.d.ts +69 -0
- package/dist/observer/render.js +350 -0
- package/dist/observer/run-inventory.d.ts +35 -0
- package/dist/observer/run-inventory.js +95 -0
- package/dist/observer/run-routes.d.ts +37 -0
- package/dist/observer/run-routes.js +373 -0
- package/dist/observer/serve.d.ts +97 -0
- package/dist/observer/serve.js +305 -0
- package/dist/observer/static.js +369 -0
- package/dist/observer/tunnel.js +112 -0
- package/dist/observer-app.html +9 -20
- package/dist/routes/computer-use/bundle-parts.d.ts +50 -0
- package/dist/routes/computer-use/bundle-parts.js +177 -0
- package/dist/routes/computer-use/bundle.d.ts +56 -0
- package/dist/routes/computer-use/bundle.js +184 -0
- package/dist/routes/computer-use/diagnostics.d.ts +38 -0
- package/dist/routes/computer-use/diagnostics.js +94 -0
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +65 -0
- package/dist/routes/computer-use/e2b-desktop/comms.js +225 -0
- package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +3 -0
- package/dist/routes/computer-use/e2b-desktop/desktop.js +91 -0
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +65 -0
- package/dist/routes/computer-use/e2b-desktop/fidelity.js +156 -0
- package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +18 -0
- package/dist/routes/computer-use/e2b-desktop/prepare.js +198 -0
- package/dist/routes/computer-use/e2b-desktop/start.d.ts +14 -0
- package/dist/routes/computer-use/e2b-desktop/start.js +193 -0
- package/dist/routes/computer-use/e2b-desktop/state.d.ts +65 -0
- package/dist/routes/computer-use/e2b-desktop/state.js +69 -0
- package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +6 -0
- package/dist/routes/computer-use/e2b-desktop/teardown.js +152 -0
- package/dist/routes/computer-use/external-comms.d.ts +20 -0
- package/dist/routes/computer-use/external-comms.js +55 -0
- package/dist/routes/computer-use/fanout-bundle.d.ts +11 -0
- package/dist/routes/computer-use/fanout-bundle.js +274 -0
- package/dist/routes/computer-use/fanout-lanes.d.ts +15 -0
- package/dist/routes/computer-use/fanout-lanes.js +302 -0
- package/dist/routes/computer-use/in-process-desktop.d.ts +17 -0
- package/dist/routes/computer-use/in-process-desktop.js +40 -0
- package/dist/routes/computer-use/lanes.d.ts +35 -0
- package/dist/routes/computer-use/lanes.js +321 -0
- package/dist/routes/computer-use/legacy-lane-spec.d.ts +62 -0
- package/dist/routes/computer-use/legacy-lane-spec.js +39 -0
- package/dist/routes/computer-use/live-flush.d.ts +42 -0
- package/dist/routes/computer-use/live-flush.js +154 -0
- package/dist/routes/computer-use/local-tree-pack.d.ts +27 -0
- package/dist/routes/computer-use/local-tree-pack.js +47 -0
- package/dist/routes/computer-use/local-vm.d.ts +20 -0
- package/dist/routes/computer-use/local-vm.js +218 -0
- package/dist/routes/computer-use/participant-desktop.d.ts +63 -0
- package/dist/routes/computer-use/participant-desktop.js +33 -0
- package/dist/routes/computer-use/participant-facts.d.ts +6 -0
- package/dist/routes/computer-use/participant-facts.js +22 -0
- package/dist/routes/computer-use/participant-model.d.ts +30 -0
- package/dist/routes/computer-use/participant-model.js +222 -0
- package/dist/routes/computer-use/participant-prompt.d.ts +53 -0
- package/dist/routes/computer-use/participant-prompt.js +87 -0
- package/dist/routes/computer-use/participant-runs.d.ts +67 -0
- package/dist/routes/computer-use/participant-runs.js +255 -0
- package/dist/routes/computer-use/plan.d.ts +56 -0
- package/dist/routes/computer-use/plan.js +308 -0
- package/dist/routes/computer-use/preflight.d.ts +26 -0
- package/dist/routes/computer-use/preflight.js +85 -0
- package/dist/routes/computer-use/rerun-selection.d.ts +19 -0
- package/dist/routes/computer-use/rerun-selection.js +121 -0
- package/dist/routes/computer-use/result.d.ts +7 -0
- package/dist/routes/computer-use/result.js +292 -0
- package/dist/routes/computer-use/route.d.ts +33 -0
- package/dist/routes/computer-use/route.js +145 -0
- package/dist/routes/computer-use/run-lanes.d.ts +59 -0
- package/dist/routes/computer-use/run-lanes.js +135 -0
- package/dist/routes/computer-use/self-report.d.ts +21 -0
- package/dist/routes/computer-use/self-report.js +231 -0
- package/dist/routes/computer-use/setup.d.ts +136 -0
- package/dist/routes/computer-use/setup.js +371 -0
- package/dist/routes/computer-use/single-bundle.d.ts +97 -0
- package/dist/routes/computer-use/single-bundle.js +393 -0
- package/dist/routes/computer-use/subject-projection.d.ts +51 -0
- package/dist/routes/computer-use/subject-projection.js +159 -0
- package/dist/routes/computer-use/types.d.ts +539 -0
- package/dist/routes/computer-use/types.js +37 -0
- package/dist/routes/preview.d.ts +13 -0
- package/dist/routes/preview.js +36 -0
- package/dist/routes/scripted/bundle.d.ts +47 -0
- package/dist/routes/scripted/bundle.js +195 -0
- package/dist/routes/scripted/plan.d.ts +30 -0
- package/dist/routes/scripted/plan.js +95 -0
- package/dist/routes/scripted/result.d.ts +48 -0
- package/dist/routes/scripted/result.js +176 -0
- package/dist/routes/scripted/route.d.ts +28 -0
- package/dist/routes/scripted/route.js +218 -0
- package/dist/routes/scripted/scenario.d.ts +21 -0
- package/dist/routes/scripted/scenario.js +102 -0
- package/dist/routes/scripted/session-result.d.ts +8 -0
- package/dist/routes/scripted/session-result.js +60 -0
- package/dist/routes/scripted/setup.d.ts +45 -0
- package/dist/routes/scripted/setup.js +126 -0
- package/dist/routes/scripted/subject.d.ts +49 -0
- package/dist/routes/scripted/subject.js +156 -0
- package/dist/routes/scripted/surface-records.d.ts +26 -0
- package/dist/routes/scripted/surface-records.js +88 -0
- package/dist/routes/scripted/surface-sessions.d.ts +13 -0
- package/dist/routes/scripted/surface-sessions.js +40 -0
- package/dist/routes/scripted/types.d.ts +88 -0
- package/dist/routes/scripted/types.js +3 -0
- package/dist/routes/shared-world/bundle.d.ts +20 -0
- package/dist/routes/shared-world/bundle.js +446 -0
- package/dist/routes/shared-world/checkpoints.d.ts +25 -0
- package/dist/routes/shared-world/checkpoints.js +46 -0
- package/dist/routes/shared-world/comms.d.ts +68 -0
- package/dist/routes/shared-world/comms.js +176 -0
- package/dist/routes/shared-world/external-public.d.ts +21 -0
- package/dist/routes/shared-world/external-public.js +130 -0
- package/dist/routes/shared-world/handoff.d.ts +62 -0
- package/dist/routes/shared-world/handoff.js +348 -0
- package/dist/routes/shared-world/lobby-code.d.ts +25 -0
- package/dist/routes/shared-world/lobby-code.js +152 -0
- package/dist/routes/shared-world/plan.d.ts +27 -0
- package/dist/routes/shared-world/plan.js +174 -0
- package/dist/routes/shared-world/provenance.d.ts +27 -0
- package/dist/routes/shared-world/provenance.js +65 -0
- package/dist/routes/shared-world/provisioned.d.ts +57 -0
- package/dist/routes/shared-world/provisioned.js +505 -0
- package/dist/routes/shared-world/result.d.ts +18 -0
- package/dist/routes/shared-world/result.js +327 -0
- package/dist/routes/shared-world/route.d.ts +21 -0
- package/dist/routes/shared-world/route.js +277 -0
- package/dist/routes/shared-world/seat-records.d.ts +20 -0
- package/dist/routes/shared-world/seat-records.js +213 -0
- package/dist/routes/shared-world/seats.d.ts +38 -0
- package/dist/routes/shared-world/seats.js +208 -0
- package/dist/routes/shared-world/setup.d.ts +48 -0
- package/dist/routes/shared-world/setup.js +200 -0
- package/dist/routes/shared-world/types.d.ts +354 -0
- package/dist/routes/shared-world/types.js +29 -0
- package/dist/routes/terminal/adapter.d.ts +37 -0
- package/dist/routes/terminal/adapter.js +201 -0
- package/dist/routes/terminal/bundle.d.ts +79 -0
- package/dist/routes/terminal/bundle.js +305 -0
- package/dist/routes/terminal/credentials.d.ts +34 -0
- package/dist/routes/terminal/credentials.js +102 -0
- package/dist/routes/terminal/dry-run.d.ts +24 -0
- package/dist/routes/terminal/dry-run.js +157 -0
- package/dist/routes/terminal/encoding.js +79 -0
- package/dist/routes/terminal/ledger.d.ts +49 -0
- package/dist/routes/terminal/ledger.js +170 -0
- package/dist/routes/terminal/lifetime.d.ts +10 -0
- package/dist/routes/terminal/lifetime.js +22 -0
- package/dist/routes/terminal/live-finish.d.ts +31 -0
- package/dist/routes/terminal/live-finish.js +215 -0
- package/dist/routes/terminal/live-sandbox.d.ts +69 -0
- package/dist/routes/terminal/live-sandbox.js +452 -0
- package/dist/routes/terminal/persona.d.ts +20 -0
- package/dist/routes/terminal/persona.js +34 -0
- package/dist/routes/terminal/plan.d.ts +21 -0
- package/dist/routes/terminal/plan.js +115 -0
- package/dist/routes/terminal/recorder.d.ts +23 -0
- package/dist/routes/terminal/recorder.js +77 -0
- package/dist/routes/terminal/result.d.ts +47 -0
- package/dist/routes/terminal/result.js +114 -0
- package/dist/routes/terminal/route.d.ts +23 -0
- package/dist/routes/terminal/route.js +170 -0
- package/dist/routes/terminal/runtime-auth.d.ts +12 -0
- package/dist/routes/terminal/runtime-auth.js +23 -0
- package/dist/routes/terminal/runtime.d.ts +14 -0
- package/dist/routes/terminal/runtime.js +47 -0
- package/dist/routes/terminal/sandbox.d.ts +35 -0
- package/dist/routes/terminal/sandbox.js +126 -0
- package/dist/routes/terminal/session.d.ts +25 -0
- package/dist/routes/terminal/session.js +199 -0
- package/dist/routes/terminal/token-usage.d.ts +15 -0
- package/dist/routes/terminal/token-usage.js +93 -0
- package/dist/routes/terminal/trace.d.ts +40 -0
- package/dist/routes/terminal/trace.js +172 -0
- package/dist/routes/terminal/types.d.ts +342 -0
- package/dist/routes/terminal/types.js +31 -0
- package/dist/run/bundle-shape.d.ts +7 -0
- package/dist/run/bundle-shape.js +369 -0
- package/dist/run/bundle.d.ts +547 -0
- package/dist/run/bundle.js +44 -0
- package/dist/run/concurrency.js +24 -0
- package/dist/run/contained-output.d.ts +50 -0
- package/dist/run/contained-output.js +351 -0
- package/dist/run/cost-summary.d.ts +28 -0
- package/dist/run/cost-summary.js +213 -0
- package/dist/run/costs.js +140 -0
- package/dist/run/detail.d.ts +62 -0
- package/dist/run/detail.js +139 -0
- package/dist/run/dry-run-inputs.d.ts +9 -0
- package/dist/run/dry-run-inputs.js +90 -0
- package/dist/run/dry-run.d.ts +6 -0
- package/dist/run/dry-run.js +362 -0
- package/dist/run/feedback-shape.d.ts +7 -0
- package/dist/run/feedback-shape.js +89 -0
- package/dist/run/git-state.d.ts +35 -0
- package/dist/run/git-state.js +316 -0
- package/dist/run/git-workspace.d.ts +32 -0
- package/dist/run/git-workspace.js +450 -0
- package/dist/run/judge.d.ts +210 -0
- package/dist/run/judge.js +240 -0
- package/dist/run/locate.d.ts +22 -0
- package/dist/run/locate.js +122 -0
- package/dist/run/outcomes.d.ts +31 -0
- package/dist/run/outcomes.js +210 -0
- package/dist/run/participant-records.d.ts +28 -0
- package/dist/run/participant-records.js +63 -0
- package/dist/run/participant.d.ts +29 -0
- package/dist/run/participant.js +12 -0
- package/dist/run/paths.d.ts +79 -0
- package/dist/run/paths.js +356 -0
- package/dist/run/preflight-receipts.d.ts +46 -0
- package/dist/run/preflight-receipts.js +173 -0
- package/dist/run/pricing.d.ts +124 -0
- package/dist/run/pricing.js +298 -0
- package/dist/run/project.d.ts +8 -0
- package/dist/run/project.js +103 -0
- package/dist/run/projection.d.ts +184 -0
- package/dist/run/projection.js +356 -0
- package/dist/run/reclaim.d.ts +41 -0
- package/dist/run/reclaim.js +183 -0
- package/dist/run/results.d.ts +88 -0
- package/dist/run/results.js +3 -0
- package/dist/run/run-index.d.ts +107 -0
- package/dist/run/run-index.js +243 -0
- package/dist/run/run.d.ts +103 -0
- package/dist/run/run.js +199 -0
- package/dist/run/sandbox-receipts.d.ts +31 -0
- package/dist/run/sandbox-receipts.js +49 -0
- package/dist/run/shared-world-evidence.d.ts +220 -0
- package/dist/run/shared-world-evidence.js +49 -0
- package/dist/run/shared-world-shape.d.ts +26 -0
- package/dist/run/shared-world-shape.js +181 -0
- package/dist/run/stats.d.ts +82 -0
- package/dist/run/stats.js +258 -0
- package/dist/run/status.d.ts +111 -0
- package/dist/run/status.js +176 -0
- package/dist/run/stored-runs.d.ts +38 -0
- package/dist/run/stored-runs.js +273 -0
- package/dist/run/stream-shape.d.ts +4 -0
- package/dist/run/stream-shape.js +160 -0
- package/dist/run/streams.d.ts +257 -0
- package/dist/run/streams.js +12 -0
- package/dist/run/study-files.d.ts +35 -0
- package/dist/run/study-files.js +164 -0
- package/dist/run/terminal-contract.d.ts +25 -0
- package/dist/run/terminal-contract.js +47 -0
- package/dist/run/text.d.ts +2 -0
- package/dist/run/text.js +4 -0
- package/dist/run/transient-comms-secrets.js +72 -0
- package/dist/run/type-guards.d.ts +6 -0
- package/dist/run/type-guards.js +18 -0
- package/dist/run-lab.d.ts +110 -0
- package/dist/run-lab.js +148 -0
- package/dist/subject/clone.d.ts +37 -0
- package/dist/subject/clone.js +62 -0
- package/dist/subject/desktop-cli.d.ts +17 -0
- package/dist/subject/desktop-cli.js +51 -0
- package/dist/subject/local-tree-archive.d.ts +82 -0
- package/dist/subject/local-tree-archive.js +431 -0
- package/dist/subject/local-tree.d.ts +28 -0
- package/dist/subject/local-tree.js +58 -0
- package/dist/subject/node-bootstrap.d.ts +12 -0
- package/dist/subject/node-bootstrap.js +66 -0
- package/dist/subject/runtime.d.ts +13 -0
- package/dist/subject/runtime.js +50 -0
- package/dist/subject/serve.d.ts +39 -0
- package/dist/subject/serve.js +249 -0
- package/dist/subject/state.d.ts +23 -0
- package/dist/subject/state.js +58 -0
- package/dist/subject/steps.d.ts +37 -0
- package/dist/subject/steps.js +39 -0
- package/dist/substrates/command-failure.d.ts +23 -0
- package/dist/substrates/command-failure.js +45 -0
- package/dist/substrates/desktop-session.d.ts +41 -0
- package/dist/substrates/desktop-session.js +59 -0
- package/dist/substrates/detached.d.ts +55 -0
- package/dist/substrates/detached.js +139 -0
- package/dist/substrates/e2b/cdp-probe.d.ts +99 -0
- package/dist/substrates/e2b/cdp-probe.js +556 -0
- package/dist/substrates/e2b/desktop-browser.d.ts +81 -0
- package/dist/substrates/e2b/desktop-browser.js +410 -0
- package/dist/substrates/e2b/desktop-cdp.d.ts +77 -0
- package/dist/substrates/e2b/desktop-cdp.js +211 -0
- package/dist/substrates/e2b/desktop-executor.d.ts +92 -0
- package/dist/substrates/e2b/desktop-executor.js +302 -0
- package/dist/substrates/e2b/desktop-geometry.d.ts +83 -0
- package/dist/substrates/e2b/desktop-geometry.js +331 -0
- package/dist/substrates/e2b/desktop-media.d.ts +29 -0
- package/dist/substrates/e2b/desktop-media.js +151 -0
- package/dist/substrates/e2b/desktop-recording.d.ts +18 -0
- package/dist/substrates/e2b/desktop-recording.js +238 -0
- package/dist/substrates/e2b/desktop-resources.d.ts +11 -0
- package/dist/substrates/e2b/desktop-resources.js +35 -0
- package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +15 -0
- package/dist/substrates/e2b/desktop-screenshot-cleanup.js +66 -0
- package/dist/substrates/e2b/lifetime.d.ts +12 -0
- package/dist/substrates/e2b/lifetime.js +18 -0
- package/dist/substrates/e2b/sandbox.d.ts +102 -0
- package/dist/substrates/e2b/sandbox.js +202 -0
- package/dist/substrates/e2b/sdk.d.ts +194 -0
- package/dist/substrates/e2b/sdk.js +168 -0
- package/dist/substrates/e2b/shell.d.ts +10 -0
- package/dist/substrates/e2b/shell.js +61 -0
- package/dist/substrates/local/captured-inbox.d.ts +6 -0
- package/dist/substrates/local/captured-inbox.js +87 -0
- package/dist/substrates/local/firecracker-desktop.d.ts +25 -0
- package/dist/substrates/local/firecracker-desktop.js +315 -0
- package/dist/substrates/local/runtime-config.d.ts +6 -0
- package/dist/substrates/local/runtime-config.js +91 -0
- package/dist/substrates/local/runtime-host.d.ts +30 -0
- package/dist/substrates/local/runtime-host.js +143 -0
- package/dist/substrates/local/runtime-release.d.ts +5 -0
- package/dist/substrates/local/runtime-release.js +32 -0
- package/dist/substrates/local/runtime-ssh.d.ts +9 -0
- package/dist/substrates/local/runtime-ssh.js +129 -0
- package/dist/substrates/local/runtime.d.ts +25 -0
- package/dist/substrates/local/runtime.js +190 -0
- package/dist/substrates/shell.d.ts +44 -0
- package/dist/substrates/shell.js +22 -0
- package/dist/tui/actions.d.ts +39 -0
- package/dist/tui/actions.js +203 -0
- package/dist/tui/contract.d.ts +144 -0
- package/dist/tui/contract.js +52 -0
- package/dist/tui/launch.js +172 -0
- package/dist/tui/project.d.ts +10 -0
- package/dist/tui/project.js +17 -0
- package/dist/tui-app.js +125 -125
- package/dist/verify/actor.d.ts +27 -0
- package/dist/verify/actor.js +292 -0
- package/dist/verify/artifacts.d.ts +47 -0
- package/dist/verify/artifacts.js +373 -0
- package/dist/verify/costs.d.ts +30 -0
- package/dist/verify/costs.js +129 -0
- package/dist/verify/liveness.d.ts +7 -0
- package/dist/verify/liveness.js +72 -0
- package/dist/verify/rerun.d.ts +3 -0
- package/dist/verify/rerun.js +46 -0
- package/dist/verify/shared-world-concurrent.d.ts +11 -0
- package/dist/verify/shared-world-concurrent.js +346 -0
- package/dist/verify/shared-world.d.ts +8 -0
- package/dist/verify/shared-world.js +295 -0
- package/dist/verify/subject.d.ts +17 -0
- package/dist/verify/subject.js +123 -0
- package/dist/verify/verify.d.ts +34 -0
- package/dist/verify/verify.js +333 -0
- package/docs/README.md +67 -0
- package/docs/architecture/actor-contract.md +215 -174
- package/docs/architecture/browser-control.md +51 -37
- package/docs/architecture/comms-inbox.md +8 -8
- package/docs/architecture/desktop-recording.md +2 -2
- package/docs/architecture/desktop-sessions.md +33 -21
- package/docs/architecture/external-public-shared-world.md +80 -64
- package/docs/architecture/github-feedback-loop.md +40 -27
- package/docs/architecture/guest-desktop.md +22 -10
- package/docs/architecture/local-browser-runtime.md +30 -21
- package/docs/architecture/observer-review.md +9 -9
- package/docs/architecture/observer.md +53 -57
- package/docs/architecture/participant-media.md +3 -3
- package/docs/architecture/project-layout.md +33 -137
- package/docs/architecture/real-email-receiving.md +7 -6
- package/docs/architecture/restricted-codex-analysis.md +211 -25
- package/docs/architecture/serve.md +89 -87
- package/docs/architecture/state-driven-executor.md +79 -64
- package/docs/architecture/task-protocol-support.md +18 -18
- package/docs/architecture/terminal-product-lane.md +92 -86
- package/docs/contracts/adapter-admission.md +8 -4
- package/docs/contracts/adapter-fixtures.md +6 -6
- package/docs/contracts/core.md +22 -24
- package/docs/contracts/feedback.md +33 -23
- package/docs/contracts/policy.md +28 -31
- package/docs/contracts/run-bundle.md +168 -82
- package/docs/contracts/schemas.md +563 -379
- package/docs/contracts/study-analysis.md +2 -2
- package/docs/contracts/study-costs.md +12 -12
- package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +36 -0
- package/docs/decisions/0002-observer-is-one-self-contained-file.md +30 -0
- package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +35 -0
- package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +31 -0
- package/docs/decisions/README.md +16 -0
- package/docs/goals/current.md +22 -50
- package/docs/principles/actor-fidelity.md +37 -40
- package/docs/principles/engineering.md +81 -0
- package/docs/principles/invariants-and-defaults.md +48 -45
- package/docs/principles/self-driving-harness.md +11 -10
- package/docs/principles/three-roles.md +12 -13
- package/docs/product/automatic-analysis.md +39 -9
- package/docs/product/lobby-trivia-3player-external-public.md +14 -13
- package/docs/product/open-source-install-experience.md +34 -38
- package/docs/ramp/README.md +91 -218
- package/docs/release/open-source-readiness.md +5 -2
- package/docs/release/public-readiness-standard.md +1 -1
- package/examples/README.md +11 -0
- package/examples/participant/README.md +80 -0
- package/examples/participant/app.mjs +55 -0
- package/examples/participant/run.mjs +116 -0
- package/examples/scorer/README.md +29 -0
- package/examples/scorer/run.mjs +63 -0
- package/examples/scorer/scorer.mjs +20 -0
- package/package.json +61 -57
- package/skills/humanish/SKILL.md +72 -60
- package/skills/humanish/agents/openai.yaml +2 -2
- package/dist/actor-contract.d.ts +0 -296
- package/dist/actor-contract.js +0 -340
- package/dist/actor-contract.js.map +0 -1
- package/dist/actor-goal-source.js +0 -32
- package/dist/actor-goal-source.js.map +0 -1
- package/dist/actor-registry.d.ts +0 -77
- package/dist/actor-registry.js +0 -106
- package/dist/actor-registry.js.map +0 -1
- package/dist/actor-stop-cause.d.ts +0 -9
- package/dist/actor-stop-cause.js +0 -42
- package/dist/actor-stop-cause.js.map +0 -1
- package/dist/adapter-extension.d.ts +0 -76
- package/dist/adapter-extension.js +0 -273
- package/dist/adapter-extension.js.map +0 -1
- package/dist/adapter-scorer-loader.d.ts +0 -42
- package/dist/adapter-scorer-loader.js +0 -129
- package/dist/adapter-scorer-loader.js.map +0 -1
- package/dist/affordance.d.ts +0 -53
- package/dist/affordance.js +0 -145
- package/dist/affordance.js.map +0 -1
- package/dist/agent-session.js +0 -43
- package/dist/agent-session.js.map +0 -1
- package/dist/argv.d.ts +0 -1
- package/dist/argv.js +0 -8
- package/dist/argv.js.map +0 -1
- package/dist/artifact-reference.d.ts +0 -22
- package/dist/artifact-reference.js +0 -47
- package/dist/artifact-reference.js.map +0 -1
- package/dist/automatic-analysis-completion.d.ts +0 -25
- package/dist/automatic-analysis-completion.js +0 -56
- package/dist/automatic-analysis-completion.js.map +0 -1
- package/dist/automatic-analysis-config.d.ts +0 -38
- package/dist/automatic-analysis-config.js +0 -68
- package/dist/automatic-analysis-config.js.map +0 -1
- package/dist/automatic-study-analysis.d.ts +0 -17
- package/dist/automatic-study-analysis.js +0 -195
- package/dist/automatic-study-analysis.js.map +0 -1
- package/dist/browser-control-client.d.ts +0 -18
- package/dist/browser-control-client.js +0 -176
- package/dist/browser-control-client.js.map +0 -1
- package/dist/browser-control-dispatcher.d.ts +0 -19
- package/dist/browser-control-dispatcher.js +0 -147
- package/dist/browser-control-dispatcher.js.map +0 -1
- package/dist/browser-control-protocol.d.ts +0 -472
- package/dist/browser-control-protocol.js +0 -185
- package/dist/browser-control-protocol.js.map +0 -1
- package/dist/browser-control-recording-transfer.d.ts +0 -4
- package/dist/browser-control-recording-transfer.js +0 -42
- package/dist/browser-control-recording-transfer.js.map +0 -1
- package/dist/browser-control-transport.d.ts +0 -27
- package/dist/browser-control-transport.js +0 -177
- package/dist/browser-control-transport.js.map +0 -1
- package/dist/browser-evidence-hygiene.js +0 -43
- package/dist/browser-evidence-hygiene.js.map +0 -1
- package/dist/chrome-cdp-probe.d.ts +0 -97
- package/dist/chrome-cdp-probe.js +0 -536
- package/dist/chrome-cdp-probe.js.map +0 -1
- package/dist/claude-agent-sdk.d.ts +0 -94
- package/dist/claude-agent-sdk.js +0 -367
- package/dist/claude-agent-sdk.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/codex-app-server-ui.d.ts +0 -39
- package/dist/codex-app-server-ui.js +0 -357
- package/dist/codex-app-server-ui.js.map +0 -1
- package/dist/codex-app-server.d.ts +0 -144
- package/dist/codex-app-server.js +0 -754
- package/dist/codex-app-server.js.map +0 -1
- package/dist/command-failure.d.ts +0 -43
- package/dist/command-failure.js +0 -73
- package/dist/command-failure.js.map +0 -1
- package/dist/comms-agentmail.d.ts +0 -25
- package/dist/comms-agentmail.js +0 -418
- package/dist/comms-agentmail.js.map +0 -1
- package/dist/comms-catch-host.d.ts +0 -52
- package/dist/comms-catch-host.js +0 -178
- package/dist/comms-catch-host.js.map +0 -1
- package/dist/comms-connections.d.ts +0 -52
- package/dist/comms-connections.js +0 -123
- package/dist/comms-connections.js.map +0 -1
- package/dist/comms-email-catch.d.ts +0 -54
- package/dist/comms-email-catch.js +0 -212
- package/dist/comms-email-catch.js.map +0 -1
- package/dist/comms-evidence.d.ts +0 -27
- package/dist/comms-evidence.js +0 -31
- package/dist/comms-evidence.js.map +0 -1
- package/dist/comms-fake-inbox.d.ts +0 -45
- package/dist/comms-fake-inbox.js +0 -184
- package/dist/comms-fake-inbox.js.map +0 -1
- package/dist/comms-images.d.ts +0 -7
- package/dist/comms-images.js +0 -39
- package/dist/comms-images.js.map +0 -1
- package/dist/comms-inbox.d.ts +0 -66
- package/dist/comms-inbox.js +0 -389
- package/dist/comms-inbox.js.map +0 -1
- package/dist/comms-lease-store.d.ts +0 -91
- package/dist/comms-lease-store.js +0 -495
- package/dist/comms-lease-store.js.map +0 -1
- package/dist/comms-receiving-evidence.d.ts +0 -46
- package/dist/comms-receiving-evidence.js +0 -35
- package/dist/comms-receiving-evidence.js.map +0 -1
- package/dist/comms-receiving-inbox.d.ts +0 -16
- package/dist/comms-receiving-inbox.js +0 -410
- package/dist/comms-receiving-inbox.js.map +0 -1
- package/dist/comms-receiving-runtime.d.ts +0 -25
- package/dist/comms-receiving-runtime.js +0 -45
- package/dist/comms-receiving-runtime.js.map +0 -1
- package/dist/comms-receiving-types.d.ts +0 -98
- package/dist/comms-receiving-types.js +0 -2
- package/dist/comms-receiving-types.js.map +0 -1
- package/dist/comms-receiving.d.ts +0 -58
- package/dist/comms-receiving.js +0 -554
- package/dist/comms-receiving.js.map +0 -1
- package/dist/comms-sandbox-catch.d.ts +0 -229
- package/dist/comms-sandbox-catch.js +0 -737
- package/dist/comms-sandbox-catch.js.map +0 -1
- package/dist/comms-setup.d.ts +0 -40
- package/dist/comms-setup.js +0 -121
- package/dist/comms-setup.js.map +0 -1
- package/dist/comms-types.d.ts +0 -72
- package/dist/comms-types.js +0 -10
- package/dist/comms-types.js.map +0 -1
- package/dist/computer-use-actor.d.ts +0 -76
- package/dist/computer-use-actor.js +0 -68
- package/dist/computer-use-actor.js.map +0 -1
- package/dist/computer-use.d.ts +0 -429
- package/dist/computer-use.js +0 -1751
- package/dist/computer-use.js.map +0 -1
- package/dist/concurrency.js +0 -27
- package/dist/concurrency.js.map +0 -1
- package/dist/concurrent-shared-world-lab.d.ts +0 -186
- package/dist/concurrent-shared-world-lab.js +0 -2181
- package/dist/concurrent-shared-world-lab.js.map +0 -1
- package/dist/core/git-state.d.ts +0 -33
- package/dist/core/git-state.js +0 -277
- package/dist/core/git-state.js.map +0 -1
- package/dist/core/git-workspace.d.ts +0 -31
- package/dist/core/git-workspace.js +0 -447
- package/dist/core/git-workspace.js.map +0 -1
- package/dist/core/index.d.ts +0 -4
- package/dist/core/index.js +0 -3
- package/dist/core/index.js.map +0 -1
- package/dist/core/run-primitives.d.ts +0 -66
- package/dist/core/run-primitives.js +0 -120
- package/dist/core/run-primitives.js.map +0 -1
- package/dist/cua-actor-lab.d.ts +0 -855
- package/dist/cua-actor-lab.js +0 -3543
- package/dist/cua-actor-lab.js.map +0 -1
- package/dist/cua-admission-limit.d.ts +0 -12
- package/dist/cua-admission-limit.js +0 -20
- package/dist/cua-admission-limit.js.map +0 -1
- package/dist/cua-desktop-lane.d.ts +0 -35
- package/dist/cua-desktop-lane.js +0 -13
- package/dist/cua-desktop-lane.js.map +0 -1
- package/dist/cua-diagnostics.d.ts +0 -38
- package/dist/cua-diagnostics.js +0 -68
- package/dist/cua-diagnostics.js.map +0 -1
- package/dist/cua-executor-error.js +0 -48
- package/dist/cua-executor-error.js.map +0 -1
- package/dist/cua-provider-error.d.ts +0 -16
- package/dist/cua-provider-error.js +0 -35
- package/dist/cua-provider-error.js.map +0 -1
- package/dist/cua-speech.js +0 -2
- package/dist/cua-speech.js.map +0 -1
- package/dist/desktop-recorder.d.ts +0 -39
- package/dist/desktop-recorder.js +0 -226
- package/dist/desktop-recorder.js.map +0 -1
- package/dist/desktop-recording-artifact.d.ts +0 -5
- package/dist/desktop-recording-artifact.js +0 -54
- package/dist/desktop-recording-artifact.js.map +0 -1
- package/dist/desktop-recording-types.d.ts +0 -24
- package/dist/desktop-recording-types.js +0 -14
- package/dist/desktop-recording-types.js.map +0 -1
- package/dist/desktop-session.d.ts +0 -41
- package/dist/desktop-session.js +0 -47
- package/dist/desktop-session.js.map +0 -1
- package/dist/device-presets.d.ts +0 -67
- package/dist/device-presets.js +0 -55
- package/dist/device-presets.js.map +0 -1
- package/dist/doctor-lab.d.ts +0 -38
- package/dist/doctor-lab.js +0 -126
- package/dist/doctor-lab.js.map +0 -1
- package/dist/e2b-cua-desktop.d.ts +0 -3
- package/dist/e2b-cua-desktop.js +0 -708
- package/dist/e2b-cua-desktop.js.map +0 -1
- package/dist/e2b-cua-provisioning.d.ts +0 -314
- package/dist/e2b-cua-provisioning.js +0 -1219
- package/dist/e2b-cua-provisioning.js.map +0 -1
- package/dist/e2b-desktop-executor.d.ts +0 -101
- package/dist/e2b-desktop-executor.js +0 -297
- package/dist/e2b-desktop-executor.js.map +0 -1
- package/dist/e2b-desktop-launch.d.ts +0 -243
- package/dist/e2b-desktop-launch.js +0 -234
- package/dist/e2b-desktop-launch.js.map +0 -1
- package/dist/e2b-desktop-media.d.ts +0 -14
- package/dist/e2b-desktop-media.js +0 -58
- package/dist/e2b-desktop-media.js.map +0 -1
- package/dist/e2b-desktop-recording.d.ts +0 -16
- package/dist/e2b-desktop-recording.js +0 -162
- package/dist/e2b-desktop-recording.js.map +0 -1
- package/dist/e2b-desktop-resources.d.ts +0 -11
- package/dist/e2b-desktop-resources.js +0 -33
- package/dist/e2b-desktop-resources.js.map +0 -1
- package/dist/e2b-desktop-screenshot-cleanup.d.ts +0 -15
- package/dist/e2b-desktop-screenshot-cleanup.js +0 -67
- package/dist/e2b-desktop-screenshot-cleanup.js.map +0 -1
- package/dist/e2b-desktop-session.d.ts +0 -7
- package/dist/e2b-desktop-session.js +0 -29
- package/dist/e2b-desktop-session.js.map +0 -1
- package/dist/e2b-detached.d.ts +0 -53
- package/dist/e2b-detached.js +0 -130
- package/dist/e2b-detached.js.map +0 -1
- package/dist/e2b-terminal-lab.d.ts +0 -383
- package/dist/e2b-terminal-lab.js +0 -2000
- package/dist/e2b-terminal-lab.js.map +0 -1
- package/dist/env-file.d.ts +0 -14
- package/dist/env-file.js +0 -108
- package/dist/env-file.js.map +0 -1
- package/dist/export-bundle.d.ts +0 -7
- package/dist/export-bundle.js +0 -441
- package/dist/export-bundle.js.map +0 -1
- package/dist/export.d.ts +0 -49
- package/dist/export.js +0 -308
- package/dist/export.js.map +0 -1
- package/dist/feedback-proof.d.ts +0 -8
- package/dist/feedback-proof.js +0 -44
- package/dist/feedback-proof.js.map +0 -1
- package/dist/feedback.d.ts +0 -76
- package/dist/feedback.js +0 -496
- package/dist/feedback.js.map +0 -1
- package/dist/first-run-path.d.ts +0 -55
- package/dist/first-run-path.js +0 -136
- package/dist/first-run-path.js.map +0 -1
- package/dist/frame-signature.d.ts +0 -24
- package/dist/frame-signature.js +0 -128
- package/dist/frame-signature.js.map +0 -1
- package/dist/guest-bootstrap.d.ts +0 -55
- package/dist/guest-bootstrap.js +0 -285
- package/dist/guest-bootstrap.js.map +0 -1
- package/dist/guest-browser-tools.d.ts +0 -8
- package/dist/guest-browser-tools.js +0 -66
- package/dist/guest-browser-tools.js.map +0 -1
- package/dist/guest-chromium-text.d.ts +0 -27
- package/dist/guest-chromium-text.js +0 -281
- package/dist/guest-chromium-text.js.map +0 -1
- package/dist/guest-desktop-executor.d.ts +0 -22
- package/dist/guest-desktop-executor.js +0 -178
- package/dist/guest-desktop-executor.js.map +0 -1
- package/dist/guest-desktop-media.d.ts +0 -33
- package/dist/guest-desktop-media.js +0 -281
- package/dist/guest-desktop-media.js.map +0 -1
- package/dist/guest-desktop-native.d.ts +0 -14
- package/dist/guest-desktop-native.js +0 -131
- package/dist/guest-desktop-native.js.map +0 -1
- package/dist/guest-media-config.d.ts +0 -15
- package/dist/guest-media-config.js +0 -8
- package/dist/guest-media-config.js.map +0 -1
- package/dist/guest-media-worker.js.map +0 -1
- package/dist/guest-runtime-desktop.d.ts +0 -42
- package/dist/guest-runtime-desktop.js +0 -314
- package/dist/guest-runtime-desktop.js.map +0 -1
- package/dist/guest-runtime-main.js.map +0 -1
- package/dist/guest-runtime-revision.js.map +0 -1
- package/dist/guest-runtime.d.ts +0 -31
- package/dist/guest-runtime.js +0 -99
- package/dist/guest-runtime.js.map +0 -1
- package/dist/image-evidence.d.ts +0 -2
- package/dist/image-evidence.js +0 -47
- package/dist/image-evidence.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init-templates.d.ts +0 -25
- package/dist/init-templates.js +0 -541
- package/dist/init-templates.js.map +0 -1
- package/dist/init.d.ts +0 -38
- package/dist/init.js +0 -532
- package/dist/init.js.map +0 -1
- package/dist/key-resolution.d.ts +0 -67
- package/dist/key-resolution.js +0 -375
- package/dist/key-resolution.js.map +0 -1
- package/dist/lab-app-runner.d.ts +0 -78
- package/dist/lab-app-runner.js +0 -403
- package/dist/lab-app-runner.js.map +0 -1
- package/dist/lab-config.d.ts +0 -968
- package/dist/lab-config.js +0 -2714
- package/dist/lab-config.js.map +0 -1
- package/dist/lab-engine.d.ts +0 -97
- package/dist/lab-engine.js +0 -285
- package/dist/lab-engine.js.map +0 -1
- package/dist/lab-preflight.d.ts +0 -70
- package/dist/lab-preflight.js +0 -388
- package/dist/lab-preflight.js.map +0 -1
- package/dist/lab-summary.d.ts +0 -57
- package/dist/lab-summary.js +0 -126
- package/dist/lab-summary.js.map +0 -1
- package/dist/labs.d.ts +0 -66
- package/dist/labs.js +0 -401
- package/dist/labs.js.map +0 -1
- package/dist/listen.js +0 -84
- package/dist/listen.js.map +0 -1
- package/dist/local-agent-claude-session.d.ts +0 -45
- package/dist/local-agent-claude-session.js +0 -203
- package/dist/local-agent-claude-session.js.map +0 -1
- package/dist/local-agent-cli.d.ts +0 -121
- package/dist/local-agent-cli.js +0 -427
- package/dist/local-agent-cli.js.map +0 -1
- package/dist/local-captured-inbox.d.ts +0 -6
- package/dist/local-captured-inbox.js +0 -65
- package/dist/local-captured-inbox.js.map +0 -1
- package/dist/local-firecracker-desktop.d.ts +0 -23
- package/dist/local-firecracker-desktop.js +0 -191
- package/dist/local-firecracker-desktop.js.map +0 -1
- package/dist/local-firecracker-study.d.ts +0 -9
- package/dist/local-firecracker-study.js +0 -135
- package/dist/local-firecracker-study.js.map +0 -1
- package/dist/local-runtime-config.d.ts +0 -6
- package/dist/local-runtime-config.js +0 -60
- package/dist/local-runtime-config.js.map +0 -1
- package/dist/local-runtime-host.d.ts +0 -31
- package/dist/local-runtime-host.js +0 -128
- package/dist/local-runtime-host.js.map +0 -1
- package/dist/local-runtime-release.d.ts +0 -7
- package/dist/local-runtime-release.js +0 -33
- package/dist/local-runtime-release.js.map +0 -1
- package/dist/local-runtime-ssh.d.ts +0 -27
- package/dist/local-runtime-ssh.js +0 -91
- package/dist/local-runtime-ssh.js.map +0 -1
- package/dist/local-runtime.d.ts +0 -25
- package/dist/local-runtime.js +0 -133
- package/dist/local-runtime.js.map +0 -1
- package/dist/observer-data.d.ts +0 -114
- package/dist/observer-data.js +0 -224
- package/dist/observer-data.js.map +0 -1
- package/dist/observer-library.js +0 -191
- package/dist/observer-library.js.map +0 -1
- package/dist/observer-serve.d.ts +0 -99
- package/dist/observer-serve.js +0 -284
- package/dist/observer-serve.js.map +0 -1
- package/dist/observer-static.js +0 -357
- package/dist/observer-static.js.map +0 -1
- package/dist/observer.d.ts +0 -118
- package/dist/observer.js +0 -947
- package/dist/observer.js.map +0 -1
- package/dist/openai-responses-cu.d.ts +0 -158
- package/dist/openai-responses-cu.js +0 -714
- package/dist/openai-responses-cu.js.map +0 -1
- package/dist/orientation.d.ts +0 -29
- package/dist/orientation.js +0 -95
- package/dist/orientation.js.map +0 -1
- package/dist/oss-lab.d.ts +0 -55
- package/dist/oss-lab.js +0 -344
- package/dist/oss-lab.js.map +0 -1
- package/dist/oss-meta-lab-scoring.d.ts +0 -15
- package/dist/oss-meta-lab-scoring.js +0 -145
- package/dist/oss-meta-lab-scoring.js.map +0 -1
- package/dist/oss-meta-lab.d.ts +0 -287
- package/dist/oss-meta-lab.js +0 -4551
- package/dist/oss-meta-lab.js.map +0 -1
- package/dist/oss-remote-telemetry.d.ts +0 -77
- package/dist/oss-remote-telemetry.js +0 -403
- package/dist/oss-remote-telemetry.js.map +0 -1
- package/dist/output-token-limit.js +0 -5
- package/dist/output-token-limit.js.map +0 -1
- package/dist/participant-assignment.d.ts +0 -12
- package/dist/participant-assignment.js +0 -15
- package/dist/participant-assignment.js.map +0 -1
- package/dist/persona-resolve.d.ts +0 -44
- package/dist/persona-resolve.js +0 -99
- package/dist/persona-resolve.js.map +0 -1
- package/dist/persona.d.ts +0 -39
- package/dist/persona.js +0 -144
- package/dist/persona.js.map +0 -1
- package/dist/pi-agent-core.d.ts +0 -77
- package/dist/pi-agent-core.js +0 -207
- package/dist/pi-agent-core.js.map +0 -1
- package/dist/pricing.d.ts +0 -145
- package/dist/pricing.js +0 -277
- package/dist/pricing.js.map +0 -1
- package/dist/program.d.ts +0 -96
- package/dist/program.js +0 -4030
- package/dist/program.js.map +0 -1
- package/dist/reasoning-effort.js +0 -26
- package/dist/reasoning-effort.js.map +0 -1
- package/dist/reclaim.d.ts +0 -31
- package/dist/reclaim.js +0 -90
- package/dist/reclaim.js.map +0 -1
- package/dist/redaction.d.ts +0 -90
- package/dist/redaction.js +0 -294
- package/dist/redaction.js.map +0 -1
- package/dist/restricted-codex-analysis.d.ts +0 -15
- package/dist/restricted-codex-analysis.js +0 -13
- package/dist/restricted-codex-analysis.js.map +0 -1
- package/dist/restricted-codex-participant-policy.d.ts +0 -44
- package/dist/restricted-codex-participant-policy.js +0 -43
- package/dist/restricted-codex-participant-policy.js.map +0 -1
- package/dist/restricted-codex-participant-run.d.ts +0 -20
- package/dist/restricted-codex-participant-run.js +0 -79
- package/dist/restricted-codex-participant-run.js.map +0 -1
- package/dist/restricted-codex-participant.d.ts +0 -20
- package/dist/restricted-codex-participant.js +0 -250
- package/dist/restricted-codex-participant.js.map +0 -1
- package/dist/restricted-codex-policy.d.ts +0 -64
- package/dist/restricted-codex-policy.js +0 -176
- package/dist/restricted-codex-policy.js.map +0 -1
- package/dist/restricted-codex-session.d.ts +0 -44
- package/dist/restricted-codex-session.js +0 -657
- package/dist/restricted-codex-session.js.map +0 -1
- package/dist/restricted-codex-transport.d.ts +0 -69
- package/dist/restricted-codex-transport.js +0 -296
- package/dist/restricted-codex-transport.js.map +0 -1
- package/dist/run-detail.d.ts +0 -61
- package/dist/run-detail.js +0 -137
- package/dist/run-detail.js.map +0 -1
- package/dist/run-index.d.ts +0 -71
- package/dist/run-index.js +0 -206
- package/dist/run-index.js.map +0 -1
- package/dist/run-narration-secrets.js +0 -68
- package/dist/run-narration-secrets.js.map +0 -1
- package/dist/run-paths.d.ts +0 -56
- package/dist/run-paths.js +0 -355
- package/dist/run-paths.js.map +0 -1
- package/dist/run-projection.d.ts +0 -186
- package/dist/run-projection.js +0 -350
- package/dist/run-projection.js.map +0 -1
- package/dist/run-status.d.ts +0 -139
- package/dist/run-status.js +0 -218
- package/dist/run-status.js.map +0 -1
- package/dist/run.d.ts +0 -1255
- package/dist/run.js +0 -5949
- package/dist/run.js.map +0 -1
- package/dist/sandbox-receipts.d.ts +0 -19
- package/dist/sandbox-receipts.js +0 -51
- package/dist/sandbox-receipts.js.map +0 -1
- package/dist/screenshot-image.d.ts +0 -11
- package/dist/screenshot-image.js +0 -26
- package/dist/screenshot-image.js.map +0 -1
- package/dist/scripted-browser-actor.d.ts +0 -297
- package/dist/scripted-browser-actor.js +0 -1399
- package/dist/scripted-browser-actor.js.map +0 -1
- package/dist/scripted-browser-lab.d.ts +0 -121
- package/dist/scripted-browser-lab.js +0 -852
- package/dist/scripted-browser-lab.js.map +0 -1
- package/dist/secret-prompt.js +0 -36
- package/dist/secret-prompt.js.map +0 -1
- package/dist/selected-output-paths.d.ts +0 -52
- package/dist/selected-output-paths.js +0 -366
- package/dist/selected-output-paths.js.map +0 -1
- package/dist/serve-exposure.d.ts +0 -62
- package/dist/serve-exposure.js +0 -129
- package/dist/serve-exposure.js.map +0 -1
- package/dist/serve-http.js +0 -45
- package/dist/serve-http.js.map +0 -1
- package/dist/serve-tunnel.js +0 -113
- package/dist/serve-tunnel.js.map +0 -1
- package/dist/shared-world-lab.d.ts +0 -269
- package/dist/shared-world-lab.js +0 -1424
- package/dist/shared-world-lab.js.map +0 -1
- package/dist/source-archive.d.ts +0 -82
- package/dist/source-archive.js +0 -408
- package/dist/source-archive.js.map +0 -1
- package/dist/stats.d.ts +0 -82
- package/dist/stats.js +0 -219
- package/dist/stats.js.map +0 -1
- package/dist/stop-conditions.d.ts +0 -39
- package/dist/stop-conditions.js +0 -66
- package/dist/stop-conditions.js.map +0 -1
- package/dist/study-analysis-codex-config.d.ts +0 -11
- package/dist/study-analysis-codex-config.js +0 -34
- package/dist/study-analysis-codex-config.js.map +0 -1
- package/dist/study-analysis-engine.d.ts +0 -47
- package/dist/study-analysis-engine.js +0 -327
- package/dist/study-analysis-engine.js.map +0 -1
- package/dist/study-analysis-evidence.d.ts +0 -27
- package/dist/study-analysis-evidence.js +0 -660
- package/dist/study-analysis-evidence.js.map +0 -1
- package/dist/study-analysis-job.d.ts +0 -97
- package/dist/study-analysis-job.js +0 -214
- package/dist/study-analysis-job.js.map +0 -1
- package/dist/study-analysis-provider.d.ts +0 -40
- package/dist/study-analysis-provider.js +0 -170
- package/dist/study-analysis-provider.js.map +0 -1
- package/dist/study-analysis-service.d.ts +0 -59
- package/dist/study-analysis-service.js +0 -257
- package/dist/study-analysis-service.js.map +0 -1
- package/dist/study-analysis-sharing.d.ts +0 -11
- package/dist/study-analysis-sharing.js +0 -35
- package/dist/study-analysis-sharing.js.map +0 -1
- package/dist/study-analysis-store.d.ts +0 -47
- package/dist/study-analysis-store.js +0 -493
- package/dist/study-analysis-store.js.map +0 -1
- package/dist/study-analysis-validation.d.ts +0 -618
- package/dist/study-analysis-validation.js +0 -384
- package/dist/study-analysis-validation.js.map +0 -1
- package/dist/study-analysis.d.ts +0 -206
- package/dist/study-analysis.js +0 -4
- package/dist/study-analysis.js.map +0 -1
- package/dist/study-costs.js +0 -114
- package/dist/study-costs.js.map +0 -1
- package/dist/subject-runtime.d.ts +0 -23
- package/dist/subject-runtime.js +0 -70
- package/dist/subject-runtime.js.map +0 -1
- package/dist/tasks.d.ts +0 -90
- package/dist/tasks.js +0 -144
- package/dist/tasks.js.map +0 -1
- package/dist/telemetry.js +0 -324
- package/dist/telemetry.js.map +0 -1
- package/dist/terminal-agent-actor.d.ts +0 -41
- package/dist/terminal-agent-actor.js +0 -25
- package/dist/terminal-agent-actor.js.map +0 -1
- package/dist/terminal-encoding.js +0 -80
- package/dist/terminal-encoding.js.map +0 -1
- package/dist/terminal-node-bootstrap.d.ts +0 -4
- package/dist/terminal-node-bootstrap.js +0 -58
- package/dist/terminal-node-bootstrap.js.map +0 -1
- package/dist/terminal-participant-activity.d.ts +0 -6
- package/dist/terminal-participant-activity.js +0 -34
- package/dist/terminal-participant-activity.js.map +0 -1
- package/dist/terminal-runtime-auth.d.ts +0 -13
- package/dist/terminal-runtime-auth.js +0 -24
- package/dist/terminal-runtime-auth.js.map +0 -1
- package/dist/terminal-runtime.d.ts +0 -16
- package/dist/terminal-runtime.js +0 -42
- package/dist/terminal-runtime.js.map +0 -1
- package/dist/terminal-token-usage.d.ts +0 -15
- package/dist/terminal-token-usage.js +0 -94
- package/dist/terminal-token-usage.js.map +0 -1
- package/dist/tui-actions.d.ts +0 -39
- package/dist/tui-actions.js +0 -178
- package/dist/tui-actions.js.map +0 -1
- package/dist/tui-contract.d.ts +0 -141
- package/dist/tui-contract.js +0 -54
- package/dist/tui-contract.js.map +0 -1
- package/dist/tui-launch.js +0 -167
- package/dist/tui-launch.js.map +0 -1
- package/dist/tui-project.d.ts +0 -9
- package/dist/tui-project.js +0 -18
- package/dist/tui-project.js.map +0 -1
- package/docs/architecture/examples/state-driven-local-app/README.md +0 -80
- package/docs/architecture/examples/state-driven-local-app/app.mjs +0 -48
- package/docs/architecture/examples/state-driven-local-app/runner.mjs +0 -105
- package/docs/architecture/local-codex-tui-actor.md +0 -213
- package/docs/architecture/oss-lab-poc.md +0 -250
- package/docs/architecture/runtime-broker-core.md +0 -30
- package/docs/release/0.100.0-local-setup.md +0 -31
- package/docs/release/0.100.1-participant-continuity.md +0 -20
- package/docs/release/0.101.0-codex-ui-tools.md +0 -28
- package/docs/release/0.102.0-participant-media.md +0 -43
- package/docs/release/0.103.0-desktop-recording.md +0 -29
- package/docs/release/0.103.1-analysis-capture-allocation.md +0 -18
- package/docs/release/0.103.2-analysis-ending-context.md +0 -21
- package/docs/release/0.104.0-local-captured-inboxes.md +0 -29
- package/docs/release/0.104.1-recording-startup.md +0 -24
- package/docs/release/0.104.2-recording-timestamps.md +0 -32
- package/docs/release/0.104.3-local-smtp-catch.md +0 -15
- package/docs/release/0.105.0-participant-backgrounds.md +0 -50
- package/docs/release/0.20.0-external-public-shared-world.md +0 -43
- package/docs/release/0.84.0-redacted-evidence.md +0 -42
- package/docs/release/0.84.1-portable-feedback.md +0 -20
- package/docs/release/0.85.0-observer-review.md +0 -56
- package/docs/release/0.85.1-observer-continuity.md +0 -20
- package/docs/release/0.86.0-participant-evidence.md +0 -50
- package/docs/release/0.86.1-task-preflight-saved-recordings.md +0 -40
- package/docs/release/0.87.0-participant-endings-and-phone-review.md +0 -64
- package/docs/release/0.88.0-study-diagnostics.md +0 -43
- package/docs/release/0.88.1-completion-evidence-and-local-app.md +0 -79
- package/docs/release/0.88.2-sequential-study-budgets.md +0 -57
- package/docs/release/0.89.0-study-findings.md +0 -79
- package/docs/release/0.89.1-analysis-finished-notice.md +0 -24
- package/docs/release/0.90.0-automatic-analysis.md +0 -21
- package/docs/release/0.91.0-analysis-quality-and-defaults.md +0 -33
- package/docs/release/0.91.1-study-review-polish.md +0 -28
- package/docs/release/0.92.0-grid-playback.md +0 -22
- package/docs/release/0.93.0-global-playback.md +0 -26
- package/docs/release/0.93.1-observer-review-controls.md +0 -24
- package/docs/release/0.94.0-reliability.md +0 -48
- package/docs/release/0.95.0-connections-setup.md +0 -38
- package/docs/release/0.96.0-real-email-receiving.md +0 -47
- package/docs/release/0.96.1-browser-navigation.md +0 -22
- package/docs/release/0.97.0-codex-account-analysis.md +0 -45
- package/docs/release/0.98.0-local-browser-studies.md +0 -31
- package/docs/release/0.99.0-local-browser-mac.md +0 -34
- package/docs/release/0.99.1-action-recovery.md +0 -19
- /package/dist/{agent-session.d.ts → actors/agent-session.d.ts} +0 -0
- /package/dist/{cua-executor-error.d.ts → actors/computer-use/executor-error.d.ts} +0 -0
- /package/dist/{cua-speech.d.ts → actors/computer-use/speech.d.ts} +0 -0
- /package/dist/{actor-goal-source.d.ts → actors/goal-source.d.ts} +0 -0
- /package/dist/{output-token-limit.d.ts → actors/output-token-limit.d.ts} +0 -0
- /package/dist/{reasoning-effort.d.ts → actors/reasoning-effort.d.ts} +0 -0
- /package/dist/{secret-prompt.d.ts → cli/secret-prompt.d.ts} +0 -0
- /package/dist/{telemetry.d.ts → cli/telemetry.d.ts} +0 -0
- /package/dist/{browser-evidence-hygiene.d.ts → evidence/browser-hygiene.d.ts} +0 -0
- /package/dist/{serve-http.d.ts → observer/http.d.ts} +0 -0
- /package/dist/{observer-library.d.ts → observer/library.d.ts} +0 -0
- /package/dist/{listen.d.ts → observer/listen.d.ts} +0 -0
- /package/dist/{observer-static.d.ts → observer/static.d.ts} +0 -0
- /package/dist/{serve-tunnel.d.ts → observer/tunnel.d.ts} +0 -0
- /package/dist/{terminal-encoding.d.ts → routes/terminal/encoding.d.ts} +0 -0
- /package/dist/{concurrency.d.ts → run/concurrency.d.ts} +0 -0
- /package/dist/{study-costs.d.ts → run/costs.d.ts} +0 -0
- /package/dist/{run-narration-secrets.d.ts → run/transient-comms-secrets.d.ts} +0 -0
- /package/dist/{tui-launch.d.ts → tui/launch.d.ts} +0 -0
|
@@ -1,2181 +0,0 @@
|
|
|
1
|
-
import { scrubPersonaBrief } from "./persona.js";
|
|
2
|
-
import { withTransientCommsSecrets } from "./run-narration-secrets.js";
|
|
3
|
-
import { prepareReceivingRun, receivingPublication } from "./comms-receiving-runtime.js";
|
|
4
|
-
import { receivingEmailValidationReason } from "./lab-config.js";
|
|
5
|
-
// The CONCURRENT shared-world lab backend (#164 phase 2): N persona lanes drive ONE shared,
|
|
6
|
-
// mutable service plane SIMULTANEOUSLY — the actual leverage of a sim. A recomposition of shipped
|
|
7
|
-
// pieces + the getHost wrapper:
|
|
8
|
-
//
|
|
9
|
-
// - ONE SUBJECT sandbox: provisionCloneSubject ONCE (clone+install+build+seed) + serve on
|
|
10
|
-
// 0.0.0.0, exposed via getHost(port) → a tokenless reachable URL (the headless service host;
|
|
11
|
-
// no GUI seat).
|
|
12
|
-
// - N ACTOR desktop sandboxes: fan-out's runCuaLane machinery (per-lane device/persona, by-id
|
|
13
|
-
// teardown) bounded by execution.concurrency, each browser pointed at the getHost URL —
|
|
14
|
-
// driving the shared service AT THE SAME TIME. INDEPENDENT (FIX-11): no pipeline gate, no
|
|
15
|
-
// fail-fast — one actor's failure must not block the swarm or corrupt the "M of N" outcomes.
|
|
16
|
-
// - A background prober snapshots the subject DB checkpoint digests on a cadence → a stateSeries
|
|
17
|
-
// of the shared world evolving under load.
|
|
18
|
-
// - ALL N+1 sandboxes torn down BY exact id in a finally — NEVER Sandbox.list.
|
|
19
|
-
//
|
|
20
|
-
// HONEST ATTRIBUTION (verify-enforced, doctrine-audit fixes incorporated): the bundle declares
|
|
21
|
-
// attributionClass: shared-world + a CONCURRENT humanish.shared-world.v1 block (topologyMode
|
|
22
|
-
// "concurrent"; laneWindows + stateSeries + outcomes; NO timeline) whose attributionLimits drop
|
|
23
|
-
// `sequential-only`/`no-concurrent-races` and add `concurrent`,
|
|
24
|
-
// `best-effort-causal-attribution`, `non-deterministic-shared-state`,
|
|
25
|
-
// `window-and-snapshot-granularity`, `contention-observed-not-proven-safe`,
|
|
26
|
-
// `state-change-not-isolated-to-actors`. laneWindows + stateSeries are INDEPENDENT series with NO
|
|
27
|
-
// per-delta→actor field — causation under concurrency is structurally inexpressible.
|
|
28
|
-
//
|
|
29
|
-
// CAPABILITY vs PROOF (FIX-1): the deterministic $0 gate proves the PLUMBING + the honesty
|
|
30
|
-
// contract — the real mapWithConcurrency produces genuinely overlapping laneWindows (a rendezvous
|
|
31
|
-
// latch in the fake session forces two lane fns in-flight while the REAL orchestrator clock
|
|
32
|
-
// measures the windows). Every generated bundle describes only its own observations; no one run
|
|
33
|
-
// establishes scale, repeatability, or adopter-harness replacement.
|
|
34
|
-
//
|
|
35
|
-
// Synthetic-subject (FIX-3): a getHost URL is internet-reachable for the run, so this route is
|
|
36
|
-
// synthetic-seeded-subjects ONLY. Verify fail-closes on subject.state.provenance != "seeded" and
|
|
37
|
-
// requires the author attestation subject.exposure: synthetic. This is author-trust + a provenance
|
|
38
|
-
// gate, NOT a no-real-data guarantee (Humanish cannot tell synthetic from real data).
|
|
39
|
-
import { resolveAutomaticAnalysis } from "./automatic-analysis-config.js";
|
|
40
|
-
import { completeAutomaticAnalysis, markFinalizedStudyResult } from "./automatic-analysis-completion.js";
|
|
41
|
-
import { desktopMediaValidationReason, taskProtocolValidationReason } from "./lab-config.js";
|
|
42
|
-
import { randomBytes } from "node:crypto";
|
|
43
|
-
import { describeMissingKeys } from "./key-resolution.js";
|
|
44
|
-
import { beginRunStatus, withRunStatusScope } from "./run-status.js";
|
|
45
|
-
import path from "node:path";
|
|
46
|
-
import { pathToFileURL } from "node:url";
|
|
47
|
-
import { adapterScoreFailureMessage, applyBrowserAdapterHooks } from "./adapter-extension.js";
|
|
48
|
-
import { DEFAULT_OPENAI_CU_MODEL } from "./openai-responses-cu.js";
|
|
49
|
-
import { MODEL_RATES } from "./pricing.js";
|
|
50
|
-
import { actorRegistry, isCuaActorDescriptor } from "./actor-registry.js";
|
|
51
|
-
import { toErrorMessage } from "./command-failure.js";
|
|
52
|
-
import { mapWithConcurrency } from "./concurrency.js";
|
|
53
|
-
import { appendSandboxReceipt } from "./sandbox-receipts.js";
|
|
54
|
-
import { labPersonaIds, resolveCommittedPersonasForCwd } from "./persona-resolve.js";
|
|
55
|
-
import { commandDigestOf, composeLaneInstructions, defaultPackLocalTree, provisionCloneSubject, provisionLocalTreeSubject, declaredScreenForRender, inboxRecipientFor, laneHasInboxRecipient, resolveLaneDevice, resolveSubjectState, runCuaLane, makeCuaRunBudget, withInboxMission } from "./cua-actor-lab.js";
|
|
56
|
-
import { DEFAULT_SANDBOX_CATCH_PORT, collectCommsThread, collectExternalCommsThread, deployCommsCatch, externalCatchHealthy, externalInboxUrl, refreshInboxSurface, writeInboxSurface } from "./comms-sandbox-catch.js";
|
|
57
|
-
import { FakeInbox } from "./comms-fake-inbox.js";
|
|
58
|
-
import { buildOriginMap } from "./comms-inbox.js";
|
|
59
|
-
import { createDesktopSandbox, loadE2BDesktopModule } from "./e2b-desktop-launch.js";
|
|
60
|
-
import { concurrentSharedWorldValidationReason, outputTokenLimitValidationReason, externalPublicSharedWorldValidationReason } from "./lab-config.js";
|
|
61
|
-
import { buildObserverData } from "./observer-data.js";
|
|
62
|
-
import { attachObserverRuntimeStreamUrls, renderObserver } from "./observer.js";
|
|
63
|
-
import { redactText } from "./redaction.js";
|
|
64
|
-
import { participantAssignment } from "./participant-assignment.js";
|
|
65
|
-
import { prepareRunArtifactPaths, validatePreparedRunArtifactPaths } from "./run-paths.js";
|
|
66
|
-
import { writeContainedOutputFile, writePreparedRunLatestPointer } from "./selected-output-paths.js";
|
|
67
|
-
import { combineCheckpointDigest, runCheckpointSnapshot, seedRecipeDigest } from "./shared-world-lab.js";
|
|
68
|
-
import { buildRunSource, PUBLIC_TARGET_CWD, REVIEW_SCHEMA, RUN_BUNDLE_SCHEMA, SHARED_WORLD_SCHEMA } from "./run.js";
|
|
69
|
-
export const CONCURRENT_SHARED_WORLD_LAB_SCHEMA = "humanish.concurrent-shared-world-lab-result.v1";
|
|
70
|
-
export const CONCURRENT_SHARED_WORLD_PROVIDER_METADATA = {
|
|
71
|
-
mode: "concurrent-shared-world-lab",
|
|
72
|
-
tool: "humanish"
|
|
73
|
-
};
|
|
74
|
-
// The verify-enforced CONCURRENT attribution ceiling (FIX-5). Mirrored in run.ts's required set.
|
|
75
|
-
export const CONCURRENT_ATTRIBUTION_LIMITS = [
|
|
76
|
-
"concurrent",
|
|
77
|
-
"best-effort-causal-attribution",
|
|
78
|
-
"non-deterministic-shared-state",
|
|
79
|
-
"window-and-snapshot-granularity",
|
|
80
|
-
"contention-observed-not-proven-safe",
|
|
81
|
-
"state-change-not-isolated-to-actors"
|
|
82
|
-
];
|
|
83
|
-
// The DEFAULT per-seat session budget is DERIVED, not flat. On a provisioned route the binding
|
|
84
|
-
// constraint is the SUBJECT sandbox (it must outlive every seat: timeoutMs + provisioning +
|
|
85
|
-
// seeding + teardown buffer, and E2B refuses a sandbox over one hour), so the derivation hands
|
|
86
|
-
// each seat the most that cap allows — capped at 15 minutes, floored at the historical 300s so a
|
|
87
|
-
// seed-heavy lab never gets LESS room than it always had. App-url seats have no subject sandbox
|
|
88
|
-
// and default to 30 minutes (seat sandbox: 30m + 10m buffer stays well under the hour). An
|
|
89
|
-
// explicit execution.timeoutMs is never adjusted. The handoff latch scales off this (40%).
|
|
90
|
-
const MAX_SANDBOX_MS = 60 * 60_000;
|
|
91
|
-
const MAX_DERIVED_SEAT_SESSION_MS = 15 * 60_000;
|
|
92
|
-
const MIN_DERIVED_SEAT_SESSION_MS = 300_000;
|
|
93
|
-
const DEFAULT_APP_URL_SEAT_SESSION_MS = 30 * 60_000;
|
|
94
|
-
function defaultSeatSessionTimeoutMs(config) {
|
|
95
|
-
const provisionedRoute = config.subject.source === "clone" || config.subject.source === "local-tree";
|
|
96
|
-
if (!provisionedRoute)
|
|
97
|
-
return DEFAULT_APP_URL_SEAT_SESSION_MS;
|
|
98
|
-
const stateBudgetMs = (config.subject.state?.seed ?? []).reduce((sum, step) => sum + (step.timeoutMs ?? DEFAULT_STATE_STEP_TIMEOUT_MS), 0);
|
|
99
|
-
const room = MAX_SANDBOX_MS - SUBJECT_PROVISION_BUDGET_MS - stateBudgetMs - SANDBOX_TIMEOUT_BUFFER_MS;
|
|
100
|
-
return Math.max(MIN_DERIVED_SEAT_SESSION_MS, Math.min(MAX_DERIVED_SEAT_SESSION_MS, room));
|
|
101
|
-
}
|
|
102
|
-
const SANDBOX_TIMEOUT_BUFFER_MS = 10 * 60_000;
|
|
103
|
-
const SUBJECT_PROVISION_BUDGET_MS = 30 * 60_000;
|
|
104
|
-
const DEFAULT_STATE_STEP_TIMEOUT_MS = 5 * 60_000;
|
|
105
|
-
const DEFAULT_PROBER_CADENCE_MS = 1000;
|
|
106
|
-
const DEFAULT_MISSION = "You are one of MANY users hitting a shared web application at the same time. The browser is already open at the app. Accomplish your role's task, then stop.";
|
|
107
|
-
// EXTERNAL-PUBLIC plane class: the honest-downgrade attribution ceiling. The concurrent family
|
|
108
|
-
// (an honest ceiling) PLUS the mandatory external-public disclosures — mirrored in run.ts's required
|
|
109
|
-
// set (CONCURRENT_ATTRIBUTION_LIMITS + EXTERNAL_PUBLIC_EXTRA_LIMITS). Verify fails closed on a missing one.
|
|
110
|
-
export const EXTERNAL_PUBLIC_ATTRIBUTION_LIMITS = [
|
|
111
|
-
...CONCURRENT_ATTRIBUTION_LIMITS,
|
|
112
|
-
"external-public-plane",
|
|
113
|
-
"operator-attested-target-not-harness-controlled",
|
|
114
|
-
"no-synthetic-attestation",
|
|
115
|
-
"no-authoritative-shared-state-proof",
|
|
116
|
-
"concurrency-by-temporal-co-occupancy-only"
|
|
117
|
-
];
|
|
118
|
-
// The FLOOR for the host-first handoff barrier deadline (ms). The host seat must surface a
|
|
119
|
-
// shared-session (/lobby/CODE) URL within the deadline or the run fails closed and no follower
|
|
120
|
-
// opens. The effective deadline SCALES with the per-seat run budget (execution.timeoutMs): a fixed
|
|
121
|
-
// 2 min is too tight for a real create-a-lobby flow on a mobile-layout seat once you subtract the
|
|
122
|
-
// seat's own desktop provisioning — the host reaches /lobby/CODE, but after the followers already
|
|
123
|
-
// gave up. So use max(FLOOR, 40% of the budget), capped at the budget. The latch resolves the
|
|
124
|
-
// instant the host actually reaches /lobby, so a generous ceiling only affects the fail-closed case.
|
|
125
|
-
const DEFAULT_HANDOFF_DEADLINE_MS = 120_000;
|
|
126
|
-
const HANDOFF_DEADLINE_BUDGET_FRACTION = 0.4;
|
|
127
|
-
// Per-seat runaway backstop for the vision-off-frame lobby-code read (used by the host to LATCH the
|
|
128
|
-
// handoff code, and by each follower to independently OBSERVE its own code for the convergence proof):
|
|
129
|
-
// at most this many single-frame reads before the seat is assumed to be somewhere without a code. Each
|
|
130
|
-
// reader stops the instant it has what it needs, so in practice only a handful fire (a seat reaches its
|
|
131
|
-
// /lobby within a few turns). NOTE: these reads are out-of-band OpenAI calls (external-public route
|
|
132
|
-
// only) and are NOT counted against execution.caps.maxUsd — this hard cap is what bounds their spend
|
|
133
|
-
// instead (each read is one cheap single-frame OCR call). If this route ever runs under a strict
|
|
134
|
-
// budget, fold the estimate in.
|
|
135
|
-
const MAX_LOBBY_CODE_VISION_READS = 30;
|
|
136
|
-
// Idle/no-progress backstop for the HOST lane specifically (default is 6/8). The host legitimately sits
|
|
137
|
-
// on an unchanging waiting-room screen while followers provision and join; it must not give up first.
|
|
138
|
-
const HOST_WAIT_IDLE_STEPS = 80;
|
|
139
|
-
const FOLLOWER_WAIT_IDLE_STEPS = 40;
|
|
140
|
-
/**
|
|
141
|
-
* The lobby-trivia (and general "/lobby/CODE") shared-session URL matcher. A code is exactly 6 chars of
|
|
142
|
-
* the [A-Z2-9] class; a locale prefix (/en/lobby/…) and a query/hash suffix are tolerated. RUNTIME-ONLY
|
|
143
|
-
* input (a live location.href); only the extracted CODE is used, and it lands only as a digest.
|
|
144
|
-
*/
|
|
145
|
-
export const LOBBY_CODE_PATTERN = /\/lobby\/([A-Z2-9]{6})(?:$|[/?#])/;
|
|
146
|
-
/** Extract the shared-session CODE from a (runtime-only) observed URL, or undefined. Exported for the
|
|
147
|
-
* handoff regex table test — pure, no side effects, never persists its input. */
|
|
148
|
-
export function extractLobbyCode(url) {
|
|
149
|
-
if (typeof url !== "string")
|
|
150
|
-
return undefined;
|
|
151
|
-
const match = url.match(LOBBY_CODE_PATTERN);
|
|
152
|
-
return match ? match[1] : undefined;
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Extract a lobby CODE from free-form ACTOR NARRATION (the host's reasoning/message where it states
|
|
156
|
-
* the lobby URL it sees), where the /lobby/CODE is followed by arbitrary prose (a space, backtick,
|
|
157
|
-
* newline) rather than end-of-string or /?# — so the strict LOBBY_CODE_PATTERN would miss it. Uses a
|
|
158
|
-
* negative-lookahead boundary (exactly 6 code chars). This is the CDP-INDEPENDENT handoff path: the
|
|
159
|
-
* host reads the code on screen and states it, and this reads it from the model's own text. Pure;
|
|
160
|
-
* input is runtime-only; only the code is used (as a digest).
|
|
161
|
-
*/
|
|
162
|
-
const LOBBY_CODE_IN_TEXT = /\/lobby\/([A-Z2-9]{6})(?![A-Z2-9])/;
|
|
163
|
-
export function extractLobbyCodeFromNarration(text) {
|
|
164
|
-
if (typeof text !== "string")
|
|
165
|
-
return undefined;
|
|
166
|
-
const inUrl = text.match(LOBBY_CODE_IN_TEXT);
|
|
167
|
-
if (inUrl)
|
|
168
|
-
return inUrl[1];
|
|
169
|
-
// Fallback: an explicitly-labeled bare code (e.g. "LOBBY_CODE=ABC123"), which the host may state
|
|
170
|
-
// if it copied the code rather than the URL. The label is matched case-insensitively, but the CODE
|
|
171
|
-
// itself must be UPPERCASE [A-Z2-9] — a real lobby code always renders uppercase, whereas an /i match
|
|
172
|
-
// on the code class would also grab an ordinary lowercase word after "lobby code " (e.g. "the lobby
|
|
173
|
-
// code screen") and latch a WRONG code. Precision-first, matching parseLobbyCodeReply's rationale.
|
|
174
|
-
const labeled = text.match(/lobby[ _-]?code[=:\s]+([A-Z2-9]{6})(?![A-Za-z2-9])/i);
|
|
175
|
-
return labeled && labeled[1] && /^[A-Z2-9]{6}$/.test(labeled[1]) ? labeled[1] : undefined;
|
|
176
|
-
}
|
|
177
|
-
/** Pull the assistant's plain text out of an OpenAI Responses API body (`output_text` convenience
|
|
178
|
-
* field, else the concatenated `output[].content[].text`). Tolerant of shape drift; pure. */
|
|
179
|
-
export function extractResponsesOutputText(parsed) {
|
|
180
|
-
if (typeof parsed !== "object" || parsed === null)
|
|
181
|
-
return undefined;
|
|
182
|
-
const obj = parsed;
|
|
183
|
-
if (typeof obj.output_text === "string" && obj.output_text.length > 0)
|
|
184
|
-
return obj.output_text;
|
|
185
|
-
const out = obj.output;
|
|
186
|
-
if (!Array.isArray(out))
|
|
187
|
-
return undefined;
|
|
188
|
-
const parts = [];
|
|
189
|
-
for (const item of out) {
|
|
190
|
-
if (typeof item !== "object" || item === null)
|
|
191
|
-
continue;
|
|
192
|
-
const content = item.content;
|
|
193
|
-
if (!Array.isArray(content))
|
|
194
|
-
continue;
|
|
195
|
-
for (const chunk of content) {
|
|
196
|
-
if (typeof chunk === "object" && chunk !== null && typeof chunk.text === "string") {
|
|
197
|
-
parts.push(chunk.text);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
return parts.length > 0 ? parts.join("\n") : undefined;
|
|
202
|
-
}
|
|
203
|
-
/** Parse a vision reply into a lobby CODE. PRECISION-FIRST: accept ONLY when the whole reply IS the
|
|
204
|
-
* six-character code, or when it echoes an explicit /lobby/CODE — never a bare 6-letter token buried in
|
|
205
|
-
* prose (e.g. "I see a home SCREEN"), because a wrong latch fails the entire run, whereas a miss just
|
|
206
|
-
* retries on the next frame while the host keeps waiting. NONE (the instructed "no code" reply) is
|
|
207
|
-
* rejected. Pure. */
|
|
208
|
-
export function parseLobbyCodeReply(reply) {
|
|
209
|
-
if (typeof reply !== "string")
|
|
210
|
-
return undefined;
|
|
211
|
-
const up = reply.trim().toUpperCase();
|
|
212
|
-
if (up.length === 0 || /\bNONE\b/.test(up))
|
|
213
|
-
return undefined;
|
|
214
|
-
if (/^[A-Z2-9]{6}$/.test(up))
|
|
215
|
-
return up; // the well-behaved "code only" reply
|
|
216
|
-
const inUrl = up.match(/\/LOBBY\/([A-Z2-9]{6})(?![A-Z2-9])/); // model echoed the invite link
|
|
217
|
-
return inUrl ? inUrl[1] : undefined;
|
|
218
|
-
}
|
|
219
|
-
const LOBBY_CODE_VISION_PROMPT = "This is a screenshot of a the example multiplayer app multiplayer lobby. If a waiting-room / invite screen is " +
|
|
220
|
-
"shown, read the 6-character lobby code (characters A-Z and 2-9 only) — it appears near a 'lobby " +
|
|
221
|
-
"code'/'room code' label or inside an invite link of the form /lobby/CODE. Your entire reply MUST be " +
|
|
222
|
-
"exactly those 6 characters in uppercase and NOTHING else (no words, no punctuation). If no lobby " +
|
|
223
|
-
"code is visible on this screen (e.g. it is the home screen or a game round), reply exactly NONE.";
|
|
224
|
-
const LOBBY_CODE_VISION_ENDPOINT = "https://api.openai.com/v1/responses";
|
|
225
|
-
// A single-frame OCR-style read. gpt-5.5 (the CU default) is used deliberately: it reliably reads the
|
|
226
|
-
// 6-char code off a dense MOBILE-viewport waiting room — a smaller/cheaper model (gpt-4.1-mini) was
|
|
227
|
-
// tried and could NOT read it. reasoning.effort stays "low" (minimal) and the output budget is small
|
|
228
|
-
// but comfortably clear of the "incomplete on reasoning overflow" edge. Kept on the same account/key
|
|
229
|
-
// as the actor; the same full-fidelity frame is already sent to this API by the CU provider, so this
|
|
230
|
-
// adds no new data-exposure surface. See onScreenshot in runHostLane.
|
|
231
|
-
const LOBBY_CODE_VISION_MODEL = "gpt-5.5";
|
|
232
|
-
// Output-token budget for the read. The answer is 6 chars, but leave clear margin over any low-effort
|
|
233
|
-
// reasoning tokens so the response never comes back status:"incomplete" with empty output.
|
|
234
|
-
const LOBBY_CODE_VISION_MAX_OUTPUT_TOKENS = 64;
|
|
235
|
-
// Per-read wall-clock cap. Without it a stalled fetch (Node fetch has no default timeout) would leave
|
|
236
|
-
// visionInFlight pinned true and silently kill the relay for the rest of the host run.
|
|
237
|
-
const LOBBY_CODE_VISION_TIMEOUT_MS = 15_000;
|
|
238
|
-
/**
|
|
239
|
-
* Vision-read a lobby CODE straight off a host waiting-room FRAME (the robust, CDP-independent handoff
|
|
240
|
-
* relay). Fail-soft: any network/HTTP/parse problem returns undefined so the caller simply retries on
|
|
241
|
-
* the next frame. The frame is runtime-only; only the extracted code is used (as a digest downstream).
|
|
242
|
-
*/
|
|
243
|
-
export async function readLobbyCodeFromFrame(frame, apiKey, options = {}) {
|
|
244
|
-
if (typeof apiKey !== "string" || apiKey.length === 0 || frame.length === 0)
|
|
245
|
-
return undefined;
|
|
246
|
-
const fetchFn = options.fetchFn ?? fetch;
|
|
247
|
-
// Default a wall-clock timeout so a stalled request can't wedge the caller's in-flight guard. An
|
|
248
|
-
// explicit signal (e.g. run abort) takes precedence when provided.
|
|
249
|
-
const signal = options.signal ?? AbortSignal.timeout(LOBBY_CODE_VISION_TIMEOUT_MS);
|
|
250
|
-
const body = {
|
|
251
|
-
model: options.model ?? LOBBY_CODE_VISION_MODEL,
|
|
252
|
-
reasoning: { effort: "low" },
|
|
253
|
-
max_output_tokens: LOBBY_CODE_VISION_MAX_OUTPUT_TOKENS,
|
|
254
|
-
input: [
|
|
255
|
-
{
|
|
256
|
-
role: "user",
|
|
257
|
-
content: [
|
|
258
|
-
{ type: "input_text", text: LOBBY_CODE_VISION_PROMPT },
|
|
259
|
-
{ type: "input_image", image_url: `data:image/png;base64,${frame.toString("base64")}` }
|
|
260
|
-
]
|
|
261
|
-
}
|
|
262
|
-
]
|
|
263
|
-
};
|
|
264
|
-
let res;
|
|
265
|
-
try {
|
|
266
|
-
res = await fetchFn(options.endpoint ?? LOBBY_CODE_VISION_ENDPOINT, {
|
|
267
|
-
method: "POST",
|
|
268
|
-
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
269
|
-
body: JSON.stringify(body),
|
|
270
|
-
signal
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
catch {
|
|
274
|
-
return undefined; // transient network error: skip this frame, next turn retries
|
|
275
|
-
}
|
|
276
|
-
if (!res.ok)
|
|
277
|
-
return undefined; // never read a non-ok body (it can echo the frame/input)
|
|
278
|
-
let parsed;
|
|
279
|
-
try {
|
|
280
|
-
parsed = await res.json();
|
|
281
|
-
}
|
|
282
|
-
catch {
|
|
283
|
-
return undefined;
|
|
284
|
-
}
|
|
285
|
-
return parseLobbyCodeReply(extractResponsesOutputText(parsed));
|
|
286
|
-
}
|
|
287
|
-
/** A minimal resolve-once latch for the host-first handoff barrier. */
|
|
288
|
-
function deferred() {
|
|
289
|
-
let resolve;
|
|
290
|
-
let reject;
|
|
291
|
-
let done = false;
|
|
292
|
-
const promise = new Promise((res, rej) => {
|
|
293
|
-
resolve = (value) => { if (!done) {
|
|
294
|
-
done = true;
|
|
295
|
-
res(value);
|
|
296
|
-
} };
|
|
297
|
-
reject = (reason) => { if (!done) {
|
|
298
|
-
done = true;
|
|
299
|
-
rej(reason);
|
|
300
|
-
} };
|
|
301
|
-
});
|
|
302
|
-
return { promise, resolve, reject, settled: () => done };
|
|
303
|
-
}
|
|
304
|
-
/** Marker error the host-first barrier rejects with when the deadline elapses (fail-closed). */
|
|
305
|
-
class HandoffTimeoutError extends Error {
|
|
306
|
-
constructor(deadlineMs) {
|
|
307
|
-
super(`the host never produced a /lobby/CODE URL within the ${deadlineMs}ms handoff deadline`);
|
|
308
|
-
this.name = "HandoffTimeoutError";
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
function readPositiveInt(value, fallback) {
|
|
312
|
-
if (value === undefined)
|
|
313
|
-
return fallback;
|
|
314
|
-
const parsed = Number.parseInt(value, 10);
|
|
315
|
-
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
|
|
316
|
-
}
|
|
317
|
-
function makeRunId() {
|
|
318
|
-
const stamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
319
|
-
return `concurrent-shared-world-${stamp}-${randomBytes(4).toString("hex")}`;
|
|
320
|
-
}
|
|
321
|
-
/** Extract the in-sandbox port from the (loopback) serve.url so getHost can expose it. */
|
|
322
|
-
function servePort(serveUrl) {
|
|
323
|
-
const url = new URL(serveUrl);
|
|
324
|
-
if (url.port)
|
|
325
|
-
return Number(url.port);
|
|
326
|
-
return url.protocol === "https:" ? 443 : 80;
|
|
327
|
-
}
|
|
328
|
-
/** Resolve an actor's seat URL against the harness-minted getHost base (entry is a same-origin
|
|
329
|
-
* relative path, validated at parse against serve.url). */
|
|
330
|
-
function resolveActorSeatUrl(baseUrl, entry) {
|
|
331
|
-
if (!entry)
|
|
332
|
-
return baseUrl;
|
|
333
|
-
try {
|
|
334
|
-
return new URL(entry, baseUrl).toString();
|
|
335
|
-
}
|
|
336
|
-
catch {
|
|
337
|
-
return baseUrl;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
/** A getHost URL must be TOKENLESS (no userinfo, no query — no authKey; invariant 1). */
|
|
341
|
-
function isTokenlessHost(value) {
|
|
342
|
-
try {
|
|
343
|
-
const url = new URL(value);
|
|
344
|
-
return url.username === "" && url.password === "" && url.search === "";
|
|
345
|
-
}
|
|
346
|
-
catch {
|
|
347
|
-
return false;
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
/** sha256-16 of a URL's ORIGIN — the publish-safe host identity persisted in the bundle (the raw
|
|
351
|
-
* getHost URL embeds the live sandbox id + matches the e2b-URL redaction, so it never lands raw). */
|
|
352
|
-
function hostOriginDigest(url) {
|
|
353
|
-
try {
|
|
354
|
-
return commandDigestOf(new URL(url).origin);
|
|
355
|
-
}
|
|
356
|
-
catch {
|
|
357
|
-
return commandDigestOf(url);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
/** A public-safe, human-readable route label for the bundle (host redacted to a placeholder; the
|
|
361
|
-
* entry path kept). Never contains the raw getHost URL. */
|
|
362
|
-
function publicSafeRouteLabel(entry) {
|
|
363
|
-
return `[provisioned-subject]${entry ?? "/"}`;
|
|
364
|
-
}
|
|
365
|
-
/**
|
|
366
|
-
* Build the ONE subject sandbox's provenance (invariant 5): clone (repo + optional commit) or
|
|
367
|
-
* local-tree (archiveSha256 + optional commit/dirty from the once-per-run host-packed archive -
|
|
368
|
-
* archiveSha256 IS the pin; there is only ONE archive, so no per-lane unanimity math applies,
|
|
369
|
-
* unlike the cua fan-out route). Used for both the in-progress and final bundle: the archive
|
|
370
|
-
* never changes mid-run (packed before any sandbox exists).
|
|
371
|
-
*/
|
|
372
|
-
function buildSubjectProvenance(args) {
|
|
373
|
-
if (args.localTreeRoute) {
|
|
374
|
-
return {
|
|
375
|
-
source: "local-tree",
|
|
376
|
-
...(args.localTreeArchive === undefined ? {} : { archiveSha256: args.localTreeArchive.archiveSha256 }),
|
|
377
|
-
...(args.subjectCommit === undefined ? {} : { commit: args.subjectCommit }),
|
|
378
|
-
...(args.localTreeArchive?.git === undefined ? {} : { dirty: args.localTreeArchive.git.dirty }),
|
|
379
|
-
envNames: args.subjectEnvNames,
|
|
380
|
-
state: args.state
|
|
381
|
-
};
|
|
382
|
-
}
|
|
383
|
-
return {
|
|
384
|
-
source: "clone",
|
|
385
|
-
repo: args.publicRepo,
|
|
386
|
-
...(args.subjectCommit === undefined ? {} : { commit: args.subjectCommit }),
|
|
387
|
-
envNames: args.subjectEnvNames,
|
|
388
|
-
state: args.state
|
|
389
|
-
};
|
|
390
|
-
}
|
|
391
|
-
function laneTaxonomyLabel(spec) {
|
|
392
|
-
const parts = [
|
|
393
|
-
spec.actorType ? `type:${spec.actorType}` : undefined,
|
|
394
|
-
spec.surface ? `surface:${spec.surface}` : undefined,
|
|
395
|
-
spec.caseGroup ? `case:${spec.caseGroup}` : undefined
|
|
396
|
-
].filter((part) => part !== undefined);
|
|
397
|
-
return parts.length > 0 ? ` (${parts.join(" / ")})` : "";
|
|
398
|
-
}
|
|
399
|
-
/** Build one actor lane's CuaLaneSpec from a roster role (per-actor device IS honored here — each
|
|
400
|
-
* actor has its OWN desktop, unlike the sequential one-sandbox PoC). */
|
|
401
|
-
function buildActorSpec(config, role, index, personas) {
|
|
402
|
-
const mission = config.actors[0]?.mission ?? DEFAULT_MISSION;
|
|
403
|
-
const device = resolveLaneDevice(config, role);
|
|
404
|
-
const resolvedPersona = role.persona === undefined ? undefined : personas.get(role.persona);
|
|
405
|
-
const composed = composeLaneInstructions({
|
|
406
|
-
mission,
|
|
407
|
-
...(role.persona === undefined ? {} : { persona: role.persona }),
|
|
408
|
-
...(resolvedPersona === undefined ? {} : { resolvedPersona }),
|
|
409
|
-
...(role.instruction === undefined ? {} : { instruction: role.instruction }),
|
|
410
|
-
device: { name: device.name, preset: device.preset }
|
|
411
|
-
});
|
|
412
|
-
const roleId = role.id ?? `role-${String(index + 1).padStart(2, "0")}`;
|
|
413
|
-
const streamId = `stream-${String(index + 1).padStart(3, "0")}`;
|
|
414
|
-
return {
|
|
415
|
-
laneId: roleId,
|
|
416
|
-
...(role.actorType === undefined ? {} : { actorType: role.actorType }),
|
|
417
|
-
...(role.surface === undefined ? {} : { surface: role.surface }),
|
|
418
|
-
...(role.caseGroup === undefined ? {} : { caseGroup: role.caseGroup }),
|
|
419
|
-
laneIndex: index,
|
|
420
|
-
simId: `sim-${String(index + 1).padStart(3, "0")}`,
|
|
421
|
-
streamId,
|
|
422
|
-
persona: composed.persona,
|
|
423
|
-
instructions: composed.instructions,
|
|
424
|
-
assignment: { mission, ...(role.instruction === undefined ? {} : { focus: role.instruction }) },
|
|
425
|
-
...((role.reasoningEffort ?? config.actors[0]?.reasoningEffort) === undefined
|
|
426
|
-
? {} : { reasoningEffort: (role.reasoningEffort ?? config.actors[0]?.reasoningEffort) }),
|
|
427
|
-
...(config.actors[0]?.maxOutputTokens === undefined ? {} : { maxOutputTokens: config.actors[0].maxOutputTokens }),
|
|
428
|
-
...((role.stopWhen ?? config.actors[0]?.stopWhen) === undefined ? {} : { stopWhen: (role.stopWhen ?? config.actors[0]?.stopWhen) }),
|
|
429
|
-
...((role.dwell ?? config.actors[0]?.dwell) === undefined ? {} : { dwell: (role.dwell ?? config.actors[0]?.dwell) }),
|
|
430
|
-
deviceName: device.name,
|
|
431
|
-
devicePreset: device.preset,
|
|
432
|
-
resolution: device.resolution,
|
|
433
|
-
screenshotDir: roleId,
|
|
434
|
-
traceArtifactPath: `actors/${streamId}.json`
|
|
435
|
-
};
|
|
436
|
-
}
|
|
437
|
-
/** Thread the host-yielded lobby CODE into a follower's mission at runtime (external-public route).
|
|
438
|
-
* The CODE flows into the follower's join instruction; it is persisted only as the composed prompt
|
|
439
|
-
* the model reads (never a raw bundle field), and the lab scrubs the CODE from all narration. The
|
|
440
|
-
* follower joins through the real UI (a direct /lobby/CODE visit does not auto-join a non-member). */
|
|
441
|
-
function withLobbyCodeMission(spec, code) {
|
|
442
|
-
return {
|
|
443
|
-
...spec,
|
|
444
|
-
instructions: `${spec.instructions}\n\nThe multiplayer lobby code is ${code}. On the home screen choose Join, enter this lobby code, enter your name, and submit to join the shared game (do not open a lobby URL directly — go through the Join flow).`
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
/** A follower blocked by an expired deadline or an ended host. It never opened a browser;
|
|
448
|
-
* keep the actual reason rather than turning every upstream failure into a timeout. */
|
|
449
|
-
function makeBlockedFollowerOutcome(spec, reason, timedOut) {
|
|
450
|
-
return {
|
|
451
|
-
spec,
|
|
452
|
-
sessionError: `handoff barrier: ${reason}; this follower failed closed WITHOUT opening (no wasted turns).`,
|
|
453
|
-
killed: false,
|
|
454
|
-
streamUrlPresent: false,
|
|
455
|
-
screenshots: [],
|
|
456
|
-
stateStepRecords: [],
|
|
457
|
-
phaseRecords: [],
|
|
458
|
-
warnings: [],
|
|
459
|
-
noEngagement: true,
|
|
460
|
-
selfReportedBlocker: false,
|
|
461
|
-
harnessError: false,
|
|
462
|
-
skippedReason: timedOut ? "handoff-timeout" : "host-ended-before-handoff"
|
|
463
|
-
};
|
|
464
|
-
}
|
|
465
|
-
async function writeConcurrentRunArtifacts(bundle, preparedRunPaths) {
|
|
466
|
-
const runPaths = await validatePreparedRunArtifactPaths(preparedRunPaths);
|
|
467
|
-
const publicBundle = {
|
|
468
|
-
...bundle,
|
|
469
|
-
cwd: PUBLIC_TARGET_CWD
|
|
470
|
-
};
|
|
471
|
-
await writeContainedOutputFile(runPaths, "run.json", `${JSON.stringify(publicBundle, null, 2)}\n`, "utf8");
|
|
472
|
-
await writeContainedOutputFile(runPaths, "review.json", `${JSON.stringify(publicBundle.review, null, 2)}\n`, "utf8");
|
|
473
|
-
await writeContainedOutputFile(runPaths, "review.md", renderConcurrentReviewMarkdown(publicBundle), "utf8");
|
|
474
|
-
await writeContainedOutputFile(runPaths, "events.ndjson", `${publicBundle.events.map((event) => JSON.stringify(event)).join("\n")}\n`, "utf8");
|
|
475
|
-
await writeContainedOutputFile(runPaths, "observer/observer-data.json", `${JSON.stringify(buildObserverData(publicBundle), null, 2)}\n`, "utf8");
|
|
476
|
-
await writePreparedRunLatestPointer(runPaths, `${JSON.stringify({
|
|
477
|
-
schema: "humanish.latest-run.v1",
|
|
478
|
-
runId: publicBundle.runId,
|
|
479
|
-
path: runPaths.relativeRunRoot,
|
|
480
|
-
updatedAt: new Date().toISOString()
|
|
481
|
-
}, null, 2)}\n`, "utf8");
|
|
482
|
-
}
|
|
483
|
-
function observerResultForConcurrentArtifacts(cwd, runId, artifactRoot, warnings = []) {
|
|
484
|
-
const observerPath = path.join(artifactRoot, "observer", "index.html");
|
|
485
|
-
const observerDataPath = path.join(artifactRoot, "observer", "observer-data.json");
|
|
486
|
-
const eventsPath = path.join(artifactRoot, "events.ndjson");
|
|
487
|
-
return {
|
|
488
|
-
schema: "humanish.observer-result.v1",
|
|
489
|
-
ok: true,
|
|
490
|
-
cwd,
|
|
491
|
-
run: runId,
|
|
492
|
-
observerPath: path.relative(cwd, observerPath),
|
|
493
|
-
observerDataPath: path.relative(cwd, observerDataPath),
|
|
494
|
-
eventsPath: path.relative(cwd, eventsPath),
|
|
495
|
-
observerUrl: pathToFileURL(observerPath).href,
|
|
496
|
-
bundlePath: path.join(artifactRoot, "run.json"),
|
|
497
|
-
opened: false,
|
|
498
|
-
warnings
|
|
499
|
-
};
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Wrapped so a DIRECT library caller gets the same status-record lifetime the CLI does: returning
|
|
503
|
-
* from this function finalizes any record the run opened, whichever of its fail-closed exits it
|
|
504
|
-
* took. `runLab` establishes a scope too and nesting is harmless — the inner scope owns what it
|
|
505
|
-
* opened. Without this a test or an adopter calling the backend directly leaves the 5s cadence
|
|
506
|
-
* ticking into a directory something else is deleting, which surfaces as an unrelated ENOTEMPTY.
|
|
507
|
-
*/
|
|
508
|
-
export async function runConcurrentSharedWorld(options) {
|
|
509
|
-
return withTransientCommsSecrets(() => runConcurrentSharedWorldWithSecrets(options));
|
|
510
|
-
}
|
|
511
|
-
async function runConcurrentSharedWorldWithSecrets(options) {
|
|
512
|
-
const analysis = resolveAutomaticAnalysis(options.config.review?.analysis);
|
|
513
|
-
const result = await withRunStatusScope(() => runConcurrentSharedWorldInScope(options));
|
|
514
|
-
return completeAutomaticAnalysis(result, analysis.ok ? analysis.config : undefined, options.automaticAnalysis, options.config.review?.analysis === undefined ? "default" : "explicit", analysis.ok && analysis.preferLargerOutput === true);
|
|
515
|
-
}
|
|
516
|
-
async function runConcurrentSharedWorldInScope(options) {
|
|
517
|
-
const { config, dryRun } = options;
|
|
518
|
-
const cwd = path.resolve(options.cwd);
|
|
519
|
-
const hooks = options.hooks ?? {};
|
|
520
|
-
const env = hooks.env ?? process.env;
|
|
521
|
-
const render = hooks.renderObserverFn ?? renderObserver;
|
|
522
|
-
const actorType = config.actors[0]?.type ?? "";
|
|
523
|
-
const roles = config.actors[0]?.lanes ?? [];
|
|
524
|
-
// All-parallel default (#350): the parser fills concurrency for multi-seat labs, so this
|
|
525
|
-
// fallback serves only library callers constructing configs directly — same meaning: every
|
|
526
|
-
// declared seat runs at once unless the author declared a cap.
|
|
527
|
-
const concurrency = config.execution?.concurrency ?? Math.max(1, roles.length);
|
|
528
|
-
const fail = (code, message, actorLabel) => ({
|
|
529
|
-
schema: CONCURRENT_SHARED_WORLD_LAB_SCHEMA,
|
|
530
|
-
ok: false,
|
|
531
|
-
cwd,
|
|
532
|
-
labId: config.id,
|
|
533
|
-
actor: actorLabel ?? actorType,
|
|
534
|
-
topology: "shared-world",
|
|
535
|
-
topologyMode: "concurrent",
|
|
536
|
-
roleCount: roles.length,
|
|
537
|
-
concurrency,
|
|
538
|
-
dryRun,
|
|
539
|
-
runId: options.runId ?? "not-created",
|
|
540
|
-
roles: [],
|
|
541
|
-
warnings: [],
|
|
542
|
-
error: { code, message }
|
|
543
|
-
});
|
|
544
|
-
const mediaReason = desktopMediaValidationReason(config, false);
|
|
545
|
-
if (mediaReason)
|
|
546
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_INVALID", mediaReason);
|
|
547
|
-
const analysis = resolveAutomaticAnalysis(config.review?.analysis);
|
|
548
|
-
if (!analysis.ok)
|
|
549
|
-
return fail("HUMANISH_LAB_ANALYSIS_INVALID", analysis.message);
|
|
550
|
-
const tasksReason = taskProtocolValidationReason(config, false);
|
|
551
|
-
if (tasksReason)
|
|
552
|
-
return fail("HUMANISH_LAB_TASKS_UNSUPPORTED", tasksReason);
|
|
553
|
-
const descriptor = actorRegistry[actorType];
|
|
554
|
-
if (!descriptor || !isCuaActorDescriptor(descriptor)) {
|
|
555
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_ACTOR_UNSUPPORTED", `actors[0].type "${actorType}" is not a registered computer-use actor.`);
|
|
556
|
-
}
|
|
557
|
-
// The PLANE-class discriminator (#164 phase 2): an app-url subject is the EXTERNAL-PUBLIC plane (a
|
|
558
|
-
// real operator-owned public deployment used directly as the shared plane — NO getHost, clone,
|
|
559
|
-
// subject sandbox, or seed); everything else is the historical provisioned-getHost plane.
|
|
560
|
-
const planeClass = config.subject.source === "app-url" ? "external-public" : "provisioned-getHost";
|
|
561
|
-
// Re-enforce the cross-validation (library API surface). The external-public branch NEVER touches
|
|
562
|
-
// the getHost synthetic gate — that gate exists because getHost is internet-reachable AND
|
|
563
|
-
// harness-owned; a public site the harness neither provisioned nor exposed has neither property.
|
|
564
|
-
const invalidReason = outputTokenLimitValidationReason(config) ?? (planeClass === "external-public"
|
|
565
|
-
? externalPublicSharedWorldValidationReason(config)
|
|
566
|
-
: concurrentSharedWorldValidationReason(config));
|
|
567
|
-
if (invalidReason) {
|
|
568
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_INVALID", invalidReason, descriptor.id);
|
|
569
|
-
}
|
|
570
|
-
if (config.actors[0]?.maxOutputTokens !== undefined && hooks.runSession) {
|
|
571
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_INVALID", "maxOutputTokens cannot be enforced by a custom runSession.", descriptor.id);
|
|
572
|
-
}
|
|
573
|
-
const caps = config.execution?.caps;
|
|
574
|
-
if (!dryRun && (caps?.maxUsd !== undefined || caps?.maxTotalUsd !== undefined)) {
|
|
575
|
-
const model = (config.actors[0]?.model ?? DEFAULT_OPENAI_CU_MODEL).trim().toLowerCase();
|
|
576
|
-
if (!MODEL_RATES[model]) {
|
|
577
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_INVALID", `The declared spend cap cannot be enforced for unpriced model "${model}".`, descriptor.id);
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
const runBudget = !dryRun && caps?.maxTotalUsd !== undefined ? makeCuaRunBudget(caps.maxTotalUsd) : undefined;
|
|
581
|
-
// provisioned-getHost fields (all absent on the external-public plane — forbidden at validation).
|
|
582
|
-
const serve = config.subject.serve;
|
|
583
|
-
const localTreeRoute = config.subject.source === "local-tree";
|
|
584
|
-
const subjectRepo = config.subject.repos?.[0] ?? "";
|
|
585
|
-
const subjectEnvNames = config.subject.env ?? [];
|
|
586
|
-
const checkpoints = config.subject.state?.checkpoint ?? [];
|
|
587
|
-
const runSession = hooks.runSession ?? descriptor.runSession;
|
|
588
|
-
// The per-seat vision lobby-code reader (default: the real single-frame OpenAI read). Injectable so the
|
|
589
|
-
// barrier's handoff + convergence proof are testable without a live vision call.
|
|
590
|
-
const readLobbyCode = hooks.readLobbyCodeFromFrame ?? readLobbyCodeFromFrame;
|
|
591
|
-
const receivingReason = receivingEmailValidationReason(config);
|
|
592
|
-
if (receivingReason)
|
|
593
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_INVALID", receivingReason, descriptor.id);
|
|
594
|
-
const openaiApiKey = env.OPENAI_API_KEY?.trim() ?? "";
|
|
595
|
-
const e2bApiKey = env.E2B_API_KEY?.trim() ?? "";
|
|
596
|
-
const knownSecretValues = [
|
|
597
|
-
openaiApiKey,
|
|
598
|
-
e2bApiKey,
|
|
599
|
-
...subjectEnvNames.map((name) => env[name] ?? ""),
|
|
600
|
-
...checkpoints.flatMap((probe) => probe.redact ?? [])
|
|
601
|
-
].filter((value) => value.length >= 4);
|
|
602
|
-
const scrubKnownValues = (text) => knownSecretValues.reduce((current, value) => current.split(value).join("[REDACTED_SECRET]"), text);
|
|
603
|
-
const redactRepoLabel = config.policies?.redactRepos ?? subjectEnvNames.includes("GITHUB_TOKEN");
|
|
604
|
-
const publicRepo = redactRepoLabel ? "repo-01" : subjectRepo;
|
|
605
|
-
const hasGithubToken = subjectEnvNames.includes("GITHUB_TOKEN");
|
|
606
|
-
if (!dryRun) {
|
|
607
|
-
const missingKeys = [
|
|
608
|
-
...(openaiApiKey ? [] : ["OPENAI_API_KEY"]),
|
|
609
|
-
...(e2bApiKey ? [] : ["E2B_API_KEY"])
|
|
610
|
-
];
|
|
611
|
-
if (missingKeys.length > 0) {
|
|
612
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_KEYS_MISSING", `Live concurrent shared-world labs need ${missingKeys.join(" and ")} in the environment (values are never persisted). ${describeMissingKeys(missingKeys, env)}`, descriptor.id);
|
|
613
|
-
}
|
|
614
|
-
const missingSubjectEnv = subjectEnvNames.filter((name) => !env[name]?.trim());
|
|
615
|
-
if (missingSubjectEnv.length > 0) {
|
|
616
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_SUBJECT_ENV_MISSING", `subject.env declares ${missingSubjectEnv.join(", ")} but the environment does not provide ${missingSubjectEnv.length === 1 ? "it" : "them"} (pass via --env-file; values are never persisted).`, descriptor.id);
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
const runId = options.runId ?? makeRunId();
|
|
620
|
-
const runPaths = await prepareRunArtifactPaths(cwd, runId);
|
|
621
|
-
// Identity + liveness on disk (#455): every backend writes this, so a watcher can classify any
|
|
622
|
-
// run without parsing bundles and without depending on the interactive-observer path.
|
|
623
|
-
const runStatus = beginRunStatus(runPaths, {
|
|
624
|
-
runId,
|
|
625
|
-
mode: dryRun ? "dry-run" : "live",
|
|
626
|
-
...(options.lab === undefined ? {} : { lab: options.lab })
|
|
627
|
-
});
|
|
628
|
-
const artifactRoot = runPaths.absoluteRunRoot;
|
|
629
|
-
const physicalArtifactRoot = runPaths.physicalRunRoot;
|
|
630
|
-
const createdAt = new Date().toISOString();
|
|
631
|
-
const timeoutMs = config.execution?.timeoutMs ?? defaultSeatSessionTimeoutMs(config);
|
|
632
|
-
const requestTimeoutMs = readPositiveInt(env.HUMANISH_E2B_REQUEST_TIMEOUT_MS, 60_000);
|
|
633
|
-
const redactScreenshots = config.policies?.redactScreenshots === true;
|
|
634
|
-
const timers = hooks.detachedTimers ?? {};
|
|
635
|
-
const now = hooks.now ?? Date.now;
|
|
636
|
-
const proberCadenceMs = hooks.proberCadenceMs ?? DEFAULT_PROBER_CADENCE_MS;
|
|
637
|
-
const seedDigest = seedRecipeDigest(config);
|
|
638
|
-
const source = await buildRunSource({ capturedAt: createdAt, cwd, humanishSource: "present", packageName: "humanish" });
|
|
639
|
-
const warnings = [];
|
|
640
|
-
const stateStepRecords = [];
|
|
641
|
-
const stateSnapshots = [];
|
|
642
|
-
// Compile committed personas so each seat's prompt carries real behavioral directives (#381).
|
|
643
|
-
const personaResolution = await resolveCommittedPersonasForCwd(cwd, labPersonaIds(config));
|
|
644
|
-
const actorSpecs = roles.map((role, i) => buildActorSpec(config, role, i, personaResolution.personas));
|
|
645
|
-
for (const spec of actorSpecs) {
|
|
646
|
-
if (spec.assignment)
|
|
647
|
-
spec.assignment = participantAssignment(spec.assignment, scrubKnownValues);
|
|
648
|
-
spec.evidenceInstructions = redactText(scrubKnownValues(spec.instructions));
|
|
649
|
-
spec.persona = scrubPersonaBrief(spec.persona, scrubKnownValues);
|
|
650
|
-
}
|
|
651
|
-
let actorResults = [];
|
|
652
|
-
let subjectCommit;
|
|
653
|
-
let subjectSandboxId;
|
|
654
|
-
let subjectKilled = false;
|
|
655
|
-
let getHostUrl;
|
|
656
|
-
// Persona inbox SURFACE (#297 slice B, shared-world): the getHost-exposed inbox URL a persona (in a
|
|
657
|
-
// DIFFERENT sandbox) opens, the serve->getHost origin-rewrite map (REQUIRED here so the app's loopback
|
|
658
|
-
// verify links resolve to a reachable host), and the dedicated surface channel + render loop.
|
|
659
|
-
let commsInboxUrl;
|
|
660
|
-
let commsOriginMap = [];
|
|
661
|
-
let surfaceRenderedCount = 0;
|
|
662
|
-
let surfaceLoop;
|
|
663
|
-
let runError;
|
|
664
|
-
let snapshotIndex = 0;
|
|
665
|
-
let liveObserver;
|
|
666
|
-
const runtimeStreamUrls = [];
|
|
667
|
-
// Off-app comms (#297): on the provisioned-getHost plane the harness owns the ONE subject sandbox, so
|
|
668
|
-
// it can redirect the app's email-API sends into an in-sandbox catch and evidence them. Gated ENTIRELY
|
|
669
|
-
// on config.comms — no comms declared → zero change. The base-URL env is injected into the subject
|
|
670
|
-
// sandbox at create (fixed port known up front); the catch is deployed before serve; the drain + digest
|
|
671
|
-
// evidence run at subject teardown, then register run-level in the bundle. NOT available on the
|
|
672
|
-
// external-public plane (the app is an operator-owned deployment the harness never provisions).
|
|
673
|
-
const commsEmail = planeClass === "provisioned-getHost" && config.comms?.email?.kind === "fake" ? config.comms.email : undefined;
|
|
674
|
-
const commsPort = commsEmail ? (commsEmail.port ?? DEFAULT_SANDBOX_CATCH_PORT) : undefined;
|
|
675
|
-
// injectEnv is absent on an adopter-hosted plane (#328): there is no subject env to inject
|
|
676
|
-
// because the operator points their own app at their own catch.
|
|
677
|
-
const commsEnv = commsEmail?.injectEnv !== undefined && commsPort !== undefined
|
|
678
|
-
? { [commsEmail.injectEnv]: `http://127.0.0.1:${commsPort}` }
|
|
679
|
-
: {};
|
|
680
|
-
let commsArtifactPath;
|
|
681
|
-
// ADOPTER-HOSTED ingress (#328): on the external-public plane the harness provisions nothing, so
|
|
682
|
-
// it cannot host a catch — but the OPERATOR can, and then humanish still does every other part of
|
|
683
|
-
// the funnel: it tells each persona its address and inbox URL, drains the declared catch over
|
|
684
|
-
// HTTP at teardown, and writes the same digest-only evidence. Declaring `external` is what turns
|
|
685
|
-
// the previously-inert block into a working one.
|
|
686
|
-
const externalComms = planeClass === "external-public" ? config.comms?.email?.external : undefined;
|
|
687
|
-
const externalCommsEmail = externalComms ? config.comms?.email : undefined;
|
|
688
|
-
if (config.comms?.email?.kind === "fake" && planeClass === "external-public" && externalComms === undefined) {
|
|
689
|
-
warnings.push("comms.email is declared but this is the external-public plane (the shared plane is an operator-owned public deployment the harness does not provision) — the in-sandbox email catch cannot be deployed and no comms evidence is collected. Declare `comms.email.external` to host the catch yourself (#328).");
|
|
690
|
-
}
|
|
691
|
-
if (externalComms) {
|
|
692
|
-
commsInboxUrl = externalInboxUrl(externalComms);
|
|
693
|
-
// Fail closed BEFORE any actor sandbox is created: a comms lab whose catch is unreachable
|
|
694
|
-
// collects nothing while every lane still spends. The probe asserts OUR service marker in
|
|
695
|
-
// /health, so an adopter's proxy answering 200 for everything cannot pass for a catch.
|
|
696
|
-
if (!dryRun && !(await externalCatchHealthy(externalComms))) {
|
|
697
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_COMMS_CATCH_UNREACHABLE", `The external comms catch or inbox is unreachable or incompatible (GET /health must identify humanish-comms-catch and advertise recipient-inbox-v1). Update Humanish on the catch host and restart it with \`humanish comms catch\` on that host, or drop comms.email to run without the inbox funnel.`);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
// EXTERNAL-PUBLIC plane state (#164 phase 2). publicAppUrl is the operator-declared shared plane;
|
|
701
|
-
// its ORIGIN is persisted digest-only (publicOriginDigest), never raw (the raw URL + the runtime
|
|
702
|
-
// observed lobby CODE never land — TENSION 3). The latch code is scrubbed from all narration.
|
|
703
|
-
const publicAppUrl = config.subject.appUrl ?? "";
|
|
704
|
-
// The operator-DECLARED origin (from subject.appUrl) — recorded for evidence/reference ONLY. The
|
|
705
|
-
// operator-OWNERSHIP claim rests on the subject.publicTarget.authorized attestation + this declared
|
|
706
|
-
// appUrl, NOT on digest equality (blocker 2): a normal cross-origin redirect (apex->www, http->https;
|
|
707
|
-
// lobby-trivia.example.test 307-redirects) makes the seats' OBSERVED origin differ from the declared one, which
|
|
708
|
-
// is expected and MUST NOT fail the run. Persisted digest-only (never the raw origin).
|
|
709
|
-
const declaredOriginDigest = planeClass === "external-public" && publicAppUrl
|
|
710
|
-
? hostOriginDigest(publicAppUrl)
|
|
711
|
-
: undefined;
|
|
712
|
-
// The OBSERVED convergence origin — computed AFTER fan-out from what the seats ACTUALLY reached (the
|
|
713
|
-
// convergence proof is what the seats OBSERVED, not what was declared). Set iff every observing seat
|
|
714
|
-
// agrees on ONE origin; that agreement IS the convergence proof and becomes plane.publicOriginDigest.
|
|
715
|
-
let publicOriginDigest;
|
|
716
|
-
// Per-lane runtime-only observed state (never persisted raw): the last observed URL and the last
|
|
717
|
-
// observed /lobby/CODE per seat, fed by onObservedUrl. The URL is digested to ORIGIN for each seat's
|
|
718
|
-
// routeHostDigest (no code leaks); the codes drive the cross-seat lobby-convergence digest.
|
|
719
|
-
const observedFinalUrls = new Array(roles.length);
|
|
720
|
-
const observedLobbyCodes = new Array(roles.length);
|
|
721
|
-
let lobbyConvergenceDigest;
|
|
722
|
-
let handoffTimedOut = false;
|
|
723
|
-
let hostHandoffFailure;
|
|
724
|
-
// A closure that scrubs the latched lobby CODE from ANY persisted narration once the host resolves
|
|
725
|
-
// it (the 6-char code has no detectable secret shape, so shape-only redaction cannot catch it).
|
|
726
|
-
let latchedLobbyCode;
|
|
727
|
-
const scrubKnownValuesWithLobbyCode = (text) => {
|
|
728
|
-
const base = scrubKnownValues(text);
|
|
729
|
-
return latchedLobbyCode && latchedLobbyCode.length > 0
|
|
730
|
-
? base.split(latchedLobbyCode).join("[REDACTED_LOBBY_CODE]")
|
|
731
|
-
: base;
|
|
732
|
-
};
|
|
733
|
-
// Pack the working tree ONCE per run, on the host, BEFORE the subject sandbox is created
|
|
734
|
-
// (mirrors the sequential route + the cua route's ordering): a packing failure fails the run
|
|
735
|
-
// closed here, never spending sandbox cost. Dry-run packs nothing.
|
|
736
|
-
let localTreeArchive;
|
|
737
|
-
let localTreeArchiveBuffer;
|
|
738
|
-
if (localTreeRoute && !dryRun) {
|
|
739
|
-
const packLocalTree = hooks.packLocalTree ?? defaultPackLocalTree;
|
|
740
|
-
try {
|
|
741
|
-
const packed = await packLocalTree({
|
|
742
|
-
root: cwd,
|
|
743
|
-
...(config.subject.localTree?.exclude === undefined ? {} : { extraExclude: config.subject.localTree.exclude }),
|
|
744
|
-
...(config.subject.localTree?.maxArchiveBytes === undefined ? {} : { maxArchiveBytes: config.subject.localTree.maxArchiveBytes })
|
|
745
|
-
});
|
|
746
|
-
localTreeArchive = packed.archive;
|
|
747
|
-
localTreeArchiveBuffer = packed.buffer;
|
|
748
|
-
process.stderr.write(`humanish concurrent shared-world local-tree: packed ${packed.archive.fileCount} entries, ${packed.archive.totalBytes} bytes, archiveSha256 ${packed.archive.archiveSha256}`
|
|
749
|
-
+ `${packed.archive.git ? ` (commit ${packed.archive.git.commit.slice(0, 12)}, ${packed.archive.git.dirty ? "dirty" : "clean"} working tree)` : " (not a git work tree)"}\n`);
|
|
750
|
-
}
|
|
751
|
-
catch (error) {
|
|
752
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_FAILED", `local-tree packing failed: ${redactText(scrubKnownValues(toErrorMessage(error)))}`, descriptor.id);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
let receiving;
|
|
756
|
-
if (!dryRun && config.comms?.email?.kind === "real") {
|
|
757
|
-
try {
|
|
758
|
-
receiving = await prepareReceivingRun({ cwd, runId, config, env, participants: actorSpecs.map(spec => spec.laneId), runPaths,
|
|
759
|
-
registerSecrets: values => { for (const value of values)
|
|
760
|
-
if (value.length >= 4 && !knownSecretValues.includes(value))
|
|
761
|
-
knownSecretValues.push(value); }
|
|
762
|
-
});
|
|
763
|
-
commsArtifactPath = "comms/receiving.json";
|
|
764
|
-
}
|
|
765
|
-
catch {
|
|
766
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_INVALID", "Real email setup failed before desktop allocation. Run humanish comms check --online and humanish comms recover to inspect authentication and pending cleanup.", descriptor.id);
|
|
767
|
-
}
|
|
768
|
-
}
|
|
769
|
-
try {
|
|
770
|
-
if (!dryRun && planeClass === "provisioned-getHost") {
|
|
771
|
-
if (!serve) {
|
|
772
|
-
// Defense-in-depth: concurrentSharedWorldValidationReason already required serve above.
|
|
773
|
-
return fail("HUMANISH_CONCURRENT_SHARED_WORLD_LAB_INVALID", "the provisioned-getHost concurrent shared-world route requires `subject.serve`.", descriptor.id);
|
|
774
|
-
}
|
|
775
|
-
let subjectModule;
|
|
776
|
-
let subjectDesktop;
|
|
777
|
-
// The in-sandbox email catch on the ONE subject sandbox (#297); drained at teardown. Undefined
|
|
778
|
-
// unless a comms lab declared it. Hoisted so the finally can drain before the subject is killed.
|
|
779
|
-
let deployedComms;
|
|
780
|
-
// Background prober dispose signal (FIX-9: cleared in finally).
|
|
781
|
-
let proberDisposed = false;
|
|
782
|
-
let releaseDispose = () => { };
|
|
783
|
-
const disposeSignal = new Promise((resolve) => { releaseDispose = resolve; });
|
|
784
|
-
let proberLoop;
|
|
785
|
-
const proberSnapshot = async () => {
|
|
786
|
-
if (!subjectDesktop)
|
|
787
|
-
return;
|
|
788
|
-
const timestamp = now();
|
|
789
|
-
const idx = snapshotIndex;
|
|
790
|
-
snapshotIndex += 1;
|
|
791
|
-
const snapshot = await runCheckpointSnapshot({
|
|
792
|
-
desktop: subjectDesktop,
|
|
793
|
-
snapshotIndex: idx,
|
|
794
|
-
name: `state-${idx}`,
|
|
795
|
-
checkpoints,
|
|
796
|
-
prevDigest: undefined,
|
|
797
|
-
scrub: scrubKnownValues,
|
|
798
|
-
requestTimeoutMs,
|
|
799
|
-
timers
|
|
800
|
-
});
|
|
801
|
-
stateSnapshots.push({ timestamp, digest: snapshot.digest });
|
|
802
|
-
};
|
|
803
|
-
try {
|
|
804
|
-
subjectModule = await (hooks.loadDesktopModule ?? loadE2BDesktopModule)();
|
|
805
|
-
// The ONE subject sandbox: headless service host (no GUI seat). The SUBJECT env is provisioned
|
|
806
|
-
// HERE; the actor sandboxes get NONE of it (FIX-10). A custom desktop template (image) is
|
|
807
|
-
// honored on BOTH the subject sandbox (here) and every actor sandbox (via runCuaLane, which
|
|
808
|
-
// reads the same config); absent keeps the byte-stable Sandbox.create(opts) default.
|
|
809
|
-
subjectDesktop = await createDesktopSandbox(subjectModule, {
|
|
810
|
-
apiKey: e2bApiKey,
|
|
811
|
-
requestTimeoutMs,
|
|
812
|
-
timeoutMs: timeoutMs + SUBJECT_PROVISION_BUDGET_MS
|
|
813
|
-
+ (config.subject.state?.seed ?? []).reduce((sum, step) => sum + (step.timeoutMs ?? DEFAULT_STATE_STEP_TIMEOUT_MS), 0)
|
|
814
|
-
+ SANDBOX_TIMEOUT_BUFFER_MS,
|
|
815
|
-
metadata: {
|
|
816
|
-
...CONCURRENT_SHARED_WORLD_PROVIDER_METADATA,
|
|
817
|
-
labId: config.id,
|
|
818
|
-
topology: "shared-world",
|
|
819
|
-
topologyMode: "concurrent",
|
|
820
|
-
role: "subject",
|
|
821
|
-
roleCount: String(roles.length)
|
|
822
|
-
},
|
|
823
|
-
...(subjectEnvNames.length > 0 || Object.keys(commsEnv).length > 0
|
|
824
|
-
? { envs: { ...Object.fromEntries(subjectEnvNames.map((name) => [name, env[name]])), ...commsEnv } }
|
|
825
|
-
: {}),
|
|
826
|
-
dpi: 96,
|
|
827
|
-
lifecycle: { onTimeout: "kill" }
|
|
828
|
-
}, config.execution?.desktop?.template);
|
|
829
|
-
subjectSandboxId = subjectDesktop.sandboxId;
|
|
830
|
-
// #358 salvage: durable id receipt the moment the subject sandbox exists.
|
|
831
|
-
await appendSandboxReceipt(runPaths, { at: new Date().toISOString(), laneId: "subject", sandboxId: subjectSandboxId });
|
|
832
|
-
if (hooks.prepareDesktop) {
|
|
833
|
-
await hooks.prepareDesktop(subjectDesktop);
|
|
834
|
-
}
|
|
835
|
-
// Start the in-sandbox email catch BEFORE the subject serve, so the app's send-API base URL
|
|
836
|
-
// (injected into its env at create) resolves the moment it boots. Fail closed if the catch can't
|
|
837
|
-
// stand up rather than let a comms-declared app silently send real mail to the internet.
|
|
838
|
-
if (commsEmail && commsPort !== undefined) {
|
|
839
|
-
// A SECOND (0.0.0.0) read-only inbox listener on commsPort+1 so the persona — which lives in a
|
|
840
|
-
// DIFFERENT sandbox here — can reach the inbox surface via getHost; capture stays loopback.
|
|
841
|
-
deployedComms = await deployCommsCatch(subjectDesktop, { port: commsPort, inboxPort: commsPort + 1, requestTimeoutMs, timers });
|
|
842
|
-
if (!deployedComms.ready) {
|
|
843
|
-
throw new Error(`comms email catch did not become ready in the subject sandbox (loopback capture ${commsPort} / inbox ${commsPort + 1})`);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
// Provision the ONE shared plane: clone + install/build + seed + serve on 0.0.0.0 + probe
|
|
847
|
-
// (clone route), or upload/extract the once-per-run packed archive + the SAME shared serve
|
|
848
|
-
// pipeline (local-tree route).
|
|
849
|
-
const onSubjectPhase = hooks.onPhase ?? ((event) => {
|
|
850
|
-
process.stderr.write(`humanish shared-world (concurrent): ${event.message}${event.durationMs === undefined ? "" : ` (${event.durationMs}ms)`}\n`);
|
|
851
|
-
});
|
|
852
|
-
if (localTreeRoute) {
|
|
853
|
-
await provisionLocalTreeSubject(subjectDesktop, {
|
|
854
|
-
archiveBuffer: localTreeArchiveBuffer,
|
|
855
|
-
serve,
|
|
856
|
-
...(config.subject.state === undefined ? {} : { state: config.subject.state }),
|
|
857
|
-
requestTimeoutMs,
|
|
858
|
-
scrub: scrubKnownValues,
|
|
859
|
-
onStateStep: (record) => { stateStepRecords.push(record); },
|
|
860
|
-
onPhase: onSubjectPhase,
|
|
861
|
-
...timers
|
|
862
|
-
});
|
|
863
|
-
}
|
|
864
|
-
else {
|
|
865
|
-
subjectCommit = await provisionCloneSubject(subjectDesktop, {
|
|
866
|
-
repo: subjectRepo,
|
|
867
|
-
depth: config.subject.clone?.depth ?? 1,
|
|
868
|
-
serve,
|
|
869
|
-
...(config.subject.state === undefined ? {} : { state: config.subject.state }),
|
|
870
|
-
hasGithubToken,
|
|
871
|
-
requestTimeoutMs,
|
|
872
|
-
scrub: scrubKnownValues,
|
|
873
|
-
onCommit: (commit) => { subjectCommit = commit; },
|
|
874
|
-
onStateStep: (record) => { stateStepRecords.push(record); },
|
|
875
|
-
onPhase: onSubjectPhase,
|
|
876
|
-
...timers
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
// Expose the served port via getHost (FIX-2). Fail closed if the SDK lacks it.
|
|
880
|
-
if (typeof subjectDesktop.getHost !== "function") {
|
|
881
|
-
throw new Error("the installed @e2b/desktop SDK does not expose getHost(port); the concurrent shared-world route requires it to reach the subject plane");
|
|
882
|
-
}
|
|
883
|
-
// getHost returns a BARE host (e.g. "3000-<sandboxId>.e2b.app", no scheme); e2b exposes the
|
|
884
|
-
// port over https. Normalize to a full URL before the tokenless check + before persisting.
|
|
885
|
-
const rawHost = subjectDesktop.getHost(servePort(serve.url));
|
|
886
|
-
const hostUrl = /^https?:\/\//i.test(rawHost) ? rawHost : `https://${rawHost}`;
|
|
887
|
-
if (!isTokenlessHost(hostUrl)) {
|
|
888
|
-
throw new Error("getHost returned a non-tokenless URL; refusing to persist a host URL that may carry a credential (invariant 1)");
|
|
889
|
-
}
|
|
890
|
-
getHostUrl = hostUrl;
|
|
891
|
-
// Persona inbox SURFACE (#297 slice B, shared-world): getHost-expose the read-only inbox listener so
|
|
892
|
-
// a persona in a DIFFERENT sandbox can open it; build the serve->getHost origin map (REQUIRED here —
|
|
893
|
-
// the app's loopback verify links must be rewritten to a reachable host); provision the surface
|
|
894
|
-
// channel; write the EMPTY inbox up front (so /inbox never 404s); and start a render loop that drains
|
|
895
|
-
// + re-renders on a cadence. The loop shares the prober's dispose signal (disposed together, before
|
|
896
|
-
// the teardown evidence drain), and uses a DEDICATED FakeInbox + cursor (independent of that drain).
|
|
897
|
-
if (commsEmail && deployedComms?.inboxPort !== undefined) {
|
|
898
|
-
const rawInboxHost = subjectDesktop.getHost(deployedComms.inboxPort);
|
|
899
|
-
const inboxHostUrl = /^https?:\/\//i.test(rawInboxHost) ? rawInboxHost : `https://${rawInboxHost}`;
|
|
900
|
-
if (!isTokenlessHost(inboxHostUrl)) {
|
|
901
|
-
throw new Error("getHost returned a non-tokenless URL for the comms inbox; refusing to advertise it (invariant 1)");
|
|
902
|
-
}
|
|
903
|
-
commsInboxUrl = `${inboxHostUrl}/inbox`;
|
|
904
|
-
commsOriginMap = buildOriginMap({
|
|
905
|
-
internalServeUrl: serve.url,
|
|
906
|
-
reachableBaseUrl: getHostUrl,
|
|
907
|
-
...(commsEmail.linkOrigin === undefined ? {} : { linkOrigin: commsEmail.linkOrigin })
|
|
908
|
-
});
|
|
909
|
-
const surfaceRecipients = (commsEmail.recipients ?? [])
|
|
910
|
-
.filter((recipient) => recipient.address !== undefined)
|
|
911
|
-
.map((recipient) => ({ lane: recipient.lane, address: recipient.address }));
|
|
912
|
-
await writeInboxSurface(subjectDesktop, deployedComms.surfaceDir, [], { originMap: commsOriginMap, requestTimeoutMs });
|
|
913
|
-
const surfaceDeployed = deployedComms;
|
|
914
|
-
const surfaceCadenceMs = 2500;
|
|
915
|
-
surfaceLoop = (async () => {
|
|
916
|
-
// Full, idempotent rebuild each tick; surfaceRenderedCount advances only on a successful render,
|
|
917
|
-
// so a transient failure retries cleanly. Real timer (dispose-interruptible + cleared) — an
|
|
918
|
-
// unbounded loop must not busy-spin on the injected instant clock.
|
|
919
|
-
for (;;) {
|
|
920
|
-
try {
|
|
921
|
-
const refreshed = await refreshInboxSurface({
|
|
922
|
-
desktop: subjectDesktop,
|
|
923
|
-
deployed: surfaceDeployed,
|
|
924
|
-
recipients: surfaceRecipients,
|
|
925
|
-
sinceCount: surfaceRenderedCount,
|
|
926
|
-
originMap: commsOriginMap,
|
|
927
|
-
requestTimeoutMs
|
|
928
|
-
});
|
|
929
|
-
if (refreshed.rendered)
|
|
930
|
-
surfaceRenderedCount = refreshed.count;
|
|
931
|
-
}
|
|
932
|
-
catch {
|
|
933
|
-
// Never throw into the render loop; the teardown drain + by-id teardown must still run.
|
|
934
|
-
}
|
|
935
|
-
if (proberDisposed)
|
|
936
|
-
break;
|
|
937
|
-
await new Promise((resolve) => {
|
|
938
|
-
const timer = setTimeout(resolve, surfaceCadenceMs);
|
|
939
|
-
void disposeSignal.then(() => { clearTimeout(timer); resolve(); });
|
|
940
|
-
});
|
|
941
|
-
if (proberDisposed)
|
|
942
|
-
break;
|
|
943
|
-
}
|
|
944
|
-
})();
|
|
945
|
-
}
|
|
946
|
-
// Baseline state snapshot, then start the background cadence prober.
|
|
947
|
-
await proberSnapshot();
|
|
948
|
-
if (options.onObserverReady) {
|
|
949
|
-
const inProgressPlaneCommit = localTreeRoute ? localTreeArchive?.git?.commit : subjectCommit;
|
|
950
|
-
const inProgressSubject = buildSubjectProvenance({
|
|
951
|
-
localTreeRoute,
|
|
952
|
-
publicRepo,
|
|
953
|
-
subjectCommit: inProgressPlaneCommit,
|
|
954
|
-
localTreeArchive,
|
|
955
|
-
subjectEnvNames,
|
|
956
|
-
state: resolveSubjectState({ declared: config.subject.state, dryRun: false, executed: stateStepRecords })
|
|
957
|
-
});
|
|
958
|
-
const inProgressBundle = buildConcurrentSharedWorldBundle({
|
|
959
|
-
config,
|
|
960
|
-
descriptor,
|
|
961
|
-
createdAt,
|
|
962
|
-
dryRun: false,
|
|
963
|
-
inProgress: true,
|
|
964
|
-
runId,
|
|
965
|
-
source,
|
|
966
|
-
roles,
|
|
967
|
-
actorSpecs,
|
|
968
|
-
actorResults: [],
|
|
969
|
-
stateSnapshots,
|
|
970
|
-
subject: inProgressSubject,
|
|
971
|
-
seedDigest,
|
|
972
|
-
...(inProgressPlaneCommit === undefined ? {} : { subjectCommit: inProgressPlaneCommit }),
|
|
973
|
-
hostDigest: hostOriginDigest(getHostUrl)
|
|
974
|
-
});
|
|
975
|
-
await writeConcurrentRunArtifacts(inProgressBundle, runPaths);
|
|
976
|
-
liveObserver = observerResultForConcurrentArtifacts(cwd, runId, artifactRoot, [
|
|
977
|
-
"Live concurrent shared-world Observer is attached before final verification; stream auth URLs are runtime-only and are not persisted."
|
|
978
|
-
]);
|
|
979
|
-
await options.onObserverReady(liveObserver);
|
|
980
|
-
}
|
|
981
|
-
proberLoop = (async () => {
|
|
982
|
-
while (!proberDisposed) {
|
|
983
|
-
let timer;
|
|
984
|
-
await Promise.race([
|
|
985
|
-
new Promise((resolve) => { timer = setTimeout(resolve, proberCadenceMs); }),
|
|
986
|
-
disposeSignal
|
|
987
|
-
]);
|
|
988
|
-
if (timer)
|
|
989
|
-
clearTimeout(timer); // FIX-9: no dangling prober timer.
|
|
990
|
-
if (proberDisposed)
|
|
991
|
-
break;
|
|
992
|
-
await proberSnapshot().catch(() => undefined);
|
|
993
|
-
}
|
|
994
|
-
})();
|
|
995
|
-
// Launch N actor sandboxes CONCURRENTLY, INDEPENDENT (FIX-11: runCuaLane + mapWithConcurrency,
|
|
996
|
-
// NOT runCuaLanes — no pipeline gate / fail-fast). Each actor's window is measured on the ONE
|
|
997
|
-
// orchestrator clock (FIX-1). cloneRoute=false + subjectEnvNames=[] keep subject creds out of
|
|
998
|
-
// every actor sandbox (FIX-10).
|
|
999
|
-
const cuaHooks = {
|
|
1000
|
-
...(hooks.loadDesktopModule ? { loadDesktopModule: hooks.loadDesktopModule } : {}),
|
|
1001
|
-
...(hooks.detachedTimers ? { detachedTimers: hooks.detachedTimers } : {}),
|
|
1002
|
-
...(hooks.env ? { env: hooks.env } : {}),
|
|
1003
|
-
...(hooks.prepareDesktop ? { prepareDesktop: (desktop) => hooks.prepareDesktop(desktop) } : {}),
|
|
1004
|
-
onRuntimeStreamReady: (stream) => {
|
|
1005
|
-
runtimeStreamUrls.push({ streamId: stream.streamId, url: stream.url });
|
|
1006
|
-
if (liveObserver) {
|
|
1007
|
-
attachObserverRuntimeStreamUrls(liveObserver, runtimeStreamUrls);
|
|
1008
|
-
}
|
|
1009
|
-
},
|
|
1010
|
-
onRuntimeStreamEnded: (stream) => {
|
|
1011
|
-
// Mark, never remove (#357): the tile falls back to recorded evidence and says why.
|
|
1012
|
-
for (const entry of runtimeStreamUrls) {
|
|
1013
|
-
if (entry.streamId === stream.streamId)
|
|
1014
|
-
entry.ended = true;
|
|
1015
|
-
}
|
|
1016
|
-
if (liveObserver) {
|
|
1017
|
-
attachObserverRuntimeStreamUrls(liveObserver, runtimeStreamUrls);
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
};
|
|
1021
|
-
const baseActorDeps = {
|
|
1022
|
-
config,
|
|
1023
|
-
descriptor,
|
|
1024
|
-
cloneRoute: false,
|
|
1025
|
-
subjectEnvNames: [],
|
|
1026
|
-
hasGithubToken: false,
|
|
1027
|
-
env,
|
|
1028
|
-
openaiApiKey,
|
|
1029
|
-
e2bApiKey,
|
|
1030
|
-
requestTimeoutMs,
|
|
1031
|
-
perLaneSandboxMs: timeoutMs + SANDBOX_TIMEOUT_BUFFER_MS,
|
|
1032
|
-
timeoutMs,
|
|
1033
|
-
laneCount: roles.length,
|
|
1034
|
-
artifactRoot: runPaths,
|
|
1035
|
-
labCwd: cwd,
|
|
1036
|
-
redactScreenshots,
|
|
1037
|
-
scrubKnownValues,
|
|
1038
|
-
runSession,
|
|
1039
|
-
...(receiving ? { receiving } : {}),
|
|
1040
|
-
now,
|
|
1041
|
-
hooks: cuaHooks,
|
|
1042
|
-
...(runBudget === undefined ? {} : { runBudget }),
|
|
1043
|
-
// Concurrent lanes are independent evidence seats: a requested-vs-verified screen
|
|
1044
|
-
// mismatch is recorded as separate facts + a warning instead of failing the lane's
|
|
1045
|
-
// device claim closed, so one seat's window-manager drift cannot abort the whole
|
|
1046
|
-
// live multi-actor world (the single-lane/fan-out routes keep fail-closed).
|
|
1047
|
-
screenMismatchPolicy: "record-evidence"
|
|
1048
|
-
};
|
|
1049
|
-
actorResults = await mapWithConcurrency(actorSpecs, Math.max(1, concurrency), async (spec, i) => {
|
|
1050
|
-
const route = resolveActorSeatUrl(getHostUrl, roles[i]?.entry);
|
|
1051
|
-
// Tell this persona its (getHost-reachable) inbox URL — but only when comms is live AND this lane
|
|
1052
|
-
// has a declared recipient it can actually receive mail into (else it would stall on an empty
|
|
1053
|
-
// inbox). Only the in-sandbox catch exists on this plane; the adopter-hosted catch is the
|
|
1054
|
-
// external-public plane's, wired in ITS execution block below (#387).
|
|
1055
|
-
const laneSpec = commsEmail && commsInboxUrl && laneHasInboxRecipient(commsEmail, spec.laneId)
|
|
1056
|
-
? withInboxMission(spec, commsInboxUrl, inboxRecipientFor(commsEmail, spec.laneId)?.address)
|
|
1057
|
-
: spec;
|
|
1058
|
-
const startedAt = now();
|
|
1059
|
-
const outcome = await runCuaLane(laneSpec, { ...baseActorDeps, appUrl: route });
|
|
1060
|
-
const endedAt = now();
|
|
1061
|
-
return { spec, outcome, startedAt, endedAt, route };
|
|
1062
|
-
});
|
|
1063
|
-
}
|
|
1064
|
-
catch (error) {
|
|
1065
|
-
runError = redactText(scrubKnownValues(toErrorMessage(error)));
|
|
1066
|
-
warnings.push(`Concurrent shared-world run failed before completion: ${runError}`);
|
|
1067
|
-
}
|
|
1068
|
-
finally {
|
|
1069
|
-
// FIX-9: stop the prober, take a final snapshot while the subject is still alive, then tear
|
|
1070
|
-
// down the ONE subject sandbox BY id (the actor sandboxes are torn down inside runCuaLane).
|
|
1071
|
-
proberDisposed = true;
|
|
1072
|
-
releaseDispose();
|
|
1073
|
-
if (proberLoop) {
|
|
1074
|
-
await proberLoop.catch(() => undefined);
|
|
1075
|
-
}
|
|
1076
|
-
// Stop the inbox-surface render loop too (shares the prober's dispose signal), before the teardown
|
|
1077
|
-
// evidence drain below — so the two in-sandbox reads never overlap and the surface state is final.
|
|
1078
|
-
if (surfaceLoop) {
|
|
1079
|
-
await surfaceLoop.catch(() => undefined);
|
|
1080
|
-
}
|
|
1081
|
-
if (subjectDesktop && getHostUrl) {
|
|
1082
|
-
await proberSnapshot().catch(() => undefined);
|
|
1083
|
-
}
|
|
1084
|
-
// Off-app comms evidence (#297): drain everything the in-sandbox catch captured, route it into a
|
|
1085
|
-
// host fake inbox addressed to the declared recipients, and write the run-level digest-only thread
|
|
1086
|
-
// artifact — while the subject is STILL alive, before it is killed below. Wrapped so a drain error
|
|
1087
|
-
// never blocks teardown (invariant: all sandboxes torn down by id in this finally).
|
|
1088
|
-
if (commsEmail && deployedComms?.ready && subjectDesktop) {
|
|
1089
|
-
try {
|
|
1090
|
-
const commsChannel = new FakeInbox();
|
|
1091
|
-
const commsInboxes = [];
|
|
1092
|
-
for (const recipient of commsEmail.recipients ?? []) {
|
|
1093
|
-
if (recipient.address !== undefined) {
|
|
1094
|
-
commsInboxes.push(await commsChannel.provisionAddress(recipient.lane, recipient.address));
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
const collected = await collectCommsThread({
|
|
1098
|
-
desktop: subjectDesktop,
|
|
1099
|
-
deployed: deployedComms,
|
|
1100
|
-
channel: commsChannel,
|
|
1101
|
-
inboxes: commsInboxes,
|
|
1102
|
-
requestTimeoutMs
|
|
1103
|
-
});
|
|
1104
|
-
if (collected.artifact) {
|
|
1105
|
-
await writeContainedOutputFile(runPaths, "comms/thread.json", `${JSON.stringify(collected.artifact, null, 2)}\n`, "utf8");
|
|
1106
|
-
commsArtifactPath = "comms/thread.json";
|
|
1107
|
-
}
|
|
1108
|
-
else if (collected.captured > 0) {
|
|
1109
|
-
warnings.push(`Comms catch captured ${collected.captured} email send(s) but none matched a declared recipient inbox — no comms evidence written. Declare comms.email.recipients[].address to match the address the app sends to.`);
|
|
1110
|
-
}
|
|
1111
|
-
else {
|
|
1112
|
-
// Zero captures is the silent-broken shape (#351): the app never posted to the catch.
|
|
1113
|
-
warnings.push(`Comms catch captured ZERO email sends — the app never delivered mail through the catch. Verify the app reads ${commsEmail.injectEnv} for its email API base URL (an SDK that ignores it sends real mail or throws) and that the flow reached an email step.`);
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
catch (error) {
|
|
1117
|
-
warnings.push(`Comms evidence collection failed (run continues; subject still torn down): ${redactText(scrubKnownValues(toErrorMessage(error)))}`);
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
if (subjectDesktop && subjectModule) {
|
|
1121
|
-
if (typeof subjectModule.Sandbox.kill === "function") {
|
|
1122
|
-
try {
|
|
1123
|
-
await subjectModule.Sandbox.kill(subjectDesktop.sandboxId, { requestTimeoutMs: 60_000 });
|
|
1124
|
-
subjectKilled = true;
|
|
1125
|
-
}
|
|
1126
|
-
catch (error) {
|
|
1127
|
-
warnings.push(`Subject sandbox teardown failed (server-side kill-on-timeout will reclaim it): ${redactText(scrubKnownValues(toErrorMessage(error)))}`);
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
else {
|
|
1131
|
-
warnings.push("Installed @e2b/desktop SDK does not expose Sandbox.kill; server-side kill-on-timeout will reclaim the subject sandbox.");
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
// EXTERNAL-PUBLIC plane (#164 phase 2): NO subject sandbox, NO getHost, NO prober. The shared plane
|
|
1137
|
-
// is the operator-declared public deployment (publicAppUrl); each seat opens it directly and reaches
|
|
1138
|
-
// the shared session through the real UI. A host-first barrier extracts the /lobby/CODE from the host
|
|
1139
|
-
// seat's CDP-observed URL (onObservedUrl) and threads it into the follower missions; a follower fails
|
|
1140
|
-
// closed WITHOUT opening if the host never yields a code within the handoff deadline.
|
|
1141
|
-
if (!dryRun && planeClass === "external-public") {
|
|
1142
|
-
const cuaHooks = {
|
|
1143
|
-
...(hooks.loadDesktopModule ? { loadDesktopModule: hooks.loadDesktopModule } : {}),
|
|
1144
|
-
...(hooks.detachedTimers ? { detachedTimers: hooks.detachedTimers } : {}),
|
|
1145
|
-
...(hooks.env ? { env: hooks.env } : {}),
|
|
1146
|
-
...(hooks.prepareDesktop ? { prepareDesktop: (desktop) => hooks.prepareDesktop(desktop) } : {}),
|
|
1147
|
-
onRuntimeStreamReady: (stream) => {
|
|
1148
|
-
runtimeStreamUrls.push({ streamId: stream.streamId, url: stream.url });
|
|
1149
|
-
if (liveObserver) {
|
|
1150
|
-
attachObserverRuntimeStreamUrls(liveObserver, runtimeStreamUrls);
|
|
1151
|
-
}
|
|
1152
|
-
},
|
|
1153
|
-
onRuntimeStreamEnded: (stream) => {
|
|
1154
|
-
// Mark, never remove (#357): the tile falls back to recorded evidence and says why.
|
|
1155
|
-
for (const entry of runtimeStreamUrls) {
|
|
1156
|
-
if (entry.streamId === stream.streamId)
|
|
1157
|
-
entry.ended = true;
|
|
1158
|
-
}
|
|
1159
|
-
if (liveObserver) {
|
|
1160
|
-
attachObserverRuntimeStreamUrls(liveObserver, runtimeStreamUrls);
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
};
|
|
1164
|
-
const baseActorDeps = {
|
|
1165
|
-
config,
|
|
1166
|
-
descriptor,
|
|
1167
|
-
cloneRoute: false,
|
|
1168
|
-
subjectEnvNames: [],
|
|
1169
|
-
hasGithubToken: false,
|
|
1170
|
-
env,
|
|
1171
|
-
openaiApiKey,
|
|
1172
|
-
e2bApiKey,
|
|
1173
|
-
requestTimeoutMs,
|
|
1174
|
-
perLaneSandboxMs: timeoutMs + SANDBOX_TIMEOUT_BUFFER_MS,
|
|
1175
|
-
timeoutMs,
|
|
1176
|
-
laneCount: roles.length,
|
|
1177
|
-
artifactRoot: runPaths,
|
|
1178
|
-
labCwd: cwd,
|
|
1179
|
-
redactScreenshots,
|
|
1180
|
-
// Scrub the latched lobby CODE (known once the host resolves it) from ALL narration.
|
|
1181
|
-
scrubKnownValues: scrubKnownValuesWithLobbyCode,
|
|
1182
|
-
runSession,
|
|
1183
|
-
...(receiving ? { receiving } : {}),
|
|
1184
|
-
now,
|
|
1185
|
-
hooks: cuaHooks,
|
|
1186
|
-
...(runBudget === undefined ? {} : { runBudget }),
|
|
1187
|
-
screenMismatchPolicy: "record-evidence"
|
|
1188
|
-
};
|
|
1189
|
-
// Publish an attached live Observer BEFORE fan-out (mirrors the provisioned path).
|
|
1190
|
-
if (options.onObserverReady) {
|
|
1191
|
-
const inProgressBundle = buildConcurrentSharedWorldBundle({
|
|
1192
|
-
config,
|
|
1193
|
-
descriptor,
|
|
1194
|
-
createdAt,
|
|
1195
|
-
dryRun: false,
|
|
1196
|
-
inProgress: true,
|
|
1197
|
-
runId,
|
|
1198
|
-
source,
|
|
1199
|
-
roles,
|
|
1200
|
-
actorSpecs,
|
|
1201
|
-
actorResults: [],
|
|
1202
|
-
stateSnapshots: [],
|
|
1203
|
-
subject: { source: "app-url", envNames: [], state: { provenance: "external-public" } },
|
|
1204
|
-
seedDigest,
|
|
1205
|
-
planeClass: "external-public",
|
|
1206
|
-
// Pre-fan-out snapshot: no seat has observed an origin yet, so the OBSERVED publicOriginDigest
|
|
1207
|
-
// is not available; surface the DECLARED origin for the live Observer's reference.
|
|
1208
|
-
...(declaredOriginDigest === undefined ? {} : { declaredOriginDigest })
|
|
1209
|
-
});
|
|
1210
|
-
await writeConcurrentRunArtifacts(inProgressBundle, runPaths);
|
|
1211
|
-
liveObserver = observerResultForConcurrentArtifacts(cwd, runId, artifactRoot, [
|
|
1212
|
-
"Live external-public concurrent shared-world Observer is attached before final verification; stream auth URLs are runtime-only and are not persisted."
|
|
1213
|
-
]);
|
|
1214
|
-
await options.onObserverReady(liveObserver);
|
|
1215
|
-
}
|
|
1216
|
-
// The host-first handoff barrier.
|
|
1217
|
-
//
|
|
1218
|
-
// TEMPORARY SHIM (tracked by #296): this CDP URL-relay handoff — reading the host's /lobby/CODE off
|
|
1219
|
-
// its own browser and threading it into the follower missions — is a temporary coordination shim.
|
|
1220
|
-
// It is to be augmented/replaced by the actor message bus (fake SMS/email invite) in #297: the
|
|
1221
|
-
// human-realistic version is the HOST SENDING the invite link and followers RECEIVING and tapping
|
|
1222
|
-
// it, rather than the orchestrator relaying the code out-of-band.
|
|
1223
|
-
const lobbyCodeLatch = deferred();
|
|
1224
|
-
const handoffDeadlineMs = hooks.handoffDeadlineMs
|
|
1225
|
-
?? Math.min(timeoutMs, Math.max(DEFAULT_HANDOFF_DEADLINE_MS, Math.floor(timeoutMs * HANDOFF_DEADLINE_BUDGET_FRACTION)));
|
|
1226
|
-
let deadlineTimer;
|
|
1227
|
-
const deadline = new Promise((_resolve, reject) => {
|
|
1228
|
-
deadlineTimer = setTimeout(() => reject(new HandoffTimeoutError(handoffDeadlineMs)), handoffDeadlineMs);
|
|
1229
|
-
});
|
|
1230
|
-
deadline.catch(() => undefined); // never an unhandled rejection
|
|
1231
|
-
// Resolve the host->follower handoff latch from WHICHEVER path sees the code first (CDP url-read,
|
|
1232
|
-
// host narration, or vision-off-frame). Idempotent: only the first code wins, and it is also stashed
|
|
1233
|
-
// as latchedLobbyCode so it gets scrubbed from any later narration. The latched code and observed URLs
|
|
1234
|
-
// are runtime-only and land in persisted METADATA only as digests (origin + convergence). (The code
|
|
1235
|
-
// is a shareable game code, not a secret, and it still renders in the host's screenshots, which are
|
|
1236
|
-
// full-fidelity unless redactScreenshots is set — the digesting is about narration/URL metadata.)
|
|
1237
|
-
const latchLobbyCode = (code, laneIndex) => {
|
|
1238
|
-
if (latchedLobbyCode !== undefined)
|
|
1239
|
-
return;
|
|
1240
|
-
observedLobbyCodes[laneIndex] = code;
|
|
1241
|
-
latchedLobbyCode = code;
|
|
1242
|
-
if (deadlineTimer) {
|
|
1243
|
-
clearTimeout(deadlineTimer);
|
|
1244
|
-
deadlineTimer = undefined;
|
|
1245
|
-
}
|
|
1246
|
-
lobbyCodeLatch.resolve(code);
|
|
1247
|
-
};
|
|
1248
|
-
// Build an onScreenshot handler that vision-reads the lobby code off THIS seat's own frame (the
|
|
1249
|
-
// CDP-independent observation). `done()` short-circuits once this seat has what it needs (the host
|
|
1250
|
-
// once latched; a follower once it has recorded its own observed code), `onCode` records/latches the
|
|
1251
|
-
// result. One read in flight at a time, bounded by MAX_LOBBY_CODE_VISION_READS so a seat that never
|
|
1252
|
-
// reaches a lobby can't rack up unbounded calls (fire-and-forget; the loop never awaits it).
|
|
1253
|
-
const makeLobbyCodeVisionReader = (done, onCode) => {
|
|
1254
|
-
let inFlight = false;
|
|
1255
|
-
let reads = 0;
|
|
1256
|
-
return (frame) => {
|
|
1257
|
-
if (done() || inFlight || reads >= MAX_LOBBY_CODE_VISION_READS)
|
|
1258
|
-
return;
|
|
1259
|
-
inFlight = true;
|
|
1260
|
-
reads += 1;
|
|
1261
|
-
void readLobbyCode(frame, openaiApiKey)
|
|
1262
|
-
.then((code) => {
|
|
1263
|
-
if (code !== undefined && !done())
|
|
1264
|
-
onCode(code);
|
|
1265
|
-
})
|
|
1266
|
-
.catch(() => undefined)
|
|
1267
|
-
.finally(() => {
|
|
1268
|
-
inFlight = false;
|
|
1269
|
-
});
|
|
1270
|
-
};
|
|
1271
|
-
};
|
|
1272
|
-
const makeLaneObservedUrl = (laneIndex, isHost) => (url) => {
|
|
1273
|
-
if (typeof url !== "string" || url.length === 0)
|
|
1274
|
-
return;
|
|
1275
|
-
observedFinalUrls[laneIndex] = url; // runtime-only; digested to origin, never persisted raw
|
|
1276
|
-
const code = extractLobbyCode(url);
|
|
1277
|
-
if (code !== undefined) {
|
|
1278
|
-
observedLobbyCodes[laneIndex] = code;
|
|
1279
|
-
if (isHost)
|
|
1280
|
-
latchLobbyCode(code, laneIndex);
|
|
1281
|
-
}
|
|
1282
|
-
};
|
|
1283
|
-
// The HOST lane (which yields the /lobby/CODE the followers wait on) runs on its OWN dedicated
|
|
1284
|
-
// slot, and the FOLLOWERS run through a bounded pool of size concurrency-1 (blockers 1 & 4):
|
|
1285
|
-
// followers block on `Promise.race([lobbyCodeLatch.promise, deadline])` while holding a worker
|
|
1286
|
-
// slot, so if the host lane were scheduled INSIDE the same bounded pool it could be starved (never
|
|
1287
|
-
// scheduled among the first `concurrency` workers) and the run would die with a spurious
|
|
1288
|
-
// HANDOFF_TIMEOUT (e.g. lanes [p2,p3,host] with concurrency 2). Giving the host its own slot,
|
|
1289
|
-
// started IMMEDIATELY and OUTSIDE the follower pool, guarantees it is ALWAYS schedulable regardless
|
|
1290
|
-
// of its roster position or of concurrency vs lane count — while total in-flight paid desktops stay
|
|
1291
|
-
// ≤ the declared concurrency (host + up to concurrency-1 followers), preserving the spend cap.
|
|
1292
|
-
const runHostLane = async (spec, laneIndex) => {
|
|
1293
|
-
const onObservedUrl = makeLaneObservedUrl(laneIndex, true);
|
|
1294
|
-
// CDP-INDEPENDENT handoff paths (the E2B-desktop CDP url-read the onObservedUrl path relies on is
|
|
1295
|
-
// unreliable in practice). Two backups, both resolving the SAME latch; whichever sees the code first
|
|
1296
|
-
// wins, all digest-only:
|
|
1297
|
-
// (1) onMessage — scan the host's own narration IF it happens to state the lobby URL; and
|
|
1298
|
-
// (2) onScreenshot — vision-read the code straight off the host's waiting-room frame. This is the
|
|
1299
|
-
// robust one: the code is rendered on screen even when CDP fails AND when the host never
|
|
1300
|
-
// narrates it, and — crucially — the host is NOT asked to announce anything, so it keeps
|
|
1301
|
-
// running (create -> wait for players -> Start -> play) instead of ending on a stray message.
|
|
1302
|
-
const onMessage = (text) => {
|
|
1303
|
-
if (latchedLobbyCode !== undefined)
|
|
1304
|
-
return;
|
|
1305
|
-
const code = extractLobbyCodeFromNarration(text);
|
|
1306
|
-
if (code !== undefined)
|
|
1307
|
-
latchLobbyCode(code, laneIndex);
|
|
1308
|
-
};
|
|
1309
|
-
// Vision-read the host's waiting-room frame and LATCH the code for the followers (stops once latched).
|
|
1310
|
-
const onScreenshot = makeLobbyCodeVisionReader(() => latchedLobbyCode !== undefined, (code) => latchLobbyCode(code, laneIndex));
|
|
1311
|
-
// The host's job includes a long LEGITIMATE idle wait — sitting in the waiting room while the
|
|
1312
|
-
// followers provision their own desktops and walk the Join flow (easily 15-30 turns of an
|
|
1313
|
-
// unchanging "waiting for players" screen). At the default idle backstop (6) the host would give up
|
|
1314
|
-
// before anyone arrives, orphaning the lobby (exactly the earlier failure). Raise the host's idle /
|
|
1315
|
-
// no-progress tolerance so it waits patiently; the per-seat timeout still bounds a truly stuck host.
|
|
1316
|
-
// Adopter-hosted inbox (#387): the persona is told its address and inbox URL on THIS plane —
|
|
1317
|
-
// previously only the provisioned plane's seats ever got the instruction, so external comms
|
|
1318
|
-
// ran on no route at all.
|
|
1319
|
-
const hostInboxSpec = externalCommsEmail && commsInboxUrl && laneHasInboxRecipient(externalCommsEmail, spec.laneId)
|
|
1320
|
-
? withInboxMission(spec, commsInboxUrl, inboxRecipientFor(externalCommsEmail, spec.laneId)?.address)
|
|
1321
|
-
: spec;
|
|
1322
|
-
const hostSpec = {
|
|
1323
|
-
...hostInboxSpec,
|
|
1324
|
-
idleSteps: spec.idleSteps ?? HOST_WAIT_IDLE_STEPS,
|
|
1325
|
-
noProgressSteps: spec.noProgressSteps ?? HOST_WAIT_IDLE_STEPS
|
|
1326
|
-
};
|
|
1327
|
-
const startedAt = now();
|
|
1328
|
-
let outcome;
|
|
1329
|
-
try {
|
|
1330
|
-
outcome = await runCuaLane(hostSpec, { ...baseActorDeps, appUrl: publicAppUrl, onObservedUrl, onMessage, onScreenshot });
|
|
1331
|
-
}
|
|
1332
|
-
finally {
|
|
1333
|
-
// If the host finished without ever surfacing a code, release followers to fail closed
|
|
1334
|
-
// immediately rather than wait the full deadline (a no-op if it already resolved).
|
|
1335
|
-
if (!lobbyCodeLatch.settled()) {
|
|
1336
|
-
const reason = outcome?.sessionError ?? outcome?.session?.reason ?? "no terminal host outcome was recorded";
|
|
1337
|
-
hostHandoffFailure = scrubKnownValuesWithLobbyCode(`Host seat ended before producing a lobby URL: ${reason}`);
|
|
1338
|
-
lobbyCodeLatch.reject(new Error(hostHandoffFailure));
|
|
1339
|
-
}
|
|
1340
|
-
}
|
|
1341
|
-
const endedAt = now();
|
|
1342
|
-
return { spec, outcome, startedAt, endedAt, route: observedFinalUrls[laneIndex] ?? publicAppUrl };
|
|
1343
|
-
};
|
|
1344
|
-
const runFollowerLane = async (spec, laneIndex) => {
|
|
1345
|
-
const onObservedUrl = makeLaneObservedUrl(laneIndex, false);
|
|
1346
|
-
// FOLLOWER: do NOT compose a mission or open the target until the host yields a lobby code.
|
|
1347
|
-
let code;
|
|
1348
|
-
try {
|
|
1349
|
-
code = await Promise.race([lobbyCodeLatch.promise, deadline]);
|
|
1350
|
-
}
|
|
1351
|
-
catch (error) {
|
|
1352
|
-
// An ended host is not a deadline expiry. Preserve its actual failure.
|
|
1353
|
-
const timedOut = error instanceof HandoffTimeoutError;
|
|
1354
|
-
handoffTimedOut ||= timedOut;
|
|
1355
|
-
const reason = scrubKnownValuesWithLobbyCode(toErrorMessage(error));
|
|
1356
|
-
const at = now();
|
|
1357
|
-
return { spec, outcome: makeBlockedFollowerOutcome(spec, reason, timedOut), startedAt: at, endedAt: at, route: publicAppUrl };
|
|
1358
|
-
}
|
|
1359
|
-
// Followers also idle-wait — in the waiting room until the host starts, and between rounds. Raise
|
|
1360
|
-
// their idle backstop too (less than the host's: they wait less), so a follower that joins ahead of
|
|
1361
|
-
// the other does not give up before the game begins. Per-seat timeout still bounds a stuck follower.
|
|
1362
|
-
const followerInboxSpec = externalCommsEmail && commsInboxUrl && laneHasInboxRecipient(externalCommsEmail, spec.laneId)
|
|
1363
|
-
? withInboxMission(spec, commsInboxUrl, inboxRecipientFor(externalCommsEmail, spec.laneId)?.address)
|
|
1364
|
-
: spec;
|
|
1365
|
-
const followerSpec = {
|
|
1366
|
-
...withLobbyCodeMission(followerInboxSpec, code),
|
|
1367
|
-
idleSteps: spec.idleSteps ?? FOLLOWER_WAIT_IDLE_STEPS,
|
|
1368
|
-
noProgressSteps: spec.noProgressSteps ?? FOLLOWER_WAIT_IDLE_STEPS
|
|
1369
|
-
};
|
|
1370
|
-
// Independently OBSERVE this follower's own lobby code by vision-reading its waiting-room frame,
|
|
1371
|
-
// and record it for the cross-seat convergence proof. This does NOT latch anything (followers gate
|
|
1372
|
-
// on the HOST's code, not their own) — it just fills this seat's observedLobbyCodes slot from a
|
|
1373
|
-
// reliable signal instead of the flaky CDP url-read, so lobbyConvergenceDigest can prove all seats
|
|
1374
|
-
// reached the SAME /lobby/CODE. If a follower somehow joined a DIFFERENT lobby, it reads a different
|
|
1375
|
-
// code and convergence correctly fails (no false proof); if it never reads one, the seat stays a
|
|
1376
|
-
// hole and convergence is honestly "not observed" for that seat.
|
|
1377
|
-
const onScreenshot = makeLobbyCodeVisionReader(() => observedLobbyCodes[laneIndex] !== undefined, (observed) => { observedLobbyCodes[laneIndex] = observed; });
|
|
1378
|
-
const startedAt = now();
|
|
1379
|
-
const outcome = await runCuaLane(followerSpec, { ...baseActorDeps, appUrl: publicAppUrl, onObservedUrl, onScreenshot });
|
|
1380
|
-
const endedAt = now();
|
|
1381
|
-
return { spec, outcome, startedAt, endedAt, route: observedFinalUrls[laneIndex] ?? publicAppUrl };
|
|
1382
|
-
};
|
|
1383
|
-
// Split the roster into the designated host lane and the followers, preserving each follower's
|
|
1384
|
-
// ORIGINAL lane index so results land back in lane order (validation guarantees EXACTLY ONE host).
|
|
1385
|
-
const hostLaneIndex = roles.findIndex((role) => role.host === true);
|
|
1386
|
-
const followerEntries = actorSpecs
|
|
1387
|
-
.map((spec, index) => ({ spec, index }))
|
|
1388
|
-
.filter(({ index }) => index !== hostLaneIndex);
|
|
1389
|
-
const laneResults = new Array(actorSpecs.length);
|
|
1390
|
-
try {
|
|
1391
|
-
const hostPromise = hostLaneIndex >= 0 && actorSpecs[hostLaneIndex] !== undefined
|
|
1392
|
-
? runHostLane(actorSpecs[hostLaneIndex], hostLaneIndex)
|
|
1393
|
-
: undefined;
|
|
1394
|
-
const followerResultsPromise = mapWithConcurrency(followerEntries, Math.max(1, concurrency - 1), ({ spec, index }) => runFollowerLane(spec, index));
|
|
1395
|
-
const [hostResult, followerResults] = await Promise.all([hostPromise, followerResultsPromise]);
|
|
1396
|
-
if (hostResult !== undefined && hostLaneIndex >= 0) {
|
|
1397
|
-
laneResults[hostLaneIndex] = hostResult;
|
|
1398
|
-
}
|
|
1399
|
-
followerEntries.forEach((entry, i) => { laneResults[entry.index] = followerResults[i]; });
|
|
1400
|
-
actorResults = laneResults;
|
|
1401
|
-
}
|
|
1402
|
-
catch (error) {
|
|
1403
|
-
runError = redactText(scrubKnownValuesWithLobbyCode(toErrorMessage(error)));
|
|
1404
|
-
warnings.push(`External-public concurrent shared-world run failed before completion: ${runError}`);
|
|
1405
|
-
}
|
|
1406
|
-
finally {
|
|
1407
|
-
if (deadlineTimer) {
|
|
1408
|
-
clearTimeout(deadlineTimer);
|
|
1409
|
-
deadlineTimer = undefined;
|
|
1410
|
-
}
|
|
1411
|
-
// Adopter-hosted drain (#328/#387): same routing and digest-only artifact as the in-sandbox
|
|
1412
|
-
// catch — only the transport differs (HTTP GET /deliveries against the catch the operator
|
|
1413
|
-
// runs). In the finally so the evidence survives a failed run; a drain error never masks
|
|
1414
|
-
// the run's own outcome.
|
|
1415
|
-
if (externalComms && externalCommsEmail) {
|
|
1416
|
-
try {
|
|
1417
|
-
const commsChannel = new FakeInbox();
|
|
1418
|
-
const commsInboxes = [];
|
|
1419
|
-
for (const recipient of externalCommsEmail.recipients ?? []) {
|
|
1420
|
-
if (recipient.address !== undefined) {
|
|
1421
|
-
commsInboxes.push(await commsChannel.provisionAddress(recipient.lane, recipient.address));
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
const authToken = externalComms.authTokenEnv === undefined ? undefined : env[externalComms.authTokenEnv];
|
|
1425
|
-
const collected = await collectExternalCommsThread({
|
|
1426
|
-
external: { ...externalComms, ...(authToken === undefined ? {} : { authToken }) },
|
|
1427
|
-
channel: commsChannel,
|
|
1428
|
-
inboxes: commsInboxes
|
|
1429
|
-
});
|
|
1430
|
-
if (collected.artifact) {
|
|
1431
|
-
const path = "comms/thread.json";
|
|
1432
|
-
await writeContainedOutputFile(runPaths, path, `${JSON.stringify(collected.artifact, null, 2)}\n`, "utf8");
|
|
1433
|
-
commsArtifactPath = path;
|
|
1434
|
-
}
|
|
1435
|
-
else if (collected.captured > 0) {
|
|
1436
|
-
warnings.push(`Comms catch captured ${collected.captured} email send(s) but none matched a declared recipient inbox — no comms evidence written. Declare comms.email.recipients[].address to match the address the app sends to.`);
|
|
1437
|
-
}
|
|
1438
|
-
else {
|
|
1439
|
-
warnings.push(`Comms catch captured ZERO email sends — your app never delivered mail through the catch at ${externalComms.catchBaseUrl}. Verify the app's email-API base URL points at it and that the flow reached an email step.`);
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
catch (error) {
|
|
1443
|
-
warnings.push(`Comms evidence collection failed against the adopter-hosted catch (run continues): ${redactText(toErrorMessage(error))}`);
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
// Observed-origin convergence proof (blocker 2): the convergence claim is about what the seats
|
|
1448
|
-
// OBSERVED, not what was DECLARED. Digest each observing seat's origin and require they AGREE on
|
|
1449
|
-
// ONE — that agreement IS the convergence proof and becomes plane.publicOriginDigest. A normal
|
|
1450
|
-
// cross-origin redirect (declared apex -> observed www) is therefore tolerated: the seats still
|
|
1451
|
-
// converge on ONE observed origin. Leave it undefined (verify fails closed) only if the seats did
|
|
1452
|
-
// not converge on a single observed origin (or none observed one).
|
|
1453
|
-
const observedOriginDigests = observedFinalUrls
|
|
1454
|
-
.filter((url) => typeof url === "string" && url.length > 0)
|
|
1455
|
-
.map((url) => hostOriginDigest(url));
|
|
1456
|
-
const distinctObservedOrigins = new Set(observedOriginDigests);
|
|
1457
|
-
publicOriginDigest = distinctObservedOrigins.size === 1
|
|
1458
|
-
? [...distinctObservedOrigins][0]
|
|
1459
|
-
// NOTHING observed (e.g. a handoff-timeout run where no seat ever navigated): fall back to the
|
|
1460
|
-
// DECLARED origin so a FAILED run's bundle stays structurally valid (every seat's route then
|
|
1461
|
-
// digests to the declared origin too). The run still fails closed for its own reason (HANDOFF_
|
|
1462
|
-
// TIMEOUT / no lobby convergence / no overlap-on-pass). GENUINE divergence (≥2 distinct observed
|
|
1463
|
-
// origins) leaves it undefined so verify fails closed on the non-convergence.
|
|
1464
|
-
: distinctObservedOrigins.size === 0
|
|
1465
|
-
? declaredOriginDigest
|
|
1466
|
-
: undefined;
|
|
1467
|
-
// Lobby-convergence proof: a digest of the shared /lobby/CODE path iff EVERY seat converged on the
|
|
1468
|
-
// SAME code (a follower stuck on "/" yields no code → no false convergence). Digest-only. NOTE:
|
|
1469
|
-
// observedLobbyCodes may be a SPARSE array (a seat that never observed a code leaves a hole), and
|
|
1470
|
-
// Array.prototype.every SKIPS holes — so count the DEFINED codes explicitly, never rely on every().
|
|
1471
|
-
const definedCodes = observedLobbyCodes.filter((code) => code !== undefined);
|
|
1472
|
-
const distinctCodes = new Set(definedCodes);
|
|
1473
|
-
if (distinctCodes.size === 1 && definedCodes.length === roles.length) {
|
|
1474
|
-
lobbyConvergenceDigest = commandDigestOf(`/lobby/${[...distinctCodes][0]}`);
|
|
1475
|
-
}
|
|
1476
|
-
if (handoffTimedOut && runError === undefined) {
|
|
1477
|
-
runError = `The host seat never produced a /lobby/CODE URL within the ${handoffDeadlineMs}ms handoff deadline; follower seats failed closed without opening.`;
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
}
|
|
1481
|
-
finally {
|
|
1482
|
-
try {
|
|
1483
|
-
await receiving?.finish();
|
|
1484
|
-
}
|
|
1485
|
-
catch {
|
|
1486
|
-
warnings.push("Email finalization could not complete. Inspect humanish comms recover; provider cleanup remains unresolved.");
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
// Subject provenance: external-public is the operator-declared, operator-owned public deployment
|
|
1490
|
-
// (neither provisioned nor seeded); the provisioned path builds clone/local-tree provenance.
|
|
1491
|
-
const subject = planeClass === "external-public"
|
|
1492
|
-
? { source: "app-url", envNames: [], state: { provenance: "external-public" } }
|
|
1493
|
-
: buildSubjectProvenance({
|
|
1494
|
-
localTreeRoute,
|
|
1495
|
-
publicRepo,
|
|
1496
|
-
subjectCommit: localTreeRoute ? localTreeArchive?.git?.commit : subjectCommit,
|
|
1497
|
-
localTreeArchive,
|
|
1498
|
-
subjectEnvNames,
|
|
1499
|
-
state: resolveSubjectState({ declared: config.subject.state, dryRun, executed: stateStepRecords })
|
|
1500
|
-
});
|
|
1501
|
-
const planeCommit = localTreeRoute ? localTreeArchive?.git?.commit : subjectCommit;
|
|
1502
|
-
// Collect per-actor warnings (each lane's own teardown/raw-screenshot notes).
|
|
1503
|
-
for (const result of actorResults) {
|
|
1504
|
-
warnings.push(...result.outcome.warnings);
|
|
1505
|
-
}
|
|
1506
|
-
const bundle = buildConcurrentSharedWorldBundle({
|
|
1507
|
-
...(options.lab === undefined ? {} : { lab: options.lab }),
|
|
1508
|
-
config,
|
|
1509
|
-
descriptor,
|
|
1510
|
-
createdAt,
|
|
1511
|
-
dryRun,
|
|
1512
|
-
runId,
|
|
1513
|
-
source,
|
|
1514
|
-
roles,
|
|
1515
|
-
actorSpecs,
|
|
1516
|
-
actorResults,
|
|
1517
|
-
stateSnapshots,
|
|
1518
|
-
subject,
|
|
1519
|
-
seedDigest,
|
|
1520
|
-
planeClass,
|
|
1521
|
-
...(planeCommit === undefined ? {} : { subjectCommit: planeCommit }),
|
|
1522
|
-
...(getHostUrl === undefined ? {} : { hostDigest: hostOriginDigest(getHostUrl) }),
|
|
1523
|
-
...(publicOriginDigest === undefined ? {} : { publicOriginDigest }),
|
|
1524
|
-
...(declaredOriginDigest === undefined ? {} : { declaredOriginDigest }),
|
|
1525
|
-
...(lobbyConvergenceDigest === undefined ? {} : { lobbyConvergenceDigest }),
|
|
1526
|
-
...(commsArtifactPath === undefined ? {} : { commsArtifactPath }),
|
|
1527
|
-
...(runError === undefined ? {} : { runError })
|
|
1528
|
-
});
|
|
1529
|
-
const adapterWarnings = [];
|
|
1530
|
-
const scorerResult = await applyBrowserAdapterHooks({
|
|
1531
|
-
hooks,
|
|
1532
|
-
bundle,
|
|
1533
|
-
context: {
|
|
1534
|
-
bundle,
|
|
1535
|
-
runDir: physicalArtifactRoot,
|
|
1536
|
-
labId: config.id,
|
|
1537
|
-
runId,
|
|
1538
|
-
actor: descriptor.id,
|
|
1539
|
-
backend: "concurrent-shared-world",
|
|
1540
|
-
dryRun,
|
|
1541
|
-
laneCount: roles.length
|
|
1542
|
-
},
|
|
1543
|
-
sanitize: (text) => redactText(scrubKnownValues(text)),
|
|
1544
|
-
warnings: adapterWarnings,
|
|
1545
|
-
hookLabel: "sharedWorldHooks",
|
|
1546
|
-
...(options.scorerProvenance === undefined ? {} : { scorerProvenance: options.scorerProvenance })
|
|
1547
|
-
});
|
|
1548
|
-
if (receiving)
|
|
1549
|
-
bundle.commsReceiving = receiving.snapshot();
|
|
1550
|
-
await writeConcurrentRunArtifacts(bundle, runPaths);
|
|
1551
|
-
// Finalize identity+liveness from the bundle just written. Deliberately here and not inside
|
|
1552
|
-
// writeConcurrentRunArtifacts — that writer is shared with the mid-run in-progress flushes, and
|
|
1553
|
-
// finalizing there would declare the run finished while it is still going (#455).
|
|
1554
|
-
await runStatus.finish({
|
|
1555
|
-
...(bundle.review?.verdict === undefined ? {} : { verdict: bundle.review.verdict }),
|
|
1556
|
-
...(bundle.review?.participants === undefined
|
|
1557
|
-
? {}
|
|
1558
|
-
: {
|
|
1559
|
-
participants: {
|
|
1560
|
-
total: bundle.review.participants.total,
|
|
1561
|
-
reachedGoal: bundle.review.participants.reachedGoal,
|
|
1562
|
-
...(bundle.review.participants.reportedFriction === undefined
|
|
1563
|
-
? {}
|
|
1564
|
-
: { reportedFriction: bundle.review.participants.reportedFriction })
|
|
1565
|
-
}
|
|
1566
|
-
}),
|
|
1567
|
-
...(bundle.cost?.estimatedTotalUsd === undefined ? {} : { estimatedCostUsd: bundle.cost.estimatedTotalUsd })
|
|
1568
|
-
});
|
|
1569
|
-
const observer = await render(cwd, runId, { open: options.open === true });
|
|
1570
|
-
if (observer.ok && liveObserver) {
|
|
1571
|
-
attachObserverRuntimeStreamUrls(observer, runtimeStreamUrls);
|
|
1572
|
-
}
|
|
1573
|
-
const roleOk = (result) => {
|
|
1574
|
-
if (dryRun)
|
|
1575
|
-
return true;
|
|
1576
|
-
return actorLanePassed(result);
|
|
1577
|
-
};
|
|
1578
|
-
// Concurrent "ok": every actor must produce a terminal, engaged PASSED session. This is a
|
|
1579
|
-
// harness/session-credibility gate, not mission-completion proof; a failed actor trace cannot
|
|
1580
|
-
// make the route green just because the harness got a terminal.
|
|
1581
|
-
const swarmRan = !dryRun && actorResults.length === roles.length
|
|
1582
|
-
&& actorResults.every(actorLanePassed);
|
|
1583
|
-
const adapterFailure = adapterScoreFailureMessage(bundle);
|
|
1584
|
-
const ok = observer.ok && runError === undefined && (dryRun || swarmRan) && adapterFailure === undefined && scorerResult.declaredVerdictFailure === undefined;
|
|
1585
|
-
const overlapProven = !dryRun && actorWindowsOverlap(actorResults);
|
|
1586
|
-
const roleResults = actorSpecs.map((spec, index) => {
|
|
1587
|
-
const result = actorResults[index];
|
|
1588
|
-
const base = { id: spec.laneId, index: index + 1, persona: spec.persona.id };
|
|
1589
|
-
if (dryRun || !result) {
|
|
1590
|
-
return { ...base, status: "contract_proof_only", ok: dryRun };
|
|
1591
|
-
}
|
|
1592
|
-
const session = result.outcome.session;
|
|
1593
|
-
const thisOk = roleOk(result);
|
|
1594
|
-
return {
|
|
1595
|
-
...base,
|
|
1596
|
-
status: session ? session.status : "failed",
|
|
1597
|
-
ok: thisOk,
|
|
1598
|
-
window: { startedAt: result.startedAt, endedAt: result.endedAt },
|
|
1599
|
-
...(session
|
|
1600
|
-
? { session: { status: session.status, completionReason: session.completionReason, reason: session.reason, screenshots: result.outcome.screenshots.length } }
|
|
1601
|
-
: {}),
|
|
1602
|
-
...(result.outcome.sandboxId === undefined
|
|
1603
|
-
? {}
|
|
1604
|
-
: { sandbox: { sandboxId: result.outcome.sandboxId, killed: result.outcome.killed } }),
|
|
1605
|
-
...(thisOk
|
|
1606
|
-
? {}
|
|
1607
|
-
: {
|
|
1608
|
-
error: {
|
|
1609
|
-
code: "HUMANISH_CONCURRENT_SHARED_WORLD_LAB_FAILED",
|
|
1610
|
-
message: result.outcome.sessionError
|
|
1611
|
-
?? (result.outcome.noEngagement
|
|
1612
|
-
? "Actor took no actions and produced no message (likely a blank/still-loading screen); not a credible goal_satisfied."
|
|
1613
|
-
: result.outcome.selfReportedBlocker
|
|
1614
|
-
? "Actor reported goal_satisfied while its final message described a blocker or asked for missing instructions; not a credible pass."
|
|
1615
|
-
: session?.completionReason === "harness_error"
|
|
1616
|
-
? `Actor seat ended with a harness error: ${session.reason}`
|
|
1617
|
-
: "Actor did not produce a terminal session.")
|
|
1618
|
-
}
|
|
1619
|
-
})
|
|
1620
|
-
};
|
|
1621
|
-
});
|
|
1622
|
-
const errorResult = (() => {
|
|
1623
|
-
if (ok)
|
|
1624
|
-
return undefined;
|
|
1625
|
-
if (handoffTimedOut) {
|
|
1626
|
-
// Checked BEFORE the observer failure: the host never yielded a /lobby/CODE within the
|
|
1627
|
-
// deadline (followers failed closed without opening), which is the ROOT CAUSE — and it can
|
|
1628
|
-
// itself make the Observer unable to render a coherent run. Report the distinct, honest
|
|
1629
|
-
// handoff-timeout code rather than a generic observer/run failure.
|
|
1630
|
-
return { code: "HUMANISH_CONCURRENT_SHARED_WORLD_LAB_HANDOFF_TIMEOUT", message: runError ?? "The host seat never produced a /lobby/CODE URL within the handoff deadline." };
|
|
1631
|
-
}
|
|
1632
|
-
if (hostHandoffFailure !== undefined) {
|
|
1633
|
-
return { code: "HUMANISH_CONCURRENT_SHARED_WORLD_LAB_FAILED", message: hostHandoffFailure };
|
|
1634
|
-
}
|
|
1635
|
-
if (!observer.ok) {
|
|
1636
|
-
return { code: "HUMANISH_CONCURRENT_SHARED_WORLD_LAB_FAILED", message: observer.error?.message ?? "Observer failed for the concurrent shared-world run." };
|
|
1637
|
-
}
|
|
1638
|
-
if (runError) {
|
|
1639
|
-
return { code: "HUMANISH_CONCURRENT_SHARED_WORLD_LAB_FAILED", message: runError };
|
|
1640
|
-
}
|
|
1641
|
-
if (adapterFailure !== undefined) {
|
|
1642
|
-
return { code: "HUMANISH_CONCURRENT_SHARED_WORLD_LAB_FAILED", message: adapterFailure };
|
|
1643
|
-
}
|
|
1644
|
-
const passed = roleResults.filter((role) => role.ok).length;
|
|
1645
|
-
return { code: "HUMANISH_CONCURRENT_SHARED_WORLD_LAB_FAILED", message: `Concurrent shared-world run did not run coherently: ${passed}/${roles.length} actor(s) reached a terminal, engaged passed session.` };
|
|
1646
|
-
})();
|
|
1647
|
-
return markFinalizedStudyResult({
|
|
1648
|
-
schema: CONCURRENT_SHARED_WORLD_LAB_SCHEMA,
|
|
1649
|
-
ok,
|
|
1650
|
-
cwd,
|
|
1651
|
-
labId: config.id,
|
|
1652
|
-
actor: descriptor.id,
|
|
1653
|
-
topology: "shared-world",
|
|
1654
|
-
topologyMode: "concurrent",
|
|
1655
|
-
roleCount: roles.length,
|
|
1656
|
-
concurrency,
|
|
1657
|
-
dryRun,
|
|
1658
|
-
runId,
|
|
1659
|
-
...(getHostUrl === undefined ? {} : { host: getHostUrl }),
|
|
1660
|
-
...(subjectSandboxId === undefined ? {} : { subjectSandbox: { sandboxId: subjectSandboxId, killed: subjectKilled } }),
|
|
1661
|
-
...(dryRun ? {} : { overlapProven }),
|
|
1662
|
-
...(dryRun ? {} : { maxSimultaneousLanes: maxSimultaneousWindows(actorResults) }),
|
|
1663
|
-
subject,
|
|
1664
|
-
roles: roleResults,
|
|
1665
|
-
observer,
|
|
1666
|
-
warnings: [...warnings, ...adapterWarnings, ...observer.warnings],
|
|
1667
|
-
...(errorResult === undefined ? {} : { error: errorResult })
|
|
1668
|
-
}, runPaths);
|
|
1669
|
-
}
|
|
1670
|
-
/** Max windows live at the same instant (sweep over start/end points). The honest simultaneity
|
|
1671
|
-
* count: lane COUNT says how many seats existed; this says how many ever ran at once. */
|
|
1672
|
-
function maxSimultaneousWindows(windows) {
|
|
1673
|
-
const points = windows
|
|
1674
|
-
.filter((w) => w.endedAt > w.startedAt)
|
|
1675
|
-
.flatMap((w) => [{ at: w.startedAt, delta: 1 }, { at: w.endedAt, delta: -1 }]);
|
|
1676
|
-
points.sort((a, b) => a.at - b.at || a.delta - b.delta); // end before start at the same instant
|
|
1677
|
-
let live = 0;
|
|
1678
|
-
let max = 0;
|
|
1679
|
-
for (const point of points) {
|
|
1680
|
-
live += point.delta;
|
|
1681
|
-
if (live > max)
|
|
1682
|
-
max = live;
|
|
1683
|
-
}
|
|
1684
|
-
return max;
|
|
1685
|
-
}
|
|
1686
|
-
/** True when ≥2 actor windows overlap in time (the proven-concurrency signal). */
|
|
1687
|
-
function actorWindowsOverlap(results) {
|
|
1688
|
-
for (let i = 0; i < results.length; i += 1) {
|
|
1689
|
-
for (let j = i + 1; j < results.length; j += 1) {
|
|
1690
|
-
const a = results[i];
|
|
1691
|
-
const b = results[j];
|
|
1692
|
-
if (a.startedAt < b.endedAt && b.startedAt < a.endedAt) {
|
|
1693
|
-
return true;
|
|
1694
|
-
}
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
return false;
|
|
1698
|
-
}
|
|
1699
|
-
function actorLanePassed(result) {
|
|
1700
|
-
if (!result)
|
|
1701
|
-
return false;
|
|
1702
|
-
const session = result.outcome.session;
|
|
1703
|
-
return session !== undefined
|
|
1704
|
-
&& session.status === "passed"
|
|
1705
|
-
&& session.completionReason !== "harness_error"
|
|
1706
|
-
&& result.outcome.sessionError === undefined
|
|
1707
|
-
&& !result.outcome.noEngagement
|
|
1708
|
-
&& !result.outcome.selfReportedBlocker;
|
|
1709
|
-
}
|
|
1710
|
-
/**
|
|
1711
|
-
* Keep three different claims separate in the stakeholder roll-up:
|
|
1712
|
-
*
|
|
1713
|
-
* - `outcome.ok` says the actor session passed the harness's credibility checks;
|
|
1714
|
-
* - `completionReason` says how the participant session ended;
|
|
1715
|
-
* - shared-world convergence is reported by the plane-specific summary alongside this line.
|
|
1716
|
-
*
|
|
1717
|
-
* None of those is adopter-scored proof that the mission text was completed. In particular, a
|
|
1718
|
-
* productive `budget_reached` session can coexist with lobby convergence without becoming a
|
|
1719
|
-
* `goal_satisfied` result (#364).
|
|
1720
|
-
*/
|
|
1721
|
-
function formatSharedWorldActorOutcomes(outcomes, expectedCount) {
|
|
1722
|
-
const passedSessions = outcomes.filter((outcome) => outcome.ok).length;
|
|
1723
|
-
const goalSatisfiedSessions = outcomes.filter((outcome) => outcome.ok && outcome.completionReason === "goal_satisfied").length;
|
|
1724
|
-
const completionReasonCounts = new Map();
|
|
1725
|
-
for (const outcome of outcomes) {
|
|
1726
|
-
const reason = outcome.completionReason ?? "not_recorded";
|
|
1727
|
-
completionReasonCounts.set(reason, (completionReasonCounts.get(reason) ?? 0) + 1);
|
|
1728
|
-
}
|
|
1729
|
-
for (let missing = outcomes.length; missing < expectedCount; missing += 1) {
|
|
1730
|
-
completionReasonCounts.set("not_recorded", (completionReasonCounts.get("not_recorded") ?? 0) + 1);
|
|
1731
|
-
}
|
|
1732
|
-
const completionReasons = [...completionReasonCounts.entries()]
|
|
1733
|
-
// ASCII contract tokens: compare directly so bundle text is byte-stable across host locales.
|
|
1734
|
-
.sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
|
|
1735
|
-
.map(([reason, count]) => `${reason} ${count}/${expectedCount}`)
|
|
1736
|
-
.join(", ");
|
|
1737
|
-
return `${passedSessions}/${expectedCount} actor session(s) passed credibility checks; mission endpoint: ${goalSatisfiedSessions}/${expectedCount} ended goal_satisfied; completion reasons: ${completionReasons}`;
|
|
1738
|
-
}
|
|
1739
|
-
/** Project the concurrent run into a humanish.run-bundle.v1 with the CONCURRENT shared-world block. */
|
|
1740
|
-
export function buildConcurrentSharedWorldBundle(args) {
|
|
1741
|
-
const { config, descriptor, createdAt, dryRun, actorSpecs, actorResults, roles } = args;
|
|
1742
|
-
const inProgress = args.inProgress === true;
|
|
1743
|
-
const external = (args.planeClass ?? "provisioned-getHost") === "external-public";
|
|
1744
|
-
const simulations = [];
|
|
1745
|
-
const streams = [];
|
|
1746
|
-
const events = [];
|
|
1747
|
-
// Public-safe label only — neither the raw getHost URL (provisioned) nor the raw public origin
|
|
1748
|
-
// (external-public) lands in the bundle. The plane identity is a DIGEST (plane.hostDigest on
|
|
1749
|
-
// getHost; plane.publicOriginDigest on external-public).
|
|
1750
|
-
const appUrl = external ? "[external-public-plane]" : "[provisioned-subject]";
|
|
1751
|
-
const planeCommit = external ? undefined : dryRun ? undefined : args.subjectCommit;
|
|
1752
|
-
events.push({
|
|
1753
|
-
id: "event-000-created",
|
|
1754
|
-
at: createdAt,
|
|
1755
|
-
level: "info",
|
|
1756
|
-
type: "concurrent-shared-world.run.created",
|
|
1757
|
-
message: `Created CONCURRENT shared-world run for ${config.id} (actor ${descriptor.id}, ${actorSpecs.length} persona(s) vs ONE shared plane, max ${config.execution?.concurrency ?? actorSpecs.length} concurrent).`
|
|
1758
|
-
});
|
|
1759
|
-
// Human-readable plane label, byte-stable for the clone route (see shared-world-lab.ts's
|
|
1760
|
-
// buildSharedWorldBundle for the same pattern). local-tree has no repo slug: it labels the
|
|
1761
|
-
// packed archive instead (archiveSha256 + dirty/clean when the packed root was a git work tree).
|
|
1762
|
-
const dryRunPlaneLabel = args.subject.source === "local-tree"
|
|
1763
|
-
? "packed working tree"
|
|
1764
|
-
: `clone of ${args.subject.repo}`;
|
|
1765
|
-
const livePlaneLabel = args.subject.source === "local-tree"
|
|
1766
|
-
? (args.subject.archiveSha256
|
|
1767
|
-
? `packed working tree (archiveSha256 ${args.subject.archiveSha256}${args.subject.dirty === true ? ", dirty working tree" : args.subject.dirty === false ? ", clean working tree" : ""})`
|
|
1768
|
-
: "packed working tree (archive digest unresolved; provisioning failed before resolution)")
|
|
1769
|
-
: `clone of ${args.subject.repo}${args.subjectCommit ? `@${args.subjectCommit}` : ""}`;
|
|
1770
|
-
// External-public plane provenance is HONESTLY different: an operator-declared, operator-OWNED
|
|
1771
|
-
// public deployment humanish neither provisioned nor seeded — NO getHost, NO clone, NO synthetic
|
|
1772
|
-
// attestation (claiming synthetic on a real site is a lie). The origin persists digest-only.
|
|
1773
|
-
const externalPlaneOwner = config.subject.publicTarget?.owner ?? "(operator-declared)";
|
|
1774
|
-
events.push({
|
|
1775
|
-
id: "event-001-plane",
|
|
1776
|
-
at: createdAt,
|
|
1777
|
-
level: "info",
|
|
1778
|
-
type: "concurrent-shared-world.plane.provenance",
|
|
1779
|
-
message: external
|
|
1780
|
-
? `Shared plane: an EXTERNAL-PUBLIC deployment (operator-attested owner ${externalPlaneOwner}, authorized) used DIRECTLY as the shared plane — NO getHost, clone, subject sandbox, or seed. The harness OBSERVES that each seat reached the operator-declared origin (publicOriginDigest); it did NOT mint or control the plane. Author-trust ownership attestation, NOT a synthetic-data claim.`
|
|
1781
|
-
: dryRun
|
|
1782
|
-
? `Shared plane declared: ${dryRunPlaneLabel}, served + getHost-exposed in-sandbox (dry-run contract; nothing ${args.subject.source === "local-tree" ? "packed" : "cloned"}). Seed recipe ${args.seedDigest}; SYNTHETIC subject (author-attested); env names: ${args.subject.envNames?.join(", ") || "none"} (values never persisted).`
|
|
1783
|
-
: `Shared plane: ${livePlaneLabel}, served + exposed at the harness-minted getHost URL; seed recipe ${args.seedDigest}; SYNTHETIC subject (author-attested); env names: ${args.subject.envNames?.join(", ") || "none"} (values never persisted).`,
|
|
1784
|
-
simId: actorSpecs[0]?.simId ?? "sim-001",
|
|
1785
|
-
streamId: actorSpecs[0]?.streamId ?? "stream-001"
|
|
1786
|
-
});
|
|
1787
|
-
let eventSeq = 2;
|
|
1788
|
-
const nextEventId = (suffix) => `event-${String(eventSeq++).padStart(3, "0")}-${suffix}`;
|
|
1789
|
-
actorSpecs.forEach((spec, index) => {
|
|
1790
|
-
const taxonomy = laneTaxonomyLabel(spec);
|
|
1791
|
-
const result = actorResults[index];
|
|
1792
|
-
const outcome = result?.outcome;
|
|
1793
|
-
const session = outcome?.session;
|
|
1794
|
-
const screenshots = outcome?.screenshots ?? [];
|
|
1795
|
-
const lastScreenshot = screenshots[screenshots.length - 1];
|
|
1796
|
-
// public-safe (origin redacted): external-public seats open the public plane; getHost seats a seat path.
|
|
1797
|
-
const route = external ? "[external-public-plane]" : publicSafeRouteLabel(roles[index]?.entry);
|
|
1798
|
-
const status = session
|
|
1799
|
-
? session.status
|
|
1800
|
-
: outcome?.sessionError
|
|
1801
|
-
? "failed"
|
|
1802
|
-
: inProgress
|
|
1803
|
-
? "running"
|
|
1804
|
-
: "contract_proof_only";
|
|
1805
|
-
const reason = session?.reason
|
|
1806
|
-
?? outcome?.sessionError
|
|
1807
|
-
?? (inProgress
|
|
1808
|
-
? "Actor desktop is running; the attached Observer hydrates the runtime stream URL without persisting it."
|
|
1809
|
-
: "Contract actor only: dry-run produced the evidence shape without launching a desktop or spending provider tokens.");
|
|
1810
|
-
const traceScreenshotMode = session?.trace.redaction.screenshots;
|
|
1811
|
-
// Include `declared` on the no-outcome fallback too (dry-run, skipped lane): otherwise an
|
|
1812
|
-
// ABSENT declared means either "the preset rendered faithfully" or "there was no live
|
|
1813
|
-
// outcome", and a dry-run bundle keeps the self-confirming shape this field exists to kill.
|
|
1814
|
-
const fallbackDeclared = declaredScreenForRender(spec.devicePreset, spec.deviceName, spec.resolution);
|
|
1815
|
-
const desktopGeometry = outcome?.desktopGeometry ?? {
|
|
1816
|
-
screen: {
|
|
1817
|
-
requested: { width: spec.resolution[0], height: spec.resolution[1] },
|
|
1818
|
-
...(fallbackDeclared ? { declared: fallbackDeclared } : {})
|
|
1819
|
-
}
|
|
1820
|
-
};
|
|
1821
|
-
const screenshotMode = traceScreenshotMode === "raw" || traceScreenshotMode === "blurred"
|
|
1822
|
-
? traceScreenshotMode
|
|
1823
|
-
: config.policies?.redactScreenshots === true ? "blurred" : "raw";
|
|
1824
|
-
simulations.push({
|
|
1825
|
-
id: spec.simId,
|
|
1826
|
-
index: index + 1,
|
|
1827
|
-
personaId: spec.persona.id,
|
|
1828
|
-
scenarioId: `concurrent-shared-world-${config.id}`,
|
|
1829
|
-
status,
|
|
1830
|
-
streamKind: "browser",
|
|
1831
|
-
mode: "browser-sim",
|
|
1832
|
-
progress: inProgress ? 35 : 100,
|
|
1833
|
-
currentStep: reason,
|
|
1834
|
-
summary: session
|
|
1835
|
-
? `Persona ${spec.laneId}${taxonomy} (${spec.persona.id}): drove the shared plane concurrently; ${session.completionReason}.`
|
|
1836
|
-
: outcome?.sessionError
|
|
1837
|
-
? `Persona ${spec.laneId}${taxonomy} failed before a terminal session verdict: ${outcome.sessionError}`
|
|
1838
|
-
: inProgress
|
|
1839
|
-
? `Persona ${spec.laneId}${taxonomy} (${spec.persona.id}) is running against the shared plane.`
|
|
1840
|
-
: `Contract persona ${spec.laneId}${taxonomy} (${spec.persona.id}) for ${descriptor.id} against the shared plane at ${appUrl}.`,
|
|
1841
|
-
streamIds: [spec.streamId],
|
|
1842
|
-
startedAt: createdAt,
|
|
1843
|
-
updatedAt: createdAt
|
|
1844
|
-
});
|
|
1845
|
-
streams.push({
|
|
1846
|
-
id: spec.streamId,
|
|
1847
|
-
simId: spec.simId,
|
|
1848
|
-
...(spec.assignment === undefined ? {} : { assignment: participantAssignment(spec.assignment) }),
|
|
1849
|
-
kind: "browser",
|
|
1850
|
-
label: `Concurrent persona ${spec.laneId}${taxonomy} — ${config.id}`,
|
|
1851
|
-
status,
|
|
1852
|
-
transport: "snapshot",
|
|
1853
|
-
updatedAt: createdAt,
|
|
1854
|
-
embed: lastScreenshot
|
|
1855
|
-
? { kind: "screenshot", url: lastScreenshot, title: `Shared plane, persona ${spec.laneId} (${screenshotMode})` }
|
|
1856
|
-
: { kind: "placeholder", title: `Shared plane, persona ${spec.laneId}` },
|
|
1857
|
-
...(desktopGeometry.viewport === undefined
|
|
1858
|
-
? {}
|
|
1859
|
-
: {
|
|
1860
|
-
viewport: {
|
|
1861
|
-
width: desktopGeometry.viewport.width,
|
|
1862
|
-
height: desktopGeometry.viewport.height,
|
|
1863
|
-
deviceScaleFactor: desktopGeometry.viewport.deviceScaleFactor,
|
|
1864
|
-
isMobile: spec.devicePreset.isMobile
|
|
1865
|
-
}
|
|
1866
|
-
}),
|
|
1867
|
-
desktopGeometry,
|
|
1868
|
-
ui: {
|
|
1869
|
-
route,
|
|
1870
|
-
intent: `Watch persona ${spec.laneId}${taxonomy} (${spec.persona.id}) drive the SHARED plane concurrently with the other personas.`,
|
|
1871
|
-
state: reason,
|
|
1872
|
-
...(session ? { actorStatus: session.status } : {}),
|
|
1873
|
-
...(lastScreenshot ? { screenshotUrl: lastScreenshot } : {})
|
|
1874
|
-
},
|
|
1875
|
-
...(session ? { actor: session.trace } : {}),
|
|
1876
|
-
artifacts: [
|
|
1877
|
-
{ label: "run bundle", path: "run.json", kind: "bundle" },
|
|
1878
|
-
{ label: "review", path: "review.md", kind: "review" },
|
|
1879
|
-
{ label: "events", path: "events.ndjson", kind: "events" },
|
|
1880
|
-
...(session
|
|
1881
|
-
? [{ label: `persona ${spec.laneId} actor trace`, path: spec.traceArtifactPath, kind: "trace" }]
|
|
1882
|
-
: []),
|
|
1883
|
-
// Run-level comms evidence belongs to the ONE shared app, not a persona — register it once, on
|
|
1884
|
-
// the first stream, so the bundle's existence-verify + public-safety scan cover it without
|
|
1885
|
-
// double-counting across seats.
|
|
1886
|
-
...(index === 0 && args.commsArtifactPath
|
|
1887
|
-
? [{ label: "comms thread", path: args.commsArtifactPath, kind: "log" }]
|
|
1888
|
-
: []),
|
|
1889
|
-
...screenshots.map((screenshot, screenshotIndex) => ({
|
|
1890
|
-
label: `persona ${spec.laneId} screenshot ${String(screenshotIndex + 1).padStart(2, "0")} (${screenshotMode})`,
|
|
1891
|
-
path: screenshot,
|
|
1892
|
-
kind: "screenshot"
|
|
1893
|
-
}))
|
|
1894
|
-
]
|
|
1895
|
-
});
|
|
1896
|
-
for (const warning of outcome?.warnings ?? []) {
|
|
1897
|
-
events.push({
|
|
1898
|
-
id: nextEventId(`warning-${spec.laneId}`),
|
|
1899
|
-
at: createdAt,
|
|
1900
|
-
level: "warn",
|
|
1901
|
-
type: "concurrent-shared-world.actor.warning",
|
|
1902
|
-
message: `Persona ${spec.laneId}: ${warning}`,
|
|
1903
|
-
simId: spec.simId,
|
|
1904
|
-
streamId: spec.streamId
|
|
1905
|
-
});
|
|
1906
|
-
}
|
|
1907
|
-
if (session) {
|
|
1908
|
-
events.push({
|
|
1909
|
-
id: nextEventId(`session-${spec.laneId}`),
|
|
1910
|
-
at: createdAt,
|
|
1911
|
-
level: session.status === "passed" ? "info" : "warn",
|
|
1912
|
-
type: `concurrent-shared-world.session.${session.completionReason}`,
|
|
1913
|
-
message: `Persona ${spec.laneId}: ${session.status} — ${session.reason}`,
|
|
1914
|
-
simId: spec.simId,
|
|
1915
|
-
streamId: spec.streamId
|
|
1916
|
-
});
|
|
1917
|
-
}
|
|
1918
|
-
else if (outcome?.sessionError) {
|
|
1919
|
-
events.push({
|
|
1920
|
-
id: nextEventId(`session-error-${spec.laneId}`),
|
|
1921
|
-
at: createdAt,
|
|
1922
|
-
level: "error",
|
|
1923
|
-
type: "concurrent-shared-world.session.error",
|
|
1924
|
-
message: `Persona ${spec.laneId}: ${outcome.sessionError}`,
|
|
1925
|
-
simId: spec.simId,
|
|
1926
|
-
streamId: spec.streamId
|
|
1927
|
-
});
|
|
1928
|
-
}
|
|
1929
|
-
else if (inProgress) {
|
|
1930
|
-
events.push({
|
|
1931
|
-
id: nextEventId(`running-${spec.laneId}`),
|
|
1932
|
-
at: createdAt,
|
|
1933
|
-
level: "info",
|
|
1934
|
-
type: "actor.running",
|
|
1935
|
-
message: `Persona ${spec.laneId}: desktop actor is running; live stream URL is runtime-only and not persisted.`,
|
|
1936
|
-
simId: spec.simId,
|
|
1937
|
-
streamId: spec.streamId
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
|
-
else {
|
|
1941
|
-
events.push({
|
|
1942
|
-
id: nextEventId(`contract-${spec.laneId}`),
|
|
1943
|
-
at: createdAt,
|
|
1944
|
-
level: "info",
|
|
1945
|
-
type: "concurrent-shared-world.contract.ready",
|
|
1946
|
-
message: `Persona ${spec.laneId}: dry-run contract actor ready; switch scenario.mode to live for a real concurrent session.`,
|
|
1947
|
-
simId: spec.simId,
|
|
1948
|
-
streamId: spec.streamId
|
|
1949
|
-
});
|
|
1950
|
-
}
|
|
1951
|
-
});
|
|
1952
|
-
// Build the concurrent shared-world evidence block. routeHostDigest is sha256-16 of the ORIGIN each
|
|
1953
|
-
// seat reached: on getHost the seat URL the actor drove (verify confirms == plane.hostDigest); on
|
|
1954
|
-
// external-public the seat's CDP-OBSERVED URL origin (verify confirms == plane.publicOriginDigest).
|
|
1955
|
-
const fallbackHostDigest = external
|
|
1956
|
-
? (args.publicOriginDigest ?? commandDigestOf("[external-public-plane]"))
|
|
1957
|
-
: (args.hostDigest ?? commandDigestOf("[provisioned-subject]"));
|
|
1958
|
-
const laneWindows = actorSpecs.map((spec, index) => {
|
|
1959
|
-
const result = actorResults[index];
|
|
1960
|
-
const session = result?.outcome.session;
|
|
1961
|
-
const routeHostDigest = result ? hostOriginDigest(result.route) : fallbackHostDigest;
|
|
1962
|
-
return {
|
|
1963
|
-
roleId: spec.laneId,
|
|
1964
|
-
...(spec.actorType === undefined ? {} : { actorType: spec.actorType }),
|
|
1965
|
-
...(spec.surface === undefined ? {} : { surface: spec.surface }),
|
|
1966
|
-
...(spec.caseGroup === undefined ? {} : { caseGroup: spec.caseGroup }),
|
|
1967
|
-
simId: spec.simId,
|
|
1968
|
-
streamId: spec.streamId,
|
|
1969
|
-
startedAt: result?.startedAt ?? 0,
|
|
1970
|
-
endedAt: result?.endedAt ?? 0,
|
|
1971
|
-
verdict: session ? session.status : result?.outcome.sessionError ? "failed" : inProgress ? "running" : "contract_proof_only",
|
|
1972
|
-
routeHostDigest,
|
|
1973
|
-
...(planeCommit === undefined ? {} : { commit: planeCommit }),
|
|
1974
|
-
seedDigest: args.seedDigest
|
|
1975
|
-
};
|
|
1976
|
-
});
|
|
1977
|
-
// Option A (external-public): NO authoritative shared-state proof — OMIT stateSeries entirely (there
|
|
1978
|
-
// is no in-sandbox filesystem to digest; concurrency is proven by temporal co-occupancy + lobby
|
|
1979
|
-
// convergence). The provisioned-getHost plane keeps its authoritative in-sandbox checkpoint series.
|
|
1980
|
-
const stateSeries = external
|
|
1981
|
-
? undefined
|
|
1982
|
-
: dryRun
|
|
1983
|
-
? [{ timestamp: 0, digest: declaredStateDigest(config) }]
|
|
1984
|
-
: [...args.stateSnapshots].sort((a, b) => a.timestamp - b.timestamp);
|
|
1985
|
-
const outcomes = actorSpecs.map((spec, index) => {
|
|
1986
|
-
const result = actorResults[index];
|
|
1987
|
-
const session = result?.outcome.session;
|
|
1988
|
-
const ok = !dryRun && actorLanePassed(result);
|
|
1989
|
-
return {
|
|
1990
|
-
roleId: spec.laneId,
|
|
1991
|
-
...(spec.actorType === undefined ? {} : { actorType: spec.actorType }),
|
|
1992
|
-
...(spec.surface === undefined ? {} : { surface: spec.surface }),
|
|
1993
|
-
...(spec.caseGroup === undefined ? {} : { caseGroup: spec.caseGroup }),
|
|
1994
|
-
simId: spec.simId,
|
|
1995
|
-
streamId: spec.streamId,
|
|
1996
|
-
status: session ? session.status : result?.outcome.sessionError ? "failed" : inProgress ? "running" : "contract_proof_only",
|
|
1997
|
-
...(session ? { completionReason: session.completionReason } : {}),
|
|
1998
|
-
ok
|
|
1999
|
-
};
|
|
2000
|
-
});
|
|
2001
|
-
// The plane block is plane-class-specific. getHost: harness-minted hostDigest + synthetic
|
|
2002
|
-
// attestation. external-public: operator-declared publicOriginDigest, NO hostDigest, NO exposure
|
|
2003
|
-
// (claiming synthetic on a real site would be a lie — verify asserts both ABSENT there).
|
|
2004
|
-
const plane = external
|
|
2005
|
-
? {
|
|
2006
|
-
seedDigest: args.seedDigest,
|
|
2007
|
-
envNames: [],
|
|
2008
|
-
// publicOriginDigest is the OBSERVED convergence origin; declaredOriginDigest records the
|
|
2009
|
-
// operator-declared origin for reference (a redirect makes them differ — not a failure).
|
|
2010
|
-
...(args.publicOriginDigest === undefined ? {} : { publicOriginDigest: args.publicOriginDigest }),
|
|
2011
|
-
...(args.declaredOriginDigest === undefined ? {} : { declaredOriginDigest: args.declaredOriginDigest })
|
|
2012
|
-
}
|
|
2013
|
-
: {
|
|
2014
|
-
...(planeCommit === undefined ? {} : { commit: planeCommit }),
|
|
2015
|
-
seedDigest: args.seedDigest,
|
|
2016
|
-
envNames: args.subject.envNames ?? [],
|
|
2017
|
-
...(args.hostDigest === undefined ? {} : { hostDigest: args.hostDigest }),
|
|
2018
|
-
exposure: "synthetic"
|
|
2019
|
-
};
|
|
2020
|
-
const sharedWorld = {
|
|
2021
|
-
schema: SHARED_WORLD_SCHEMA,
|
|
2022
|
-
topology: "shared-world",
|
|
2023
|
-
topologyMode: "concurrent",
|
|
2024
|
-
// Byte-stable: the provisioned-getHost plane omits planeClass (absent == provisioned-getHost).
|
|
2025
|
-
...(external ? { planeClass: "external-public" } : {}),
|
|
2026
|
-
roleCount: actorSpecs.length,
|
|
2027
|
-
plane,
|
|
2028
|
-
attributionLimits: external ? [...EXTERNAL_PUBLIC_ATTRIBUTION_LIMITS] : [...CONCURRENT_ATTRIBUTION_LIMITS],
|
|
2029
|
-
laneWindows,
|
|
2030
|
-
// Option A: external-public carries NO stateSeries.
|
|
2031
|
-
...(stateSeries === undefined ? {} : { stateSeries }),
|
|
2032
|
-
outcomes,
|
|
2033
|
-
...(args.lobbyConvergenceDigest === undefined ? {} : { lobbyConvergenceDigest: args.lobbyConvergenceDigest })
|
|
2034
|
-
};
|
|
2035
|
-
const overlaps = actorWindowsOverlap(actorResults);
|
|
2036
|
-
const deltas = (stateSeries ?? []).filter((snapshot, i) => i > 0 && snapshot.digest !== (stateSeries ?? [])[i - 1].digest).length;
|
|
2037
|
-
const stateSeriesLabel = external
|
|
2038
|
-
? "stateSeries omitted (no authoritative shared-state proof on the external-public plane)"
|
|
2039
|
-
: `stateSeries ${(stateSeries ?? []).length} snapshot(s), ${deltas} delta(s)`;
|
|
2040
|
-
const convergenceLabel = external
|
|
2041
|
-
? `; lobby convergence ${args.lobbyConvergenceDigest ? "PROVEN (all seats reached one /lobby/CODE)" : "not observed"}`
|
|
2042
|
-
: "";
|
|
2043
|
-
// The count that matters is how many lanes were LIVE AT ONCE, not how many lanes exist — a
|
|
2044
|
-
// 6-lane run capped at 3 must never read as 6-wide concurrency (#350, the field failure).
|
|
2045
|
-
const capForReport = config.execution?.concurrency ?? laneWindows.length;
|
|
2046
|
-
const maxLive = maxSimultaneousWindows(laneWindows);
|
|
2047
|
-
events.push({
|
|
2048
|
-
id: nextEventId("concurrency"),
|
|
2049
|
-
at: createdAt,
|
|
2050
|
-
level: "info",
|
|
2051
|
-
type: "concurrent-shared-world.concurrency",
|
|
2052
|
-
message: `Concurrency: ${laneWindows.length} lane(s)${dryRun ? " (dry-run contract; $0)" : `, up to ${maxLive} live at once (cap ${capForReport}), overlap ${overlaps ? "PROVEN" : "not observed"}`}; ${stateSeriesLabel}${convergenceLabel}. Attribution ceiling: ${sharedWorld.attributionLimits.join(", ")}. ${dryRun ? "This contract-only run proves no live concurrency, scale, or adoption." : "This run reports only its own observed overlap and state changes; it does not prove scale, repeatability, or adopter-harness replacement."}`
|
|
2053
|
-
});
|
|
2054
|
-
// Concurrent verdict: dryRun → contract; else every actor produced a terminal, engaged PASSED
|
|
2055
|
-
// session → pass; otherwise fail. Mission endpoint and completion reasons are reported
|
|
2056
|
-
// separately below; `outcomes[].ok` is not renamed into mission success (#364).
|
|
2057
|
-
const verdict = dryRun
|
|
2058
|
-
? "contract_proof_only"
|
|
2059
|
-
: inProgress
|
|
2060
|
-
? "contract_proof_only"
|
|
2061
|
-
: (actorResults.length === actorSpecs.length
|
|
2062
|
-
&& actorResults.every(actorLanePassed)
|
|
2063
|
-
? "pass"
|
|
2064
|
-
: "fail");
|
|
2065
|
-
const actorOutcomeSummary = formatSharedWorldActorOutcomes(outcomes, actorSpecs.length);
|
|
2066
|
-
const review = {
|
|
2067
|
-
schema: REVIEW_SCHEMA,
|
|
2068
|
-
verdict,
|
|
2069
|
-
// Plane-class-aware: the external-public plane has NO getHost/clone/seed and carries NO
|
|
2070
|
-
// authoritative state series, so its summary must not claim a getHost-exposed plane (dry-run) nor
|
|
2071
|
-
// report "state delta(s) under load" (live) — it reports lobby convergence instead.
|
|
2072
|
-
summary: dryRun
|
|
2073
|
-
? external
|
|
2074
|
-
? `Dry-run concurrent shared-world contract: ${actorSpecs.length} persona(s) declared against ONE external-public shared plane (a real public deployment used directly; no getHost/clone/seed); no sandboxes launched, $0 spend.`
|
|
2075
|
-
: `Dry-run concurrent shared-world contract: ${actorSpecs.length} persona(s) declared against ONE getHost-exposed plane (${descriptor.id}); no sandboxes launched, $0 spend.`
|
|
2076
|
-
: inProgress
|
|
2077
|
-
? `In-progress concurrent shared-world Observer snapshot: ${actorSpecs.length} persona(s) running against ONE shared plane; final verification is pending.`
|
|
2078
|
-
: external
|
|
2079
|
-
? `Concurrent shared-world (ONE external-public plane, ${actorSpecs.length} simultaneous personas): swarm ${verdict === "pass" ? "ran coherently" : "did not run coherently"}; ${actorOutcomeSummary}; overlap ${overlaps ? "proven" : "not observed"}; ${args.lobbyConvergenceDigest ? `${actorSpecs.length} seats converged on one lobby` : "lobby convergence not observed"}.`
|
|
2080
|
-
: `Concurrent shared-world (ONE plane, ${actorSpecs.length} simultaneous personas): swarm ${verdict === "pass" ? "ran coherently" : "did not run coherently"}; ${actorOutcomeSummary}; overlap ${overlaps ? "proven" : "not observed"}; ${deltas} state delta(s) under load.`,
|
|
2081
|
-
gaps: dryRun
|
|
2082
|
-
? ["This dry-run launched no concurrent shared-world session; it proves contract shape only, not live behavior, scale, or adopter-harness replacement."]
|
|
2083
|
-
: inProgress
|
|
2084
|
-
? ["Final actor traces, screenshots, state deltas, and verification are pending; this Observer is for live watch only."]
|
|
2085
|
-
: actorResults
|
|
2086
|
-
.filter((result) => result.outcome.sessionError !== undefined
|
|
2087
|
-
|| result.outcome.noEngagement
|
|
2088
|
-
|| result.outcome.selfReportedBlocker
|
|
2089
|
-
|| result.outcome.session === undefined
|
|
2090
|
-
|| result.outcome.session.status !== "passed")
|
|
2091
|
-
.map((result) => `${result.spec.laneId}: ${result.outcome.sessionError ?? result.outcome.session?.reason ?? "did not pass"}`)
|
|
2092
|
-
};
|
|
2093
|
-
const anyRaw = actorResults.some((result) => result.outcome.session?.trace.redaction.screenshots === "raw");
|
|
2094
|
-
const ranLive = actorResults.some((result) => result.outcome.session !== undefined || result.outcome.sessionError !== undefined);
|
|
2095
|
-
return {
|
|
2096
|
-
schema: RUN_BUNDLE_SCHEMA,
|
|
2097
|
-
...receivingPublication(args.config, args.dryRun),
|
|
2098
|
-
runId: args.runId,
|
|
2099
|
-
mode: dryRun ? "dry-run" : "live",
|
|
2100
|
-
simCount: actorSpecs.length,
|
|
2101
|
-
createdAt,
|
|
2102
|
-
cwd: PUBLIC_TARGET_CWD,
|
|
2103
|
-
...(args.lab === undefined ? {} : { lab: args.lab }),
|
|
2104
|
-
artifactRoot: path.join(".humanish", "runs", args.runId),
|
|
2105
|
-
source: args.source,
|
|
2106
|
-
persona: {
|
|
2107
|
-
id: actorSpecs[0]?.persona.id ?? "concurrent-persona",
|
|
2108
|
-
name: `Concurrent shared-world swarm (${actorSpecs.length} personas)`,
|
|
2109
|
-
source: `lab:${config.id}`,
|
|
2110
|
-
sourceDigest: actorSpecs[0]?.persona.promptDigest ?? args.seedDigest
|
|
2111
|
-
},
|
|
2112
|
-
scenario: {
|
|
2113
|
-
id: `concurrent-shared-world-${config.id}`,
|
|
2114
|
-
title: config.title ?? `Concurrent shared-world: ${config.id}`,
|
|
2115
|
-
goal: redactText(actorSpecs[0]?.evidenceInstructions ?? actorSpecs[0]?.instructions ?? "Concurrent shared-world interaction."),
|
|
2116
|
-
source: `lab:${config.id}`,
|
|
2117
|
-
sourceDigest: actorSpecs[0]?.persona.promptDigest ?? args.seedDigest
|
|
2118
|
-
},
|
|
2119
|
-
lifecycle: [
|
|
2120
|
-
{
|
|
2121
|
-
at: createdAt,
|
|
2122
|
-
event: "concurrent-shared-world.run.created",
|
|
2123
|
-
message: `Created concurrent shared-world run with ONE shared plane and ${actorSpecs.length} simultaneous actor seats (actor ${descriptor.id}).`
|
|
2124
|
-
}
|
|
2125
|
-
],
|
|
2126
|
-
simulations,
|
|
2127
|
-
streams,
|
|
2128
|
-
events,
|
|
2129
|
-
redaction: {
|
|
2130
|
-
status: "passed",
|
|
2131
|
-
notes: ranLive
|
|
2132
|
-
? anyRaw
|
|
2133
|
-
? "Typed text recorded as length only and reasoning/messages pass through text redaction. Some personas captured FULL-FIDELITY (raw) screenshots, retained for local use — NOT redacted for publishing; set policies.redactScreenshots: true to blur a share-as-is bundle. stateSeries persists digest-only."
|
|
2134
|
-
: "Typed text recorded as length only and reasoning/messages pass through text redaction. Screenshots are blurred at capture (policies.redactScreenshots: true) for a share-as-is bundle. stateSeries persists digest-only."
|
|
2135
|
-
: inProgress
|
|
2136
|
-
? "In-progress live Observer snapshot: runtime stream auth URLs are process-local only and are not persisted. Final typed text, traces, and screenshots are pending. stateSeries persists digest-only."
|
|
2137
|
-
: "Dry-run concurrent shared-world contract bundle: no sandboxes launched and no screenshots captured. Typed text is recorded as length only and reasoning/messages pass through text redaction whenever a session runs. stateSeries persists digest-only."
|
|
2138
|
-
},
|
|
2139
|
-
artifacts: {
|
|
2140
|
-
run: "run.json",
|
|
2141
|
-
reviewJson: "review.json",
|
|
2142
|
-
reviewMarkdown: "review.md",
|
|
2143
|
-
observerData: "observer/observer-data.json",
|
|
2144
|
-
events: "events.ndjson"
|
|
2145
|
-
},
|
|
2146
|
-
review,
|
|
2147
|
-
feedbackCandidates: [],
|
|
2148
|
-
// Custom desktop image provenance (subject + every actor sandbox launched on it); omitted on the default.
|
|
2149
|
-
...(config.execution?.desktop?.template === undefined ? {} : { desktopTemplate: config.execution.desktop.template }),
|
|
2150
|
-
subject: args.subject,
|
|
2151
|
-
attributionClass: "shared-world",
|
|
2152
|
-
sharedWorld
|
|
2153
|
-
};
|
|
2154
|
-
}
|
|
2155
|
-
/** The declared (dry-run) state digest: the probe RECIPE (command digests), no run. */
|
|
2156
|
-
function declaredStateDigest(config) {
|
|
2157
|
-
const probes = config.subject.state?.checkpoint ?? [];
|
|
2158
|
-
return combineCheckpointDigest(probes.map((probe) => `${probe.name}=${commandDigestOf(probe.command)}`));
|
|
2159
|
-
}
|
|
2160
|
-
function renderConcurrentReviewMarkdown(bundle) {
|
|
2161
|
-
const plane = bundle.events.find((event) => event.type === "concurrent-shared-world.plane.provenance");
|
|
2162
|
-
const concurrency = bundle.events.find((event) => event.type === "concurrent-shared-world.concurrency");
|
|
2163
|
-
const sw = bundle.sharedWorld;
|
|
2164
|
-
return [
|
|
2165
|
-
`# ${bundle.scenario.title}`,
|
|
2166
|
-
"",
|
|
2167
|
-
`- run: ${bundle.runId}`,
|
|
2168
|
-
`- mode: ${bundle.mode}`,
|
|
2169
|
-
`- attribution class: ${bundle.attributionClass ?? "isolated"}`,
|
|
2170
|
-
`- topology: ${sw?.topology ?? "(none)"} / ${sw?.topologyMode ?? "(none)"}`,
|
|
2171
|
-
`- personas: ${sw?.roleCount ?? 0}`,
|
|
2172
|
-
`- verdict: ${bundle.review.verdict}`,
|
|
2173
|
-
`- summary: ${bundle.review.summary}`,
|
|
2174
|
-
...(plane ? [`- plane: ${plane.message}`] : []),
|
|
2175
|
-
...(concurrency ? [`- concurrency: ${concurrency.message}`] : []),
|
|
2176
|
-
...(sw ? [`- attribution limits: ${sw.attributionLimits.join(", ")}`] : []),
|
|
2177
|
-
...(bundle.review.gaps.length > 0 ? ["", "## Gaps", ...bundle.review.gaps.map((gap) => `- ${gap}`)] : []),
|
|
2178
|
-
""
|
|
2179
|
-
].join("\n");
|
|
2180
|
-
}
|
|
2181
|
-
//# sourceMappingURL=concurrent-shared-world-lab.js.map
|