humanish 0.108.0 → 0.109.1
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 +58 -59
- package/CHANGELOG.md +22 -0
- package/CONTEXT.md +44 -44
- package/README.md +3 -3
- package/TELEMETRY.md +2 -2
- package/dist/actors/codex/app-server-trace.js +2 -1
- package/dist/actors/codex/restricted-participant.js +12 -12
- package/dist/actors/codex/restricted-session.d.ts +2 -2
- package/dist/actors/computer-use/actor.d.ts +6 -6
- package/dist/actors/computer-use/actor.js +2 -2
- package/dist/actors/computer-use/admission-limit.d.ts +2 -2
- package/dist/actors/computer-use/admission-limit.js +3 -3
- 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.js +5 -5
- package/dist/actors/computer-use/loop/debrief.js +2 -2
- package/dist/actors/computer-use/loop/ending.d.ts +1 -1
- package/dist/actors/computer-use/loop/ending.js +12 -11
- package/dist/actors/computer-use/loop/observation.js +6 -5
- package/dist/actors/computer-use/loop/provider-call.js +11 -11
- package/dist/actors/computer-use/loop/session.d.ts +4 -4
- package/dist/actors/computer-use/loop/session.js +2 -2
- package/dist/actors/computer-use/loop/trace.js +3 -2
- package/dist/actors/computer-use/loop/types.d.ts +24 -24
- package/dist/actors/computer-use/loop/usage.d.ts +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-provider.d.ts +2 -2
- package/dist/actors/computer-use/openai-provider.js +8 -8
- 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 +4 -4
- package/dist/actors/contract.js +1 -1
- package/dist/actors/local-agent/claude-session.js +3 -3
- package/dist/actors/local-agent/cli.d.ts +1 -1
- package/dist/actors/local-agent/cli.js +1 -1
- package/dist/actors/reasoning-effort.js +3 -3
- package/dist/actors/registry.d.ts +2 -2
- package/dist/actors/registry.js +3 -3
- package/dist/actors/scripted-browser/actor.d.ts +2 -2
- package/dist/actors/scripted-browser/actor.js +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/execute.d.ts +1 -1
- package/dist/analysis/execute.js +1 -1
- 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/comms.js +14 -22
- package/dist/cli/commands/migrate.js +15 -4
- package/dist/cli/commands/observe.d.ts +0 -1
- package/dist/cli/commands/observe.js +0 -15
- package/dist/cli/commands/run-command.d.ts +2 -2
- package/dist/cli/commands/run-command.js +3 -3
- package/dist/cli/commands/runs.js +9 -7
- package/dist/cli/commands/setup.js +5 -7
- package/dist/cli/commands/study-format.d.ts +9 -0
- package/dist/cli/commands/{lab-format.js → study-format.js} +5 -5
- 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} +12 -12
- 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} +3 -3
- 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} +7 -7
- 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} +34 -34
- package/dist/cli/commands/{lab-scorer.d.ts → study-scorer.d.ts} +5 -5
- package/dist/cli/commands/{lab-scorer.js → study-scorer.js} +1 -1
- package/dist/cli/commands/study.js +13 -49
- package/dist/cli/commands/tui.js +12 -12
- package/dist/cli/commands/watch.js +30 -65
- package/dist/cli/deprecations.d.ts +1 -13
- package/dist/cli/deprecations.js +0 -30
- package/dist/cli/doctor.d.ts +3 -3
- package/dist/cli/doctor.js +16 -16
- package/dist/cli/first-run-path.d.ts +4 -4
- package/dist/cli/first-run-path.js +7 -7
- package/dist/cli/io.d.ts +3 -3
- package/dist/cli/io.js +2 -2
- package/dist/cli/observer-follow.d.ts +2 -2
- package/dist/cli/observer-follow.js +2 -2
- package/dist/cli/orientation.d.ts +4 -4
- package/dist/cli/orientation.js +58 -20
- package/dist/cli/program.js +3 -4
- package/dist/cli/telemetry.d.ts +1 -1
- package/dist/cli/telemetry.js +14 -20
- package/dist/comms/catch-host.d.ts +1 -1
- package/dist/comms/catch-host.js +3 -3
- package/dist/comms/connections.d.ts +1 -1
- package/dist/comms/connections.js +2 -2
- package/dist/comms/external-evidence.d.ts +5 -5
- package/dist/comms/external-evidence.js +4 -3
- package/dist/comms/fake-inbox.d.ts +2 -2
- package/dist/comms/fake-inbox.js +2 -2
- package/dist/comms/receiving-runtime.d.ts +4 -4
- package/dist/comms/sandbox-catch.d.ts +2 -2
- package/dist/comms/sandbox-catch.js +2 -2
- package/dist/comms/setup.d.ts +2 -2
- package/dist/comms/setup.js +29 -32
- package/dist/evidence/redaction.d.ts +11 -0
- package/dist/evidence/redaction.js +43 -0
- package/dist/feedback/draft.js +2 -2
- package/dist/feedback/export-bundle.js +5 -4
- package/dist/feedback/export.js +3 -2
- 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 +17 -17
- 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.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 +5 -5
- package/dist/index.d.ts +13 -15
- package/dist/index.js +6 -8
- package/dist/observer/artifact.d.ts +1 -1
- package/dist/observer/artifact.js +1 -1
- package/dist/observer/data.d.ts +1 -1
- package/dist/observer/library.d.ts +2 -0
- package/dist/observer/library.js +4 -1
- package/dist/observer/render.js +7 -1
- package/dist/observer/run-routes.d.ts +1 -0
- package/dist/observer/run-routes.js +37 -12
- package/dist/observer/serve.d.ts +1 -1
- package/dist/observer-app.html +1 -1
- package/dist/routes/computer-use/bundle-parts.js +3 -2
- package/dist/routes/computer-use/bundle.d.ts +2 -2
- package/dist/routes/computer-use/bundle.js +7 -6
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +5 -5
- package/dist/routes/computer-use/e2b-desktop/comms.js +5 -4
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/prepare.js +3 -3
- package/dist/routes/computer-use/e2b-desktop/start.js +3 -4
- package/dist/routes/computer-use/e2b-desktop/state.d.ts +2 -2
- package/dist/routes/computer-use/e2b-desktop/teardown.js +2 -3
- package/dist/routes/computer-use/external-comms.d.ts +3 -3
- package/dist/routes/computer-use/fanout-bundle.js +11 -10
- package/dist/routes/computer-use/fanout-records.js +2 -2
- package/dist/routes/computer-use/in-process-desktop.js +1 -1
- package/dist/routes/computer-use/live-flush.d.ts +3 -3
- package/dist/routes/computer-use/live-phase.d.ts +2 -3
- package/dist/routes/computer-use/live-phase.js +3 -3
- 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 +2 -2
- package/dist/routes/computer-use/participant-desktop.d.ts +3 -3
- package/dist/routes/computer-use/participant-desktop.js +1 -1
- package/dist/routes/computer-use/participant-execution.js +1 -1
- package/dist/routes/computer-use/participant-model.js +3 -3
- package/dist/routes/computer-use/participant-prompt.d.ts +5 -5
- package/dist/routes/computer-use/participant-prompt.js +3 -3
- package/dist/routes/computer-use/participant-runs.d.ts +10 -10
- package/dist/routes/computer-use/participant-runs.js +14 -13
- package/dist/routes/computer-use/plan.d.ts +12 -12
- package/dist/routes/computer-use/plan.js +27 -27
- package/dist/routes/computer-use/preflight.d.ts +5 -5
- package/dist/routes/computer-use/preflight.js +5 -5
- package/dist/routes/computer-use/rerun-selection.d.ts +1 -1
- package/dist/routes/computer-use/rerun-selection.js +3 -2
- package/dist/routes/computer-use/result.d.ts +4 -4
- package/dist/routes/computer-use/result.js +13 -12
- package/dist/routes/computer-use/route.d.ts +12 -12
- package/dist/routes/computer-use/route.js +19 -19
- package/dist/routes/computer-use/self-report.js +1 -1
- package/dist/routes/computer-use/setup.d.ts +22 -22
- package/dist/routes/computer-use/setup.js +15 -15
- package/dist/routes/computer-use/single-bundle.d.ts +4 -4
- package/dist/routes/computer-use/single-bundle.js +14 -13
- package/dist/routes/computer-use/subject-projection.d.ts +3 -3
- package/dist/routes/computer-use/types.d.ts +34 -34
- package/dist/routes/computer-use/types.js +3 -3
- package/dist/routes/preview.d.ts +6 -6
- package/dist/routes/preview.js +5 -5
- package/dist/routes/scripted/bundle.d.ts +6 -6
- package/dist/routes/scripted/bundle.js +10 -9
- package/dist/routes/scripted/plan.d.ts +7 -7
- package/dist/routes/scripted/plan.js +6 -6
- package/dist/routes/scripted/result.d.ts +3 -3
- package/dist/routes/scripted/result.js +9 -9
- package/dist/routes/scripted/route.d.ts +9 -9
- package/dist/routes/scripted/route.js +11 -11
- package/dist/routes/scripted/scenario.d.ts +1 -1
- package/dist/routes/scripted/scenario.js +3 -3
- package/dist/routes/scripted/setup.d.ts +6 -6
- package/dist/routes/scripted/setup.js +4 -4
- package/dist/routes/scripted/subject.d.ts +5 -5
- package/dist/routes/scripted/subject.js +3 -3
- package/dist/routes/scripted/surface-records.d.ts +1 -1
- package/dist/routes/scripted/surface-records.js +2 -2
- package/dist/routes/scripted/surface-sessions.d.ts +3 -3
- package/dist/routes/scripted/types.d.ts +17 -17
- package/dist/routes/scripted/types.js +1 -1
- package/dist/routes/shared-world/bundle-records.js +3 -3
- package/dist/routes/shared-world/bundle.js +15 -14
- package/dist/routes/shared-world/checkpoints.d.ts +3 -3
- package/dist/routes/shared-world/checkpoints.js +1 -1
- package/dist/routes/shared-world/comms.d.ts +9 -9
- package/dist/routes/shared-world/comms.js +6 -5
- package/dist/routes/shared-world/participant-specs.d.ts +3 -3
- package/dist/routes/shared-world/participant-specs.js +7 -7
- package/dist/routes/shared-world/plan.d.ts +9 -9
- package/dist/routes/shared-world/plan.js +9 -9
- package/dist/routes/shared-world/provisioned.d.ts +8 -8
- package/dist/routes/shared-world/provisioned.js +4 -4
- package/dist/routes/shared-world/result.d.ts +6 -6
- package/dist/routes/shared-world/result.js +11 -10
- package/dist/routes/shared-world/route.d.ts +11 -11
- package/dist/routes/shared-world/route.js +19 -19
- package/dist/routes/shared-world/setup.d.ts +13 -13
- package/dist/routes/shared-world/setup.js +19 -19
- package/dist/routes/shared-world/types.d.ts +27 -27
- package/dist/routes/terminal/adapter.d.ts +2 -2
- package/dist/routes/terminal/adapter.js +4 -4
- package/dist/routes/terminal/bundle.d.ts +11 -11
- package/dist/routes/terminal/bundle.js +12 -12
- package/dist/routes/terminal/credentials.d.ts +4 -4
- package/dist/routes/terminal/credentials.js +5 -5
- package/dist/routes/terminal/dry-run.d.ts +4 -4
- package/dist/routes/terminal/dry-run.js +9 -9
- package/dist/routes/terminal/ledger.d.ts +2 -2
- 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 +7 -7
- package/dist/routes/terminal/live-sandbox.d.ts +2 -2
- package/dist/routes/terminal/live-sandbox.js +3 -2
- package/dist/routes/terminal/participant-text.js +2 -1
- package/dist/routes/terminal/persona.d.ts +2 -2
- package/dist/routes/terminal/persona.js +2 -2
- package/dist/routes/terminal/plan.d.ts +7 -7
- package/dist/routes/terminal/plan.js +5 -5
- package/dist/routes/terminal/result.d.ts +5 -5
- package/dist/routes/terminal/result.js +7 -7
- package/dist/routes/terminal/route.d.ts +9 -9
- package/dist/routes/terminal/route.js +14 -14
- package/dist/routes/terminal/session.d.ts +5 -5
- package/dist/routes/terminal/session.js +7 -7
- package/dist/routes/terminal/trace.d.ts +2 -2
- package/dist/routes/terminal/types.d.ts +24 -24
- package/dist/routes/terminal/types.js +2 -2
- package/dist/run/bundle.d.ts +7 -7
- package/dist/run/bundle.js +2 -2
- package/dist/run/costs.d.ts +23 -0
- package/dist/run/costs.js +72 -43
- package/dist/run/dry-run-inputs.d.ts +1 -1
- package/dist/run/dry-run-inputs.js +1 -1
- package/dist/run/dry-run.js +2 -2
- package/dist/run/outcomes.d.ts +1 -1
- package/dist/run/participant.d.ts +1 -1
- package/dist/run/preflight-receipts.js +1 -1
- package/dist/run/pricing.js +2 -2
- package/dist/run/projection.d.ts +32 -32
- package/dist/run/projection.js +44 -44
- package/dist/run/reclaim.d.ts +1 -1
- package/dist/run/reclaim.js +1 -1
- package/dist/run/results.d.ts +2 -2
- 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 +11 -1
- package/dist/run/run-index.js +63 -49
- package/dist/run/run.d.ts +3 -3
- package/dist/run/run.js +2 -2
- package/dist/run/shared-world-evidence.d.ts +1 -1
- package/dist/run/shared-world-shape.js +1 -1
- package/dist/run/stats.d.ts +3 -3
- package/dist/run/stats.js +14 -14
- package/dist/run/status.d.ts +10 -2
- package/dist/run/status.js +6 -3
- package/dist/run/streams.d.ts +2 -2
- package/dist/run/study-provenance.d.ts +4 -2
- package/dist/run/study-provenance.js +7 -4
- package/dist/run/study-result.d.ts +0 -5
- package/dist/run/study-result.js +1 -1
- package/dist/run-study.d.ts +112 -0
- package/dist/{run-lab.js → run-study.js} +52 -45
- package/dist/{lab → study}/adapter-extension.d.ts +8 -20
- package/dist/{lab → study}/adapter-extension.js +2 -14
- package/dist/{lab → study}/adapter-scorer-loader.d.ts +10 -10
- package/dist/{lab → study}/adapter-scorer-loader.js +3 -3
- package/dist/study/composition-rules.d.ts +7 -0
- package/dist/{lab → study}/composition-rules.js +12 -12
- package/dist/study/config.d.ts +15 -0
- package/dist/{lab → study}/config.js +37 -20
- package/dist/study/convert.d.ts +1 -1
- package/dist/study/convert.js +15 -15
- package/dist/{lab → study}/device-presets.d.ts +2 -2
- package/dist/{lab → study}/discover.d.ts +29 -23
- package/dist/{lab → study}/discover.js +97 -118
- package/dist/{lab → study}/doctor.d.ts +11 -11
- package/dist/{lab → study}/doctor.js +18 -18
- package/dist/study/files.d.ts +2 -2
- package/dist/study/files.js +6 -5
- package/dist/{lab → study}/init-templates.d.ts +2 -2
- package/dist/{lab → study}/init-templates.js +16 -11
- package/dist/{lab → study}/init.d.ts +1 -1
- package/dist/{lab → study}/init.js +7 -4
- package/dist/{lab → study}/keys.d.ts +2 -2
- package/dist/{lab → study}/keys.js +10 -10
- package/dist/study/migrate.d.ts +8 -3
- package/dist/study/migrate.js +60 -4
- package/dist/{lab → study}/parse/actors.d.ts +5 -5
- package/dist/{lab → study}/parse/actors.js +5 -5
- package/dist/study/parse/comms.d.ts +12 -0
- package/dist/study/parse/execution.d.ts +19 -0
- package/dist/{lab → study}/parse/study-v3.d.ts +3 -5
- package/dist/{lab → study}/parse/study-v3.js +3 -3
- package/dist/{lab → study}/parse/subject-state.d.ts +8 -8
- package/dist/{lab → study}/parse/subject-state.js +4 -4
- package/dist/{lab → study}/parse/subject.d.ts +3 -3
- package/dist/{lab → study}/parse/subject.js +8 -8
- package/dist/{lab → study}/parse/values.d.ts +2 -2
- package/dist/{lab → study}/persona-resolve.d.ts +4 -4
- package/dist/{lab → study}/persona-resolve.js +2 -2
- 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 +10 -10
- package/dist/{lab → study}/plan-participants.js +4 -4
- package/dist/{lab → study}/plan-types.d.ts +28 -28
- package/dist/{lab → study}/plan-types.js +2 -2
- package/dist/study/plan.d.ts +13 -0
- package/dist/{lab → study}/plan.js +20 -20
- package/dist/study/preflight-probes.d.ts +3 -0
- package/dist/{lab → study}/preflight-probes.js +9 -8
- package/dist/study/preflight-result.d.ts +8 -0
- package/dist/{lab → study}/preflight-result.js +3 -3
- package/dist/{lab → study}/preflight.d.ts +31 -31
- package/dist/{lab → study}/preflight.js +8 -8
- 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 +12 -12
- package/dist/{lab/run-lab-events.d.ts → study/run-study-events.d.ts} +10 -10
- package/dist/{lab/run-lab-events.js → study/run-study-events.js} +4 -4
- package/dist/{lab/run-lab-homes.d.ts → study/run-study-homes.d.ts} +8 -17
- package/dist/study/run-study-homes.js +3 -0
- package/dist/study/run-study-options.d.ts +28 -0
- package/dist/{lab/run-lab-options.js → study/run-study-options.js} +16 -15
- package/dist/{lab/lab-deps.d.ts → study/study-deps.d.ts} +2 -2
- package/dist/{lab/lab-deps.js → study/study-deps.js} +2 -2
- package/dist/{lab → study}/summary.d.ts +10 -10
- package/dist/{lab → study}/summary.js +15 -15
- package/dist/{lab → study}/tasks.d.ts +3 -3
- package/dist/{lab → study}/tasks.js +1 -1
- package/dist/{lab → study}/types.d.ts +104 -104
- package/dist/{lab → study}/types.js +1 -1
- package/dist/{lab → study}/validation.d.ts +19 -19
- package/dist/{lab → study}/validation.js +13 -13
- package/dist/{lab → study}/warnings.d.ts +4 -4
- package/dist/{lab → study}/warnings.js +1 -1
- package/dist/subject/clone.d.ts +6 -6
- package/dist/subject/clone.js +2 -2
- package/dist/subject/local-tree-archive.d.ts +2 -2
- package/dist/subject/local-tree-archive.js +3 -3
- package/dist/subject/local-tree.d.ts +3 -3
- package/dist/subject/runtime.js +2 -2
- package/dist/subject/serve.d.ts +4 -4
- package/dist/subject/state.d.ts +3 -3
- package/dist/subject/state.js +1 -1
- package/dist/subject/steps.d.ts +1 -1
- package/dist/subject/steps.js +1 -1
- package/dist/substrates/desktop-session.js +2 -2
- package/dist/substrates/detached.d.ts +1 -1
- package/dist/substrates/e2b/desktop-browser.d.ts +4 -4
- package/dist/substrates/e2b/desktop-browser.js +1 -1
- package/dist/substrates/e2b/desktop-cdp.d.ts +1 -1
- package/dist/substrates/e2b/desktop-cdp.js +1 -1
- package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
- package/dist/substrates/e2b/desktop-executor.js +12 -12
- package/dist/substrates/e2b/desktop-geometry.d.ts +1 -1
- package/dist/substrates/e2b/desktop-geometry.js +1 -1
- package/dist/substrates/e2b/desktop-media.d.ts +3 -3
- package/dist/substrates/e2b/lifetime.js +1 -1
- package/dist/substrates/e2b/sandbox.d.ts +3 -3
- package/dist/substrates/e2b/sandbox.js +1 -1
- package/dist/substrates/e2b/sdk.d.ts +1 -1
- package/dist/substrates/e2b/sdk.js +1 -1
- package/dist/substrates/local/runtime-config.d.ts +4 -4
- package/dist/substrates/local/runtime-config.js +4 -4
- package/dist/tui/contract.d.ts +8 -8
- package/dist/tui/contract.js +2 -2
- package/dist/tui/launch.d.ts +3 -3
- package/dist/tui/launch.js +22 -16
- package/dist/tui-app.js +139 -139
- package/dist/verify/subject.d.ts +1 -1
- package/dist/verify/subject.js +1 -1
- package/dist/verify/verify.js +2 -1
- package/docs/architecture/actor-contract.md +5 -5
- package/docs/architecture/browser-control.md +1 -1
- package/docs/architecture/external-public-shared-world.md +8 -7
- package/docs/architecture/github-feedback-loop.md +1 -1
- package/docs/architecture/task-protocol-support.md +1 -1
- package/docs/architecture/terminal-product-route.md +18 -18
- package/docs/contracts/adapter-fixtures.md +2 -2
- package/docs/contracts/errors.md +8 -8
- package/docs/contracts/run-bundle.md +6 -4
- package/docs/contracts/schemas.md +61 -42
- package/docs/contracts/study-analysis.md +4 -1
- package/docs/contracts/study-costs.md +17 -2
- package/examples/README.md +1 -1
- package/examples/scorer/scorer.mjs +3 -3
- package/package.json +2 -1
- package/skills/humanish/SKILL.md +8 -6
- package/skills/humanish/agents/openai.yaml +1 -1
- package/dist/cli/commands/lab-format.d.ts +0 -9
- 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/lab/composition-rules.d.ts +0 -7
- package/dist/lab/config.d.ts +0 -7
- package/dist/lab/deprecated-fields.d.ts +0 -10
- package/dist/lab/deprecated-fields.js +0 -24
- package/dist/lab/parse/comms.d.ts +0 -12
- package/dist/lab/parse/execution.d.ts +0 -19
- package/dist/lab/plan.d.ts +0 -13
- package/dist/lab/preflight-probes.d.ts +0 -3
- package/dist/lab/preflight-result.d.ts +0 -8
- package/dist/lab/route-inputs.d.ts +0 -28
- package/dist/lab/run-lab-homes.js +0 -7
- package/dist/lab/run-lab-options.d.ts +0 -28
- package/dist/library-aliases.d.ts +0 -56
- package/dist/library-aliases.js +0 -22
- package/dist/run-lab.d.ts +0 -112
- /package/dist/{lab → study}/device-presets.js +0 -0
- /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}/parse/comms.js +0 -0
- /package/dist/{lab → study}/parse/execution.js +0 -0
- /package/dist/{lab → study}/parse/values.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
- /package/dist/{lab → study}/routing.js +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
import { DEFAULT_ANALYSIS_MAX_COST_USD } from "../analysis/automatic-config.js";
|
|
1
2
|
export const DEFAULT_LOCAL_BROWSER_STARTER = {
|
|
2
3
|
appUrl: "http://127.0.0.1:3000",
|
|
3
4
|
mission: "Use the app's primary flow. Explain anything confusing and stop when the task is complete or you are stuck.",
|
|
4
5
|
};
|
|
5
|
-
function
|
|
6
|
+
function localBrowserStudy(starter = DEFAULT_LOCAL_BROWSER_STARTER) {
|
|
6
7
|
return {
|
|
7
8
|
path: "humanish/studies/local-browser.yaml",
|
|
8
9
|
plane: "source",
|
|
@@ -34,19 +35,23 @@ defaults:
|
|
|
34
35
|
};
|
|
35
36
|
}
|
|
36
37
|
/**
|
|
37
|
-
* The flagship live
|
|
38
|
+
* The flagship live study. A ChatGPT-account Codex participant has no API-dollar price, so preflight
|
|
38
39
|
* refuses a dollar cap on it (HUMANISH_COMPUTER_USE_UNPRICED_CAP); that variant is bounded by the
|
|
39
40
|
* session timeout instead of a cap it could never enforce.
|
|
40
41
|
*/
|
|
41
|
-
function
|
|
42
|
+
function tryLiveStudy(actor, localAgent = "codex") {
|
|
42
43
|
const account = actor === "local-agent";
|
|
43
44
|
const needs = account
|
|
44
45
|
? ` Needs E2B_API_KEY and the coding agent signed in on this machine. Cost: one small task, a few
|
|
45
46
|
E2B desktop minutes and the agent's account usage. humanish cannot put a dollar cap on account
|
|
46
|
-
usage, so the ten-minute session limit below bounds the run
|
|
47
|
+
usage, so the ten-minute session limit below bounds the run. When OPENAI_API_KEY is set, the
|
|
48
|
+
analysis after the run bills it: humanish refuses that request before it starts if its estimate
|
|
49
|
+
is over $${DEFAULT_ANALYSIS_MAX_COST_USD}. Set review.analysis: false to skip it.`
|
|
47
50
|
: ` Needs E2B_API_KEY and OPENAI_API_KEY. Cost: one small task with a $2 cap on estimated model
|
|
48
51
|
spend. The run stops before its next model request once the estimate passes $2, so the last
|
|
49
|
-
request can go slightly over, and hosted desktop time is billed separately
|
|
52
|
+
request can go slightly over, and hosted desktop time is billed separately. The analysis after
|
|
53
|
+
the run bills the same key outside that cap: humanish refuses it before it starts if its
|
|
54
|
+
estimate is over $${DEFAULT_ANALYSIS_MAX_COST_USD}. Set review.analysis: false to skip it.`;
|
|
50
55
|
const participant = account
|
|
51
56
|
? `# Your machine has a coding agent signed in, so this study uses it: no provider API key, only
|
|
52
57
|
# E2B. To use a provider key instead, swap to \`type: openai-computer-use\` and add caps.maxUsd.
|
|
@@ -229,8 +234,8 @@ defaults:
|
|
|
229
234
|
open: true
|
|
230
235
|
`,
|
|
231
236
|
},
|
|
232
|
-
|
|
233
|
-
|
|
237
|
+
tryLiveStudy("openai-computer-use"),
|
|
238
|
+
localBrowserStudy(),
|
|
234
239
|
{
|
|
235
240
|
path: "humanish/studies/cua-browser.yaml",
|
|
236
241
|
plane: "source",
|
|
@@ -401,16 +406,16 @@ export const humanishScripts = {
|
|
|
401
406
|
"humanish:verify": "humanish verify",
|
|
402
407
|
};
|
|
403
408
|
/**
|
|
404
|
-
* The starter files, with the live
|
|
409
|
+
* The starter files, with the live study written for the brain this machine can use.
|
|
405
410
|
*
|
|
406
|
-
* `local-agent` is not a variant of the
|
|
411
|
+
* `local-agent` is not a variant of the study so much as a different participant: on a machine with
|
|
407
412
|
* a signed-in Codex and no provider key, the study runs with the operator's own agent and needs
|
|
408
413
|
* only E2B. Writing the other one there would hand someone homework instead of a first run.
|
|
409
414
|
*/
|
|
410
415
|
export function starterFilesFor(actor, localBrowser = DEFAULT_LOCAL_BROWSER_STARTER, localAgent) {
|
|
411
416
|
return starterFiles.map((file) => file.path === "humanish/studies/local-browser.yaml"
|
|
412
|
-
?
|
|
417
|
+
? localBrowserStudy(localBrowser)
|
|
413
418
|
: file.path === "humanish/studies/try-live.yaml"
|
|
414
|
-
?
|
|
419
|
+
? tryLiveStudy(actor, localAgent)
|
|
415
420
|
: file);
|
|
416
421
|
}
|
|
@@ -5,7 +5,7 @@ export interface InitOptions {
|
|
|
5
5
|
yes?: boolean;
|
|
6
6
|
/** Injected so a test can decide what credentials this machine appears to have. */
|
|
7
7
|
env?: NodeJS.ProcessEnv;
|
|
8
|
-
/** Configure the starter local-browser
|
|
8
|
+
/** Configure the starter local-browser study without making the operator edit YAML. */
|
|
9
9
|
localBrowser?: {
|
|
10
10
|
appUrl: string;
|
|
11
11
|
mission?: string;
|
|
@@ -8,7 +8,7 @@ import { assertPreparedSelectedOutputDirectory, prepareContainedOutputDirectory,
|
|
|
8
8
|
import { validateCwd } from "../run/project.js";
|
|
9
9
|
import { pathExists, readTextIfExists, validateInitProjectPaths } from "./init-paths.js";
|
|
10
10
|
import { planGitignore, planPackageJson } from "./init-plan.js";
|
|
11
|
-
import { otherStudyFiles, STUDY_DIRECTORIES, studyFileStem } from "
|
|
11
|
+
import { otherStudyFiles, STUDY_DIRECTORIES, studyFileStem } from "./files.js";
|
|
12
12
|
const INIT_RESPONSE_SCHEMA = "humanish.init-result.v1";
|
|
13
13
|
export async function runInit(options) {
|
|
14
14
|
const requestedCwd = path.resolve(options.cwd);
|
|
@@ -38,7 +38,7 @@ export async function runInit(options) {
|
|
|
38
38
|
return failed(initialPathCheck);
|
|
39
39
|
}
|
|
40
40
|
await planAgentsFile(preparedProjectRoot, cwd, plan);
|
|
41
|
-
// The starter live
|
|
41
|
+
// The starter live study is written for the brain this machine can actually use. Shipping it as
|
|
42
42
|
// openai-computer-use on a machine with no provider key but a signed-in Codex would hand someone
|
|
43
43
|
// a file that asks for a credential they were just told they do not need.
|
|
44
44
|
const machine = await firstRunEnvironment(options.env ?? process.env, requestedCwd);
|
|
@@ -149,8 +149,11 @@ async function planStarterFiles(preparedProjectRoot, cwd, files, localBrowserReq
|
|
|
149
149
|
target: file.plane,
|
|
150
150
|
reason: `${others.join(", ")} already uses the name ${stem}`,
|
|
151
151
|
});
|
|
152
|
+
// humanish no longer reads a labs/ file, but migrate needs its name free to move it.
|
|
152
153
|
const legacy = others.some((other) => other.split(path.sep).includes("labs"));
|
|
153
|
-
plan.warnings.push(
|
|
154
|
+
plan.warnings.push(legacy
|
|
155
|
+
? `Skipped ${file.path}: ${others.join(", ")} already uses the name ${stem}. Move it to a studies/ directory; humanish migrate converts and moves a v2 file.`
|
|
156
|
+
: `Skipped ${file.path}: ${others.join(", ")} already uses the name ${stem}, and a second file with that name would make \`run ${stem}\` fail.`);
|
|
154
157
|
}
|
|
155
158
|
else if (existing === null) {
|
|
156
159
|
plan.changes.push({
|
|
@@ -268,7 +271,7 @@ function validateLocalBrowserStarter(input) {
|
|
|
268
271
|
return { ok: true, value };
|
|
269
272
|
}
|
|
270
273
|
/**
|
|
271
|
-
* What this machine can run, for the starter
|
|
274
|
+
* What this machine can run, for the starter study and the next steps. Local CLI status is
|
|
272
275
|
* classified without returning its output or reading its credential file. Provider keys go
|
|
273
276
|
* through the same discovery chain as every other command (process env, the project overlay,
|
|
274
277
|
* `e2b auth login`, the `humanish keys set` store) and only their presence is read, never a value.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** The first key in `raw` that
|
|
2
|
-
export declare function
|
|
1
|
+
/** The first key in `raw` that V2_KEYS does not list, as an error message; undefined if none. */
|
|
2
|
+
export declare function findUnknownV2Key(raw: unknown): string | undefined;
|
|
3
3
|
/** The first key in a humanish.study.v3 document that the format does not have; undefined if none. */
|
|
4
4
|
export declare function findUnknownStudyKey(raw: unknown): string | undefined;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Every mapping key
|
|
1
|
+
// Every mapping key parseStudy reads, by path. A key that is not listed fails the study as
|
|
2
2
|
// unknown, so a typo stops the run instead of being dropped. `true` marks a leaf: its parser
|
|
3
3
|
// checks the value (scalars, lists, and mappings that check their own keys). Each level satisfies
|
|
4
4
|
// the parsed type's keys, so a field added to a Lab* interface must be added here too.
|
|
@@ -166,7 +166,7 @@ const EMAIL = {
|
|
|
166
166
|
allowedOrigins: true,
|
|
167
167
|
recipients: { lane: true, address: true },
|
|
168
168
|
};
|
|
169
|
-
const
|
|
169
|
+
const V2_KEYS = {
|
|
170
170
|
schema: true,
|
|
171
171
|
id: true,
|
|
172
172
|
title: true,
|
|
@@ -225,14 +225,14 @@ const STUDY_KEYS = {
|
|
|
225
225
|
caps: CAPS,
|
|
226
226
|
execution: without(EXECUTION, "caps"),
|
|
227
227
|
scenario: true,
|
|
228
|
-
policies:
|
|
229
|
-
review:
|
|
230
|
-
defaults:
|
|
231
|
-
comms:
|
|
228
|
+
policies: V2_KEYS.policies,
|
|
229
|
+
review: V2_KEYS.review,
|
|
230
|
+
defaults: V2_KEYS.defaults,
|
|
231
|
+
comms: V2_KEYS.comms,
|
|
232
232
|
};
|
|
233
|
-
/** The first key in `raw` that
|
|
234
|
-
export function
|
|
235
|
-
return walk(raw,
|
|
233
|
+
/** The first key in `raw` that V2_KEYS does not list, as an error message; undefined if none. */
|
|
234
|
+
export function findUnknownV2Key(raw) {
|
|
235
|
+
return walk(raw, V2_KEYS, "", "study");
|
|
236
236
|
}
|
|
237
237
|
/** The first key in a humanish.study.v3 document that the format does not have; undefined if none. */
|
|
238
238
|
export function findUnknownStudyKey(raw) {
|
|
@@ -270,7 +270,7 @@ function unknownKeysMessage(path, unknown, known, noun) {
|
|
|
270
270
|
const suggestion = closest(key, known);
|
|
271
271
|
return suggestion ? `${key} (did you mean \`${suggestion}\`?)` : key;
|
|
272
272
|
});
|
|
273
|
-
return `Unknown ${noun} field
|
|
273
|
+
return `Unknown ${noun} ${unknown.length === 1 ? "field" : "fields"}${path ? ` in \`${path}\`` : ""}: ${named.join(", ")}. Known fields: ${known.join(", ")}.`;
|
|
274
274
|
}
|
|
275
275
|
// The known key within edit distance 2, or one that differs only in case.
|
|
276
276
|
function closest(key, known) {
|
package/dist/study/migrate.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { StudyRoute } from "
|
|
1
|
+
import type { StudyRoute } from "./routing.js";
|
|
2
2
|
import { type DroppedKey, type MovedKey } from "./convert.js";
|
|
3
3
|
/** The schema of `humanish migrate --json`. */
|
|
4
4
|
declare const MIGRATE_SCHEMA = "humanish.migrate-result.v1";
|
|
@@ -21,6 +21,8 @@ export interface MigrateResult {
|
|
|
21
21
|
readonly files: readonly MigrateFile[];
|
|
22
22
|
/** Files left behind after a clean-up step found them changed: sources, backups or temp files. */
|
|
23
23
|
readonly unresolved?: readonly string[];
|
|
24
|
+
/** The labs/ directories the moves emptied and migrate removed, or with `--dry-run` would remove. */
|
|
25
|
+
readonly removedDirectories?: readonly string[];
|
|
24
26
|
readonly error?: {
|
|
25
27
|
readonly code: "HUMANISH_MIGRATE_REFUSED" | "HUMANISH_MIGRATE_FAILED";
|
|
26
28
|
readonly phase: "plan" | "stage" | "commit" | "clean-up";
|
|
@@ -34,8 +36,11 @@ export interface MigrateOptions {
|
|
|
34
36
|
/** Files to convert. Without any, the six study directories are scanned. */
|
|
35
37
|
readonly paths?: readonly string[];
|
|
36
38
|
readonly dryRun?: boolean;
|
|
37
|
-
/**
|
|
38
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Called with the plan before anything is written, so a caller can print every destination and
|
|
41
|
+
* each labs/ directory the moves empty, which migrate then removes.
|
|
42
|
+
*/
|
|
43
|
+
readonly onPlan?: (files: readonly MigrateFile[], emptied: readonly string[]) => void;
|
|
39
44
|
/** Replaces `fs.link`. Tests use it to stand in for a filesystem without hard links. */
|
|
40
45
|
readonly link?: (from: string, to: string) => Promise<void>;
|
|
41
46
|
/** Called between stage and commit, and between commit and clean-up. Tests change files there. */
|
package/dist/study/migrate.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
// name, so no file this run did not write is ever overwritten. A failure undoes the commits.
|
|
9
9
|
// 4. Clean up: delete each moved source and each rewrite's original, once checked (owned-files.ts).
|
|
10
10
|
// A file that changed since the plan is kept and listed; a rewrite's original as <name>.v2.bak.
|
|
11
|
+
// Then a labs/ directory whose every entry moved is removed with a plain rmdir, which fails, and
|
|
12
|
+
// keeps the directory, when anything else is in it by then.
|
|
11
13
|
import { randomUUID } from "node:crypto";
|
|
12
14
|
import { link, lstat, readdir, readFile, realpath, rename, rmdir } from "node:fs/promises";
|
|
13
15
|
import path from "node:path";
|
|
@@ -317,6 +319,46 @@ async function undoCommits(root, writes, linkFile) {
|
|
|
317
319
|
}
|
|
318
320
|
return unrestored;
|
|
319
321
|
}
|
|
322
|
+
// Each labs/ directory whose every entry, a dotfile or a subdirectory included, is a file this run
|
|
323
|
+
// moves out. Only these are removed after the move.
|
|
324
|
+
async function emptiedRetiredDirectories(root, writes) {
|
|
325
|
+
const moving = new Map();
|
|
326
|
+
for (const write of writes) {
|
|
327
|
+
if (write.file.action !== "move")
|
|
328
|
+
continue;
|
|
329
|
+
const directory = path.dirname(write.sourcePath);
|
|
330
|
+
const relative = path.relative(root, directory);
|
|
331
|
+
const retired = STUDY_DIRECTORIES.some((entry) => entry.family === "labs" && entry.relativeDir === relative);
|
|
332
|
+
if (!retired)
|
|
333
|
+
continue;
|
|
334
|
+
const entry = moving.get(directory) ?? { write, names: new Set() };
|
|
335
|
+
entry.names.add(path.basename(write.sourcePath));
|
|
336
|
+
moving.set(directory, entry);
|
|
337
|
+
}
|
|
338
|
+
const emptied = [];
|
|
339
|
+
for (const [directory, { write, names }] of moving) {
|
|
340
|
+
const entries = await readdir(directory).catch(() => undefined);
|
|
341
|
+
if (entries !== undefined && entries.every((name) => names.has(name)))
|
|
342
|
+
emptied.push(write);
|
|
343
|
+
}
|
|
344
|
+
return emptied;
|
|
345
|
+
}
|
|
346
|
+
// Remove each emptied labs/ directory, if it is still the one the plan read. rmdir is not
|
|
347
|
+
// recursive, so a file that appeared in it since the plan keeps it. Returns the removed paths.
|
|
348
|
+
async function removeEmptiedDirectories(root, emptied) {
|
|
349
|
+
const removed = [];
|
|
350
|
+
for (const write of emptied) {
|
|
351
|
+
try {
|
|
352
|
+
await assertDirectory(write.sourceDirectory, root);
|
|
353
|
+
await rmdir(path.dirname(write.sourcePath));
|
|
354
|
+
removed.push(path.relative(root, path.dirname(write.sourcePath)));
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
// Not empty, or not the directory the plan read: it stays.
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
return removed;
|
|
361
|
+
}
|
|
320
362
|
// Delete each moved source and each rewrite's original, but only once the v3 file is in place as
|
|
321
363
|
// written, and only if the old file is still the one the plan read (removeChecked). Anything kept
|
|
322
364
|
// is listed; a rewrite's original is kept as <name>.v2.bak.
|
|
@@ -356,9 +398,17 @@ export async function migrateStudies(options) {
|
|
|
356
398
|
const linkFile = options.link ?? link;
|
|
357
399
|
try {
|
|
358
400
|
({ files, writes } = await planWrites(root, options));
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
401
|
+
const emptied = await emptiedRetiredDirectories(root, writes);
|
|
402
|
+
const emptiedPaths = emptied.map((write) => path.relative(root, path.dirname(write.sourcePath)));
|
|
403
|
+
options.onPlan?.(files, emptiedPaths);
|
|
404
|
+
if (options.dryRun === true || writes.length === 0) {
|
|
405
|
+
return {
|
|
406
|
+
...base,
|
|
407
|
+
ok: true,
|
|
408
|
+
files,
|
|
409
|
+
...(emptiedPaths.length === 0 ? {} : { removedDirectories: emptiedPaths }),
|
|
410
|
+
};
|
|
411
|
+
}
|
|
362
412
|
try {
|
|
363
413
|
await stage(root, writes, created);
|
|
364
414
|
options.onPhase?.("stage");
|
|
@@ -386,7 +436,13 @@ export async function migrateStudies(options) {
|
|
|
386
436
|
},
|
|
387
437
|
};
|
|
388
438
|
}
|
|
389
|
-
|
|
439
|
+
const removed = await removeEmptiedDirectories(root, emptied);
|
|
440
|
+
return {
|
|
441
|
+
...base,
|
|
442
|
+
ok: true,
|
|
443
|
+
files,
|
|
444
|
+
...(removed.length === 0 ? {} : { removedDirectories: removed }),
|
|
445
|
+
};
|
|
390
446
|
}
|
|
391
447
|
catch (error) {
|
|
392
448
|
const failure = error instanceof MigrateError
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StudyActor, StudyParticipantEntry, StudyParticipantFocus, StudyParseFailure } from "../types.js";
|
|
2
2
|
export declare const PARTICIPANT_ID_PATTERN: RegExp;
|
|
3
3
|
export declare const PARTICIPANT_ID_MAX_CHARS = 40;
|
|
4
4
|
/** The participant entries an actor declares, after roster groups expand into them. The manifest
|
|
5
5
|
* spells them `actors[].lanes`. Undefined when the actor declares none. */
|
|
6
|
-
export declare function rosterOf<Entry =
|
|
6
|
+
export declare function rosterOf<Entry = StudyParticipantEntry>(actor: {
|
|
7
7
|
readonly lanes?: readonly Entry[];
|
|
8
8
|
} | undefined): readonly Entry[] | undefined;
|
|
9
9
|
/** An actor's per-participant focus on the app-url route. The manifest spells it `laneFocus`. */
|
|
10
|
-
export declare function focusOf(actor: Pick<
|
|
10
|
+
export declare function focusOf(actor: Pick<StudyActor, "laneFocus"> | undefined): StudyParticipantFocus | undefined;
|
|
11
11
|
export declare function parseActors(raw: unknown): {
|
|
12
12
|
ok: true;
|
|
13
|
-
value:
|
|
14
|
-
} |
|
|
13
|
+
value: StudyActor[];
|
|
14
|
+
} | StudyParseFailure;
|
|
@@ -6,7 +6,7 @@ import { registeredComputerUseActors, registeredScriptedBrowserActors, registere
|
|
|
6
6
|
import { invalid, posInt, str } from "./values.js";
|
|
7
7
|
import { isRecord } from "../../run/type-guards.js";
|
|
8
8
|
// A participant id interpolates into its evidence paths (screenshots/<id>/, actors/<id>.json), so
|
|
9
|
-
// it must be a public-safe path token, same shape as a
|
|
9
|
+
// it must be a public-safe path token, same shape as a study id.
|
|
10
10
|
export const PARTICIPANT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
|
|
11
11
|
export const PARTICIPANT_ID_MAX_CHARS = 40;
|
|
12
12
|
const METADATA_MAX_CHARS = 80;
|
|
@@ -19,7 +19,7 @@ export function rosterOf(actor) {
|
|
|
19
19
|
export function focusOf(actor) {
|
|
20
20
|
return actor?.laneFocus;
|
|
21
21
|
}
|
|
22
|
-
// Actor ids humanish no longer registers. Rejecting them at parse keeps a
|
|
22
|
+
// Actor ids humanish no longer registers. Rejecting them at parse keeps a study that names one
|
|
23
23
|
// from running on a route that ignores actors[0].type, such as a this-repo dry run.
|
|
24
24
|
const REMOVED_ACTOR_TYPES = new Set(["pi-agent-core", "claude-agent-sdk"]);
|
|
25
25
|
// Only actors of a run kind a route dispatches. codex-app-server is registered but declares only
|
|
@@ -33,7 +33,7 @@ function routableActorTypes() {
|
|
|
33
33
|
}
|
|
34
34
|
export function parseActors(raw) {
|
|
35
35
|
if (!Array.isArray(raw) || raw.length === 0) {
|
|
36
|
-
return invalid("
|
|
36
|
+
return invalid("`actors` must be a non-empty array.");
|
|
37
37
|
}
|
|
38
38
|
// Multi-actor fan-out is not wired yet (only actors[0] is consumed). Fail closed rather than
|
|
39
39
|
// silently ignore actors[1..]; multi-actor support lands in a later slice.
|
|
@@ -50,7 +50,7 @@ export function parseActors(raw) {
|
|
|
50
50
|
return invalid(`actors[${index}].type is required.`);
|
|
51
51
|
}
|
|
52
52
|
if (REMOVED_ACTOR_TYPES.has(type)) {
|
|
53
|
-
return invalid(`actors[${index}].type "${type}" is no longer a humanish actor. Use an actor a
|
|
53
|
+
return invalid(`actors[${index}].type "${type}" is no longer a humanish actor. Use an actor a study route runs (one of: ${routableActorTypes().join(", ")}). To drive a study with a signed-in Claude Code, use type: local-agent with localAgent: claude.`);
|
|
54
54
|
}
|
|
55
55
|
const actor = { type };
|
|
56
56
|
const count = posInt(entry.count);
|
|
@@ -189,7 +189,7 @@ function parseRosterGroups(raw, actorIndex) {
|
|
|
189
189
|
* Participant ids (when declared) must be public-safe path tokens and unique; grouping metadata
|
|
190
190
|
* must be public-safe tokens; a device must be a known preset name. The
|
|
191
191
|
* route-scoped cross-validation (`lanes` XOR `count`/`laneFocus`, device XOR raw resolution, cap 16)
|
|
192
|
-
* runs in
|
|
192
|
+
* runs in parseStudy where the route is known.
|
|
193
193
|
*/
|
|
194
194
|
function parseParticipantEntries(raw, actorIndex) {
|
|
195
195
|
if (raw === undefined) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StudyComms, StudyCommsEmail, StudyCommsRecipient, StudyParseFailure } from "../types.js";
|
|
2
|
+
export declare function parseComms(raw: unknown): {
|
|
3
|
+
ok: true;
|
|
4
|
+
value: StudyComms | undefined;
|
|
5
|
+
} | StudyParseFailure;
|
|
6
|
+
/** The participant a declared inbox recipient belongs to. The manifest spells it `lane`. */
|
|
7
|
+
export declare function recipientParticipantId(recipient: StudyCommsRecipient): string;
|
|
8
|
+
/** The declared recipients that name an address, in declaration order, by participant id. */
|
|
9
|
+
export declare function addressedRecipients(email: Pick<StudyCommsEmail, "recipients">): {
|
|
10
|
+
participantId: string;
|
|
11
|
+
address: string;
|
|
12
|
+
}[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { StudyParseFailure, StudyDefaults, StudyExecution, StudyPolicies, StudyReview, StudyScenario } from "../types.js";
|
|
2
|
+
export declare function parseExecution(raw: unknown): {
|
|
3
|
+
ok: true;
|
|
4
|
+
value: StudyExecution | undefined;
|
|
5
|
+
} | StudyParseFailure;
|
|
6
|
+
export declare function parsePersonas(raw: unknown): Record<string, unknown>[] | undefined;
|
|
7
|
+
export declare function parseScenario(raw: unknown): {
|
|
8
|
+
ok: true;
|
|
9
|
+
value: StudyScenario | undefined;
|
|
10
|
+
} | StudyParseFailure;
|
|
11
|
+
export declare function parsePolicies(raw: unknown): {
|
|
12
|
+
ok: true;
|
|
13
|
+
value: StudyPolicies | undefined;
|
|
14
|
+
} | StudyParseFailure;
|
|
15
|
+
export declare function parseReview(raw: unknown): {
|
|
16
|
+
ok: true;
|
|
17
|
+
value: StudyReview | undefined;
|
|
18
|
+
} | StudyParseFailure;
|
|
19
|
+
export declare function parseDefaults(raw: unknown): StudyDefaults | undefined;
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
/** A route a study declares. */
|
|
4
|
-
export type StudyRoute = (typeof ROUTES)[number];
|
|
1
|
+
import type { StudyRoute } from "../routing.js";
|
|
2
|
+
import { type StudyParseFailure } from "../types.js";
|
|
5
3
|
export interface StudyDocument {
|
|
6
4
|
readonly route: StudyRoute;
|
|
7
5
|
/** The same document in the humanish.lab.v2 spelling. */
|
|
@@ -12,7 +10,7 @@ export interface StudyDocument {
|
|
|
12
10
|
type Parsed<T> = {
|
|
13
11
|
ok: true;
|
|
14
12
|
value: T;
|
|
15
|
-
} |
|
|
13
|
+
} | StudyParseFailure;
|
|
16
14
|
/** Rewrite a humanish.study.v3 document into humanish.lab.v2, or refuse it. */
|
|
17
15
|
export declare function studyToV2(raw: Record<string, unknown>): Parsed<StudyDocument>;
|
|
18
16
|
/**
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// humanish.study.v3, the study format. A study declares its route, one `actor`, its `participants`
|
|
2
2
|
// and one `caps` block. studyToV2 rewrites a v3 document into the v2 spelling, so both formats run
|
|
3
|
-
// through one parser and parse into the same
|
|
3
|
+
// through one parser and parse into the same StudyConfig. parseStudy then checks the declared
|
|
4
4
|
// route against the one the config takes, and refuses any field that route does not read.
|
|
5
5
|
import { isRecord } from "../../run/type-guards.js";
|
|
6
6
|
import { findUnknownStudyKey } from "../keys.js";
|
|
7
|
-
import {
|
|
7
|
+
import { V2_SCHEMA } from "../types.js";
|
|
8
8
|
import { PARTICIPANT_ID_MAX_CHARS, PARTICIPANT_ID_PATTERN } from "./actors.js";
|
|
9
9
|
import { invalid, posInt } from "./values.js";
|
|
10
10
|
// The values `route:` takes: every route routeOf can return.
|
|
@@ -81,7 +81,7 @@ export function studyToV2(raw) {
|
|
|
81
81
|
? withKey(raw.execution, "caps", caps)
|
|
82
82
|
: raw.execution;
|
|
83
83
|
const subject = route === "shared-world" ? withKey(raw.subject, "topology", "shared-world") : raw.subject;
|
|
84
|
-
const v2 = { schema:
|
|
84
|
+
const v2 = { schema: V2_SCHEMA };
|
|
85
85
|
const fields = [
|
|
86
86
|
["id", raw.id],
|
|
87
87
|
["title", raw.title],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StudyParseFailure, StudySubjectState } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Literal non-secret subject env. Real apps need configuration before they will boot: a public base
|
|
4
4
|
* URL, a transport selector, a feature flag, and none of that is secret. Routing it through
|
|
@@ -10,21 +10,21 @@ import type { LabConfigParseFailure, LabSubjectState } from "../types.js";
|
|
|
10
10
|
export declare function parseEnvValues(raw: unknown): {
|
|
11
11
|
ok: true;
|
|
12
12
|
value?: Record<string, string>;
|
|
13
|
-
} |
|
|
13
|
+
} | StudyParseFailure;
|
|
14
14
|
/**
|
|
15
|
-
* Structural parse of `subject.state` into a candidate
|
|
15
|
+
* Structural parse of `subject.state` into a candidate StudySubjectState. Deliberately keeps
|
|
16
16
|
* unrecognized `when`/`timeoutMs` values in the candidate (instead of silently dropping
|
|
17
17
|
* them) so subjectStateInvalidReason rejects them: a state declaration that silently does
|
|
18
18
|
* less than it says would claim more than its mechanism does.
|
|
19
19
|
*/
|
|
20
20
|
export declare function parseState(raw: unknown): {
|
|
21
21
|
ok: true;
|
|
22
|
-
value:
|
|
23
|
-
} |
|
|
22
|
+
value: StudySubjectState | undefined;
|
|
23
|
+
} | StudyParseFailure;
|
|
24
24
|
/**
|
|
25
|
-
* Semantic validation for `subject.state`, shared by
|
|
26
|
-
* (the route re-enforces it on configs that arrive through
|
|
25
|
+
* Semantic validation for `subject.state`, shared by parseStudy and the engine
|
|
26
|
+
* (the route re-enforces it on configs that arrive through runStudyWith). Returns
|
|
27
27
|
* the failure message, or null when the declaration is valid. Reads the candidate
|
|
28
28
|
* defensively: library callers can hand the engine arbitrarily-shaped objects.
|
|
29
29
|
*/
|
|
30
|
-
export declare function subjectStateInvalidReason(state:
|
|
30
|
+
export declare function subjectStateInvalidReason(state: StudySubjectState, env: readonly string[] | undefined): string | null;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The state and env channels of a served subject (clone or local-tree): `subject.envValues`,
|
|
2
2
|
// the structural parse of `subject.state`, and subjectStateInvalidReason, the semantic check
|
|
3
|
-
//
|
|
3
|
+
// parseStudy and the computer-use route share.
|
|
4
4
|
import { containsSensitive } from "../../evidence/redaction.js";
|
|
5
5
|
import { ENV_NAME_PATTERN, invalid, posInt, str, strList } from "./values.js";
|
|
6
6
|
import { isRecord } from "../../run/type-guards.js";
|
|
@@ -39,7 +39,7 @@ export function parseEnvValues(raw) {
|
|
|
39
39
|
return { ok: true, value: envValues };
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
* Structural parse of `subject.state` into a candidate
|
|
42
|
+
* Structural parse of `subject.state` into a candidate StudySubjectState. Deliberately keeps
|
|
43
43
|
* unrecognized `when`/`timeoutMs` values in the candidate (instead of silently dropping
|
|
44
44
|
* them) so subjectStateInvalidReason rejects them: a state declaration that silently does
|
|
45
45
|
* less than it says would claim more than its mechanism does.
|
|
@@ -96,8 +96,8 @@ const STATE_STEP_WHENS = [
|
|
|
96
96
|
"after-ready",
|
|
97
97
|
];
|
|
98
98
|
/**
|
|
99
|
-
* Semantic validation for `subject.state`, shared by
|
|
100
|
-
* (the route re-enforces it on configs that arrive through
|
|
99
|
+
* Semantic validation for `subject.state`, shared by parseStudy and the engine
|
|
100
|
+
* (the route re-enforces it on configs that arrive through runStudyWith). Returns
|
|
101
101
|
* the failure message, or null when the declaration is valid. Reads the candidate
|
|
102
102
|
* defensively: library callers can hand the engine arbitrarily-shaped objects.
|
|
103
103
|
*/
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StudyParseFailure, StudySubject } from "../types.js";
|
|
2
2
|
export declare function parseSubject(raw: unknown): {
|
|
3
3
|
ok: true;
|
|
4
|
-
value:
|
|
5
|
-
} |
|
|
4
|
+
value: StudySubject;
|
|
5
|
+
} | StudyParseFailure;
|
|
6
6
|
export declare const PUBLIC_TARGET_OWNER_PATTERN: RegExp;
|
|
7
7
|
export declare function isLoopbackUrl(value: string): boolean;
|
|
8
8
|
/** A well-formed http(s) URL (any host). Shape gate before the loopback/public-target policy. */
|
|
@@ -4,7 +4,7 @@ import { parseEnvValues, parseState, subjectStateInvalidReason } from "./subject
|
|
|
4
4
|
import { isRecord } from "../../run/type-guards.js";
|
|
5
5
|
export function parseSubject(raw) {
|
|
6
6
|
if (!isRecord(raw)) {
|
|
7
|
-
return invalid("
|
|
7
|
+
return invalid("`subject` is required and must be an object.");
|
|
8
8
|
}
|
|
9
9
|
const source = str(raw.source);
|
|
10
10
|
if (source !== "this-repo" &&
|
|
@@ -71,19 +71,19 @@ function misplacedFieldFailure(source, raw) {
|
|
|
71
71
|
// tree): both routes serve a subject in-sandbox with the same install/build/start/url +
|
|
72
72
|
// env-name + seed/external/checkpoint shapes.
|
|
73
73
|
if (source !== "clone" && source !== "local-tree" && raw.serve !== undefined) {
|
|
74
|
-
return invalid("`subject.serve` applies only to clone subjects or local-tree subjects (
|
|
74
|
+
return invalid("`subject.serve` applies only to clone subjects or local-tree subjects (humanish serves the cloned or packed app in the sandbox).");
|
|
75
75
|
}
|
|
76
76
|
if (source !== "clone" && source !== "local-tree" && raw.env !== undefined) {
|
|
77
77
|
return invalid("`subject.env` applies only to clone subjects or local-tree subjects (the served app's environment channel).");
|
|
78
78
|
}
|
|
79
79
|
if (source !== "clone" && source !== "local-tree" && raw.state !== undefined) {
|
|
80
|
-
return invalid("`subject.state` applies only to clone subjects or local-tree subjects (
|
|
80
|
+
return invalid("`subject.state` applies only to clone subjects or local-tree subjects (humanish seeds the state it serves).");
|
|
81
81
|
}
|
|
82
82
|
// repos/clone are clone-only (a fresh-clone subject's git inputs). local-tree packs the
|
|
83
83
|
// resolution cwd itself, so it has no repo slug to clone and gets its own precise reasons
|
|
84
84
|
// rather than falling through to the generic clone-only message below.
|
|
85
85
|
if (source === "local-tree" && raw.repos !== undefined) {
|
|
86
|
-
return invalid("`subject.repos` does not apply to local-tree subjects. The local-tree route packs the
|
|
86
|
+
return invalid("`subject.repos` does not apply to local-tree subjects. The local-tree route packs the study's working directory itself; there is no owner/repo slug to clone.");
|
|
87
87
|
}
|
|
88
88
|
if (source === "local-tree" && raw.clone !== undefined) {
|
|
89
89
|
return invalid("`subject.clone` does not apply to local-tree subjects. Declare `subject.localTree` instead (keep/exclude/maxArchiveBytes).");
|
|
@@ -126,7 +126,7 @@ function parseCloneSubject(raw, subject) {
|
|
|
126
126
|
function parseLocalTreeSubject(raw, subject) {
|
|
127
127
|
// A local-tree subject exists to be packed and served; there is no other way to boot it, so
|
|
128
128
|
// serve is required here. Clone subjects get the same requirement from each route's checks in
|
|
129
|
-
//
|
|
129
|
+
// parseStudy.
|
|
130
130
|
if (raw.serve === undefined) {
|
|
131
131
|
return invalid("`subject.serve` is required when source is local-tree: a local-tree subject exists to be packed and served, so declare install/build/start/url exactly like the clone route.");
|
|
132
132
|
}
|
|
@@ -175,7 +175,7 @@ function parseServedApp(raw, subject) {
|
|
|
175
175
|
return stateResult;
|
|
176
176
|
}
|
|
177
177
|
if (stateResult.value) {
|
|
178
|
-
// Semantic validation is shared with the engine (
|
|
178
|
+
// Semantic validation is shared with the engine (runCuaActorStudy re-enforces it for
|
|
179
179
|
// configs that arrive through the library API without the parser).
|
|
180
180
|
const reason = subjectStateInvalidReason(stateResult.value, subject.env);
|
|
181
181
|
if (reason) {
|
|
@@ -241,7 +241,7 @@ function parsePublicTarget(raw) {
|
|
|
241
241
|
return { ok: true, value: { owner, authorized: true } };
|
|
242
242
|
}
|
|
243
243
|
// The product name interpolates into evidence labels and the composed prompt; the public-safe
|
|
244
|
-
// token shape is the same strict constraint as a
|
|
244
|
+
// token shape is the same strict constraint as a study id.
|
|
245
245
|
const PRODUCT_NAME_PATTERN = /^[A-Za-z0-9][A-Za-z0-9_.-]*$/;
|
|
246
246
|
function parseProduct(raw) {
|
|
247
247
|
if (!isRecord(raw)) {
|
|
@@ -289,7 +289,7 @@ function parseProduct(raw) {
|
|
|
289
289
|
},
|
|
290
290
|
};
|
|
291
291
|
}
|
|
292
|
-
// Public-safe stance: a computer-use actor's entry URL is always an app the
|
|
292
|
+
// Public-safe stance: a computer-use actor's entry URL is always an app the study owner runs on
|
|
293
293
|
// loopback (inside the sandbox), never an arbitrary public site. (The constraint binds the
|
|
294
294
|
// entry point; a navigation watchdog for mid-session escapes is a later slice.) Exported so
|
|
295
295
|
// the engine re-enforces the same boundary on configs that arrive through the library API.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StudyParseFailure } from "../types.js";
|
|
2
2
|
export declare const REPO_SLUG_PATTERN: RegExp;
|
|
3
3
|
export declare const ENV_NAME_PATTERN: RegExp;
|
|
4
|
-
export declare function invalid(message: string):
|
|
4
|
+
export declare function invalid(message: string): StudyParseFailure;
|
|
5
5
|
export declare function str(value: unknown): string | undefined;
|
|
6
6
|
export declare function optionalStr(key: string, value: unknown): Record<string, string>;
|
|
7
7
|
export declare function strList(value: unknown): string[] | undefined;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ResolvedPersona } from "./persona.js";
|
|
2
2
|
import { type PreparedSelectedOutputDirectory } from "../run/contained-output.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { StudyActor } from "./types.js";
|
|
4
4
|
/** Title-case an id for the fallback display name (`skeptical-power-user` -> `Skeptical Power User`). */
|
|
5
5
|
export declare function personaTitleFromId(personaId: string): string;
|
|
6
6
|
/**
|
|
@@ -22,11 +22,11 @@ export declare function resolveCommittedPersonas(projectRoot: PreparedSelectedOu
|
|
|
22
22
|
warnings: string[];
|
|
23
23
|
}>;
|
|
24
24
|
/**
|
|
25
|
-
* Every persona id a
|
|
25
|
+
* Every persona id a study config could put on a browser participant: the roster when one is
|
|
26
26
|
* declared, otherwise the actor-level persona that every fan-out participant inherits.
|
|
27
27
|
*/
|
|
28
|
-
export declare function
|
|
29
|
-
actors?: readonly Pick<
|
|
28
|
+
export declare function studyPersonaIds(config: {
|
|
29
|
+
actors?: readonly Pick<StudyActor, "persona" | "lanes">[];
|
|
30
30
|
}): string[];
|
|
31
31
|
/**
|
|
32
32
|
* Same resolution from a plain cwd, for the labs that carry a directory string rather than an
|
|
@@ -81,10 +81,10 @@ export async function resolveCommittedPersonas(projectRoot, personaIds) {
|
|
|
81
81
|
return { personas, warnings };
|
|
82
82
|
}
|
|
83
83
|
/**
|
|
84
|
-
* Every persona id a
|
|
84
|
+
* Every persona id a study config could put on a browser participant: the roster when one is
|
|
85
85
|
* declared, otherwise the actor-level persona that every fan-out participant inherits.
|
|
86
86
|
*/
|
|
87
|
-
export function
|
|
87
|
+
export function studyPersonaIds(config) {
|
|
88
88
|
const ids = [];
|
|
89
89
|
for (const actor of config.actors ?? []) {
|
|
90
90
|
if (actor.persona)
|