humanish 0.107.0 → 0.108.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +22 -17
- package/CHANGELOG.md +14 -0
- package/CONTEXT.md +51 -44
- package/README.md +145 -172
- 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-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 +8 -6
- 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 +2 -2
- package/dist/actors/codex/restricted-session.js +10 -5
- package/dist/actors/computer-use/actor.d.ts +16 -16
- package/dist/actors/computer-use/actor.js +2 -2
- package/dist/actors/computer-use/admission-limit.d.ts +1 -1
- package/dist/actors/computer-use/admission-limit.js +1 -1
- package/dist/actors/computer-use/loop/actions.d.ts +3 -3
- package/dist/actors/computer-use/loop/actions.js +10 -10
- 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/ending.d.ts +5 -5
- package/dist/actors/computer-use/loop/ending.js +7 -7
- package/dist/actors/computer-use/loop/observation.d.ts +2 -2
- package/dist/actors/computer-use/loop/observation.js +9 -9
- package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
- package/dist/actors/computer-use/loop/provider-call.js +1 -1
- package/dist/actors/computer-use/loop/session.js +3 -3
- 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 +9 -8
- package/dist/actors/computer-use/loop/types.d.ts +25 -23
- package/dist/actors/computer-use/loop/usage.js +2 -2
- 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 +11 -8
- package/dist/actors/computer-use/openai-provider.js +45 -34
- 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/contract.d.ts +78 -43
- package/dist/actors/contract.js +29 -23
- package/dist/actors/local-agent/claude-session.d.ts +1 -1
- package/dist/actors/local-agent/claude-session.js +10 -9
- package/dist/actors/local-agent/cli.d.ts +8 -6
- 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 +6 -6
- package/dist/actors/registry.d.ts +10 -10
- package/dist/actors/registry.js +18 -17
- package/dist/actors/scripted-browser/actor.d.ts +8 -8
- package/dist/actors/scripted-browser/actor.js +16 -16
- 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/codex-config.d.ts +6 -2
- package/dist/analysis/codex-config.js +22 -14
- package/dist/analysis/service.js +5 -5
- package/dist/cli/commands/analyze.js +19 -16
- package/dist/cli/commands/codex.js +9 -9
- package/dist/cli/commands/comms.js +54 -33
- package/dist/cli/commands/feedback.js +20 -21
- package/dist/cli/commands/lab-format.d.ts +5 -4
- package/dist/cli/commands/lab-format.js +35 -23
- package/dist/cli/commands/lab-route-computer-use.js +6 -7
- package/dist/cli/commands/lab-route-preview.js +4 -3
- package/dist/cli/commands/lab-route-shared-world.js +3 -3
- package/dist/cli/commands/lab-run.js +10 -11
- package/dist/cli/commands/lab-scorer.d.ts +2 -2
- package/dist/cli/commands/lab-scorer.js +1 -1
- package/dist/cli/commands/migrate.d.ts +4 -0
- package/dist/cli/commands/migrate.js +65 -0
- package/dist/cli/commands/observe.js +147 -108
- 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 +137 -138
- package/dist/cli/commands/setup.d.ts +2 -2
- package/dist/cli/commands/setup.js +26 -21
- package/dist/cli/commands/study.d.ts +3 -0
- package/dist/cli/commands/study.js +182 -0
- package/dist/cli/commands/tui.d.ts +4 -4
- package/dist/cli/commands/tui.js +21 -21
- package/dist/cli/commands/watch.js +60 -75
- package/dist/cli/deprecations.d.ts +18 -0
- package/dist/cli/deprecations.js +48 -0
- package/dist/cli/doctor.d.ts +15 -5
- package/dist/cli/doctor.js +103 -48
- package/dist/cli/first-run-path.d.ts +12 -10
- package/dist/cli/first-run-path.js +30 -28
- package/dist/cli/io.d.ts +41 -6
- package/dist/cli/io.js +97 -22
- package/dist/cli/observer-follow.d.ts +2 -2
- package/dist/cli/observer-follow.js +5 -6
- package/dist/cli/orientation.d.ts +6 -3
- package/dist/cli/orientation.js +43 -39
- 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 +109 -40
- package/dist/cli/telemetry.d.ts +15 -15
- package/dist/cli/telemetry.js +48 -40
- 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 +14 -14
- package/dist/comms/email-catch.d.ts +3 -3
- package/dist/comms/email-catch.js +8 -8
- package/dist/comms/external-evidence.js +2 -2
- package/dist/comms/extract.js +2 -2
- package/dist/comms/fake-inbox.d.ts +2 -2
- package/dist/comms/fake-inbox.js +2 -2
- package/dist/comms/receiving-render.d.ts +1 -1
- package/dist/comms/receiving-render.js +2 -2
- 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 +36 -37
- package/dist/comms/sandbox-catch.js +34 -35
- package/dist/comms/setup.js +42 -8
- 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 +36 -78
- package/dist/feedback/export-bundle.js +1 -1
- package/dist/feedback/export.d.ts +5 -1
- package/dist/feedback/export.js +7 -8
- package/dist/feedback/feedback.d.ts +2 -2
- package/dist/feedback/feedback.js +21 -3
- package/dist/guest/chromium-text.js +2 -2
- package/dist/guest/desktop-native.d.ts +1 -1
- package/dist/guest/runtime.js +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.js +8 -6
- package/dist/keys/key-resolution.d.ts +5 -5
- package/dist/keys/key-resolution.js +23 -23
- package/dist/lab/adapter-extension.d.ts +7 -7
- package/dist/lab/adapter-extension.js +13 -36
- package/dist/lab/adapter-scorer-loader.d.ts +7 -7
- package/dist/lab/adapter-scorer-loader.js +32 -32
- package/dist/lab/composition-rules.js +42 -42
- package/dist/lab/config.js +65 -25
- package/dist/lab/deprecated-fields.d.ts +10 -0
- package/dist/lab/deprecated-fields.js +24 -0
- package/dist/lab/device-presets.d.ts +8 -8
- package/dist/lab/device-presets.js +11 -11
- package/dist/lab/discover.d.ts +13 -9
- package/dist/lab/discover.js +117 -57
- package/dist/lab/doctor.d.ts +10 -3
- package/dist/lab/doctor.js +47 -9
- package/dist/lab/init-templates.js +147 -147
- package/dist/lab/init.d.ts +1 -1
- package/dist/lab/init.js +41 -9
- package/dist/lab/keys.d.ts +2 -0
- package/dist/lab/keys.js +42 -8
- package/dist/lab/lab-deps.d.ts +7 -12
- package/dist/lab/parse/actors.js +9 -9
- package/dist/lab/parse/comms.js +5 -5
- package/dist/lab/parse/execution.js +13 -13
- package/dist/lab/parse/study-v3.d.ts +23 -0
- package/dist/lab/parse/study-v3.js +259 -0
- package/dist/lab/parse/subject-state.d.ts +7 -7
- package/dist/lab/parse/subject-state.js +16 -16
- package/dist/lab/parse/subject.js +28 -28
- package/dist/lab/parse/values.d.ts +1 -1
- package/dist/lab/parse/values.js +3 -3
- package/dist/lab/persona-resolve.d.ts +4 -4
- package/dist/lab/persona-resolve.js +4 -4
- package/dist/lab/plan-participants.d.ts +2 -2
- package/dist/lab/plan-types.d.ts +4 -4
- package/dist/lab/plan.d.ts +1 -7
- package/dist/lab/plan.js +10 -41
- package/dist/lab/preflight-probes.js +11 -11
- package/dist/lab/preflight-result.d.ts +2 -1
- package/dist/lab/preflight-result.js +5 -4
- package/dist/lab/preflight.d.ts +7 -5
- package/dist/lab/preflight.js +5 -5
- package/dist/lab/routing.d.ts +31 -25
- package/dist/lab/routing.js +60 -29
- package/dist/lab/run-lab-events.d.ts +0 -3
- package/dist/lab/run-lab-events.js +0 -6
- package/dist/lab/run-lab-homes.d.ts +22 -10
- package/dist/lab/run-lab-homes.js +5 -1
- package/dist/lab/run-lab-options.d.ts +1 -1
- package/dist/lab/run-lab-options.js +16 -13
- package/dist/lab/summary.d.ts +7 -6
- package/dist/lab/summary.js +10 -10
- package/dist/lab/tasks.d.ts +15 -15
- package/dist/lab/tasks.js +14 -14
- package/dist/lab/types.d.ts +101 -95
- package/dist/lab/types.js +2 -0
- package/dist/lab/validation.d.ts +13 -13
- package/dist/lab/validation.js +44 -42
- package/dist/lab/warnings.d.ts +10 -0
- package/dist/lab/warnings.js +61 -33
- package/dist/library-aliases.d.ts +56 -0
- package/dist/library-aliases.js +22 -0
- package/dist/observer/artifact.d.ts +1 -1
- package/dist/observer/artifact.js +6 -6
- 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 +1 -1
- package/dist/observer/library.js +4 -2
- package/dist/observer/listen.js +5 -4
- package/dist/observer/render.d.ts +1 -1
- package/dist/observer/render.js +10 -5
- package/dist/observer/run-routes.d.ts +3 -3
- package/dist/observer/run-routes.js +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 +15 -15
- package/dist/routes/computer-use/bundle.js +3 -3
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/comms.js +14 -14
- package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +4 -3
- package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
- package/dist/routes/computer-use/e2b-desktop/prepare.js +7 -7
- package/dist/routes/computer-use/e2b-desktop/start.js +9 -8
- package/dist/routes/computer-use/e2b-desktop/teardown.js +5 -4
- package/dist/routes/computer-use/external-comms.d.ts +1 -1
- package/dist/routes/computer-use/external-comms.js +1 -1
- package/dist/routes/computer-use/fanout-bundle.js +18 -18
- package/dist/routes/computer-use/fanout-records.js +10 -11
- package/dist/routes/computer-use/live-flush.d.ts +1 -1
- package/dist/routes/computer-use/live-flush.js +6 -6
- package/dist/routes/computer-use/live-phase.d.ts +4 -2
- package/dist/routes/computer-use/live-phase.js +6 -6
- package/dist/routes/computer-use/local-vm.js +1 -1
- package/dist/routes/computer-use/participant-desktop.d.ts +4 -4
- package/dist/routes/computer-use/participant-desktop.js +4 -4
- package/dist/routes/computer-use/participant-execution.d.ts +4 -4
- package/dist/routes/computer-use/participant-execution.js +9 -9
- package/dist/routes/computer-use/participant-model.d.ts +6 -0
- package/dist/routes/computer-use/participant-model.js +31 -13
- package/dist/routes/computer-use/participant-prompt.d.ts +11 -11
- package/dist/routes/computer-use/participant-prompt.js +6 -6
- package/dist/routes/computer-use/participant-runs.d.ts +7 -7
- package/dist/routes/computer-use/participant-runs.js +13 -13
- package/dist/routes/computer-use/plan.js +22 -22
- package/dist/routes/computer-use/preflight.js +21 -21
- package/dist/routes/computer-use/rerun-selection.js +1 -1
- package/dist/routes/computer-use/result.js +11 -11
- package/dist/routes/computer-use/route.d.ts +2 -1
- package/dist/routes/computer-use/route.js +15 -14
- package/dist/routes/computer-use/self-report.d.ts +7 -7
- package/dist/routes/computer-use/self-report.js +31 -31
- package/dist/routes/computer-use/setup.d.ts +1 -1
- package/dist/routes/computer-use/setup.js +17 -18
- package/dist/routes/computer-use/single-bundle.d.ts +7 -7
- package/dist/routes/computer-use/single-bundle.js +28 -30
- package/dist/routes/computer-use/subject-projection.d.ts +1 -1
- package/dist/routes/computer-use/subject-projection.js +6 -6
- package/dist/routes/computer-use/types.d.ts +40 -42
- package/dist/routes/computer-use/types.js +10 -10
- package/dist/routes/preview.d.ts +8 -2
- package/dist/routes/preview.js +8 -4
- package/dist/routes/scripted/bundle.d.ts +2 -2
- package/dist/routes/scripted/bundle.js +13 -12
- package/dist/routes/scripted/plan.d.ts +1 -1
- package/dist/routes/scripted/plan.js +9 -9
- package/dist/routes/scripted/result.js +5 -5
- package/dist/routes/scripted/route.js +5 -6
- package/dist/routes/scripted/scenario.js +2 -2
- package/dist/routes/scripted/setup.js +7 -7
- package/dist/routes/scripted/subject.js +1 -1
- package/dist/routes/scripted/surface-records.js +3 -3
- package/dist/routes/scripted/types.d.ts +3 -5
- package/dist/routes/scripted/types.js +1 -1
- package/dist/routes/shared-world/bundle-records.js +9 -8
- package/dist/routes/shared-world/bundle.d.ts +5 -5
- package/dist/routes/shared-world/bundle.js +40 -38
- package/dist/routes/shared-world/checkpoints.d.ts +1 -1
- package/dist/routes/shared-world/checkpoints.js +1 -1
- package/dist/routes/shared-world/comms.d.ts +5 -5
- package/dist/routes/shared-world/comms.js +14 -14
- 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 +7 -6
- package/dist/routes/shared-world/participant-specs.js +31 -24
- package/dist/routes/shared-world/plan.js +7 -7
- 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.js +14 -13
- package/dist/routes/shared-world/result.js +20 -21
- package/dist/routes/shared-world/route.js +23 -22
- package/dist/routes/shared-world/setup.d.ts +3 -3
- package/dist/routes/shared-world/setup.js +4 -4
- package/dist/routes/shared-world/types.d.ts +30 -28
- package/dist/routes/shared-world/types.js +4 -4
- package/dist/routes/terminal/adapter.d.ts +3 -3
- package/dist/routes/terminal/adapter.js +5 -5
- package/dist/routes/terminal/bundle.d.ts +3 -3
- package/dist/routes/terminal/bundle.js +22 -21
- package/dist/routes/terminal/credentials.d.ts +4 -4
- package/dist/routes/terminal/credentials.js +7 -7
- package/dist/routes/terminal/dry-run.js +4 -4
- package/dist/routes/terminal/encoding.js +2 -2
- package/dist/routes/terminal/ledger.d.ts +3 -3
- package/dist/routes/terminal/ledger.js +14 -14
- package/dist/routes/terminal/live-finish.js +3 -3
- package/dist/routes/terminal/live-sandbox.js +12 -13
- package/dist/routes/terminal/persona.js +1 -1
- package/dist/routes/terminal/plan.js +11 -11
- package/dist/routes/terminal/recorder.js +2 -2
- package/dist/routes/terminal/result.js +8 -8
- package/dist/routes/terminal/route.js +6 -7
- package/dist/routes/terminal/sandbox.d.ts +1 -1
- package/dist/routes/terminal/sandbox.js +1 -1
- package/dist/routes/terminal/session.js +8 -7
- 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 +2 -2
- package/dist/routes/terminal/trace.js +2 -2
- package/dist/routes/terminal/types.d.ts +26 -28
- package/dist/routes/terminal/types.js +3 -3
- package/dist/run/bundle-shape.js +3 -3
- package/dist/run/bundle.d.ts +46 -46
- package/dist/run/bundle.js +2 -1
- package/dist/run/cost-summary.js +3 -3
- package/dist/run/costs.js +7 -1
- package/dist/run/detail.d.ts +6 -6
- package/dist/run/detail.js +4 -4
- package/dist/run/dry-run-inputs.js +1 -1
- package/dist/run/dry-run.js +18 -18
- package/dist/run/judge.d.ts +19 -13
- package/dist/run/judge.js +18 -8
- package/dist/run/paths.d.ts +1 -1
- package/dist/run/paths.js +1 -1
- package/dist/run/pricing.d.ts +11 -6
- package/dist/run/pricing.js +20 -13
- package/dist/run/projection.d.ts +14 -14
- package/dist/run/projection.js +15 -15
- package/dist/run/reclaim.js +2 -2
- package/dist/run/results.d.ts +5 -5
- package/dist/run/run-index.d.ts +8 -6
- package/dist/run/run-index.js +15 -16
- 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 +5 -4
- package/dist/run/run.js +1 -1
- 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 +36 -35
- 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 +6 -6
- package/dist/run/stats.d.ts +12 -6
- package/dist/run/stats.js +116 -58
- package/dist/run/status.d.ts +8 -29
- package/dist/run/status.js +5 -27
- package/dist/run/stored-runs.js +2 -1
- package/dist/run/stream-shape.js +1 -1
- package/dist/run/streams.d.ts +6 -6
- package/dist/run/study-provenance.d.ts +47 -0
- package/dist/run/study-provenance.js +63 -0
- package/dist/run/study-result.d.ts +16 -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-lab.d.ts +7 -7
- package/dist/run-lab.js +1 -3
- package/dist/study/convert.d.ts +33 -0
- package/dist/study/convert.js +432 -0
- 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 +43 -0
- 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/subject/clone.d.ts +1 -1
- package/dist/subject/desktop-cli.d.ts +1 -1
- package/dist/subject/desktop-cli.js +2 -2
- package/dist/subject/local-tree-archive.js +1 -1
- package/dist/subject/local-tree.d.ts +1 -1
- package/dist/subject/node-bootstrap.js +1 -1
- package/dist/subject/runtime.js +8 -9
- package/dist/subject/serve.d.ts +1 -1
- package/dist/subject/serve.js +3 -3
- package/dist/subject/state.d.ts +1 -1
- package/dist/subject/steps.d.ts +5 -5
- package/dist/subject/steps.js +4 -4
- package/dist/substrates/command-failure.d.ts +3 -3
- package/dist/substrates/command-failure.js +3 -3
- 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 +2 -2
- package/dist/substrates/e2b/desktop-browser.js +8 -8
- package/dist/substrates/e2b/desktop-cdp.d.ts +9 -9
- package/dist/substrates/e2b/desktop-cdp.js +8 -8
- package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
- package/dist/substrates/e2b/desktop-executor.js +1 -1
- package/dist/substrates/e2b/desktop-geometry.d.ts +3 -3
- package/dist/substrates/e2b/desktop-geometry.js +7 -7
- package/dist/substrates/e2b/desktop-media.d.ts +1 -1
- 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/sandbox.d.ts +1 -1
- package/dist/substrates/e2b/sandbox.js +1 -1
- package/dist/substrates/e2b/sdk.d.ts +11 -11
- package/dist/substrates/e2b/sdk.js +6 -6
- package/dist/tui/actions.d.ts +1 -1
- package/dist/tui/actions.js +13 -13
- package/dist/tui/contract.d.ts +16 -16
- package/dist/tui/contract.js +10 -10
- package/dist/tui/launch.d.ts +4 -4
- package/dist/tui/launch.js +18 -19
- package/dist/tui/project.js +5 -5
- package/dist/tui-app.js +82 -82
- 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 +4 -4
- package/dist/verify/subject.js +18 -18
- package/dist/verify/verify.js +92 -43
- package/docs/README.md +25 -32
- package/docs/architecture/actor-contract.md +56 -87
- package/docs/architecture/desktop-sessions.md +7 -7
- package/docs/architecture/external-public-shared-world.md +61 -59
- package/docs/architecture/github-feedback-loop.md +1 -4
- 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 +5 -5
- package/docs/architecture/terminal-product-route.md +67 -107
- package/docs/contracts/README.md +24 -0
- package/docs/contracts/adapter-admission.md +3 -3
- package/docs/contracts/adapter-fixtures.md +2 -5
- 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 +45 -44
- package/docs/contracts/schemas.md +421 -362
- package/docs/contracts/study-analysis.md +3 -3
- package/docs/contracts/study-costs.md +11 -7
- 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/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/package.json +16 -17
- package/skills/humanish/SKILL.md +60 -58
- 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.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/observer/static.d.ts +0 -39
- package/dist/observer/static.js +0 -369
- 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
|
@@ -39,7 +39,7 @@ type BrowserScoringFacts = Omit<BrowserLabScoringContext, "backend" | "laneCount
|
|
|
39
39
|
/** The scorer functions a computer-use or shared-world run calls: `RunLabOptions.scorer`. */
|
|
40
40
|
export interface BrowserScorer {
|
|
41
41
|
/**
|
|
42
|
-
* Browser-route extension seam
|
|
42
|
+
* Browser-route extension seam: a thin adapter may score the assembled
|
|
43
43
|
* browser/shared-world evidence without forking core. The score is stored as
|
|
44
44
|
* namespaced `bundle.adapterScore`; product-specific component detail belongs
|
|
45
45
|
* in `data`, not in core enums or review text.
|
|
@@ -64,9 +64,9 @@ export interface ScorerOutcome {
|
|
|
64
64
|
/** Why the scorer failed the run, in order; empty when it did not. */
|
|
65
65
|
failures: string[];
|
|
66
66
|
}
|
|
67
|
-
/** A
|
|
67
|
+
/** A declared scorer that returned a malformed value never rendered a verdict. */
|
|
68
68
|
export declare const DECLARED_SCORER_MALFORMED = "Declared product scorer returned a malformed value instead of a verdict; a declared gate that cannot render a pass is recorded as a fail, never a silent pass.";
|
|
69
|
-
/** A
|
|
69
|
+
/** A declared scorer that threw never rendered a verdict. `detail` is already sanitized. */
|
|
70
70
|
export declare function declaredScorerThrew(detail: string): string;
|
|
71
71
|
export declare function applyBrowserScorer(args: {
|
|
72
72
|
scorer: BrowserScorer | undefined;
|
|
@@ -74,9 +74,9 @@ export declare function applyBrowserScorer(args: {
|
|
|
74
74
|
bundle: RunBundle;
|
|
75
75
|
sanitize: (text: string) => string;
|
|
76
76
|
warnings: string[];
|
|
77
|
-
/** Present only when the scorer was
|
|
77
|
+
/** Present only when the scorer was config-declared; core-stamped onto the bundle as
|
|
78
78
|
* evidence of which out-of-tree module was loaded. Absent for library callers. Its presence also
|
|
79
|
-
* makes a
|
|
79
|
+
* makes a throwing or malformed scorer a failure: a declared gate that cannot render a pass is
|
|
80
80
|
* a fail, never a silent green. */
|
|
81
81
|
scorerProvenance?: RunScorerProvenance;
|
|
82
82
|
}): Promise<ScorerOutcome>;
|
|
@@ -88,10 +88,10 @@ export declare function applyBrowserScorer(args: {
|
|
|
88
88
|
export declare function isAdapterFeedbackCandidate(value: unknown): value is RunFeedbackCandidate;
|
|
89
89
|
export declare function adapterScoreFailureMessage(bundle: RunBundle): string | undefined;
|
|
90
90
|
/**
|
|
91
|
-
* Deep-freeze a structured clone so a loaded scorer sees a
|
|
91
|
+
* Deep-freeze a structured clone so a loaded scorer sees a read-only bundle: it cannot mutate
|
|
92
92
|
* noSpend/cost/review in place to launder a verdict (which would defeat the costProbe-not-loadable
|
|
93
93
|
* guarantee). A tamper attempt throws in the scorer's strict-mode ESM and is caught as a hook failure.
|
|
94
|
-
* Legitimate read-only scoring is unaffected. The seam always stamps the
|
|
94
|
+
* Legitimate read-only scoring is unaffected. The seam always stamps the real bundle, never this view.
|
|
95
95
|
*/
|
|
96
96
|
export declare function frozenBundleView(bundle: RunBundle): RunBundle;
|
|
97
97
|
export {};
|
|
@@ -1,45 +1,22 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { isRunAdapterScore } from "../run/bundle-shape.js";
|
|
3
|
+
import { withDeprecatedFields } from "./deprecated-fields.js";
|
|
3
4
|
import { isRunFeedbackCandidate } from "../run/feedback-shape.js";
|
|
4
5
|
import { isRecord } from "../run/type-guards.js";
|
|
5
6
|
const OLDER_BACKEND = {
|
|
6
7
|
"computer-use": "cua",
|
|
7
8
|
"shared-world": "concurrent-shared-world",
|
|
8
9
|
};
|
|
9
|
-
|
|
10
|
-
function warnOlderField(name, replacement) {
|
|
11
|
-
if (warnedFields.has(name))
|
|
12
|
-
return;
|
|
13
|
-
warnedFields.add(name);
|
|
14
|
-
process.emitWarning(`BrowserLabScoringContext.${name} is deprecated and is removed in the next minor. Use ${replacement}.`, { type: "DeprecationWarning", code: "HUMANISH_SCORING_CONTEXT_FIELD_DEPRECATED" });
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* The scorer's context: the facts, plus the older `backend` and `laneCount` as getters that warn
|
|
18
|
-
* once when a scorer reads them. They are not enumerable, so a spread, `Object.assign`,
|
|
19
|
-
* `JSON.stringify` or `structuredClone` of the context skips them and warns about no field the
|
|
20
|
-
* code never named. `"backend" in ctx` still finds them. Core never reads them.
|
|
21
|
-
*/
|
|
10
|
+
/** The scorer's context: the facts, plus the older `backend` and `laneCount` (deprecated-fields.ts). */
|
|
22
11
|
function scorerContext(facts) {
|
|
23
|
-
return
|
|
24
|
-
backend: {
|
|
25
|
-
|
|
26
|
-
get: () => {
|
|
27
|
-
warnOlderField("backend", "route");
|
|
28
|
-
return OLDER_BACKEND[facts.route];
|
|
29
|
-
},
|
|
30
|
-
},
|
|
31
|
-
laneCount: {
|
|
32
|
-
enumerable: false,
|
|
33
|
-
get: () => {
|
|
34
|
-
warnOlderField("laneCount", "participantCount");
|
|
35
|
-
return facts.participantCount;
|
|
36
|
-
},
|
|
37
|
-
},
|
|
12
|
+
return withDeprecatedFields({ ...facts }, { name: "BrowserLabScoringContext", code: "HUMANISH_SCORING_CONTEXT_FIELD_DEPRECATED" }, {
|
|
13
|
+
backend: { replacement: "route", read: () => OLDER_BACKEND[facts.route] },
|
|
14
|
+
laneCount: { replacement: "participantCount", read: () => facts.participantCount },
|
|
38
15
|
});
|
|
39
16
|
}
|
|
40
|
-
/** A
|
|
17
|
+
/** A declared scorer that returned a malformed value never rendered a verdict. */
|
|
41
18
|
export const DECLARED_SCORER_MALFORMED = "Declared product scorer returned a malformed value instead of a verdict; a declared gate that cannot render a pass is recorded as a fail, never a silent pass.";
|
|
42
|
-
/** A
|
|
19
|
+
/** A declared scorer that threw never rendered a verdict. `detail` is already sanitized. */
|
|
43
20
|
export function declaredScorerThrew(detail) {
|
|
44
21
|
return `Declared product scorer threw before returning a verdict (${detail}); a crashed declared gate is recorded as a fail, never a silent pass.`;
|
|
45
22
|
}
|
|
@@ -49,13 +26,13 @@ export async function applyBrowserScorer(args) {
|
|
|
49
26
|
return { failures: [] };
|
|
50
27
|
const declared = scorerProvenance !== undefined;
|
|
51
28
|
// Record the loaded scorer's identity regardless of hook outcome (a throwing/invalid scorer was
|
|
52
|
-
// still loaded and attempted). A
|
|
53
|
-
//
|
|
29
|
+
// still loaded and attempted). A valid status:"fail" is a failure (library + declared, the
|
|
30
|
+
// original path); a declared scorer that throws or returns a malformed value is one too (below).
|
|
54
31
|
if (scorerProvenance)
|
|
55
32
|
bundle.scorerProvenance = scorerProvenance;
|
|
56
|
-
// The scorer sees a
|
|
33
|
+
// The scorer sees a read-only view of the bundle: it cannot mutate noSpend/cost/review in place to
|
|
57
34
|
// launder a verdict (a tamper attempt throws in the scorer's strict-mode ESM and is caught below as
|
|
58
|
-
// a hook failure). The seam still stamps the
|
|
35
|
+
// a hook failure). The seam still stamps the real bundle.
|
|
59
36
|
const scoringContext = scorerContext({
|
|
60
37
|
...context,
|
|
61
38
|
bundle: frozenBundleView(context.bundle),
|
|
@@ -142,10 +119,10 @@ export function adapterScoreFailureMessage(bundle) {
|
|
|
142
119
|
: undefined;
|
|
143
120
|
}
|
|
144
121
|
/**
|
|
145
|
-
* Deep-freeze a structured clone so a loaded scorer sees a
|
|
122
|
+
* Deep-freeze a structured clone so a loaded scorer sees a read-only bundle: it cannot mutate
|
|
146
123
|
* noSpend/cost/review in place to launder a verdict (which would defeat the costProbe-not-loadable
|
|
147
124
|
* guarantee). A tamper attempt throws in the scorer's strict-mode ESM and is caught as a hook failure.
|
|
148
|
-
* Legitimate read-only scoring is unaffected. The seam always stamps the
|
|
125
|
+
* Legitimate read-only scoring is unaffected. The seam always stamps the real bundle, never this view.
|
|
149
126
|
*/
|
|
150
127
|
export function frozenBundleView(bundle) {
|
|
151
128
|
const clone = structuredClone(bundle);
|
|
@@ -2,14 +2,14 @@ import type { BrowserLabScoringContext } from "./adapter-extension.js";
|
|
|
2
2
|
import type { TerminalProductScoringContext } from "../routes/terminal/types.js";
|
|
3
3
|
import type { LabRoute } from "./plan.js";
|
|
4
4
|
import type { RunAdapterArtifact, RunAdapterScore, RunFeedbackCandidate, RunScorerProvenance } from "../run/bundle.js";
|
|
5
|
-
/** The read-model context a loaded scorer sees
|
|
5
|
+
/** The read-model context a loaded scorer sees: the terminal or browser scoring context. The module
|
|
6
6
|
* narrows it at runtime (`"product" in ctx` ⇒ terminal; `"route" in ctx` ⇒ browser). */
|
|
7
7
|
export type AdapterScoringContext = TerminalProductScoringContext | BrowserLabScoringContext;
|
|
8
8
|
/**
|
|
9
|
-
* The adopter-facing scorer module contract
|
|
10
|
-
* `.js`/`.cjs` whose package.json type matches)
|
|
11
|
-
* loader wires
|
|
12
|
-
* picked up (the whitelist is the scope guard). A module exporting
|
|
9
|
+
* The adopter-facing scorer module contract. Export any subset of these from a `.mjs` (or a
|
|
10
|
+
* `.js`/`.cjs` whose package.json type matches): named exports or a single default object. The
|
|
11
|
+
* loader wires only these three; an exported `executor`/`env`/`provisionSubject`/`costProbe` is never
|
|
12
|
+
* picked up (the whitelist is the scope guard). A module exporting none of them is a hard load error.
|
|
13
13
|
*
|
|
14
14
|
* `C` is the context `score` and `deriveFeedback` read: `BrowserLabScoringContext` for a scorer
|
|
15
15
|
* written for computer use and shared world, `TerminalProductScoringContext` for one written for
|
|
@@ -37,7 +37,7 @@ export declare function terminalScorer(scorer: AdapterScorerModule<TerminalProdu
|
|
|
37
37
|
export declare function browserRouteScorer(scorer: AdapterScorerModule): AdapterScorerModule<BrowserLabScoringContext>;
|
|
38
38
|
/** The scorer as a terminal run calls it, with the terminal context (see browserRouteScorer). */
|
|
39
39
|
export declare function terminalRouteScorer(scorer: AdapterScorerModule): AdapterScorerModule<TerminalProductScoringContext>;
|
|
40
|
-
type AdapterScorerLoadErrorCode = "
|
|
40
|
+
type AdapterScorerLoadErrorCode = "HUMANISH_STUDY_SCORER_BAD_REF" | "HUMANISH_STUDY_SCORER_NOT_FOUND" | "HUMANISH_STUDY_SCORER_LOAD_FAILED" | "HUMANISH_STUDY_SCORER_NO_HOOKS" | "HUMANISH_STUDY_SCORER_UNSUPPORTED_BACKEND";
|
|
41
41
|
export type AdapterScorerLoadResult = {
|
|
42
42
|
ok: true;
|
|
43
43
|
hooks: AdapterScorerModule;
|
|
@@ -52,7 +52,7 @@ export type AdapterScorerLoadResult = {
|
|
|
52
52
|
/**
|
|
53
53
|
* Resolve + load a config-declared scorer module. Resolution clones scenario.ref exactly
|
|
54
54
|
* (prepareSelectedOutputDirectory → cwd-clamp → readContainedRegularFile), then `import()`s the
|
|
55
|
-
* entry file in a
|
|
55
|
+
* entry file in a broad try/catch. The digest is over the readContainedRegularFile entry bytes.
|
|
56
56
|
*/
|
|
57
57
|
export declare function loadAdapterScorer(args: {
|
|
58
58
|
cwd: string;
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
//
|
|
2
|
-
// scorer module, load it fail-closed (typed error + exit 2,
|
|
1
|
+
// CLI-loadable adopter scorer. Resolve `review.scorer.ref` / `--scorer` to an out-of-tree
|
|
2
|
+
// scorer module, load it fail-closed (typed error + exit 2, before any spend), and pick off only the
|
|
3
3
|
// whitelisted read-model hooks {score, deriveFeedback, deriveArtifacts}. `costProbe` is deliberately
|
|
4
|
-
//
|
|
4
|
+
// not loadable: an injected provider cost line overwrites the core-measured one and can forge a
|
|
5
5
|
// satisfied no-spend proof, so it stays library-only.
|
|
6
6
|
//
|
|
7
|
-
//
|
|
8
|
-
// who runs `humanish lab run` in their own checkout
|
|
9
|
-
// package.json script.
|
|
10
|
-
// declared. Containment is
|
|
7
|
+
// Trust model: the party who writes `review.scorer.ref` is the party
|
|
8
|
+
// who runs `humanish lab run` in their own checkout: identical trust to humanish.lab.yml or a
|
|
9
|
+
// package.json script. The loader adds no new execution capability; it relocates where the reference is
|
|
10
|
+
// declared. Containment is entry-file-only: `readContainedRegularFile` blocks abs/`..`/symlink/
|
|
11
11
|
// hardlink/realpath-escape/TOCTOU on the entry module, but `import()` then executes the transitive
|
|
12
12
|
// graph + npm deps with no clamp, and `import()` runs top-level module code before any whitelist
|
|
13
|
-
// check. The whitelist bounds the
|
|
13
|
+
// check. The whitelist bounds the wired hook surface and does not cover import-time code; the
|
|
14
14
|
// trusted-in-process boundary is the actual safety carrier. The seam's output re-scrub is a
|
|
15
|
-
// best-effort denylist
|
|
15
|
+
// best-effort denylist that provides no containment. `review.scorer.ref` entries are executable code, so review a
|
|
16
16
|
// PR that adds one as code, not config.
|
|
17
17
|
import { realpath } from "node:fs/promises";
|
|
18
18
|
import path from "node:path";
|
|
@@ -43,20 +43,20 @@ export function browserRouteScorer(scorer) {
|
|
|
43
43
|
export function terminalRouteScorer(scorer) {
|
|
44
44
|
return scorer;
|
|
45
45
|
}
|
|
46
|
-
/** The routes
|
|
47
|
-
* (scripted or preview) aborts at load
|
|
46
|
+
/** The routes that can run the loaded scorer. A declared scorer on any other route
|
|
47
|
+
* (scripted or preview) aborts at load: a gate that cannot run must never green-pass. */
|
|
48
48
|
const SCORER_CAPABLE_ROUTES = new Set([
|
|
49
49
|
"terminal",
|
|
50
50
|
"computer-use",
|
|
51
51
|
"shared-world",
|
|
52
52
|
]);
|
|
53
|
-
/** `.mjs` is
|
|
54
|
-
* package.json `type`. `.ts` is rejected
|
|
53
|
+
/** `.mjs` is the recommended extension; `.js`/`.cjs` accepted but the module system is the adopter repo's
|
|
54
|
+
* package.json `type`. `.ts` is rejected: the compiled `dist/` CLI ships no TypeScript loader. */
|
|
55
55
|
const SCORER_EXTENSIONS = new Set([".mjs", ".js", ".cjs"]);
|
|
56
56
|
/**
|
|
57
57
|
* Resolve + load a config-declared scorer module. Resolution clones scenario.ref exactly
|
|
58
58
|
* (prepareSelectedOutputDirectory → cwd-clamp → readContainedRegularFile), then `import()`s the
|
|
59
|
-
* entry file in a
|
|
59
|
+
* entry file in a broad try/catch. The digest is over the readContainedRegularFile entry bytes.
|
|
60
60
|
*/
|
|
61
61
|
export async function loadAdapterScorer(args) {
|
|
62
62
|
const { route, source } = args;
|
|
@@ -64,25 +64,25 @@ export async function loadAdapterScorer(args) {
|
|
|
64
64
|
ok: false,
|
|
65
65
|
error: { code, message },
|
|
66
66
|
});
|
|
67
|
-
// A declared gate that cannot run on this route must
|
|
67
|
+
// A declared gate that cannot run on this route must abort (never silently green-pass).
|
|
68
68
|
if (!SCORER_CAPABLE_ROUTES.has(route)) {
|
|
69
|
-
return fail("
|
|
69
|
+
return fail("HUMANISH_STUDY_SCORER_UNSUPPORTED_BACKEND", `review.scorer.ref is set, but this study runs on the ${route} route, which cannot run a scorer. The run stops here so the scorer is not silently skipped. Use it with a terminal, computer-use or shared-world study, or remove review.scorer.ref.`);
|
|
70
70
|
}
|
|
71
71
|
const trimmed = args.ref.trim();
|
|
72
72
|
if (!trimmed) {
|
|
73
|
-
return fail("
|
|
73
|
+
return fail("HUMANISH_STUDY_SCORER_BAD_REF", "review.scorer.ref must be a non-empty repo-relative path ending in .mjs (recommended), .js, or .cjs.");
|
|
74
74
|
}
|
|
75
|
-
// Provenance is recorded repo-relative
|
|
75
|
+
// Provenance is recorded repo-relative: an absolute ref (even one that happens to land inside cwd)
|
|
76
76
|
// is rejected up front rather than silently rewritten to its in-tree relative form.
|
|
77
77
|
if (path.isAbsolute(trimmed)) {
|
|
78
|
-
return fail("
|
|
78
|
+
return fail("HUMANISH_STUDY_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must be a path relative to the project, not an absolute path, because the run records it relative to the project.`);
|
|
79
79
|
}
|
|
80
80
|
const ext = path.extname(trimmed).toLowerCase();
|
|
81
81
|
if (ext === ".ts") {
|
|
82
|
-
return fail("
|
|
82
|
+
return fail("HUMANISH_STUDY_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" ends in .ts, but the shipped CLI runs compiled JS with no TypeScript loader. Precompile to .mjs (recommended) or .js/.cjs.`);
|
|
83
83
|
}
|
|
84
84
|
if (!SCORER_EXTENSIONS.has(ext)) {
|
|
85
|
-
return fail("
|
|
85
|
+
return fail("HUMANISH_STUDY_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must be a path relative to the project ending in .mjs (recommended), .js or .cjs.`);
|
|
86
86
|
}
|
|
87
87
|
// Root token: realpath(cwd) → prepareSelectedOutputDirectory(dirname, cwd). Mirrors scenario.ref.
|
|
88
88
|
const physicalCwd = await realpath(path.resolve(args.cwd));
|
|
@@ -91,18 +91,18 @@ export async function loadAdapterScorer(args) {
|
|
|
91
91
|
const absolutePath = path.resolve(root.physicalPath, trimmed);
|
|
92
92
|
const relative = path.relative(root.physicalPath, absolutePath);
|
|
93
93
|
if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
|
|
94
|
-
return fail("
|
|
94
|
+
return fail("HUMANISH_STUDY_SCORER_BAD_REF", `review.scorer.ref "${trimmed}" must stay inside the project directory, because the run records it relative to the project; a path into a parent directory cannot be recorded that way.`);
|
|
95
95
|
}
|
|
96
96
|
const relPosix = relative.split(path.sep).join("/");
|
|
97
|
-
// Fail-closed containment gate on the
|
|
97
|
+
// Fail-closed containment gate on the entry file only: rejects symlink, nlink>1, realpath-escape,
|
|
98
98
|
// TOCTOU. Its returned bytes are the digest input.
|
|
99
99
|
const bytes = await readContainedRegularFile(root, relPosix);
|
|
100
100
|
if (!bytes) {
|
|
101
|
-
return fail("
|
|
101
|
+
return fail("HUMANISH_STUDY_SCORER_NOT_FOUND", `review.scorer.ref "${trimmed}" could not be read as a regular file inside the project (${relPosix}). Use a plain file there: not a symlink or a hard link, and not a path that resolves outside the project.`);
|
|
102
102
|
}
|
|
103
103
|
const digest = digestText(bytes.toString("utf8"));
|
|
104
|
-
// Import the entry module in a
|
|
105
|
-
// / top-level throw). import() executes the transitive graph
|
|
104
|
+
// Import the entry module in a broad try/catch (ERR_MODULE_NOT_FOUND / SyntaxError / ERR_REQUIRE_ESM
|
|
105
|
+
// / top-level throw). import() executes the transitive graph, and the cwd clamp guards only the entry
|
|
106
106
|
// file; out-of-tree/transitive code is acceptable only because of the trust boundary above.
|
|
107
107
|
let mod;
|
|
108
108
|
try {
|
|
@@ -114,12 +114,12 @@ export async function loadAdapterScorer(args) {
|
|
|
114
114
|
const hint = /ERR_REQUIRE_ESM|import statement outside a module|Cannot use import statement|Unexpected (?:token|identifier)|SyntaxError/i.test(detail)
|
|
115
115
|
? ' Use a .mjs entry file, or set "type": "module" in the nearest package.json.'
|
|
116
116
|
: "";
|
|
117
|
-
return fail("
|
|
117
|
+
return fail("HUMANISH_STUDY_SCORER_LOAD_FAILED", `review.scorer.ref "${trimmed}" failed to load: ${redactText(detail)}.${hint}`);
|
|
118
118
|
}
|
|
119
|
-
// mod.default ?? mod, then pick off
|
|
120
|
-
// wired
|
|
119
|
+
// mod.default ?? mod, then pick off only the whitelist. An exported executor/env/costProbe is never
|
|
120
|
+
// wired; the whitelist is the scope guard. `exports` records the hooks actually wired for this
|
|
121
121
|
// backend: deriveArtifacts is browser-only, so on the terminal route it is neither wired nor
|
|
122
|
-
// recorded (a scorer that exported
|
|
122
|
+
// recorded (a scorer that exported only deriveArtifacts there wires nothing and fails closed below,
|
|
123
123
|
// never a silent no-op).
|
|
124
124
|
const picked = (mod.default ?? mod);
|
|
125
125
|
const terminalRoute = route === "terminal";
|
|
@@ -139,9 +139,9 @@ export async function loadAdapterScorer(args) {
|
|
|
139
139
|
}
|
|
140
140
|
if (exports.length === 0) {
|
|
141
141
|
const artifactsOnly = terminalRoute && typeof picked.deriveArtifacts === "function";
|
|
142
|
-
return fail("
|
|
142
|
+
return fail("HUMANISH_STUDY_SCORER_NO_HOOKS", artifactsOnly
|
|
143
143
|
? `review.scorer.ref "${trimmed}" exported only deriveArtifacts, which is browser-only and inert on the terminal route. Export score and/or deriveFeedback for a terminal-product scorer.`
|
|
144
|
-
: `review.scorer.ref "${trimmed}" loaded but
|
|
144
|
+
: `review.scorer.ref "${trimmed}" loaded but exports none of score, deriveFeedback or deriveArtifacts. Export at least one, as a named export or on a default object. costProbe cannot be loaded from a scorer file.`);
|
|
145
145
|
}
|
|
146
146
|
const provenance = {
|
|
147
147
|
schema: "humanish.scorer-provenance.v1",
|
|
@@ -8,8 +8,8 @@
|
|
|
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) ??
|
|
@@ -32,7 +32,7 @@ export function compositionReason(config) {
|
|
|
32
32
|
}
|
|
33
33
|
/** Why a this-repo lab cannot run live. The parser and the preview planner both refuse with it. */
|
|
34
34
|
export const THIS_REPO_DRY_RUN_ONLY = "this-repo labs 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
|
|
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") {
|
|
@@ -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 runCuaActorLab with
|
|
54
|
+
// it fails closed in runCuaActorLab 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.";
|
|
@@ -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,10 +130,10 @@ 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
139
|
return "clone scripted-browser labs require exactly one repo in subject.repos.";
|
|
@@ -143,41 +143,41 @@ function scriptedBrowserValidationReason(config) {
|
|
|
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,7 +185,7 @@ 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
191
|
return "computer-use clone labs serve one repo; declare exactly one repo in subject.repos.";
|
|
@@ -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)) {
|