humanish 0.107.0 → 0.109.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/ARCHITECTURE.md +73 -69
- package/CHANGELOG.md +27 -0
- package/CONTEXT.md +51 -44
- package/README.md +148 -175
- package/SECURITY.md +16 -26
- package/TELEMETRY.md +8 -6
- package/dist/actors/affordance.d.ts +4 -4
- package/dist/actors/affordance.js +12 -12
- package/dist/actors/agent-session.d.ts +2 -2
- package/dist/actors/agent-session.js +7 -7
- package/dist/actors/codex/app-server-actor-trace.d.ts +1 -1
- package/dist/actors/codex/app-server-actor-trace.js +1 -1
- package/dist/actors/codex/app-server-trace.js +2 -1
- package/dist/actors/codex/app-server-ui.js +1 -1
- package/dist/actors/codex/codex-admission.d.ts +91 -0
- package/dist/actors/codex/codex-admission.js +150 -0
- package/dist/actors/codex/restricted-executable.d.ts +4 -4
- package/dist/actors/codex/restricted-executable.js +8 -8
- package/dist/actors/codex/restricted-launch.d.ts +2 -1
- package/dist/actors/codex/restricted-launch.js +1 -1
- package/dist/actors/codex/restricted-participant.js +20 -18
- package/dist/actors/codex/restricted-policy.d.ts +2 -2
- package/dist/actors/codex/restricted-policy.js +2 -2
- package/dist/actors/codex/restricted-session.d.ts +3 -3
- package/dist/actors/codex/restricted-session.js +10 -5
- package/dist/actors/computer-use/actor.d.ts +18 -18
- package/dist/actors/computer-use/actor.js +4 -4
- package/dist/actors/computer-use/admission-limit.d.ts +3 -3
- package/dist/actors/computer-use/admission-limit.js +4 -4
- package/dist/actors/computer-use/executor-error.d.ts +2 -2
- package/dist/actors/computer-use/executor-error.js +3 -3
- package/dist/actors/computer-use/loop/actions.d.ts +3 -3
- package/dist/actors/computer-use/loop/actions.js +15 -15
- package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
- package/dist/actors/computer-use/loop/backstop.js +14 -12
- package/dist/actors/computer-use/loop/debrief.js +2 -2
- package/dist/actors/computer-use/loop/ending.d.ts +6 -6
- package/dist/actors/computer-use/loop/ending.js +18 -17
- package/dist/actors/computer-use/loop/observation.d.ts +2 -2
- package/dist/actors/computer-use/loop/observation.js +15 -14
- package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
- package/dist/actors/computer-use/loop/provider-call.js +12 -12
- package/dist/actors/computer-use/loop/session.d.ts +4 -4
- package/dist/actors/computer-use/loop/session.js +4 -4
- package/dist/actors/computer-use/loop/spend.d.ts +1 -1
- package/dist/actors/computer-use/loop/spend.js +1 -1
- package/dist/actors/computer-use/loop/trace.js +11 -9
- package/dist/actors/computer-use/loop/types.d.ts +47 -45
- package/dist/actors/computer-use/loop/usage.d.ts +2 -2
- package/dist/actors/computer-use/loop/usage.js +2 -2
- package/dist/actors/computer-use/loop.d.ts +6 -1
- package/dist/actors/computer-use/loop.js +26 -4
- package/dist/actors/computer-use/openai-context.d.ts +37 -0
- package/dist/actors/computer-use/openai-context.js +214 -0
- package/dist/actors/computer-use/openai-provider.d.ts +13 -10
- package/dist/actors/computer-use/openai-provider.js +52 -41
- package/dist/actors/computer-use/openai-requests.d.ts +36 -10
- package/dist/actors/computer-use/openai-requests.js +82 -15
- package/dist/actors/computer-use/openai-wire.d.ts +19 -7
- package/dist/actors/computer-use/openai-wire.js +36 -34
- package/dist/actors/computer-use/provider-error.d.ts +4 -4
- package/dist/actors/computer-use/provider-error.js +6 -6
- package/dist/actors/contract.d.ts +82 -47
- package/dist/actors/contract.js +30 -24
- package/dist/actors/local-agent/claude-session.d.ts +1 -1
- package/dist/actors/local-agent/claude-session.js +13 -12
- package/dist/actors/local-agent/cli.d.ts +9 -7
- package/dist/actors/local-agent/cli.js +24 -28
- package/dist/actors/local-agent/readiness.d.ts +2 -2
- package/dist/actors/local-agent/readiness.js +4 -4
- package/dist/actors/reasoning-effort.js +8 -8
- package/dist/actors/registry.d.ts +12 -12
- package/dist/actors/registry.js +21 -20
- package/dist/actors/scripted-browser/actor.d.ts +10 -10
- package/dist/actors/scripted-browser/actor.js +17 -17
- package/dist/actors/scripted-browser/browser-command.js +1 -1
- package/dist/actors/scripted-browser/steps.js +1 -1
- package/dist/actors/scripted-browser/types.d.ts +1 -1
- package/dist/actors/stop-conditions.d.ts +1 -1
- package/dist/analysis/automatic-completion.d.ts +7 -7
- package/dist/analysis/automatic-completion.js +1 -1
- package/dist/analysis/automatic-config.d.ts +6 -6
- package/dist/analysis/automatic-config.js +1 -1
- package/dist/analysis/codex-config.d.ts +6 -2
- package/dist/analysis/codex-config.js +22 -14
- package/dist/analysis/execute.d.ts +1 -1
- package/dist/analysis/execute.js +1 -1
- package/dist/analysis/service.js +5 -5
- package/dist/analysis/types.d.ts +6 -0
- package/dist/browser-control/client.js +16 -16
- package/dist/browser-control/dispatcher.js +4 -4
- package/dist/browser-control/protocol.js +14 -14
- package/dist/browser-control/recording-transfer.js +4 -4
- package/dist/browser-control/transport.js +7 -7
- package/dist/cli/commands/analysis-signals.d.ts +2 -2
- package/dist/cli/commands/analyze.js +19 -16
- package/dist/cli/commands/codex.js +9 -9
- package/dist/cli/commands/comms.js +48 -35
- package/dist/cli/commands/feedback.js +20 -21
- package/dist/cli/commands/migrate.d.ts +4 -0
- package/dist/cli/commands/migrate.js +65 -0
- package/dist/cli/commands/observe.d.ts +0 -1
- package/dist/cli/commands/observe.js +136 -112
- package/dist/cli/commands/run-command.d.ts +10 -0
- package/dist/cli/commands/run-command.js +85 -0
- package/dist/cli/commands/runs.js +136 -139
- package/dist/cli/commands/setup.d.ts +2 -2
- package/dist/cli/commands/setup.js +27 -24
- package/dist/cli/commands/study-format.d.ts +9 -0
- package/dist/cli/commands/{lab-format.js → study-format.js} +39 -27
- package/dist/cli/commands/{lab-route-computer-use.d.ts → study-route-computer-use.d.ts} +6 -6
- package/dist/cli/commands/{lab-route-computer-use.js → study-route-computer-use.js} +17 -18
- package/dist/cli/commands/{lab-route-open.d.ts → study-route-open.d.ts} +4 -4
- package/dist/cli/commands/{lab-route-open.js → study-route-open.js} +2 -2
- package/dist/cli/commands/{lab-route-preview.d.ts → study-route-preview.d.ts} +7 -7
- package/dist/cli/commands/{lab-route-preview.js → study-route-preview.js} +7 -6
- package/dist/cli/commands/study-route-run.d.ts +19 -0
- package/dist/cli/commands/{lab-route-run.js → study-route-run.js} +6 -6
- package/dist/cli/commands/study-route-scripted.d.ts +17 -0
- package/dist/cli/commands/{lab-route-scripted.js → study-route-scripted.js} +4 -4
- package/dist/cli/commands/{lab-route-shared-world.d.ts → study-route-shared-world.d.ts} +5 -5
- package/dist/cli/commands/{lab-route-shared-world.js → study-route-shared-world.js} +10 -10
- package/dist/cli/commands/study-route-terminal.d.ts +17 -0
- package/dist/cli/commands/{lab-route-terminal.js → study-route-terminal.js} +4 -4
- package/dist/cli/commands/study-run.d.ts +9 -0
- package/dist/cli/commands/{lab-run.js → study-run.js} +44 -45
- package/dist/cli/commands/{lab-scorer.d.ts → study-scorer.d.ts} +7 -7
- package/dist/cli/commands/{lab-scorer.js → study-scorer.js} +2 -2
- package/dist/cli/commands/study.d.ts +3 -0
- package/dist/cli/commands/study.js +146 -0
- package/dist/cli/commands/tui.d.ts +4 -4
- package/dist/cli/commands/tui.js +31 -31
- package/dist/cli/commands/watch.js +71 -121
- package/dist/cli/deprecations.d.ts +6 -0
- package/dist/cli/deprecations.js +18 -0
- package/dist/cli/doctor.d.ts +18 -8
- package/dist/cli/doctor.js +114 -59
- package/dist/cli/first-run-path.d.ts +15 -13
- package/dist/cli/first-run-path.js +35 -33
- package/dist/cli/io.d.ts +44 -9
- package/dist/cli/io.js +98 -23
- package/dist/cli/observer-follow.d.ts +3 -3
- package/dist/cli/observer-follow.js +6 -7
- package/dist/cli/orientation.d.ts +10 -7
- package/dist/cli/orientation.js +89 -47
- package/dist/cli/product-sentence.d.ts +6 -0
- package/dist/cli/product-sentence.js +6 -0
- package/dist/cli/program.d.ts +6 -1
- package/dist/cli/program.js +111 -43
- package/dist/cli/telemetry.d.ts +16 -16
- package/dist/cli/telemetry.js +46 -44
- package/dist/cli.js +1 -1
- package/dist/comms/capture-surface.d.ts +13 -12
- package/dist/comms/capture-surface.js +23 -22
- package/dist/comms/catch-host.d.ts +7 -7
- package/dist/comms/catch-host.js +17 -17
- package/dist/comms/connections.d.ts +1 -1
- package/dist/comms/connections.js +2 -2
- package/dist/comms/email-catch.d.ts +3 -3
- package/dist/comms/email-catch.js +8 -8
- package/dist/comms/external-evidence.d.ts +5 -5
- package/dist/comms/external-evidence.js +5 -4
- package/dist/comms/extract.js +2 -2
- package/dist/comms/fake-inbox.d.ts +3 -3
- package/dist/comms/fake-inbox.js +3 -3
- package/dist/comms/receiving-render.d.ts +1 -1
- package/dist/comms/receiving-render.js +2 -2
- package/dist/comms/receiving-runtime.d.ts +4 -4
- package/dist/comms/sandbox-catch-script.d.ts +6 -6
- package/dist/comms/sandbox-catch-script.js +6 -6
- package/dist/comms/sandbox-catch.d.ts +38 -39
- package/dist/comms/sandbox-catch.js +36 -37
- package/dist/comms/setup.d.ts +2 -2
- package/dist/comms/setup.js +56 -25
- package/dist/comms/thread-evidence.d.ts +1 -1
- package/dist/comms/thread-evidence.js +6 -6
- package/dist/comms/types.d.ts +6 -6
- package/dist/comms/types.js +3 -3
- package/dist/evidence/frame-signature.d.ts +1 -1
- package/dist/evidence/frame-signature.js +4 -4
- package/dist/evidence/redaction.d.ts +3 -3
- package/dist/evidence/redaction.js +4 -4
- package/dist/feedback/draft.js +38 -80
- package/dist/feedback/export-bundle.js +1 -1
- package/dist/feedback/export.d.ts +5 -1
- package/dist/feedback/export.js +10 -10
- package/dist/feedback/feedback.d.ts +2 -2
- package/dist/feedback/feedback.js +21 -3
- package/dist/feedback/proof.d.ts +1 -1
- package/dist/feedback/proof.js +2 -2
- package/dist/guest/bootstrap.js +6 -6
- package/dist/guest/browser-tools.js +8 -8
- package/dist/guest/chromium-text.js +19 -19
- package/dist/guest/desktop-executor.d.ts +2 -2
- package/dist/guest/desktop-executor.js +20 -20
- package/dist/guest/desktop-keys.js +4 -4
- package/dist/guest/desktop-media.d.ts +2 -2
- package/dist/guest/desktop-media.js +16 -16
- package/dist/guest/desktop-native.d.ts +1 -1
- package/dist/guest/desktop-native.js +10 -10
- package/dist/guest/runtime-desktop.js +2 -2
- package/dist/guest/runtime-processes.d.ts +2 -2
- package/dist/guest/runtime-processes.js +2 -2
- package/dist/guest/runtime.js +6 -6
- package/dist/index.d.ts +14 -14
- package/dist/index.js +8 -8
- package/dist/keys/key-resolution.d.ts +5 -5
- package/dist/keys/key-resolution.js +23 -23
- package/dist/observer/artifact.d.ts +2 -2
- package/dist/observer/artifact.js +7 -7
- package/dist/observer/data.d.ts +6 -6
- package/dist/observer/data.js +5 -4
- package/dist/observer/exposure.d.ts +1 -1
- package/dist/observer/exposure.js +11 -11
- package/dist/observer/http.js +1 -1
- package/dist/observer/library.d.ts +3 -1
- package/dist/observer/library.js +8 -3
- package/dist/observer/listen.js +5 -4
- package/dist/observer/render.d.ts +1 -1
- package/dist/observer/render.js +17 -6
- package/dist/observer/run-routes.d.ts +4 -3
- package/dist/observer/run-routes.js +38 -13
- package/dist/observer/serve.d.ts +1 -1
- package/dist/observer/serve.js +7 -3
- package/dist/observer/tunnel.js +1 -1
- package/dist/observer-app.html +4 -4
- package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
- package/dist/routes/computer-use/bundle-parts.js +18 -17
- package/dist/routes/computer-use/bundle.d.ts +2 -2
- package/dist/routes/computer-use/bundle.js +10 -9
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +6 -6
- package/dist/routes/computer-use/e2b-desktop/comms.js +18 -17
- package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +5 -4
- package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
- package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/prepare.js +10 -10
- package/dist/routes/computer-use/e2b-desktop/start.js +7 -7
- package/dist/routes/computer-use/e2b-desktop/state.d.ts +2 -2
- package/dist/routes/computer-use/e2b-desktop/teardown.js +2 -2
- package/dist/routes/computer-use/external-comms.d.ts +4 -4
- package/dist/routes/computer-use/external-comms.js +1 -1
- package/dist/routes/computer-use/fanout-bundle.js +27 -26
- package/dist/routes/computer-use/fanout-records.js +12 -13
- package/dist/routes/computer-use/live-flush.d.ts +4 -4
- package/dist/routes/computer-use/live-flush.js +6 -6
- package/dist/routes/computer-use/live-phase.d.ts +5 -4
- package/dist/routes/computer-use/live-phase.js +8 -8
- package/dist/routes/computer-use/local-tree-pack.d.ts +5 -5
- package/dist/routes/computer-use/local-tree-pack.js +1 -1
- package/dist/routes/computer-use/local-vm.d.ts +8 -8
- package/dist/routes/computer-use/local-vm.js +3 -3
- package/dist/routes/computer-use/participant-desktop.d.ts +7 -7
- package/dist/routes/computer-use/participant-desktop.js +5 -5
- package/dist/routes/computer-use/participant-execution.d.ts +4 -4
- package/dist/routes/computer-use/participant-execution.js +10 -10
- package/dist/routes/computer-use/participant-model.d.ts +6 -0
- package/dist/routes/computer-use/participant-model.js +33 -15
- package/dist/routes/computer-use/participant-prompt.d.ts +15 -15
- package/dist/routes/computer-use/participant-prompt.js +9 -9
- package/dist/routes/computer-use/participant-runs.d.ts +16 -16
- package/dist/routes/computer-use/participant-runs.js +26 -25
- package/dist/routes/computer-use/plan.d.ts +12 -12
- package/dist/routes/computer-use/plan.js +42 -42
- package/dist/routes/computer-use/preflight.d.ts +5 -5
- package/dist/routes/computer-use/preflight.js +25 -25
- package/dist/routes/computer-use/rerun-selection.d.ts +1 -1
- package/dist/routes/computer-use/rerun-selection.js +4 -3
- package/dist/routes/computer-use/result.d.ts +4 -4
- package/dist/routes/computer-use/result.js +22 -21
- package/dist/routes/computer-use/route.d.ts +12 -11
- package/dist/routes/computer-use/route.js +31 -30
- package/dist/routes/computer-use/self-report.d.ts +7 -7
- package/dist/routes/computer-use/self-report.js +32 -32
- package/dist/routes/computer-use/setup.d.ts +23 -23
- package/dist/routes/computer-use/setup.js +28 -29
- package/dist/routes/computer-use/single-bundle.d.ts +11 -11
- package/dist/routes/computer-use/single-bundle.js +40 -41
- package/dist/routes/computer-use/subject-projection.d.ts +4 -4
- package/dist/routes/computer-use/subject-projection.js +6 -6
- package/dist/routes/computer-use/types.d.ts +71 -73
- package/dist/routes/computer-use/types.js +12 -12
- package/dist/routes/preview.d.ts +13 -7
- package/dist/routes/preview.js +11 -7
- package/dist/routes/scripted/bundle.d.ts +7 -7
- package/dist/routes/scripted/bundle.js +20 -18
- package/dist/routes/scripted/plan.d.ts +8 -8
- package/dist/routes/scripted/plan.js +13 -13
- package/dist/routes/scripted/result.d.ts +3 -3
- package/dist/routes/scripted/result.js +13 -13
- package/dist/routes/scripted/route.d.ts +9 -9
- package/dist/routes/scripted/route.js +15 -16
- package/dist/routes/scripted/scenario.d.ts +1 -1
- package/dist/routes/scripted/scenario.js +5 -5
- package/dist/routes/scripted/setup.d.ts +6 -6
- package/dist/routes/scripted/setup.js +8 -8
- package/dist/routes/scripted/subject.d.ts +5 -5
- package/dist/routes/scripted/subject.js +4 -4
- package/dist/routes/scripted/surface-records.d.ts +1 -1
- package/dist/routes/scripted/surface-records.js +4 -4
- package/dist/routes/scripted/surface-sessions.d.ts +3 -3
- package/dist/routes/scripted/types.d.ts +18 -20
- package/dist/routes/scripted/types.js +2 -2
- package/dist/routes/shared-world/bundle-records.js +11 -10
- package/dist/routes/shared-world/bundle.d.ts +5 -5
- package/dist/routes/shared-world/bundle.js +46 -43
- package/dist/routes/shared-world/checkpoints.d.ts +4 -4
- package/dist/routes/shared-world/checkpoints.js +2 -2
- package/dist/routes/shared-world/comms.d.ts +14 -14
- package/dist/routes/shared-world/comms.js +19 -18
- package/dist/routes/shared-world/external-public.d.ts +4 -3
- package/dist/routes/shared-world/external-public.js +16 -12
- package/dist/routes/shared-world/handoff.d.ts +7 -6
- package/dist/routes/shared-world/handoff.js +65 -57
- package/dist/routes/shared-world/lobby-code.d.ts +2 -2
- package/dist/routes/shared-world/lobby-code.js +9 -9
- package/dist/routes/shared-world/participant-specs.d.ts +10 -9
- package/dist/routes/shared-world/participant-specs.js +38 -31
- package/dist/routes/shared-world/plan.d.ts +9 -9
- package/dist/routes/shared-world/plan.js +16 -16
- package/dist/routes/shared-world/provenance.d.ts +2 -2
- package/dist/routes/shared-world/provenance.js +2 -2
- package/dist/routes/shared-world/provisioned.d.ts +8 -8
- package/dist/routes/shared-world/provisioned.js +18 -17
- package/dist/routes/shared-world/result.d.ts +6 -6
- package/dist/routes/shared-world/result.js +29 -29
- package/dist/routes/shared-world/route.d.ts +11 -11
- package/dist/routes/shared-world/route.js +40 -39
- package/dist/routes/shared-world/setup.d.ts +16 -16
- package/dist/routes/shared-world/setup.js +23 -23
- package/dist/routes/shared-world/types.d.ts +55 -53
- package/dist/routes/shared-world/types.js +4 -4
- package/dist/routes/terminal/adapter.d.ts +5 -5
- package/dist/routes/terminal/adapter.js +9 -9
- package/dist/routes/terminal/bundle.d.ts +13 -13
- package/dist/routes/terminal/bundle.js +28 -27
- package/dist/routes/terminal/credentials.d.ts +8 -8
- package/dist/routes/terminal/credentials.js +12 -12
- package/dist/routes/terminal/dry-run.d.ts +4 -4
- package/dist/routes/terminal/dry-run.js +12 -12
- package/dist/routes/terminal/encoding.js +2 -2
- package/dist/routes/terminal/ledger.d.ts +5 -5
- package/dist/routes/terminal/ledger.js +14 -14
- package/dist/routes/terminal/lifetime.d.ts +1 -1
- package/dist/routes/terminal/lifetime.js +1 -1
- package/dist/routes/terminal/live-finish.d.ts +2 -2
- package/dist/routes/terminal/live-finish.js +10 -10
- package/dist/routes/terminal/live-sandbox.d.ts +2 -2
- package/dist/routes/terminal/live-sandbox.js +15 -15
- package/dist/routes/terminal/participant-text.js +2 -1
- package/dist/routes/terminal/persona.d.ts +2 -2
- package/dist/routes/terminal/persona.js +3 -3
- package/dist/routes/terminal/plan.d.ts +7 -7
- package/dist/routes/terminal/plan.js +15 -15
- package/dist/routes/terminal/recorder.js +2 -2
- package/dist/routes/terminal/result.d.ts +5 -5
- package/dist/routes/terminal/result.js +14 -14
- package/dist/routes/terminal/route.d.ts +9 -9
- package/dist/routes/terminal/route.js +19 -20
- package/dist/routes/terminal/sandbox.d.ts +1 -1
- package/dist/routes/terminal/sandbox.js +1 -1
- package/dist/routes/terminal/session.d.ts +5 -5
- package/dist/routes/terminal/session.js +14 -13
- package/dist/routes/terminal/token-usage.d.ts +1 -1
- package/dist/routes/terminal/token-usage.js +7 -8
- package/dist/routes/terminal/trace.d.ts +4 -4
- package/dist/routes/terminal/trace.js +2 -2
- package/dist/routes/terminal/types.d.ts +48 -50
- package/dist/routes/terminal/types.js +5 -5
- package/dist/run/bundle-shape.js +3 -3
- package/dist/run/bundle.d.ts +49 -49
- package/dist/run/bundle.js +3 -2
- package/dist/run/cost-summary.js +3 -3
- package/dist/run/costs.d.ts +23 -0
- package/dist/run/costs.js +79 -44
- package/dist/run/detail.d.ts +6 -6
- package/dist/run/detail.js +4 -4
- package/dist/run/dry-run-inputs.d.ts +1 -1
- package/dist/run/dry-run-inputs.js +2 -2
- package/dist/run/dry-run.js +20 -20
- package/dist/run/judge.d.ts +19 -13
- package/dist/run/judge.js +18 -8
- package/dist/run/outcomes.d.ts +1 -1
- package/dist/run/participant.d.ts +1 -1
- package/dist/run/paths.d.ts +1 -1
- package/dist/run/paths.js +1 -1
- package/dist/run/preflight-receipts.js +1 -1
- package/dist/run/pricing.d.ts +11 -6
- package/dist/run/pricing.js +22 -15
- package/dist/run/projection.d.ts +46 -46
- package/dist/run/projection.js +57 -57
- package/dist/run/reclaim.d.ts +1 -1
- package/dist/run/reclaim.js +3 -3
- package/dist/run/results.d.ts +5 -5
- package/dist/run/run-cost.d.ts +53 -0
- package/dist/run/run-cost.js +105 -0
- package/dist/run/run-index-analysis.d.ts +15 -0
- package/dist/run/run-index-analysis.js +77 -0
- package/dist/run/run-index.d.ts +19 -7
- package/dist/run/run-index.js +77 -64
- package/dist/run/run-not-found.d.ts +5 -0
- package/dist/run/run-not-found.js +15 -0
- package/dist/run/run.d.ts +6 -5
- package/dist/run/run.js +3 -3
- package/dist/run/sandbox-receipts.d.ts +2 -2
- package/dist/run/sandbox-receipts.js +3 -3
- package/dist/run/shared-world-evidence.d.ts +37 -36
- package/dist/run/shared-world-evidence.js +4 -4
- package/dist/run/shared-world-shape.d.ts +1 -1
- package/dist/run/shared-world-shape.js +7 -7
- package/dist/run/stats.d.ts +14 -8
- package/dist/run/stats.js +121 -63
- package/dist/run/status.d.ts +16 -29
- package/dist/run/status.js +10 -29
- package/dist/run/stored-runs.js +2 -1
- package/dist/run/stream-shape.js +1 -1
- package/dist/run/streams.d.ts +7 -7
- package/dist/run/study-provenance.d.ts +49 -0
- package/dist/run/study-provenance.js +66 -0
- package/dist/run/study-result.d.ts +11 -0
- package/dist/run/study-result.js +9 -0
- package/dist/run/text.d.ts +2 -0
- package/dist/run/text.js +4 -0
- package/dist/run-study.d.ts +112 -0
- package/dist/{run-lab.js → run-study.js} +52 -47
- package/dist/{lab → study}/adapter-extension.d.ts +15 -27
- package/dist/{lab → study}/adapter-extension.js +10 -45
- package/dist/{lab → study}/adapter-scorer-loader.d.ts +17 -17
- package/dist/{lab → study}/adapter-scorer-loader.js +34 -34
- package/dist/study/composition-rules.d.ts +7 -0
- package/dist/{lab → study}/composition-rules.js +53 -53
- package/dist/study/config.d.ts +15 -0
- package/dist/{lab → study}/config.js +98 -41
- package/dist/study/convert.d.ts +33 -0
- package/dist/study/convert.js +432 -0
- package/dist/{lab → study}/device-presets.d.ts +10 -10
- package/dist/{lab → study}/device-presets.js +11 -11
- package/dist/study/discover.d.ts +75 -0
- package/dist/{lab → study}/discover.js +134 -95
- package/dist/{lab → study}/doctor.d.ts +19 -12
- package/dist/{lab → study}/doctor.js +58 -20
- package/dist/study/field-paths.d.ts +12 -0
- package/dist/study/field-paths.js +126 -0
- package/dist/study/files.d.ts +26 -0
- package/dist/study/files.js +44 -0
- package/dist/{lab → study}/init-templates.d.ts +2 -2
- package/dist/study/init-templates.js +421 -0
- package/dist/{lab → study}/init.d.ts +2 -2
- package/dist/{lab → study}/init.js +46 -11
- package/dist/study/keys.d.ts +4 -0
- package/dist/{lab → study}/keys.js +46 -12
- package/dist/study/migrate.d.ts +48 -0
- package/dist/study/migrate.js +408 -0
- package/dist/study/owned-files.d.ts +38 -0
- package/dist/study/owned-files.js +182 -0
- package/dist/{lab → study}/parse/actors.d.ts +5 -5
- package/dist/{lab → study}/parse/actors.js +14 -14
- package/dist/study/parse/comms.d.ts +12 -0
- package/dist/{lab → study}/parse/comms.js +5 -5
- package/dist/study/parse/execution.d.ts +19 -0
- package/dist/{lab → study}/parse/execution.js +13 -13
- package/dist/study/parse/study-v3.d.ts +21 -0
- package/dist/study/parse/study-v3.js +259 -0
- package/dist/study/parse/subject-state.d.ts +30 -0
- package/dist/{lab → study}/parse/subject-state.js +19 -19
- package/dist/{lab → study}/parse/subject.d.ts +3 -3
- package/dist/{lab → study}/parse/subject.js +34 -34
- package/dist/{lab → study}/parse/values.d.ts +3 -3
- package/dist/{lab → study}/parse/values.js +3 -3
- package/dist/{lab → study}/persona-resolve.d.ts +8 -8
- package/dist/{lab → study}/persona-resolve.js +6 -6
- package/dist/{lab → study}/plan-base.d.ts +7 -7
- package/dist/{lab → study}/plan-base.js +1 -1
- package/dist/{lab → study}/plan-participants.d.ts +12 -12
- package/dist/{lab → study}/plan-participants.js +4 -4
- package/dist/{lab → study}/plan-types.d.ts +31 -31
- package/dist/{lab → study}/plan-types.js +2 -2
- package/dist/study/plan.d.ts +13 -0
- package/dist/study/plan.js +101 -0
- package/dist/study/preflight-probes.d.ts +3 -0
- package/dist/{lab → study}/preflight-probes.js +20 -19
- package/dist/study/preflight-result.d.ts +8 -0
- package/dist/{lab → study}/preflight-result.js +5 -4
- package/dist/study/preflight.d.ts +94 -0
- package/dist/{lab → study}/preflight.js +12 -12
- package/dist/{lab → study}/requirements.d.ts +3 -3
- package/dist/{lab → study}/requirements.js +1 -1
- package/dist/study/route-inputs.d.ts +28 -0
- package/dist/{lab → study}/route-inputs.js +1 -1
- package/dist/{lab → study}/routing.d.ts +39 -33
- package/dist/{lab → study}/routing.js +60 -29
- package/dist/{lab/run-lab-events.d.ts → study/run-study-events.d.ts} +10 -13
- package/dist/{lab/run-lab-events.js → study/run-study-events.js} +3 -9
- package/dist/{lab/run-lab-homes.d.ts → study/run-study-homes.d.ts} +21 -18
- package/dist/{lab/run-lab-homes.js → study/run-study-homes.js} +1 -1
- package/dist/study/run-study-options.d.ts +28 -0
- package/dist/{lab/run-lab-options.js → study/run-study-options.js} +29 -25
- package/dist/{lab/lab-deps.d.ts → study/study-deps.d.ts} +8 -13
- package/dist/{lab/lab-deps.js → study/study-deps.js} +2 -2
- package/dist/{lab → study}/summary.d.ts +16 -15
- package/dist/{lab → study}/summary.js +21 -21
- package/dist/{lab → study}/tasks.d.ts +18 -18
- package/dist/{lab → study}/tasks.js +14 -14
- package/dist/{lab → study}/types.d.ts +202 -196
- package/dist/{lab → study}/types.js +3 -1
- package/dist/{lab → study}/validation.d.ts +27 -27
- package/dist/{lab → study}/validation.js +53 -51
- package/dist/study/warnings.d.ts +12 -0
- package/dist/{lab → study}/warnings.js +62 -34
- package/dist/subject/clone.d.ts +7 -7
- package/dist/subject/clone.js +2 -2
- package/dist/subject/desktop-cli.d.ts +1 -1
- package/dist/subject/desktop-cli.js +2 -2
- package/dist/subject/local-tree-archive.d.ts +2 -2
- package/dist/subject/local-tree-archive.js +4 -4
- package/dist/subject/local-tree.d.ts +4 -4
- package/dist/subject/node-bootstrap.js +1 -1
- package/dist/subject/runtime.js +9 -10
- package/dist/subject/serve.d.ts +5 -5
- package/dist/subject/serve.js +3 -3
- package/dist/subject/state.d.ts +4 -4
- package/dist/subject/state.js +1 -1
- package/dist/subject/steps.d.ts +6 -6
- package/dist/subject/steps.js +5 -5
- package/dist/substrates/command-failure.d.ts +3 -3
- package/dist/substrates/command-failure.js +3 -3
- package/dist/substrates/desktop-session.js +2 -2
- package/dist/substrates/detached.d.ts +6 -6
- package/dist/substrates/detached.js +7 -7
- package/dist/substrates/e2b/cdp-probe.d.ts +9 -9
- package/dist/substrates/e2b/cdp-probe.js +14 -17
- package/dist/substrates/e2b/desktop-browser.d.ts +6 -6
- package/dist/substrates/e2b/desktop-browser.js +9 -9
- package/dist/substrates/e2b/desktop-cdp.d.ts +10 -10
- package/dist/substrates/e2b/desktop-cdp.js +9 -9
- package/dist/substrates/e2b/desktop-executor.d.ts +2 -2
- package/dist/substrates/e2b/desktop-executor.js +13 -13
- package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
- package/dist/substrates/e2b/desktop-geometry.js +8 -8
- package/dist/substrates/e2b/desktop-media.d.ts +4 -4
- package/dist/substrates/e2b/desktop-media.js +1 -1
- package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
- package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
- package/dist/substrates/e2b/lifetime.js +1 -1
- package/dist/substrates/e2b/sandbox.d.ts +4 -4
- package/dist/substrates/e2b/sandbox.js +2 -2
- package/dist/substrates/e2b/sdk.d.ts +12 -12
- package/dist/substrates/e2b/sdk.js +7 -7
- package/dist/substrates/local/runtime-config.d.ts +4 -4
- package/dist/substrates/local/runtime-config.js +4 -4
- package/dist/tui/actions.d.ts +1 -1
- package/dist/tui/actions.js +13 -13
- package/dist/tui/contract.d.ts +23 -23
- package/dist/tui/contract.js +11 -11
- package/dist/tui/launch.d.ts +7 -7
- package/dist/tui/launch.js +36 -31
- package/dist/tui/project.js +5 -5
- package/dist/tui-app.js +139 -139
- package/dist/verify/actor.d.ts +8 -8
- package/dist/verify/actor.js +36 -36
- package/dist/verify/artifacts.d.ts +2 -2
- package/dist/verify/artifacts.js +3 -3
- package/dist/verify/context-growth.d.ts +9 -0
- package/dist/verify/context-growth.js +62 -0
- package/dist/verify/costs.d.ts +6 -6
- package/dist/verify/costs.js +8 -8
- package/dist/verify/shared-world-concurrent.d.ts +2 -2
- package/dist/verify/shared-world-concurrent.js +79 -76
- package/dist/verify/shared-world.d.ts +2 -2
- package/dist/verify/shared-world.js +16 -16
- package/dist/verify/subject.d.ts +5 -5
- package/dist/verify/subject.js +19 -19
- package/dist/verify/verify.js +94 -44
- package/docs/README.md +25 -32
- package/docs/architecture/actor-contract.md +60 -91
- package/docs/architecture/browser-control.md +1 -1
- package/docs/architecture/desktop-sessions.md +7 -7
- package/docs/architecture/external-public-shared-world.md +68 -65
- package/docs/architecture/github-feedback-loop.md +2 -5
- package/docs/architecture/guest-desktop.md +2 -2
- package/docs/architecture/observer.md +34 -34
- package/docs/architecture/restricted-codex-analysis.md +34 -28
- package/docs/architecture/serve.md +34 -37
- package/docs/architecture/state-driven-executor.md +55 -58
- package/docs/architecture/task-protocol-support.md +6 -6
- package/docs/architecture/terminal-product-route.md +70 -110
- package/docs/contracts/README.md +24 -0
- package/docs/contracts/adapter-admission.md +3 -3
- package/docs/contracts/adapter-fixtures.md +4 -7
- package/docs/contracts/core.md +1 -3
- package/docs/contracts/errors.md +62 -0
- package/docs/contracts/feedback.md +8 -9
- package/docs/contracts/policy.md +7 -12
- package/docs/contracts/run-bundle.md +42 -44
- package/docs/contracts/schemas.md +446 -368
- package/docs/contracts/study-analysis.md +7 -4
- package/docs/contracts/study-costs.md +28 -9
- package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
- package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
- package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
- package/docs/principles/actor-fidelity.md +4 -4
- package/docs/principles/engineering.md +3 -3
- package/docs/principles/invariants-and-defaults.md +38 -38
- package/docs/principles/self-driving-harness.md +1 -5
- package/docs/principles/three-roles.md +1 -1
- package/docs/product/automatic-analysis.md +7 -7
- package/examples/README.md +1 -1
- package/examples/participant/README.md +5 -5
- package/examples/participant/run.mjs +11 -10
- package/examples/scorer/README.md +3 -3
- package/examples/scorer/run.mjs +11 -12
- package/examples/scorer/scorer.mjs +3 -3
- package/package.json +16 -17
- package/skills/humanish/SKILL.md +64 -60
- package/skills/humanish/agents/openai.yaml +1 -1
- package/AGENTS.md +0 -99
- package/CONTRIBUTING.md +0 -148
- package/dist/actors/codex/qualified-versions.d.ts +0 -72
- package/dist/actors/codex/qualified-versions.js +0 -132
- package/dist/cli/commands/lab-format.d.ts +0 -8
- package/dist/cli/commands/lab-route-run.d.ts +0 -19
- package/dist/cli/commands/lab-route-scripted.d.ts +0 -17
- package/dist/cli/commands/lab-route-terminal.d.ts +0 -17
- package/dist/cli/commands/lab-run.d.ts +0 -9
- package/dist/cli/commands/lab.d.ts +0 -3
- package/dist/cli/commands/lab.js +0 -199
- package/dist/cli/renamed-options.d.ts +0 -11
- package/dist/cli/renamed-options.js +0 -18
- package/dist/lab/composition-rules.d.ts +0 -7
- package/dist/lab/config.d.ts +0 -7
- package/dist/lab/discover.d.ts +0 -65
- package/dist/lab/init-templates.js +0 -416
- package/dist/lab/keys.d.ts +0 -2
- package/dist/lab/parse/comms.d.ts +0 -12
- package/dist/lab/parse/execution.d.ts +0 -19
- package/dist/lab/parse/subject-state.d.ts +0 -30
- package/dist/lab/plan.d.ts +0 -19
- package/dist/lab/plan.js +0 -132
- package/dist/lab/preflight-probes.d.ts +0 -3
- package/dist/lab/preflight-result.d.ts +0 -7
- package/dist/lab/preflight.d.ts +0 -92
- package/dist/lab/route-inputs.d.ts +0 -28
- package/dist/lab/run-lab-options.d.ts +0 -28
- package/dist/lab/warnings.d.ts +0 -2
- package/dist/observer/static.d.ts +0 -39
- package/dist/observer/static.js +0 -369
- package/dist/run-lab.d.ts +0 -112
- package/docs/architecture/comms-inbox.md +0 -122
- package/docs/architecture/desktop-recording.md +0 -80
- package/docs/architecture/local-browser-runtime.md +0 -178
- package/docs/architecture/observer-review.md +0 -144
- package/docs/architecture/participant-media.md +0 -90
- package/docs/architecture/project-layout.md +0 -62
- package/docs/architecture/real-email-receiving.md +0 -136
- package/docs/assets/humanish-drawdb-hero.png +0 -0
- package/docs/assets/humanish-observer-hero.png +0 -0
- package/docs/goals/current.md +0 -207
- package/docs/product/lobby-trivia-3player-external-public.md +0 -77
- package/docs/product/open-source-install-experience.md +0 -240
- package/docs/ramp/README.md +0 -295
- package/docs/release/open-source-readiness.md +0 -222
- package/docs/release/public-readiness-standard.md +0 -210
- package/docs/roadmap/world-class-open-source-v0.md +0 -311
- /package/dist/{lab → study}/init-paths.d.ts +0 -0
- /package/dist/{lab → study}/init-paths.js +0 -0
- /package/dist/{lab → study}/init-plan.d.ts +0 -0
- /package/dist/{lab → study}/init-plan.js +0 -0
- /package/dist/{lab → study}/participant-assignment.d.ts +0 -0
- /package/dist/{lab → study}/participant-assignment.js +0 -0
- /package/dist/{lab → study}/persona.d.ts +0 -0
- /package/dist/{lab → study}/persona.js +0 -0
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
// Which subject, target and actor compositions a
|
|
1
|
+
// Which subject, target and actor compositions a study may declare. Each rule returns the refusal
|
|
2
2
|
// message for the first thing its composition gets wrong, or null. compositionReason runs them in
|
|
3
|
-
// the parser's order, and only
|
|
3
|
+
// the parser's order, and only parseStudy calls it. planStudy does not: each route planner checks
|
|
4
4
|
// a library caller's config itself, under its route's error codes. The planners call the shared
|
|
5
|
-
// checks in
|
|
5
|
+
// checks in study/validation.ts and desktopCliProductReason below. The other subject rules here have
|
|
6
6
|
// planner counterparts whose conditions and wording differ (clone serve and repo, local-tree
|
|
7
7
|
// target, in-process fan-out, loopback targets, scripted scenario.ref).
|
|
8
8
|
import { isLoopbackUrl } from "./parse/subject.js";
|
|
9
9
|
import { REPO_SLUG_PATTERN } from "./parse/values.js";
|
|
10
10
|
import { declaredTargets } from "./plan-participants.js";
|
|
11
|
-
import { actorResolvesToComputerUse, actorResolvesToScriptedBrowser, actorResolvesToTerminal,
|
|
12
|
-
import { cloneTargetValidationReason,
|
|
11
|
+
import { actorResolvesToComputerUse, actorResolvesToScriptedBrowser, actorResolvesToTerminal, computerUseParticipantCount, registeredComputerUseActors, registeredScriptedBrowserActors, registeredTerminalActors, isComputerUseComposition, } from "./routing.js";
|
|
12
|
+
import { cloneTargetValidationReason, computerUseValidationReason, sharedWorldValidationReason, } from "./validation.js";
|
|
13
13
|
import { rosterOf } from "./parse/actors.js";
|
|
14
14
|
/** The first composition rule a config breaks, in the parser's order, or null. */
|
|
15
15
|
export function compositionReason(config) {
|
|
@@ -22,7 +22,7 @@ export function compositionReason(config) {
|
|
|
22
22
|
cloneComputerUseValidationReason(config) ??
|
|
23
23
|
localTreeValidationReason(config) ??
|
|
24
24
|
// Independent computer-use participants: the roster contract on every route that resolves to cua.
|
|
25
|
-
(isComputerUseComposition(config) ?
|
|
25
|
+
(isComputerUseComposition(config) ? computerUseValidationReason(config) : null) ??
|
|
26
26
|
// Whenever shared world is declared, not only when it routes, so a half-declared shared world
|
|
27
27
|
// fails with a precise reason instead of running as independent participants.
|
|
28
28
|
(config.subject.topology === "shared-world" ? sharedWorldValidationReason(config) : null) ??
|
|
@@ -30,14 +30,14 @@ export function compositionReason(config) {
|
|
|
30
30
|
terminalValidationReason(config) ??
|
|
31
31
|
cloneActorValidationReason(config));
|
|
32
32
|
}
|
|
33
|
-
/** Why a this-repo
|
|
34
|
-
export const THIS_REPO_DRY_RUN_ONLY = "this-repo
|
|
35
|
-
// this-repo subjects run locally and dry-run only
|
|
33
|
+
/** Why a this-repo study cannot run live. The parser and the preview planner both refuse with it. */
|
|
34
|
+
export const THIS_REPO_DRY_RUN_ONLY = "this-repo studies are dry-run only; use a clone or app-url subject for a live run.";
|
|
35
|
+
// this-repo subjects run locally and dry-run only: there is no live execution target for the
|
|
36
36
|
// host repo (clone/app-url provide that). Reject the mis-configs rather than silently mishandle.
|
|
37
37
|
function thisRepoValidationReason(config) {
|
|
38
38
|
if (config.subject.source === "this-repo") {
|
|
39
39
|
if (config.execution?.target) {
|
|
40
|
-
return "`execution.target` applies only to clone/app-url/local-app subjects; this-repo
|
|
40
|
+
return "`execution.target` applies only to clone/app-url/local-app subjects; this-repo studies run locally.";
|
|
41
41
|
}
|
|
42
42
|
if (config.scenario?.mode === "live") {
|
|
43
43
|
return THIS_REPO_DRY_RUN_ONLY;
|
|
@@ -51,51 +51,51 @@ function thisRepoValidationReason(config) {
|
|
|
51
51
|
// desktop), and no public-target policy (it is always loopback; the loopback shape was already
|
|
52
52
|
// enforced in parseSubject). The actual "no inProcess executor supplied" case is inherently an
|
|
53
53
|
// engine-time decision (the parser cannot know whether a library caller will pass one), so
|
|
54
|
-
// it fails closed in
|
|
54
|
+
// it fails closed in runCuaActorStudy with HUMANISH_COMPUTER_USE_LOCAL_APP_NO_EXECUTOR.
|
|
55
55
|
function localAppValidationReason(config) {
|
|
56
56
|
if (config.subject.source === "local-app") {
|
|
57
57
|
const type = config.actors[0]?.type ?? "";
|
|
58
58
|
if (config.execution?.target !== undefined && config.execution.target !== "local") {
|
|
59
|
-
return "local-app
|
|
59
|
+
return "A local-app subject drives a local dev server in this process, with no E2B desktop. Set `execution.target: local` or omit it. To run on a hosted desktop, use an app-url subject with `execution.target: e2b-desktop`.";
|
|
60
60
|
}
|
|
61
61
|
if (!actorResolvesToComputerUse(type)) {
|
|
62
62
|
return `actors[0].type must be a registered computer-use actor for local-app subjects (one of: ${registeredComputerUseActors().join(", ")}); the caller's custom executor runs the computer-use loop. Got "${type}".`;
|
|
63
63
|
}
|
|
64
|
-
if (
|
|
64
|
+
if (computerUseParticipantCount(config) > 1) {
|
|
65
65
|
return "Fan-out to more than one participant is not supported on the in-process/local-app route: fan-out provisions one independent E2B desktop per participant, which the in-process route deliberately skips. Set actors[0].count to 1 and drop actors[0].lanes (use an app-url or clone subject on execution.target: e2b-desktop for fan-out).";
|
|
66
66
|
}
|
|
67
67
|
if (rosterOf(config.actors[0]) !== undefined) {
|
|
68
68
|
return "`actors[0].lanes` (fan-out roster) is not supported on the in-process/local-app route: it provisions one E2B desktop per participant, which this route skips. Use an app-url or clone subject with execution.target: e2b-desktop.";
|
|
69
69
|
}
|
|
70
70
|
if (config.policies?.allowPublicTargets === true) {
|
|
71
|
-
return "`policies.allowPublicTargets`
|
|
71
|
+
return "`policies.allowPublicTargets` does not apply to a local-app subject: it is always a loopback dev server, so there is no public target to allow. Remove the setting.";
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
return null;
|
|
75
75
|
}
|
|
76
|
-
// app-url routes: the actor type is a real dispatch key (registry-resolved). The actor
|
|
76
|
+
// app-url routes: the actor type is a real dispatch key (registry-resolved). The actor's run kind
|
|
77
77
|
// picks the substrate: a scripted-browser actor runs locally against the declared loopback
|
|
78
78
|
// app; a computer-use actor drives a hosted desktop browser. Fail closed on mis-configs.
|
|
79
79
|
function appUrlValidationReason(config) {
|
|
80
80
|
if (config.subject.source === "app-url") {
|
|
81
81
|
const type = config.actors[0]?.type ?? "";
|
|
82
82
|
if (actorResolvesToScriptedBrowser(type)) {
|
|
83
|
-
// Scripted-browser route (all fail-closed
|
|
83
|
+
// Scripted-browser route (all fail-closed, so claims match mechanism: a field that cannot act on
|
|
84
84
|
// this route is rejected, never silently ignored).
|
|
85
85
|
if (config.execution?.target !== undefined && config.execution.target !== "local") {
|
|
86
|
-
return "scripted-browser
|
|
86
|
+
return "A scripted-browser actor on an app-url subject runs on this machine. Set `execution.target: local` or omit it. To run scripted steps on a hosted desktop, use a clone subject.";
|
|
87
87
|
}
|
|
88
88
|
if (!config.scenario?.ref) {
|
|
89
|
-
return "scripted-browser
|
|
89
|
+
return "A scripted-browser study needs `scenario.ref`: the actor runs the browser steps in that scenario file.";
|
|
90
90
|
}
|
|
91
91
|
if ((config.actors[0]?.count ?? 1) > 2) {
|
|
92
|
-
return "scripted-browser
|
|
92
|
+
return "A scripted-browser study takes `actors[0].count` 1 (desktop) or 2 (desktop and mobile). Higher counts are not supported yet.";
|
|
93
93
|
}
|
|
94
94
|
if (config.policies?.redactScreenshots === true) {
|
|
95
|
-
return "`policies.redactScreenshots: true` is not
|
|
95
|
+
return "`policies.redactScreenshots: true` is not supported on the scripted-browser route yet, so its screenshots would be stored unredacted in .humanish/. Remove the setting, or use a computer-use actor, which blurs screenshots as it takes them.";
|
|
96
96
|
}
|
|
97
97
|
if (config.policies?.allowPublicTargets === true) {
|
|
98
|
-
return "`policies.allowPublicTargets` is not supported on the scripted-browser route
|
|
98
|
+
return "`policies.allowPublicTargets` is not supported on the scripted-browser route: the step driver allows only loopback URLs at every navigation. Remove the setting, or drive the public URL with a computer-use actor.";
|
|
99
99
|
}
|
|
100
100
|
if (!isLoopbackUrl(config.subject.appUrl ?? "")) {
|
|
101
101
|
return "`subject.appUrl` must be a loopback URL (127.0.0.1/localhost) on the scripted-browser route.";
|
|
@@ -106,7 +106,7 @@ function appUrlValidationReason(config) {
|
|
|
106
106
|
return "app-url computer-use subjects require `execution.target: local` or `e2b-desktop`.";
|
|
107
107
|
}
|
|
108
108
|
if (!actorResolvesToComputerUse(type)) {
|
|
109
|
-
return `actors[0].type must be a registered computer-use actor for app-url × e2b-desktop
|
|
109
|
+
return `actors[0].type must be a registered computer-use actor for app-url × e2b-desktop studies (one of: ${registeredComputerUseActors().join(", ")}); for local scripted execution use a registered scripted-browser actor (${registeredScriptedBrowserActors().join(", ")}). Got "${type}".`;
|
|
110
110
|
}
|
|
111
111
|
// Multi-participant fan-out is consumed on this route (`per-lane-worlds`; the shared cua
|
|
112
112
|
// cross-validation below enforces `lanes`/`count` XOR rules, the 16 cap, and the
|
|
@@ -116,7 +116,7 @@ function appUrlValidationReason(config) {
|
|
|
116
116
|
const targets = [config.subject.appUrl ?? "", ...declaredTargets(config)];
|
|
117
117
|
const unsafeTarget = targets.find((target) => !config.policies?.allowPublicTargets && !isLoopbackUrl(target));
|
|
118
118
|
if (unsafeTarget !== undefined) {
|
|
119
|
-
return "`subject.appUrl` and `actors[0].lanes[].target` must be loopback URLs (127.0.0.1
|
|
119
|
+
return "`subject.appUrl` and `actors[0].lanes[].target` must be loopback URLs (127.0.0.1 or localhost). To drive a deployed or preview URL you own, set `policies.allowPublicTargets: true`.";
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
122
|
}
|
|
@@ -130,54 +130,54 @@ function scriptedBrowserValidationReason(config) {
|
|
|
130
130
|
return "scripted-browser actors require `subject.source: app-url` (a running app at a loopback URL) or `subject.source: clone` with `execution.target: e2b-desktop` (a provisioned synthetic subject).";
|
|
131
131
|
}
|
|
132
132
|
if (config.execution?.target !== "e2b-desktop") {
|
|
133
|
-
return "clone
|
|
133
|
+
return "A clone subject with a scripted-browser actor needs `execution.target: e2b-desktop`: humanish builds the clone in an E2B sandbox, opens it at a public sandbox URL and runs the scenario's browser steps against it.";
|
|
134
134
|
}
|
|
135
135
|
if (!config.subject.serve) {
|
|
136
|
-
return "clone
|
|
136
|
+
return "A clone subject with a scripted-browser actor needs `subject.serve` (start and url): humanish starts the app in the sandbox before the browser steps run.";
|
|
137
137
|
}
|
|
138
138
|
if ((config.subject.repos?.length ?? 0) !== 1) {
|
|
139
|
-
return "clone scripted-browser
|
|
139
|
+
return "clone scripted-browser studies require exactly one repo in subject.repos.";
|
|
140
140
|
}
|
|
141
141
|
const repo = config.subject.repos?.[0] ?? "";
|
|
142
142
|
if (!REPO_SLUG_PATTERN.test(repo)) {
|
|
143
143
|
return `subject.repos[0] must be an owner/repo slug (got "${repo}").`;
|
|
144
144
|
}
|
|
145
145
|
if (config.subject.topology !== undefined) {
|
|
146
|
-
return "clone scripted-browser
|
|
146
|
+
return "A clone scripted-browser study does not support `subject.topology` yet: it runs one synthetic subject for its scripted actor. Remove `subject.topology`.";
|
|
147
147
|
}
|
|
148
148
|
if (config.subject.clone?.fanout !== undefined || config.subject.clone?.keep === true) {
|
|
149
|
-
return "clone scripted-browser
|
|
149
|
+
return "A clone scripted-browser study does not support `subject.clone.fanout` or `subject.clone.keep` yet: its subject is always one sandbox, removed after the run.";
|
|
150
150
|
}
|
|
151
151
|
if (!config.scenario?.ref) {
|
|
152
|
-
return "scripted-browser
|
|
152
|
+
return "A scripted-browser study needs `scenario.ref`: the actor runs the browser steps in that scenario file.";
|
|
153
153
|
}
|
|
154
154
|
if ((config.actors[0]?.count ?? 1) > 2) {
|
|
155
|
-
return "scripted-browser
|
|
155
|
+
return "A scripted-browser study takes `actors[0].count` 1 (desktop) or 2 (desktop and mobile). Higher counts are not supported yet.";
|
|
156
156
|
}
|
|
157
157
|
if (rosterOf(config.actors[0]) !== undefined) {
|
|
158
|
-
return "`actors[0].lanes` is not supported on the scripted-browser route yet
|
|
158
|
+
return "`actors[0].lanes` is not supported on the scripted-browser route yet. Use `actors[0].count` to choose the desktop and mobile surfaces.";
|
|
159
159
|
}
|
|
160
160
|
if (config.policies?.redactScreenshots === true) {
|
|
161
|
-
return "`policies.redactScreenshots: true` is not
|
|
161
|
+
return "`policies.redactScreenshots: true` is not supported on the scripted-browser route yet, so its screenshots would be stored unredacted in .humanish/. Remove the setting, or use a computer-use actor, which blurs screenshots as it takes them.";
|
|
162
162
|
}
|
|
163
163
|
if (config.policies?.allowPublicTargets === true) {
|
|
164
|
-
return "`policies.allowPublicTargets`
|
|
164
|
+
return "`policies.allowPublicTargets` does not apply to a clone scripted-browser study: its only public URL is the sandbox URL humanish opens for its synthetic subject. Remove the setting.";
|
|
165
165
|
}
|
|
166
166
|
if (config.subject.exposure !== "synthetic") {
|
|
167
|
-
return "clone scripted-browser
|
|
167
|
+
return "A clone scripted-browser study needs `subject.exposure: synthetic`. The subject is reachable from the internet at a public sandbox URL during the run, so the study must declare that its data is synthetic.";
|
|
168
168
|
}
|
|
169
169
|
if (!config.subject.state?.seed ||
|
|
170
170
|
config.subject.state.seed.length === 0 ||
|
|
171
171
|
(config.subject.state.external?.length ?? 0) > 0) {
|
|
172
|
-
return "clone scripted-browser
|
|
172
|
+
return "A clone scripted-browser study needs `subject.state.seed` and cannot use `subject.state.external`: a subject at a public sandbox URL may hold only seeded synthetic data.";
|
|
173
173
|
}
|
|
174
174
|
if (!config.subject.serve.start.includes("0.0.0.0")) {
|
|
175
|
-
return "clone scripted-browser
|
|
175
|
+
return "A clone scripted-browser study needs `subject.serve.start` to listen on all interfaces (for example `-H 0.0.0.0`, `--host 0.0.0.0` or `HOST=0.0.0.0`): the public sandbox URL reaches only a port bound to 0.0.0.0. The readiness probe still uses loopback.";
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
return null;
|
|
179
179
|
}
|
|
180
|
-
// clone × e2b-desktop disambiguates on the actor
|
|
180
|
+
// clone × e2b-desktop disambiguates on the actor's run kind: a computer-use actor means the study
|
|
181
181
|
// clones and serves the subject in-sandbox, then drives it. Scripted-browser actors were checked
|
|
182
182
|
// above.
|
|
183
183
|
function cloneComputerUseValidationReason(config) {
|
|
@@ -185,10 +185,10 @@ function cloneComputerUseValidationReason(config) {
|
|
|
185
185
|
config.execution?.target === "e2b-desktop" &&
|
|
186
186
|
actorResolvesToComputerUse(config.actors[0]?.type)) {
|
|
187
187
|
if (!config.subject.serve) {
|
|
188
|
-
return "clone
|
|
188
|
+
return "A clone subject on the computer-use route needs `subject.serve` (start and url): humanish starts the app in the sandbox before the participant opens it.";
|
|
189
189
|
}
|
|
190
190
|
if ((config.subject.repos?.length ?? 0) !== 1) {
|
|
191
|
-
return "computer-use clone
|
|
191
|
+
return "computer-use clone studies serve one repo; declare exactly one repo in subject.repos.";
|
|
192
192
|
}
|
|
193
193
|
const repo = config.subject.repos?.[0] ?? "";
|
|
194
194
|
if (!REPO_SLUG_PATTERN.test(repo)) {
|
|
@@ -216,18 +216,18 @@ function localTreeValidationReason(config) {
|
|
|
216
216
|
}
|
|
217
217
|
return null;
|
|
218
218
|
}
|
|
219
|
-
// desktop-cli route: a computer-use participant studies a CLI/TUI the way a person does
|
|
219
|
+
// desktop-cli route: a computer-use participant studies a CLI/TUI the way a person does: at a
|
|
220
220
|
// desktop, in a terminal window, by looking at it. The sibling of terminal-product, and the
|
|
221
221
|
// distinction is the population: terminal-product sends an autonomous agent
|
|
222
|
-
// through a pipe with stdin disabled, which
|
|
222
|
+
// through a pipe with stdin disabled, which matches what an agent meets and
|
|
223
223
|
// structurally cannot study an interactive surface. This route sends someone who can see it.
|
|
224
224
|
//
|
|
225
|
-
// Fail-closed on the pairing
|
|
225
|
+
// Fail-closed on the pairing: a hosted desktop and a computer-use actor, because
|
|
226
226
|
// "watch a person use a terminal" is not something the other substrates can do.
|
|
227
227
|
/** A desktop-cli subject with no product to study. The computer-use planner checks this too. */
|
|
228
228
|
export function desktopCliProductReason(config) {
|
|
229
229
|
return config.subject.source === "desktop-cli" && config.subject.product?.name === undefined
|
|
230
|
-
? "desktop-cli
|
|
230
|
+
? "A desktop-cli subject needs `subject.product.name`: the CLI the participant is asked to use."
|
|
231
231
|
: null;
|
|
232
232
|
}
|
|
233
233
|
function desktopCliValidationReason(config) {
|
|
@@ -236,7 +236,7 @@ function desktopCliValidationReason(config) {
|
|
|
236
236
|
return productReason;
|
|
237
237
|
if (config.subject.source === "desktop-cli" && config.subject.product !== undefined) {
|
|
238
238
|
if (config.execution?.target !== undefined && config.execution.target !== "e2b-desktop") {
|
|
239
|
-
return "desktop-cli
|
|
239
|
+
return "A desktop-cli subject runs on a hosted desktop. Set `execution.target: e2b-desktop` or omit it.";
|
|
240
240
|
}
|
|
241
241
|
if (!actorResolvesToComputerUse(config.actors[0]?.type ?? "")) {
|
|
242
242
|
return "desktop-cli subjects need a registered computer-use actor: the participant reads the screen and types, which is what makes an interactive surface studiable at all.";
|
|
@@ -248,16 +248,16 @@ function desktopCliValidationReason(config) {
|
|
|
248
248
|
}
|
|
249
249
|
return null;
|
|
250
250
|
}
|
|
251
|
-
// terminal-product route: a real autonomous agent studies a CLI/product from public surfaces
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
//
|
|
251
|
+
// terminal-product route: a real autonomous agent studies a CLI/product from public surfaces inside
|
|
252
|
+
// an E2B shell. Fail-closed (claims match mechanism: a field that cannot act on this route is a
|
|
253
|
+
// parse error): a registered terminal actor only, execution.target e2b-terminal or absent (absent
|
|
254
|
+
// defaults to e2b-terminal, the only target where an in-sandbox agent runs), one participant until
|
|
255
|
+
// fan-out lands.
|
|
256
256
|
function terminalValidationReason(config) {
|
|
257
257
|
if (config.subject.source === "terminal-product") {
|
|
258
258
|
const type = config.actors[0]?.type ?? "";
|
|
259
259
|
if (config.execution?.target !== undefined && config.execution.target !== "e2b-terminal") {
|
|
260
|
-
return "terminal-product
|
|
260
|
+
return "A terminal-product subject runs its agent in an E2B shell. Set `execution.target: e2b-terminal` or omit it; `local` and `e2b-desktop` are not supported.";
|
|
261
261
|
}
|
|
262
262
|
if (!actorResolvesToTerminal(type)) {
|
|
263
263
|
return `actors[0].type must be a registered terminal actor for terminal-product subjects (one of: ${registeredTerminalActors().join(", ")}). Got "${type}".`;
|
|
@@ -268,7 +268,7 @@ function terminalValidationReason(config) {
|
|
|
268
268
|
}
|
|
269
269
|
else if (config.execution?.target === "e2b-terminal") {
|
|
270
270
|
// e2b-terminal is the terminal-product substrate only. Any other source declaring it is a
|
|
271
|
-
// mis-config
|
|
271
|
+
// mis-config: reject, never silently mishandle (mirrors app-url's e2b-desktop pairing rule).
|
|
272
272
|
return "`execution.target: e2b-terminal` requires `subject.source: terminal-product` with a registered terminal actor.";
|
|
273
273
|
}
|
|
274
274
|
else if (actorResolvesToTerminal(config.actors[0]?.type)) {
|
|
@@ -278,14 +278,14 @@ function terminalValidationReason(config) {
|
|
|
278
278
|
}
|
|
279
279
|
return null;
|
|
280
280
|
}
|
|
281
|
-
// A clone
|
|
281
|
+
// A clone study is served in-sandbox for a participant to drive, so only a computer-use or a
|
|
282
282
|
// scripted-browser actor can run it. Any other actor would parse and then fail at run start.
|
|
283
283
|
// Terminal actors were already refused above with their own message.
|
|
284
284
|
function cloneActorValidationReason(config) {
|
|
285
285
|
if (config.subject.source === "clone") {
|
|
286
286
|
const type = config.actors[0]?.type ?? "";
|
|
287
287
|
if (!actorResolvesToComputerUse(type) && !actorResolvesToScriptedBrowser(type)) {
|
|
288
|
-
return `clone subjects need a registered computer-use actor (one of: ${registeredComputerUseActors().join(", ")}) or scripted-browser actor (one of: ${registeredScriptedBrowserActors().join(", ")});
|
|
288
|
+
return `clone subjects need a registered computer-use actor (one of: ${registeredComputerUseActors().join(", ")}) or scripted-browser actor (one of: ${registeredScriptedBrowserActors().join(", ")}); humanish clones and serves the app for that participant to drive. Got "${type}".`;
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
return null;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type StudyParseResult } from "./types.js";
|
|
2
|
+
/** The message for a humanish.lab.v2 document, which the package and the CLI no longer run. */
|
|
3
|
+
export declare const V2_UNSUPPORTED_MESSAGE = "This is a humanish.lab.v2 study, which humanish no longer reads. Convert its file with humanish migrate <path>.";
|
|
4
|
+
/**
|
|
5
|
+
* The package's study parser (src/index.ts) and the one discovery uses: a humanish.study.v3
|
|
6
|
+
* document. It refuses a humanish.lab.v2 one with HUMANISH_STUDY_V2_UNSUPPORTED.
|
|
7
|
+
*/
|
|
8
|
+
export declare function parseStudy(raw: unknown): StudyParseResult;
|
|
9
|
+
/**
|
|
10
|
+
* Validate a parsed YAML object, humanish.study.v3 or humanish.lab.v2, into a StudyConfig. Pure:
|
|
11
|
+
* the caller owns file IO. Structural validation only. Fields the engine does not yet consume are
|
|
12
|
+
* accepted but reported in `warnings` so `study show` never silently swallows a setting that does
|
|
13
|
+
* nothing. migrate's conversion (convert.ts) calls it directly, since it reads v2 files.
|
|
14
|
+
*/
|
|
15
|
+
export declare function parseStudyDocument(raw: unknown): StudyParseResult;
|
|
@@ -1,38 +1,41 @@
|
|
|
1
|
-
// humanish.lab.v2: a
|
|
1
|
+
// The normalized config, in the humanish.lab.v2 spelling: a study composes code primitives, with no
|
|
2
|
+
// hardcoded study kind.
|
|
3
|
+
// A humanish.study.v3 file is rewritten into this spelling first (parse/study-v3.ts), and then must
|
|
4
|
+
// take the route it declares and set no field that route does not read.
|
|
2
5
|
//
|
|
3
6
|
// Scope (read before trusting field names): the engine routes by
|
|
4
|
-
// subject.source × execution.target (disambiguated by the actor
|
|
7
|
+
// subject.source × execution.target (disambiguated by the actor's run kind where both axes
|
|
5
8
|
// collide) and consumes a deliberately small set of fields:
|
|
6
9
|
// subject.source/repos/appUrl/serve/env/state/clone.{depth,fanout,keep}, actors[0].count,
|
|
7
10
|
// execution.target + execution.desktop.codexAppServer, scenario.mode,
|
|
8
11
|
// policies.redactRepos, defaults.open.
|
|
9
12
|
// On the computer-use routes (app-url × e2b-desktop, and clone × e2b-desktop with a
|
|
10
|
-
// computer-use actor), `actors[0].type`
|
|
13
|
+
// computer-use actor), `actors[0].type` selects the actor: it must resolve to a registered
|
|
11
14
|
// computer-use actor, and that descriptor runs the session. Those routes also consume
|
|
12
15
|
// actors[0].{mission,persona,laneFocus.instruction,model,reasoningEffort}, execution.timeoutMs,
|
|
13
16
|
// execution.desktop.{browser,resolution,sandboxTimeoutMs}, and (clone)
|
|
14
17
|
// subject.{serve,env,state,clone.depth}.
|
|
15
18
|
// On the scripted-browser route (app-url × local-or-absent, or clone × e2b-desktop, with a
|
|
16
|
-
// registered scripted-browser actor), `actors[0].type`
|
|
19
|
+
// registered scripted-browser actor), `actors[0].type` selects the actor too, and the route
|
|
17
20
|
// consumes scenario.ref (required there, because the committed scenario's browser steps are what the
|
|
18
21
|
// actor executes), actors[0].{persona,count}, and execution.timeoutMs. On the provisioned
|
|
19
22
|
// clone slice it also consumes subject.{repos,serve,env,state,exposure,clone.depth} and
|
|
20
23
|
// execution.desktop.template. actors[0].{mission,laneFocus,model} are inert on that route
|
|
21
24
|
// because no model runs, and most execution.desktop.* fields remain forward-declared (device
|
|
22
|
-
// presets belong to the
|
|
25
|
+
// presets belong to the computer-use route; scripted surfaces are the driver's own desktop/mobile
|
|
23
26
|
// viewports where isMobile/DSF genuinely render via playwright emulation).
|
|
24
27
|
// On the other routes those fields remain forward-declared and are not yet consumed:
|
|
25
|
-
//
|
|
28
|
+
// parseStudy emits a warning listing any such field that is set, so `study show` shows
|
|
26
29
|
// the truth.
|
|
27
30
|
//
|
|
28
|
-
// NOTE on actors[0].count: it
|
|
31
|
+
// NOTE on actors[0].count: it carries route-specific meanings. Preview route: simCount;
|
|
29
32
|
// scripted-browser route: surface roster {1 = desktop, 2 = desktop + mobile}, default 1 (the
|
|
30
33
|
// defaults-table single-participant row governs; count: 2 is the declared override); computer-use
|
|
31
34
|
// E2B route: the homogeneous fan-out participant count (N identical participants, each its own E2B
|
|
32
|
-
// desktop), capped at 16; the in-process/local-app
|
|
33
|
-
// fan out).
|
|
35
|
+
// desktop), capped at 16; the in-process/local-app computer-use route stays single-participant (no
|
|
36
|
+
// E2B to fan out).
|
|
34
37
|
//
|
|
35
|
-
// NOTE on actors[0].lanes / actors[0].roster (computer-use E2B route
|
|
38
|
+
// NOTE on actors[0].lanes / actors[0].roster (computer-use E2B route): a
|
|
36
39
|
// differentiated fan-out roster: each `{ id?, persona?, device?, instruction?, target? }` becomes one
|
|
37
40
|
// independent E2B desktop (`per-lane-worlds`, the default topology). `roster[]` is parser sugar for
|
|
38
41
|
// repeated groups and is normalized into `lanes[]` before the engine sees it. `lanes|roster` XOR
|
|
@@ -40,45 +43,94 @@
|
|
|
40
43
|
// XOR `actors[0].laneFocus` (each entry's `instruction` is the roster's steer); `lanes[].device` XOR
|
|
41
44
|
// raw `execution.desktop.resolution`. `execution.concurrency` bounds in-flight participants (default:
|
|
42
45
|
// the participant count, all at once; env HUMANISH_CUA_MAX_CONCURRENCY may only lower it, per invariant
|
|
43
|
-
// 3). On every non-
|
|
44
|
-
// rejected on the
|
|
45
|
-
// URL this participant opens instead of `subject.appUrl`; it is the generic
|
|
46
|
-
// handoff, not a service topology primitive.
|
|
46
|
+
// 3). On every non-computer-use route normalized `lanes` are inert (warned). subject.clone.fanout
|
|
47
|
+
// is rejected on the computer-use route. `lanes[].target` is app-url × computer-use only: an
|
|
48
|
+
// absolute browser URL this participant opens instead of `subject.appUrl`; it is the generic
|
|
49
|
+
// setup-produced-target handoff, not a service topology primitive.
|
|
47
50
|
//
|
|
48
51
|
// There is deliberately no v1 compatibility: v1 had zero real users. Breaking schema changes
|
|
49
|
-
// bump the version
|
|
50
|
-
import {
|
|
52
|
+
// bump the version.
|
|
53
|
+
import { isLocalBrowserStudy, localBrowserDefaults, localBrowserUnsupportedReason, } from "../substrates/local/runtime-config.js";
|
|
51
54
|
import { isRecord } from "../run/type-guards.js";
|
|
52
55
|
import { compositionReason } from "./composition-rules.js";
|
|
53
|
-
import {
|
|
56
|
+
import { findUnknownV2Key } from "./keys.js";
|
|
54
57
|
import { parseActors, rosterOf } from "./parse/actors.js";
|
|
55
58
|
import { parseComms, recipientParticipantId } from "./parse/comms.js";
|
|
56
59
|
import { parseDefaults, parseExecution, parsePersonas, parsePolicies, parseReview, parseScenario, } from "./parse/execution.js";
|
|
60
|
+
import { studySpelling, studyToV2 } from "./parse/study-v3.js";
|
|
57
61
|
import { parseSubject } from "./parse/subject.js";
|
|
58
62
|
import { invalid, optionalStr, str } from "./parse/values.js";
|
|
59
|
-
import { isComputerUseComposition, isSharedWorldComposition } from "./routing.js";
|
|
63
|
+
import { isComputerUseComposition, isSharedWorldComposition, routeOf } from "./routing.js";
|
|
60
64
|
import { declaredParticipantIds } from "./plan-participants.js";
|
|
61
|
-
import { ID_PATTERN,
|
|
65
|
+
import { ID_PATTERN, V2_SCHEMA, STUDY_SCHEMA, } from "./types.js";
|
|
62
66
|
import { automaticAnalysisRouteReason, desktopMediaValidationReason, outputTokenLimitValidationReason, receivingEmailValidationReason, scenarioCapsValidationReason, taskProtocolValidationReason, } from "./validation.js";
|
|
63
|
-
import { forwardDeclaredWarnings } from "./warnings.js";
|
|
67
|
+
import { forwardDeclaredWarnings, inertFieldLabels } from "./warnings.js";
|
|
68
|
+
import { plural } from "../run/text.js";
|
|
69
|
+
/** The message for a humanish.lab.v2 document, which the package and the CLI no longer run. */
|
|
70
|
+
export const V2_UNSUPPORTED_MESSAGE = "This is a humanish.lab.v2 study, which humanish no longer reads. Convert its file with humanish migrate <path>.";
|
|
64
71
|
/**
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
* `warnings` so `lab inspect` never silently swallows a setting that does nothing.
|
|
72
|
+
* The package's study parser (src/index.ts) and the one discovery uses: a humanish.study.v3
|
|
73
|
+
* document. It refuses a humanish.lab.v2 one with HUMANISH_STUDY_V2_UNSUPPORTED.
|
|
68
74
|
*/
|
|
69
|
-
export function
|
|
75
|
+
export function parseStudy(raw) {
|
|
76
|
+
if (isRecord(raw) && raw.schema === V2_SCHEMA)
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
error: { code: "HUMANISH_STUDY_V2_UNSUPPORTED", message: V2_UNSUPPORTED_MESSAGE },
|
|
80
|
+
};
|
|
81
|
+
return parseStudyDocument(raw);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Validate a parsed YAML object, humanish.study.v3 or humanish.lab.v2, into a StudyConfig. Pure:
|
|
85
|
+
* the caller owns file IO. Structural validation only. Fields the engine does not yet consume are
|
|
86
|
+
* accepted but reported in `warnings` so `study show` never silently swallows a setting that does
|
|
87
|
+
* nothing. migrate's conversion (convert.ts) calls it directly, since it reads v2 files.
|
|
88
|
+
*/
|
|
89
|
+
export function parseStudyDocument(raw) {
|
|
70
90
|
if (!isRecord(raw)) {
|
|
71
|
-
return invalid("
|
|
91
|
+
return invalid("A study file must be a YAML object.");
|
|
72
92
|
}
|
|
73
|
-
if (raw.schema
|
|
74
|
-
return
|
|
93
|
+
if (raw.schema === STUDY_SCHEMA)
|
|
94
|
+
return parseV3(raw);
|
|
95
|
+
if (raw.schema !== V2_SCHEMA) {
|
|
96
|
+
return invalid(`The study schema must be ${STUDY_SCHEMA} or ${V2_SCHEMA}.`);
|
|
75
97
|
}
|
|
76
|
-
|
|
98
|
+
return parseV2(raw);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* A v3 study parses through the v2 parser, then must take the route it declares and set no field
|
|
102
|
+
* that route does not read. A v2 file gets those fields as a warning instead.
|
|
103
|
+
*/
|
|
104
|
+
function parseV3(raw) {
|
|
105
|
+
const document = studyToV2(raw);
|
|
106
|
+
if (!document.ok)
|
|
107
|
+
return document;
|
|
108
|
+
const { route, v2, participantSource } = document.value;
|
|
109
|
+
const spell = (message) => studySpelling(message, route, participantSource);
|
|
110
|
+
const parsed = parseV2(v2);
|
|
111
|
+
if (!parsed.ok)
|
|
112
|
+
return invalid(spell(parsed.error.message));
|
|
113
|
+
const taken = routeOf(parsed.config);
|
|
114
|
+
if (taken !== route) {
|
|
115
|
+
return invalid(`This study declares route: ${route}, but its subject (source: ${parsed.config.subject.source}) and actor (type: ${parsed.config.actors[0]?.type}) take the ${taken} route. Change \`route\`, or change the subject or actor.`);
|
|
116
|
+
}
|
|
117
|
+
const inert = inertFieldLabels(parsed.config);
|
|
118
|
+
if (inert.length > 0) {
|
|
119
|
+
return invalid(spell(`route: ${route} does not read ${inert.join(", ")}. Remove ${inert.length === 1 ? "it" : "them"}.`));
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
ok: true,
|
|
123
|
+
config: { ...parsed.config, schema: STUDY_SCHEMA },
|
|
124
|
+
warnings: parsed.warnings.map(spell),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function parseV2(raw) {
|
|
128
|
+
const unknownKey = findUnknownV2Key(raw);
|
|
77
129
|
if (unknownKey)
|
|
78
130
|
return invalid(unknownKey);
|
|
79
131
|
const id = str(raw.id);
|
|
80
132
|
if (!id || !ID_PATTERN.test(id)) {
|
|
81
|
-
return invalid("
|
|
133
|
+
return invalid("The study id must be a public-safe token starting with a letter or digit (/^[A-Za-z0-9][A-Za-z0-9_.-]*$/).");
|
|
82
134
|
}
|
|
83
135
|
const subjectResult = parseSubject(raw.subject);
|
|
84
136
|
if (!subjectResult.ok) {
|
|
@@ -93,7 +145,7 @@ export function parseLabConfig(raw) {
|
|
|
93
145
|
return executionResult;
|
|
94
146
|
}
|
|
95
147
|
const config = {
|
|
96
|
-
schema:
|
|
148
|
+
schema: V2_SCHEMA,
|
|
97
149
|
id,
|
|
98
150
|
...optionalStr("title", raw.title),
|
|
99
151
|
...optionalStr("description", raw.description),
|
|
@@ -139,7 +191,7 @@ export function parseLabConfig(raw) {
|
|
|
139
191
|
if (commsResult.value)
|
|
140
192
|
config.comms = commsResult.value;
|
|
141
193
|
if (config.comms?.email?.smtp && config.subject.topology === "shared-world") {
|
|
142
|
-
return invalid("SMTP capture is not yet
|
|
194
|
+
return invalid("SMTP capture is not supported yet for shared-world studies. Use the default per-lane-worlds topology for SMTP, or configure supported HTTP email capture for concurrent shared-world studies.");
|
|
143
195
|
}
|
|
144
196
|
const mediaReason = desktopMediaValidationReason(config);
|
|
145
197
|
if (mediaReason)
|
|
@@ -150,11 +202,12 @@ export function parseLabConfig(raw) {
|
|
|
150
202
|
const scenarioCapsReason = scenarioCapsValidationReason(config);
|
|
151
203
|
if (scenarioCapsReason)
|
|
152
204
|
return invalid(scenarioCapsReason);
|
|
153
|
-
// All-parallel default
|
|
154
|
-
// every
|
|
155
|
-
// computer-use participants resolve that default from the final participant count
|
|
156
|
-
// --count override, so the parser leaves it unset for them. A shared
|
|
157
|
-
// its default is filled here for the envelopes and warnings that read
|
|
205
|
+
// All-parallel default: a multi-participant study that does not declare execution.concurrency
|
|
206
|
+
// runs every participant at once; the declared field is a cap the author chose, never a mode.
|
|
207
|
+
// Independent computer-use participants resolve that default from the final participant count
|
|
208
|
+
// when they plan, after any --count override, so the parser leaves it unset for them. A shared
|
|
209
|
+
// world's roster is fixed, so its default is filled here for the envelopes and warnings that read
|
|
210
|
+
// the parsed config.
|
|
158
211
|
{
|
|
159
212
|
const participantCount = rosterOf(config.actors[0])?.length ?? config.actors[0]?.count ?? 1;
|
|
160
213
|
if (participantCount > 1 &&
|
|
@@ -163,8 +216,8 @@ export function parseLabConfig(raw) {
|
|
|
163
216
|
config.execution = { ...config.execution, concurrency: participantCount };
|
|
164
217
|
}
|
|
165
218
|
}
|
|
166
|
-
// Email that just works
|
|
167
|
-
// inbox instruction, gated on recipients[]. Guessed participant ids broke a field run
|
|
219
|
+
// Email that just works: the funnel's only handoff to an actor is the per-participant
|
|
220
|
+
// inbox instruction, gated on recipients[]. Guessed participant ids broke a field run:
|
|
168
221
|
// recipients copied from a single-participant example matched nothing, so every actor was left inbox-blind with zero
|
|
169
222
|
// signal. Omitted recipients are therefore filled (one deterministic address per participant);
|
|
170
223
|
// a recipient naming an unknown participant is a hard error listing the real ids; declared
|
|
@@ -184,7 +237,7 @@ export function parseLabConfig(raw) {
|
|
|
184
237
|
else {
|
|
185
238
|
const unknown = email.recipients.filter((recipient) => !participantIds.includes(recipientParticipantId(recipient)));
|
|
186
239
|
if (unknown.length > 0) {
|
|
187
|
-
return invalid(`comms.email.recipients name participant
|
|
240
|
+
return invalid(`comms.email.recipients name ${plural(unknown.length, "participant")} that ${unknown.length === 1 ? "does" : "do"} not exist: ${unknown.map((r) => `"${recipientParticipantId(r)}"`).join(", ")}. This study's participant ids are: ${participantIds.join(", ")}. A recipient's \`lane\` must match one of them exactly: the inbox instruction is injected per participant, and a mismatch disables the email funnel for that participant.`);
|
|
188
241
|
}
|
|
189
242
|
if (!email.recipients.some((recipient) => recipient.address !== undefined)) {
|
|
190
243
|
return invalid("comms.email.recipients cover no participant with an address, so no actor would be told an inbox exists and no captured mail could match. Give at least one recipient an address, or omit `recipients` entirely (every participant then gets a deterministic address automatically).");
|
|
@@ -201,10 +254,14 @@ export function parseLabConfig(raw) {
|
|
|
201
254
|
if (analysisReason)
|
|
202
255
|
return invalid(analysisReason);
|
|
203
256
|
const normalized = localBrowserDefaults(config);
|
|
204
|
-
if (
|
|
257
|
+
if (isLocalBrowserStudy(normalized)) {
|
|
205
258
|
const reason = localBrowserUnsupportedReason(normalized);
|
|
206
259
|
if (reason)
|
|
207
260
|
return invalid(reason);
|
|
208
261
|
}
|
|
209
|
-
return {
|
|
262
|
+
return {
|
|
263
|
+
ok: true,
|
|
264
|
+
config: normalized,
|
|
265
|
+
warnings: forwardDeclaredWarnings(normalized),
|
|
266
|
+
};
|
|
210
267
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type StudyRoute } from "./routing.js";
|
|
2
|
+
/** A key the conversion moved, by its v2 path and its v3 path. */
|
|
3
|
+
export interface MovedKey {
|
|
4
|
+
readonly from: string;
|
|
5
|
+
readonly to: string;
|
|
6
|
+
}
|
|
7
|
+
/** A key the conversion dropped because the study's route never reads it. */
|
|
8
|
+
export interface DroppedKey {
|
|
9
|
+
readonly path: string;
|
|
10
|
+
readonly value: unknown;
|
|
11
|
+
/** The comments that sat on the dropped key, which the v3 file no longer has. */
|
|
12
|
+
readonly comments?: string;
|
|
13
|
+
}
|
|
14
|
+
/** A v2 file converted to v3. */
|
|
15
|
+
interface StudyConversion {
|
|
16
|
+
readonly text: string;
|
|
17
|
+
readonly route: StudyRoute;
|
|
18
|
+
readonly moved: readonly MovedKey[];
|
|
19
|
+
readonly dropped: readonly DroppedKey[];
|
|
20
|
+
}
|
|
21
|
+
/** The conversion, or why the file cannot be converted as it stands. */
|
|
22
|
+
export type StudyConversionResult = {
|
|
23
|
+
readonly ok: true;
|
|
24
|
+
readonly conversion: StudyConversion;
|
|
25
|
+
} | {
|
|
26
|
+
readonly ok: false;
|
|
27
|
+
readonly reason: string;
|
|
28
|
+
};
|
|
29
|
+
/** Whether a parsed YAML value is a v3 study file. */
|
|
30
|
+
export declare function isStudyV3(raw: unknown): boolean;
|
|
31
|
+
/** Convert one v2 file's text. `cwd` is the project the plan check plans in. */
|
|
32
|
+
export declare function convertStudyText(text: string, cwd: string): StudyConversionResult;
|
|
33
|
+
export {};
|