humanish 0.106.1 → 0.107.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -4
- package/ARCHITECTURE.md +17 -16
- package/CHANGELOG.md +14 -0
- package/CONTEXT.md +42 -39
- package/CONTRIBUTING.md +8 -8
- package/README.md +8 -3
- package/dist/actors/codex/app-server-client.js +2 -1
- package/dist/actors/codex/app-server-trace.d.ts +0 -1
- package/dist/actors/codex/app-server-trace.js +1 -3
- package/dist/actors/codex/app-server.js +2 -1
- package/dist/actors/codex/protocol-compat.d.ts +27 -0
- package/dist/actors/codex/protocol-compat.js +357 -0
- package/dist/actors/codex/protocol-contract.d.ts +61 -0
- package/dist/actors/codex/protocol-contract.js +471 -0
- package/dist/actors/codex/qualified-versions.d.ts +30 -3
- package/dist/actors/codex/qualified-versions.js +50 -5
- package/dist/actors/codex/restricted-executable.d.ts +24 -0
- package/dist/actors/codex/restricted-executable.js +97 -22
- package/dist/actors/codex/restricted-launch.d.ts +7 -1
- package/dist/actors/codex/restricted-launch.js +42 -3
- package/dist/actors/codex/restricted-notifications.d.ts +101 -0
- package/dist/actors/codex/restricted-notifications.js +277 -0
- package/dist/actors/codex/restricted-participant.d.ts +30 -0
- package/dist/actors/codex/restricted-participant.js +60 -2
- package/dist/actors/codex/restricted-policy.d.ts +9 -1
- package/dist/actors/codex/restricted-session.d.ts +14 -1
- package/dist/actors/codex/restricted-session.js +50 -17
- package/dist/actors/codex/restricted-transport.d.ts +29 -0
- package/dist/actors/codex/restricted-transport.js +139 -27
- package/dist/actors/codex/restricted-turn.d.ts +19 -4
- package/dist/actors/codex/restricted-turn.js +43 -30
- package/dist/actors/computer-use/actor.d.ts +1 -1
- package/dist/actors/computer-use/actor.js +4 -4
- package/dist/actors/computer-use/loop/backstop.js +1 -1
- package/dist/actors/computer-use/loop/ending.d.ts +2 -2
- package/dist/actors/computer-use/loop/ending.js +2 -2
- package/dist/actors/computer-use/loop/spend.d.ts +1 -1
- package/dist/actors/computer-use/loop/spend.js +3 -3
- package/dist/actors/computer-use/loop/trace.js +2 -2
- package/dist/actors/computer-use/loop/types.d.ts +14 -5
- package/dist/actors/computer-use/loop.js +4 -4
- package/dist/actors/computer-use/openai-provider.d.ts +1 -1
- package/dist/actors/computer-use/openai-provider.js +2 -2
- package/dist/actors/contract.d.ts +9 -7
- package/dist/actors/local-agent/cli.js +1 -1
- package/dist/actors/scripted-browser/actor.d.ts +2 -2
- package/dist/actors/scripted-browser/journey.js +15 -4
- package/dist/actors/scripted-browser/steps.js +18 -0
- package/dist/actors/scripted-browser/types.d.ts +11 -1
- package/dist/actors/stop-conditions.js +1 -3
- package/dist/analysis/automatic-completion.d.ts +13 -8
- package/dist/analysis/automatic-completion.js +14 -8
- package/dist/analysis/automatic-config.d.ts +1 -1
- package/dist/analysis/automatic-config.js +2 -2
- package/dist/analysis/automatic.d.ts +10 -4
- package/dist/analysis/automatic.js +17 -13
- package/dist/analysis/diagnostics.d.ts +23 -0
- package/dist/analysis/diagnostics.js +112 -0
- package/dist/analysis/evidence-sources.js +2 -2
- package/dist/analysis/evidence.js +6 -6
- package/dist/analysis/execute.d.ts +7 -1
- package/dist/analysis/execute.js +39 -12
- package/dist/analysis/job.d.ts +8 -5
- package/dist/analysis/job.js +15 -14
- package/dist/analysis/load.d.ts +1 -1
- package/dist/analysis/load.js +5 -5
- package/dist/analysis/provider.d.ts +9 -1
- package/dist/analysis/restricted-codex.d.ts +2 -0
- package/dist/analysis/restricted-codex.js +10 -1
- package/dist/analysis/service.d.ts +2 -0
- package/dist/analysis/service.js +31 -12
- package/dist/analysis/sharing.d.ts +2 -2
- package/dist/analysis/sharing.js +5 -5
- package/dist/analysis/store-executions.d.ts +5 -5
- package/dist/analysis/store-executions.js +12 -12
- package/dist/analysis/store.d.ts +4 -4
- package/dist/analysis/store.js +13 -13
- package/dist/cli/commands/analysis-signals.d.ts +2 -1
- package/dist/cli/commands/analysis-signals.js +4 -1
- package/dist/cli/commands/analyze.js +4 -2
- package/dist/cli/commands/comms.js +8 -1
- package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
- package/dist/cli/commands/lab-route-computer-use.js +26 -14
- package/dist/cli/commands/lab-route-preview.d.ts +1 -3
- package/dist/cli/commands/lab-route-preview.js +3 -4
- package/dist/cli/commands/lab-route-run.d.ts +6 -4
- package/dist/cli/commands/lab-route-run.js +6 -2
- package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
- package/dist/cli/commands/lab-route-scripted.js +0 -1
- package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
- package/dist/cli/commands/lab-route-shared-world.js +0 -1
- package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
- package/dist/cli/commands/lab-route-terminal.js +0 -1
- package/dist/cli/commands/lab-run.js +76 -45
- package/dist/cli/commands/lab-scorer.d.ts +0 -2
- package/dist/cli/commands/lab.js +12 -6
- package/dist/cli/commands/observe.js +22 -0
- package/dist/cli/commands/run-signals.d.ts +30 -0
- package/dist/cli/commands/run-signals.js +146 -0
- package/dist/cli/commands/runs.js +10 -8
- package/dist/cli/commands/watch.js +12 -10
- package/dist/cli/doctor.d.ts +3 -0
- package/dist/cli/doctor.js +10 -2
- package/dist/cli/io.d.ts +5 -4
- package/dist/cli/io.js +12 -8
- package/dist/cli/program.js +3 -3
- package/dist/cli/renamed-options.d.ts +11 -0
- package/dist/cli/renamed-options.js +18 -0
- package/dist/cli/telemetry.d.ts +2 -2
- package/dist/cli/telemetry.js +1 -1
- package/dist/comms/capture-surface.d.ts +1 -1
- package/dist/comms/catch-host.d.ts +1 -1
- package/dist/comms/connections.js +4 -4
- package/dist/comms/external-evidence.d.ts +27 -0
- package/dist/comms/external-evidence.js +93 -0
- package/dist/comms/lease-store.js +7 -7
- package/dist/comms/types.js +1 -1
- package/dist/evidence/browser-hygiene.d.ts +1 -1
- package/dist/evidence/browser-hygiene.js +1 -1
- package/dist/evidence/redaction.js +1 -1
- package/dist/evidence/secret-scrub.d.ts +9 -0
- package/dist/evidence/secret-scrub.js +96 -0
- package/dist/feedback/draft.js +7 -9
- package/dist/feedback/export-bundle.js +4 -4
- package/dist/feedback/export.js +9 -9
- package/dist/feedback/feedback.d.ts +1 -1
- package/dist/index.d.ts +3 -6
- package/dist/index.js +3 -6
- package/dist/keys/key-resolution.d.ts +3 -1
- package/dist/keys/key-resolution.js +18 -16
- package/dist/lab/adapter-extension.d.ts +28 -6
- package/dist/lab/adapter-extension.js +65 -126
- package/dist/lab/adapter-scorer-loader.d.ts +25 -5
- package/dist/lab/adapter-scorer-loader.js +24 -0
- package/dist/lab/composition-rules.js +20 -20
- package/dist/lab/config.js +28 -26
- package/dist/lab/device-presets.d.ts +2 -2
- package/dist/lab/discover.js +1 -3
- package/dist/lab/doctor.d.ts +44 -9
- package/dist/lab/doctor.js +149 -41
- package/dist/lab/init-plan.js +1 -3
- package/dist/lab/keys.js +1 -1
- package/dist/lab/lab-deps.d.ts +85 -0
- package/dist/lab/lab-deps.js +4 -0
- package/dist/lab/parse/actors.js +8 -7
- package/dist/lab/parse/comms.js +3 -2
- package/dist/lab/parse/execution.js +3 -2
- package/dist/lab/parse/subject-state.js +2 -1
- package/dist/lab/parse/subject.js +2 -1
- package/dist/lab/parse/values.d.ts +0 -1
- package/dist/lab/parse/values.js +0 -3
- package/dist/lab/persona-resolve.d.ts +3 -3
- package/dist/lab/persona-resolve.js +4 -4
- package/dist/lab/persona.js +1 -3
- package/dist/lab/plan-base.d.ts +0 -2
- package/dist/lab/plan-base.js +6 -4
- package/dist/lab/plan-participants.d.ts +5 -5
- package/dist/lab/plan-participants.js +2 -2
- package/dist/lab/plan-types.d.ts +22 -4
- package/dist/lab/plan.d.ts +3 -11
- package/dist/lab/plan.js +18 -42
- package/dist/lab/preflight-result.js +0 -2
- package/dist/lab/preflight.d.ts +0 -3
- package/dist/lab/preflight.js +1 -1
- package/dist/lab/requirements.d.ts +20 -0
- package/dist/lab/requirements.js +54 -0
- package/dist/lab/route-inputs.d.ts +23 -12
- package/dist/lab/route-inputs.js +48 -51
- package/dist/lab/routing.d.ts +19 -24
- package/dist/lab/routing.js +14 -47
- package/dist/lab/run-lab-events.d.ts +6 -11
- package/dist/lab/run-lab-events.js +3 -11
- package/dist/lab/run-lab-homes.d.ts +64 -0
- package/dist/lab/run-lab-homes.js +3 -0
- package/dist/lab/run-lab-options.d.ts +12 -66
- package/dist/lab/run-lab-options.js +45 -275
- package/dist/lab/summary.d.ts +9 -4
- package/dist/lab/summary.js +15 -8
- package/dist/lab/types.d.ts +132 -132
- package/dist/lab/validation.d.ts +15 -15
- package/dist/lab/validation.js +28 -28
- package/dist/lab/warnings.js +20 -19
- package/dist/observer/artifact.d.ts +1 -1
- package/dist/observer/artifact.js +3 -3
- package/dist/observer/data.js +2 -2
- package/dist/observer/render.js +2 -2
- package/dist/observer/run-routes.d.ts +1 -1
- package/dist/observer/run-routes.js +5 -5
- package/dist/observer/serve.d.ts +17 -0
- package/dist/observer/serve.js +34 -3
- package/dist/routes/computer-use/bundle-parts.d.ts +1 -1
- package/dist/routes/computer-use/bundle-parts.js +10 -3
- package/dist/routes/computer-use/bundle.d.ts +4 -11
- package/dist/routes/computer-use/bundle.js +9 -15
- package/dist/routes/computer-use/diagnostics.d.ts +1 -1
- package/dist/routes/computer-use/diagnostics.js +1 -1
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +10 -10
- package/dist/routes/computer-use/e2b-desktop/comms.js +11 -14
- package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
- package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -7
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +13 -13
- package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -11
- package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
- package/dist/routes/computer-use/e2b-desktop/prepare.js +33 -36
- package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/start.js +24 -23
- package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
- package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
- package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/teardown.js +29 -17
- package/dist/routes/computer-use/external-comms.d.ts +4 -4
- package/dist/routes/computer-use/external-comms.js +19 -43
- package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
- package/dist/routes/computer-use/fanout-bundle.js +25 -29
- package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +25 -19
- package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
- package/dist/routes/computer-use/in-process-desktop.js +3 -9
- package/dist/routes/computer-use/live-flush.d.ts +7 -5
- package/dist/routes/computer-use/live-flush.js +19 -27
- package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +12 -11
- package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
- package/dist/routes/computer-use/local-tree-pack.js +4 -5
- package/dist/routes/computer-use/local-vm.d.ts +11 -8
- package/dist/routes/computer-use/local-vm.js +39 -66
- package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
- package/dist/routes/computer-use/participant-desktop.js +5 -25
- package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +10 -10
- package/dist/routes/computer-use/{lanes.js → participant-execution.js} +35 -22
- package/dist/routes/computer-use/participant-facts.d.ts +7 -1
- package/dist/routes/computer-use/participant-facts.js +12 -1
- package/dist/routes/computer-use/participant-model.d.ts +19 -11
- package/dist/routes/computer-use/participant-model.js +49 -25
- package/dist/routes/computer-use/participant-prompt.d.ts +3 -3
- package/dist/routes/computer-use/participant-prompt.js +4 -4
- package/dist/routes/computer-use/participant-runs.d.ts +6 -6
- package/dist/routes/computer-use/participant-runs.js +8 -8
- package/dist/routes/computer-use/plan.d.ts +21 -29
- package/dist/routes/computer-use/plan.js +52 -60
- package/dist/routes/computer-use/preflight.d.ts +3 -5
- package/dist/routes/computer-use/preflight.js +20 -16
- package/dist/routes/computer-use/rerun-selection.js +10 -6
- package/dist/routes/computer-use/result.d.ts +1 -1
- package/dist/routes/computer-use/result.js +40 -30
- package/dist/routes/computer-use/route.d.ts +3 -4
- package/dist/routes/computer-use/route.js +21 -19
- package/dist/routes/computer-use/self-report.d.ts +2 -2
- package/dist/routes/computer-use/self-report.js +4 -4
- package/dist/routes/computer-use/setup.d.ts +8 -14
- package/dist/routes/computer-use/setup.js +96 -72
- package/dist/routes/computer-use/single-bundle.d.ts +8 -11
- package/dist/routes/computer-use/single-bundle.js +20 -25
- package/dist/routes/computer-use/subject-projection.d.ts +5 -7
- package/dist/routes/computer-use/subject-projection.js +20 -19
- package/dist/routes/computer-use/types.d.ts +169 -210
- package/dist/routes/computer-use/types.js +13 -5
- package/dist/routes/preview.js +0 -1
- package/dist/routes/scripted/bundle.d.ts +3 -6
- package/dist/routes/scripted/bundle.js +11 -16
- package/dist/routes/scripted/plan.d.ts +5 -7
- package/dist/routes/scripted/plan.js +6 -4
- package/dist/routes/scripted/result.d.ts +4 -1
- package/dist/routes/scripted/result.js +10 -6
- package/dist/routes/scripted/route.js +10 -11
- package/dist/routes/scripted/scenario.d.ts +1 -1
- package/dist/routes/scripted/scenario.js +1 -1
- package/dist/routes/scripted/setup.d.ts +3 -2
- package/dist/routes/scripted/setup.js +22 -21
- package/dist/routes/scripted/subject.d.ts +8 -3
- package/dist/routes/scripted/subject.js +9 -5
- package/dist/routes/scripted/surface-records.js +1 -1
- package/dist/routes/scripted/surface-sessions.d.ts +2 -2
- package/dist/routes/scripted/surface-sessions.js +4 -4
- package/dist/routes/scripted/types.d.ts +19 -36
- package/dist/routes/scripted/types.js +1 -2
- package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +8 -8
- package/dist/routes/shared-world/bundle.d.ts +2 -2
- package/dist/routes/shared-world/bundle.js +22 -26
- package/dist/routes/shared-world/checkpoints.d.ts +4 -4
- package/dist/routes/shared-world/checkpoints.js +4 -4
- package/dist/routes/shared-world/comms.d.ts +5 -4
- package/dist/routes/shared-world/comms.js +28 -41
- package/dist/routes/shared-world/external-public.d.ts +5 -5
- package/dist/routes/shared-world/external-public.js +19 -20
- package/dist/routes/shared-world/handoff.d.ts +4 -4
- package/dist/routes/shared-world/handoff.js +50 -50
- package/dist/routes/shared-world/lobby-code.d.ts +5 -5
- package/dist/routes/shared-world/lobby-code.js +13 -13
- package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +8 -6
- package/dist/routes/shared-world/{seats.js → participant-specs.js} +43 -48
- package/dist/routes/shared-world/plan.d.ts +2 -6
- package/dist/routes/shared-world/plan.js +1 -2
- package/dist/routes/shared-world/provenance.d.ts +4 -4
- package/dist/routes/shared-world/provenance.js +4 -4
- package/dist/routes/shared-world/provisioned.d.ts +3 -2
- package/dist/routes/shared-world/provisioned.js +46 -40
- package/dist/routes/shared-world/result.js +31 -19
- package/dist/routes/shared-world/route.js +37 -41
- package/dist/routes/shared-world/setup.d.ts +5 -4
- package/dist/routes/shared-world/setup.js +12 -14
- package/dist/routes/shared-world/types.d.ts +53 -126
- package/dist/routes/shared-world/types.js +2 -2
- package/dist/routes/terminal/adapter.d.ts +8 -8
- package/dist/routes/terminal/adapter.js +28 -125
- package/dist/routes/terminal/bundle.d.ts +7 -12
- package/dist/routes/terminal/bundle.js +24 -34
- package/dist/routes/terminal/credentials.d.ts +2 -2
- package/dist/routes/terminal/credentials.js +16 -16
- package/dist/routes/terminal/dry-run.d.ts +1 -1
- package/dist/routes/terminal/dry-run.js +9 -11
- package/dist/routes/terminal/encoding.d.ts +1 -1
- package/dist/routes/terminal/encoding.js +2 -2
- package/dist/routes/terminal/ledger.d.ts +6 -6
- package/dist/routes/terminal/ledger.js +9 -9
- package/dist/routes/terminal/live-finish.d.ts +1 -2
- package/dist/routes/terminal/live-finish.js +21 -20
- package/dist/routes/terminal/live-sandbox.d.ts +3 -2
- package/dist/routes/terminal/live-sandbox.js +20 -20
- package/dist/routes/terminal/participant-text.d.ts +23 -0
- package/dist/routes/terminal/participant-text.js +165 -0
- package/dist/routes/terminal/plan.d.ts +2 -6
- package/dist/routes/terminal/plan.js +13 -9
- package/dist/routes/terminal/recorder.d.ts +6 -1
- package/dist/routes/terminal/recorder.js +12 -4
- package/dist/routes/terminal/result.js +4 -4
- package/dist/routes/terminal/route.js +26 -26
- package/dist/routes/terminal/runtime.d.ts +3 -2
- package/dist/routes/terminal/runtime.js +3 -3
- package/dist/routes/terminal/sandbox.d.ts +3 -3
- package/dist/routes/terminal/sandbox.js +9 -9
- package/dist/routes/terminal/session.js +16 -14
- package/dist/routes/terminal/token-usage.js +5 -5
- package/dist/routes/terminal/trace.d.ts +5 -8
- package/dist/routes/terminal/trace.js +9 -64
- package/dist/routes/terminal/types.d.ts +85 -93
- package/dist/routes/terminal/types.js +9 -4
- package/dist/run/active-runs.d.ts +13 -0
- package/dist/run/active-runs.js +12 -0
- package/dist/run/bundle-shape.d.ts +2 -1
- package/dist/run/bundle-shape.js +4 -4
- package/dist/run/bundle.d.ts +63 -56
- package/dist/run/bundle.js +9 -8
- package/dist/run/cost-summary.js +3 -2
- package/dist/run/costs.d.ts +6 -6
- package/dist/run/costs.js +10 -10
- package/dist/run/detail.d.ts +5 -5
- package/dist/run/detail.js +6 -6
- package/dist/run/dry-run.js +5 -12
- package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
- package/dist/run/{study-files.js → evidence-files.js} +5 -5
- package/dist/run/feedback-shape.js +1 -1
- package/dist/run/judge.d.ts +16 -4
- package/dist/run/judge.js +24 -7
- package/dist/run/locate.d.ts +2 -0
- package/dist/run/locate.js +3 -1
- package/dist/run/outcomes.d.ts +3 -3
- package/dist/run/outcomes.js +3 -3
- package/dist/run/participant-records.d.ts +2 -2
- package/dist/run/participant-records.js +2 -2
- package/dist/run/paths.js +1 -1
- package/dist/run/pricing.d.ts +19 -9
- package/dist/run/pricing.js +30 -18
- package/dist/run/projection.d.ts +13 -13
- package/dist/run/projection.js +8 -8
- package/dist/run/reclaim.d.ts +6 -0
- package/dist/run/reclaim.js +13 -3
- package/dist/run/results.d.ts +1 -1
- package/dist/run/run-index.d.ts +1 -1
- package/dist/run/run-index.js +11 -11
- package/dist/run/run.d.ts +4 -2
- package/dist/run/run.js +9 -5
- package/dist/run/sandbox-receipts.d.ts +4 -4
- package/dist/run/sandbox-receipts.js +4 -4
- package/dist/run/shared-world-evidence.d.ts +47 -47
- package/dist/run/shared-world-shape.d.ts +3 -3
- package/dist/run/shared-world-shape.js +11 -11
- package/dist/run/stats.d.ts +5 -5
- package/dist/run/stats.js +8 -8
- package/dist/run/status.d.ts +16 -6
- package/dist/run/status.js +31 -8
- package/dist/run/streams.d.ts +26 -19
- package/dist/run/terminal-contract.d.ts +5 -5
- package/dist/run/terminal-contract.js +4 -4
- package/dist/run/transient-comms-secrets.d.ts +5 -0
- package/dist/run/transient-comms-secrets.js +12 -0
- package/dist/run-lab.d.ts +36 -34
- package/dist/run-lab.js +41 -37
- package/dist/subject/desktop-cli.d.ts +1 -1
- package/dist/subject/desktop-cli.js +1 -1
- package/dist/subject/local-tree-archive.d.ts +1 -1
- package/dist/subject/local-tree-archive.js +4 -4
- package/dist/subject/local-tree.d.ts +2 -2
- package/dist/subject/local-tree.js +1 -1
- package/dist/subject/node-bootstrap.d.ts +1 -1
- package/dist/subject/node-bootstrap.js +4 -4
- package/dist/subject/runtime.js +5 -5
- package/dist/subject/serve.js +1 -1
- package/dist/subject/steps.d.ts +4 -4
- package/dist/subject/steps.js +5 -5
- package/dist/substrates/e2b/cdp-probe.d.ts +2 -2
- package/dist/substrates/e2b/cdp-probe.js +1 -1
- package/dist/substrates/e2b/desktop-browser.d.ts +3 -3
- package/dist/substrates/e2b/desktop-browser.js +4 -4
- package/dist/substrates/e2b/desktop-cdp.d.ts +7 -7
- package/dist/substrates/e2b/desktop-cdp.js +4 -4
- package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
- package/dist/substrates/e2b/desktop-geometry.js +3 -3
- package/dist/substrates/e2b/desktop-media.js +2 -2
- package/dist/substrates/e2b/sandbox.js +1 -1
- package/dist/substrates/e2b/sdk.js +2 -2
- package/dist/substrates/local/runtime-host.d.ts +2 -0
- package/dist/substrates/local/runtime-host.js +6 -0
- package/dist/tui/actions.d.ts +7 -5
- package/dist/tui/actions.js +18 -9
- package/dist/tui-app.js +42 -42
- package/dist/verify/actor.d.ts +10 -10
- package/dist/verify/actor.js +15 -15
- package/dist/verify/artifacts.d.ts +1 -1
- package/dist/verify/artifacts.js +3 -3
- package/dist/verify/costs.d.ts +2 -2
- package/dist/verify/costs.js +2 -2
- package/dist/verify/liveness.d.ts +1 -1
- package/dist/verify/liveness.js +4 -1
- package/dist/verify/rerun.d.ts +1 -1
- package/dist/verify/rerun.js +1 -1
- package/dist/verify/shared-world.js +2 -2
- package/dist/verify/verify.js +6 -6
- package/docs/README.md +1 -1
- package/docs/architecture/actor-contract.md +60 -22
- package/docs/architecture/desktop-sessions.md +9 -9
- package/docs/architecture/external-public-shared-world.md +5 -0
- package/docs/architecture/observer.md +4 -4
- package/docs/architecture/restricted-codex-analysis.md +36 -2
- package/docs/architecture/state-driven-executor.md +4 -5
- package/docs/architecture/task-protocol-support.md +3 -5
- package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +24 -16
- package/docs/contracts/run-bundle.md +10 -8
- package/docs/contracts/schemas.md +109 -53
- package/docs/contracts/study-analysis.md +24 -0
- package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
- package/docs/product/automatic-analysis.md +1 -0
- package/docs/ramp/README.md +2 -1
- package/package.json +4 -4
- package/skills/humanish/SKILL.md +3 -2
- package/skills/humanish/agents/openai.yaml +1 -1
- package/dist/deprecated.d.ts +0 -90
- package/dist/deprecated.js +0 -106
- package/dist/lab/bag-overrides.d.ts +0 -18
- package/dist/lab/bag-overrides.js +0 -121
- package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
- package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
- /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
- /package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +0 -0
- /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { automaticAnalysisBudget, formatAutomaticAnalysisBudget, } from "../../analysis/automatic-config.js";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
3
|
import { Command } from "commander";
|
|
4
|
-
import {
|
|
4
|
+
import { deriveRunFacts } from "../telemetry.js";
|
|
5
5
|
import { resolveLabManifest } from "../../lab/discover.js";
|
|
6
|
-
import { resolveLabDryRun } from "../../lab/plan.js";
|
|
6
|
+
import { planLab, resolveLabDryRun } from "../../lab/plan.js";
|
|
7
|
+
import { keyNamesOf } from "../../lab/requirements.js";
|
|
7
8
|
import { routeOf } from "../../lab/plan.js";
|
|
8
9
|
import { computerUseRouteRun } from "./lab-route-computer-use.js";
|
|
9
10
|
import { runRoute } from "./lab-route-run.js";
|
|
@@ -12,8 +13,9 @@ import { sharedWorldRouteRun } from "./lab-route-shared-world.js";
|
|
|
12
13
|
import { previewRouteRun } from "./lab-route-preview.js";
|
|
13
14
|
import { terminalRouteRun } from "./lab-route-terminal.js";
|
|
14
15
|
import { maybeLoadAdapterScorer } from "./lab-scorer.js";
|
|
15
|
-
import { discoverCliKeys, formatRunHuman,
|
|
16
|
+
import { discoverCliKeys, formatRunHuman, noteRunFacts, writeResult, } from "../io.js";
|
|
16
17
|
import { watchExposeRequested } from "../observer-follow.js";
|
|
18
|
+
import { beginRunSignalPhase } from "./run-signals.js";
|
|
17
19
|
import { WATCH_SAFE_NOT_APPLICABLE_MESSAGE } from "../../observer/exposure.js";
|
|
18
20
|
export async function runLabCommand(args) {
|
|
19
21
|
const resolved = await resolveLabManifest(args.options.cwd, args.lab);
|
|
@@ -35,7 +37,7 @@ export async function runLabCommand(args) {
|
|
|
35
37
|
const lab = { id: config.id, path: resolved.path, origin: resolved.origin };
|
|
36
38
|
// Named here, once, for every route: a preview or terminal result carries no labId, so the
|
|
37
39
|
// starter lab `first-run` went unnamed in telemetry while the computer-use ones were named.
|
|
38
|
-
|
|
40
|
+
noteRunFacts(args.command, deriveRunFacts({ labId: config.id }));
|
|
39
41
|
const route = routeOf(config);
|
|
40
42
|
if (route !== "computer-use" && labRerunFlagsRequested(args.options)) {
|
|
41
43
|
writeUnsupportedRerunFlagsResult(args, route);
|
|
@@ -76,52 +78,81 @@ export async function runLabCommand(args) {
|
|
|
76
78
|
return;
|
|
77
79
|
}
|
|
78
80
|
// Only a live run reads provider keys, so a dry run looks none up: no `gh auth token`, no e2b
|
|
79
|
-
// login, overlay or key store.
|
|
80
|
-
//
|
|
81
|
+
// login, overlay or key store. A live run fills every key it finds and prints a line only for
|
|
82
|
+
// the keys its plan reads. This comes after the option refusals above, which read no key, and
|
|
83
|
+
// before the route's CLI setup and prepareLab, which do.
|
|
81
84
|
if (resolveLabDryRun(config, args.options.dryRun, true) === false) {
|
|
82
|
-
|
|
85
|
+
const announced = announcedKeyNames(config, args.options);
|
|
86
|
+
await discoverCliKeys({
|
|
87
|
+
io: args.io,
|
|
88
|
+
cwd: args.options.cwd,
|
|
89
|
+
...(announced === undefined ? {} : { announced }),
|
|
90
|
+
});
|
|
83
91
|
}
|
|
84
92
|
// The route's CLI setup refuses bad options, runLab's plan refuses bad labs, and the route's local
|
|
85
93
|
// checks (keys, runtime auth, subject env, the local agent, caps) refuse this machine, all before
|
|
86
94
|
// the scorer loads, so none imports the scorer's host code. The scripted route's checks and the
|
|
87
95
|
// run-id claim still come after it; the scripted route takes no scorer.
|
|
88
|
-
const
|
|
89
|
-
if (
|
|
96
|
+
const routeRun = routeRunFor(route, { ...args, config });
|
|
97
|
+
if (routeRun === undefined)
|
|
90
98
|
return;
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
//
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
99
|
+
// Every route's runLab options carry the lab's provenance, from here only.
|
|
100
|
+
const run = { ...routeRun, options: { ...routeRun.options, lab } };
|
|
101
|
+
// From here a signal marks the run interrupted and reclaims its sandboxes (run-signals.ts).
|
|
102
|
+
const signals = beginRunSignalPhase(args.io);
|
|
103
|
+
try {
|
|
104
|
+
// #316: resolve + load a config-declared/CLI-flagged adopter scorer FAIL-CLOSED, before any
|
|
105
|
+
// spend, and only for a plan that will run. A declared gate that cannot load (bad ref, not
|
|
106
|
+
// found, load failure, no hooks, unsupported route) aborts with exit 2 rather than green-passing.
|
|
107
|
+
await runRoute(config, run, async () => {
|
|
108
|
+
const scorerLoad = await maybeLoadAdapterScorer({
|
|
109
|
+
cwd: args.options.cwd,
|
|
110
|
+
config,
|
|
111
|
+
route,
|
|
112
|
+
flag: args.options.scorer,
|
|
113
|
+
});
|
|
114
|
+
if (!scorerLoad.ok) {
|
|
115
|
+
const result = {
|
|
116
|
+
schema: "humanish.run-result.v1",
|
|
117
|
+
ok: false,
|
|
118
|
+
cwd: resolve(args.options.cwd),
|
|
119
|
+
warnings: [],
|
|
120
|
+
error: scorerLoad.error,
|
|
121
|
+
};
|
|
122
|
+
writeResult(args.command, args.io, result, formatRunHuman);
|
|
123
|
+
args.io.setExitCode(2);
|
|
124
|
+
return undefined;
|
|
125
|
+
}
|
|
126
|
+
const scorer = scorerLoad.scorer;
|
|
127
|
+
if (scorer) {
|
|
128
|
+
// Cross-repo guardrail: `humanish lab run` now import()s host JS named in the manifest.
|
|
129
|
+
// Surface it so the invoker (who may not be the manifest author) knows executable code ran.
|
|
130
|
+
args.io.writeErr(`warning: review scorer ${scorer.provenance.ref} (${scorer.provenance.source}) is executable host code loaded and run in-process — review it as code, not config.\n`);
|
|
131
|
+
}
|
|
132
|
+
const analysisBudget = automaticAnalysisBudget(config.review?.analysis, route);
|
|
133
|
+
if (analysisBudget && resolveLabDryRun(config, args.options.dryRun, true) === false) {
|
|
134
|
+
args.io.writeErr(`${formatAutomaticAnalysisBudget(analysisBudget)}\n`);
|
|
135
|
+
}
|
|
136
|
+
return scorer === undefined ? {} : { scorer };
|
|
137
|
+
},
|
|
138
|
+
// The run is over before presentation, which may own shutdown itself (watch's Observer).
|
|
139
|
+
// A shutdown already begun keeps its handlers and finishes through its cleanups.
|
|
140
|
+
signals.release);
|
|
141
|
+
}
|
|
142
|
+
finally {
|
|
143
|
+
signals.release();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* The filled keys a live run prints a line for: the ones its plan reads. Count and rerun options
|
|
148
|
+
* change who runs, not which keys. Undefined, so every fill is printed, when a scorer is declared,
|
|
149
|
+
* since its host code may read any key, and when the lab does not plan.
|
|
150
|
+
*/
|
|
151
|
+
function announcedKeyNames(config, options) {
|
|
152
|
+
if (options.scorer !== undefined || config.review?.scorer !== undefined)
|
|
153
|
+
return undefined;
|
|
154
|
+
const planned = planLab(config, { cwd: options.cwd, dryRun: false });
|
|
155
|
+
return planned.ok ? keyNamesOf(planned.planned.plan) : undefined;
|
|
125
156
|
}
|
|
126
157
|
/** The route's CLI setup. Undefined when the setup has already written its own result. */
|
|
127
158
|
function routeRunFor(route, args) {
|
|
@@ -142,7 +173,7 @@ function routeRunFor(route, args) {
|
|
|
142
173
|
}
|
|
143
174
|
}
|
|
144
175
|
function labRerunFlagsRequested(options) {
|
|
145
|
-
return options.rerunFailedFrom !== undefined || options.
|
|
176
|
+
return options.rerunFailedFrom !== undefined || options.participants !== undefined;
|
|
146
177
|
}
|
|
147
178
|
function writeUnsupportedRerunFlagsResult(args, route) {
|
|
148
179
|
const result = {
|
|
@@ -152,7 +183,7 @@ function writeUnsupportedRerunFlagsResult(args, route) {
|
|
|
152
183
|
warnings: [],
|
|
153
184
|
error: {
|
|
154
185
|
code: "HUMANISH_UNSUPPORTED_RERUN_FLAGS",
|
|
155
|
-
message: `--rerun-failed-from/--
|
|
186
|
+
message: `--rerun-failed-from/--participants apply only to computer-use fan-out labs; this lab resolved to the ${route} route.`,
|
|
156
187
|
},
|
|
157
188
|
};
|
|
158
189
|
writeResult(args.command, args.io, result, formatRunHuman);
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { RunLabProvenance } from "../../run/status.js";
|
|
2
1
|
import { type AdapterScorerModule } from "../../lab/adapter-scorer-loader.js";
|
|
3
2
|
import type { LabRoute } from "../../lab/plan.js";
|
|
4
3
|
import type { RunScorerProvenance } from "../../run/bundle.js";
|
|
@@ -18,7 +17,6 @@ export interface LoadedAdapterScorer {
|
|
|
18
17
|
export declare function maybeLoadAdapterScorer(args: {
|
|
19
18
|
cwd: string;
|
|
20
19
|
config: LabConfig;
|
|
21
|
-
labProvenance?: RunLabProvenance;
|
|
22
20
|
route: LabRoute;
|
|
23
21
|
flag: string | undefined;
|
|
24
22
|
}): Promise<{
|
package/dist/cli/commands/lab.js
CHANGED
|
@@ -4,6 +4,7 @@ import { Command, Option } from "commander";
|
|
|
4
4
|
import { inspectLabManifest, listLabManifests } from "../../lab/discover.js";
|
|
5
5
|
import { runLabPreflight, } from "../../lab/preflight.js";
|
|
6
6
|
import { runLabCommand } from "./lab-run.js";
|
|
7
|
+
import { countOption, participantsOption } from "../renamed-options.js";
|
|
7
8
|
import { applyEnvFileOption, JSON_OPTION_DESCRIPTION, parsePositiveInteger, writeResult, } from "../io.js";
|
|
8
9
|
export function registerLabCommands(parent, io) {
|
|
9
10
|
const lab = parent
|
|
@@ -45,10 +46,13 @@ export function registerLabCommands(parent, io) {
|
|
|
45
46
|
.option("--no-open", "Render without opening a browser.")
|
|
46
47
|
.option("--detach", "Render/open once and exit without attached watch server.")
|
|
47
48
|
.option("--port <port>", "Local observer server port when following.", "0")
|
|
48
|
-
.option("--
|
|
49
|
-
|
|
49
|
+
.option("--count <count>", "Override the participant count of a preview or computer-use lab.")
|
|
50
|
+
// The older spelling of --count, hidden and noted on stderr (renamed-options.ts).
|
|
51
|
+
.addOption(new Option("--sims <count>").hideHelp())
|
|
50
52
|
.option("--rerun-failed-from <run>", "CUA fan-out only: create a new run for failed participants from a prior run.")
|
|
51
|
-
.option("--
|
|
53
|
+
.option("--participants <ids>", "CUA rerun only: comma-separated participant ids from the source run. Ids are the lab's declared actors[0].lanes[].id, or lane-01, lane-02, … by position.")
|
|
54
|
+
// The older spelling of --participants, hidden and noted on stderr (renamed-options.ts).
|
|
55
|
+
.addOption(new Option("--lanes <participant-ids>").hideHelp())
|
|
52
56
|
.option("--run-id <id>", "Explicit lab run id; refused when that run already exists.")
|
|
53
57
|
.option("--cwd <path>", "Target project directory.", ".")
|
|
54
58
|
.option("--scorer <path>", "Terminal/computer-use/shared-world labs only: repo-relative adopter scorer module (.mjs). Overrides review.scorer.ref. Executable code: review it as code.")
|
|
@@ -57,7 +61,7 @@ export function registerLabCommands(parent, io) {
|
|
|
57
61
|
"",
|
|
58
62
|
"Examples:",
|
|
59
63
|
" humanish lab run first-run",
|
|
60
|
-
" humanish lab run fanout-demo --rerun-failed-from latest --
|
|
64
|
+
" humanish lab run fanout-demo --rerun-failed-from latest --participants lane-02,lane-04",
|
|
61
65
|
" humanish lab run my-terminal-lab --scorer scorers/product.mjs",
|
|
62
66
|
" humanish lab run .humanish/labs/private-dogfood.yaml --env-file .humanish/local/provider.env",
|
|
63
67
|
"",
|
|
@@ -118,6 +122,8 @@ async function handleLabPreflight(io, labName, options, command) {
|
|
|
118
122
|
io.setExitCode(result.ok ? 0 : 2);
|
|
119
123
|
}
|
|
120
124
|
async function handleLabRun(io, labName, options, command) {
|
|
125
|
+
const count = countOption(io, options);
|
|
126
|
+
const participants = participantsOption(io, options);
|
|
121
127
|
if (!(await applyEnvFileOption({
|
|
122
128
|
command,
|
|
123
129
|
cwd: options.cwd,
|
|
@@ -133,7 +139,7 @@ async function handleLabRun(io, labName, options, command) {
|
|
|
133
139
|
io,
|
|
134
140
|
lab: labName,
|
|
135
141
|
mode: "run",
|
|
136
|
-
options,
|
|
142
|
+
options: { ...options, count, participants },
|
|
137
143
|
});
|
|
138
144
|
}
|
|
139
145
|
function formatLabListHuman(result) {
|
|
@@ -177,7 +183,7 @@ function formatLabPreflightHuman(result) {
|
|
|
177
183
|
return ([
|
|
178
184
|
`humanish lab preflight ${result.ok ? "passed" : "failed"}`,
|
|
179
185
|
`lab: ${result.labId ?? result.lab}`,
|
|
180
|
-
...(result.
|
|
186
|
+
...(result.route ? [`route: ${result.route}`] : []),
|
|
181
187
|
`reachability: ${result.reachability}`,
|
|
182
188
|
`targets: ${checkedTargets.length ? `${reachableTargets.length}/${checkedTargets.length} reachable` : `${result.targets.length} declared, not checked`}`,
|
|
183
189
|
...(blockedTargets.length ? [`blocked-targets: ${blockedTargets.length}`] : []),
|
|
@@ -292,6 +292,7 @@ async function reportServe(io, command, options, server, plan, edge) {
|
|
|
292
292
|
: {}),
|
|
293
293
|
runsListed: server.runsListed,
|
|
294
294
|
...(server.shareReadyCount !== undefined ? { shareReadyCount: server.shareReadyCount } : {}),
|
|
295
|
+
...(server.hiddenRuns !== undefined ? { hiddenRuns: server.hiddenRuns } : {}),
|
|
295
296
|
...(server.entryRunId ? { entryRunId: server.entryRunId } : {}),
|
|
296
297
|
opened: openResult.opened,
|
|
297
298
|
...(openResult.command ? { openCommand: openResult.command } : {}),
|
|
@@ -309,6 +310,26 @@ async function reportServe(io, command, options, server, plan, edge) {
|
|
|
309
310
|
},
|
|
310
311
|
}, { json: wantsMachine });
|
|
311
312
|
}
|
|
313
|
+
/**
|
|
314
|
+
* The runs --safe left out, grouped by grade and reasons, and how to share one. A run held back
|
|
315
|
+
* only for raw screenshots can be exported as a copy with blurred screenshots; the read-results
|
|
316
|
+
* docs name that step.
|
|
317
|
+
*/
|
|
318
|
+
function hiddenRunLines(groups) {
|
|
319
|
+
const total = groups.reduce((sum, group) => sum + group.runs, 0);
|
|
320
|
+
if (total === 0)
|
|
321
|
+
return [];
|
|
322
|
+
const runs = (count) => `${count} run${count === 1 ? "" : "s"}`;
|
|
323
|
+
const lines = [`hidden: ${runs(total)} not share_ready`];
|
|
324
|
+
for (const group of groups) {
|
|
325
|
+
const reasons = group.reasons.length > 0 ? ` (${group.reasons.join(", ")})` : "";
|
|
326
|
+
lines.push(` ${runs(group.runs)} ${group.status}${reasons}`);
|
|
327
|
+
}
|
|
328
|
+
if (groups.some((group) => group.reasons.join(",") === "RAW_SCREENSHOTS"))
|
|
329
|
+
lines.push("share: a run held back only for RAW_SCREENSHOTS can be copied with blurred screenshots: `humanish export --run <id> --format bundle --redact-screenshots --out <dir>`, then `humanish serve --safe --cwd <dir>`");
|
|
330
|
+
lines.push("why: `humanish verify --run <id>` explains each reason");
|
|
331
|
+
return lines;
|
|
332
|
+
}
|
|
312
333
|
function formatServeHuman(result) {
|
|
313
334
|
if (!result.ok) {
|
|
314
335
|
return ([
|
|
@@ -323,6 +344,7 @@ function formatServeHuman(result) {
|
|
|
323
344
|
`mode: ${result.mode}${modeSuffix}`,
|
|
324
345
|
`library: ${result.url ?? ""}`,
|
|
325
346
|
`runs: ${result.runsListed}`,
|
|
347
|
+
...hiddenRunLines(result.hiddenRuns ?? []),
|
|
326
348
|
];
|
|
327
349
|
if (result.publicUrl) {
|
|
328
350
|
lines.push(`public: ${result.publicUrl}`);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type ReclaimHooks } from "../../run/reclaim.js";
|
|
2
|
+
import type { RunInterruptSignal } from "../../run/status.js";
|
|
3
|
+
import type { CliIo } from "../io.js";
|
|
4
|
+
interface RunSignalTarget {
|
|
5
|
+
on(event: RunInterruptSignal, listener: () => void): unknown;
|
|
6
|
+
removeListener(event: RunInterruptSignal, listener: () => void): unknown;
|
|
7
|
+
}
|
|
8
|
+
/** Seams for tests; the CLI passes none. */
|
|
9
|
+
export interface RunSignalOptions {
|
|
10
|
+
signalTarget?: RunSignalTarget;
|
|
11
|
+
exit?: (code: number) => void;
|
|
12
|
+
reclaim?: ReclaimHooks;
|
|
13
|
+
deadlineMs?: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Register work a committed shutdown finishes before it exits, such as closing watch's Observer
|
|
17
|
+
* server and tunnel. It runs within the same deadline as reclaim. The returned function removes it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function onRunShutdown(cleanup: () => Promise<void>): () => void;
|
|
20
|
+
/**
|
|
21
|
+
* Install the run's signal handling. `end` removes it. `release` removes it unless a shutdown has
|
|
22
|
+
* begun, which keeps its handlers so a second signal still exits at once.
|
|
23
|
+
*/
|
|
24
|
+
export declare function beginRunSignalPhase(io: Pick<CliIo, "writeErr">, options?: RunSignalOptions): {
|
|
25
|
+
end(): void;
|
|
26
|
+
release(): void;
|
|
27
|
+
};
|
|
28
|
+
/** Analysis is starting, and its own cancel handlers take the signals from here. */
|
|
29
|
+
export declare function handOverRunSignals(): void;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// The run command's signal handling outside post-run analysis. The first interrupt, terminate or
|
|
2
|
+
// hangup signal marks each unfinished run in this process interrupted, kills the E2B sandboxes
|
|
3
|
+
// its create-time receipts name, runs the registered shutdown cleanups (watch's Observer server
|
|
4
|
+
// and tunnel) and exits 128+n, all within one deadline; a second signal exits at once. Routes
|
|
5
|
+
// take no abort signal, so the bundle is not finished, but the record ends at once and no
|
|
6
|
+
// journaled sandbox waits for its timeout. Analysis has its own cancel handlers
|
|
7
|
+
// (analysis-signals.ts) and takes over when it starts.
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { activeRuns } from "../../run/active-runs.js";
|
|
10
|
+
import { LATEST_RUN_ALIAS } from "../../run/locate.js";
|
|
11
|
+
import { reclaimPinnedRunSandboxes, } from "../../run/reclaim.js";
|
|
12
|
+
import { SANDBOX_RECEIPTS_ARTIFACT } from "../../run/sandbox-receipts.js";
|
|
13
|
+
import { exitCodeForSignal } from "../observer-follow.js";
|
|
14
|
+
/** How long the handler waits for interrupt, reclaim and cleanups before it exits anyway. */
|
|
15
|
+
const INTERRUPT_RECLAIM_DEADLINE_MS = 10_000;
|
|
16
|
+
/** Each kill's own request timeout, inside the deadline. */
|
|
17
|
+
const KILL_REQUEST_TIMEOUT_MS = 8_000;
|
|
18
|
+
const SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
19
|
+
let current;
|
|
20
|
+
const shutdownCleanups = new Set();
|
|
21
|
+
/**
|
|
22
|
+
* Register work a committed shutdown finishes before it exits, such as closing watch's Observer
|
|
23
|
+
* server and tunnel. It runs within the same deadline as reclaim. The returned function removes it.
|
|
24
|
+
*/
|
|
25
|
+
export function onRunShutdown(cleanup) {
|
|
26
|
+
shutdownCleanups.add(cleanup);
|
|
27
|
+
return () => {
|
|
28
|
+
shutdownCleanups.delete(cleanup);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Install the run's signal handling. `end` removes it. `release` removes it unless a shutdown has
|
|
33
|
+
* begun, which keeps its handlers so a second signal still exits at once.
|
|
34
|
+
*/
|
|
35
|
+
export function beginRunSignalPhase(io, options = {}) {
|
|
36
|
+
const target = options.signalTarget ?? process;
|
|
37
|
+
const exit = options.exit ??
|
|
38
|
+
((code) => {
|
|
39
|
+
process.exit(code);
|
|
40
|
+
});
|
|
41
|
+
const handlers = new Map();
|
|
42
|
+
let stopping = false;
|
|
43
|
+
const end = () => {
|
|
44
|
+
for (const [signal, handler] of handlers)
|
|
45
|
+
target.removeListener(signal, handler);
|
|
46
|
+
handlers.clear();
|
|
47
|
+
if (current?.end === end)
|
|
48
|
+
current = undefined;
|
|
49
|
+
};
|
|
50
|
+
const release = () => {
|
|
51
|
+
if (!stopping)
|
|
52
|
+
end();
|
|
53
|
+
};
|
|
54
|
+
const onSignal = (signal) => {
|
|
55
|
+
if (stopping) {
|
|
56
|
+
exit(exitCodeForSignal(signal));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
stopping = true;
|
|
60
|
+
void stopActiveRuns(io, signal, options)
|
|
61
|
+
.catch(() => undefined)
|
|
62
|
+
.finally(() => exit(exitCodeForSignal(signal)));
|
|
63
|
+
};
|
|
64
|
+
current?.end();
|
|
65
|
+
for (const signal of SIGNALS) {
|
|
66
|
+
const handler = () => onSignal(signal);
|
|
67
|
+
handlers.set(signal, handler);
|
|
68
|
+
target.on(signal, handler);
|
|
69
|
+
}
|
|
70
|
+
current = { end, release };
|
|
71
|
+
return { end, release };
|
|
72
|
+
}
|
|
73
|
+
/** Analysis is starting, and its own cancel handlers take the signals from here. */
|
|
74
|
+
export function handOverRunSignals() {
|
|
75
|
+
current?.release();
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Interrupt, reclaim and the registered cleanups all run inside one deadline that starts before
|
|
79
|
+
* the first status write is awaited, so a stalled write or kill still ends in a bounded exit.
|
|
80
|
+
*/
|
|
81
|
+
async function stopActiveRuns(io, signal, options) {
|
|
82
|
+
const deadlineMs = options.deadlineMs ?? INTERRUPT_RECLAIM_DEADLINE_MS;
|
|
83
|
+
const runs = activeRuns();
|
|
84
|
+
// Absent: still pending at the deadline. Null: the run had finished, so there is nothing to say.
|
|
85
|
+
const reports = new Map();
|
|
86
|
+
const work = Promise.all([
|
|
87
|
+
...runs.map(async (run) => {
|
|
88
|
+
// False when the run had already finished: its route released what it held.
|
|
89
|
+
if (!(await run.status.interrupt(signal))) {
|
|
90
|
+
reports.set(run, null);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const reclaimed = await reclaimPinnedRunSandboxes(run.cwd, run.paths, {
|
|
94
|
+
requestTimeoutMs: KILL_REQUEST_TIMEOUT_MS,
|
|
95
|
+
...options.reclaim,
|
|
96
|
+
}).catch(() => undefined);
|
|
97
|
+
reports.set(run, reclaimSummary(run, reclaimed));
|
|
98
|
+
}),
|
|
99
|
+
...[...shutdownCleanups].map((cleanup) => cleanup().catch(() => undefined)),
|
|
100
|
+
]);
|
|
101
|
+
const finished = await withDeadline(work, deadlineMs);
|
|
102
|
+
for (const run of runs) {
|
|
103
|
+
const report = reports.get(run);
|
|
104
|
+
if (report === null)
|
|
105
|
+
continue;
|
|
106
|
+
const text = report ??
|
|
107
|
+
(finished === "deadline"
|
|
108
|
+
? `stopping did not finish within ${deadlineMs / 1000} s; ${recovery(run)}.`
|
|
109
|
+
: `reclaim failed; ${recovery(run)}.`);
|
|
110
|
+
try {
|
|
111
|
+
io.writeErr(`humanish: ${signal}: run ${run.runId} marked interrupted; ${text}\n`);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// A hung-up terminal cannot take the line; the status record and reclaim receipt hold it.
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function withDeadline(work, ms) {
|
|
119
|
+
let timer;
|
|
120
|
+
const deadline = new Promise((resolve) => {
|
|
121
|
+
timer = setTimeout(() => resolve("deadline"), ms);
|
|
122
|
+
});
|
|
123
|
+
return Promise.race([work, deadline]).finally(() => clearTimeout(timer));
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* How to finish what the handler could not. A run whose id is the alias `latest` cannot be named
|
|
127
|
+
* to reclaim, which would resolve the newest run instead, so it gets its receipts path.
|
|
128
|
+
*/
|
|
129
|
+
function recovery(run) {
|
|
130
|
+
return run.runId === LATEST_RUN_ALIAS
|
|
131
|
+
? `its id is \`${LATEST_RUN_ALIAS}\`, which \`humanish reclaim --run\` reads as the newest run, so kill the ids in ${path.join(run.paths.relativeRunRoot, SANDBOX_RECEIPTS_ARTIFACT)} by hand`
|
|
132
|
+
: `run \`humanish reclaim --run ${run.runId}\``;
|
|
133
|
+
}
|
|
134
|
+
function reclaimSummary(run, reclaimed) {
|
|
135
|
+
if (reclaimed === undefined)
|
|
136
|
+
return `reclaim failed; ${recovery(run)}.`;
|
|
137
|
+
if (reclaimed.error !== undefined)
|
|
138
|
+
return reclaimed.error.message;
|
|
139
|
+
if (reclaimed.outcomes.length === 0)
|
|
140
|
+
return "no sandbox receipts to reclaim.";
|
|
141
|
+
const counts = new Map();
|
|
142
|
+
for (const outcome of reclaimed.outcomes)
|
|
143
|
+
counts.set(outcome.state, (counts.get(outcome.state) ?? 0) + 1);
|
|
144
|
+
const tally = [...counts].map(([state, count]) => `${count} ${state}`).join(", ");
|
|
145
|
+
return reclaimed.ok ? `sandboxes: ${tally}.` : `sandboxes: ${tally}; ${recovery(run)} to retry.`;
|
|
146
|
+
}
|
|
@@ -6,6 +6,7 @@ import { runDryRun } from "../../run/dry-run.js";
|
|
|
6
6
|
import { verifyRun } from "../../verify/verify.js";
|
|
7
7
|
import { reclaimPreflightSandboxes, reclaimRunSandboxes, } from "../../run/reclaim.js";
|
|
8
8
|
import { runLabCommand } from "./lab-run.js";
|
|
9
|
+
import { countOption } from "../renamed-options.js";
|
|
9
10
|
import { applyEnvFileOption, formatRunHuman, JSON_OPTION_DESCRIPTION, parsePositiveInteger, writeResult, } from "../io.js";
|
|
10
11
|
const SCRIPTED_BROWSER_DOCS_URL = "https://humanish.dev/docs/lab-manifests#scripted-browser-scenarios";
|
|
11
12
|
export function registerRunCommand(parent, io) {
|
|
@@ -24,7 +25,9 @@ export function registerRunCommand(parent, io) {
|
|
|
24
25
|
.option("--no-open", "Render without opening a browser.")
|
|
25
26
|
.option("--detach", "Render/open once and exit without an attached watch server.")
|
|
26
27
|
.option("--port <port>", "Local observer server port when following.", "0")
|
|
27
|
-
.option("--
|
|
28
|
+
.option("--count <count>", "Override the participant count of a preview or computer-use lab, or of the synthetic run without a lab.")
|
|
29
|
+
// The older spelling of --count, hidden and noted on stderr (renamed-options.ts).
|
|
30
|
+
.addOption(new Option("--sims <count>").hideHelp())
|
|
28
31
|
// Agents with an older installed skill still send --app-url. Accepting it hidden lets the
|
|
29
32
|
// refusal name the replacement; commander's bare unknown-option error names nothing. Delete
|
|
30
33
|
// after 0.106.x.
|
|
@@ -34,6 +37,7 @@ export function registerRunCommand(parent, io) {
|
|
|
34
37
|
.option("--run-id <id>", "Explicit run id for deterministic fixture tests; refused when that run already exists.")
|
|
35
38
|
.option("--json", JSON_OPTION_DESCRIPTION)
|
|
36
39
|
.action(async (lab, options, command) => {
|
|
40
|
+
const count = countOption(io, options);
|
|
37
41
|
if (options.appUrl !== undefined) {
|
|
38
42
|
const result = {
|
|
39
43
|
schema: "humanish.run-result.v1",
|
|
@@ -67,12 +71,12 @@ export function registerRunCommand(parent, io) {
|
|
|
67
71
|
mode: "run",
|
|
68
72
|
// Forwarded wholesale, exactly as `lab run` does. Cherry-picking a subset here is what
|
|
69
73
|
// made the two commands disagree in the first place.
|
|
70
|
-
options: options,
|
|
74
|
+
options: { ...options, count },
|
|
71
75
|
});
|
|
72
76
|
return;
|
|
73
77
|
}
|
|
74
|
-
const participantCount =
|
|
75
|
-
if (
|
|
78
|
+
const participantCount = count === undefined ? undefined : parsePositiveInteger(count);
|
|
79
|
+
if (participantCount === null) {
|
|
76
80
|
const result = {
|
|
77
81
|
schema: "humanish.run-result.v1",
|
|
78
82
|
ok: false,
|
|
@@ -80,7 +84,7 @@ export function registerRunCommand(parent, io) {
|
|
|
80
84
|
warnings: [],
|
|
81
85
|
error: {
|
|
82
86
|
code: "HUMANISH_INVALID_SIM_COUNT",
|
|
83
|
-
message: "--
|
|
87
|
+
message: "--count must be a positive integer.",
|
|
84
88
|
},
|
|
85
89
|
};
|
|
86
90
|
writeResult(command, io, result, formatRunHuman);
|
|
@@ -91,9 +95,7 @@ export function registerRunCommand(parent, io) {
|
|
|
91
95
|
cwd: options.cwd,
|
|
92
96
|
...(options.dryRun === undefined ? {} : { dryRun: options.dryRun }),
|
|
93
97
|
...(options.runId === undefined ? {} : { runId: options.runId }),
|
|
94
|
-
...(participantCount === undefined
|
|
95
|
-
? {}
|
|
96
|
-
: { simCount: participantCount }),
|
|
98
|
+
...(participantCount === undefined ? {} : { simCount: participantCount }),
|
|
97
99
|
// Rendered the way `watch` renders it, so a bundle is the same bundle whichever command
|
|
98
100
|
// produced it (#597). A render failure is a warning on the result.
|
|
99
101
|
observer: { open: false },
|
|
@@ -3,6 +3,7 @@ import { renderObserver, serveObserver } from "../../observer/render.js";
|
|
|
3
3
|
import { WATCH_SAFE_NOT_APPLICABLE_MESSAGE } from "../../observer/exposure.js";
|
|
4
4
|
import { runDryRun } from "../../run/dry-run.js";
|
|
5
5
|
import { runLabCommand } from "./lab-run.js";
|
|
6
|
+
import { countOption } from "../renamed-options.js";
|
|
6
7
|
import { applyEnvFileOption, collectRepeated, formatRunHuman, JSON_OPTION_DESCRIPTION, parseObserverPort, parsePositiveInteger, wantsJson, writeResult, } from "../io.js";
|
|
7
8
|
import { followObserver, formatObserverHuman, watchExposeRequested } from "../observer-follow.js";
|
|
8
9
|
export function registerWatchCommand(parent, io) {
|
|
@@ -14,8 +15,9 @@ export function registerWatchCommand(parent, io) {
|
|
|
14
15
|
.option("--lab <id-or-path>", "Explicit lab id or .yaml path.")
|
|
15
16
|
.option("--run <id>", "Watch an existing run id or latest pointer.")
|
|
16
17
|
.option("--dry-run", "Lab only: render contract evidence without live provider spend.")
|
|
17
|
-
.option("--
|
|
18
|
-
|
|
18
|
+
.option("--count <count>", "With a lab, override a preview or computer-use lab's participant count. Without one, start a fresh synthetic run with this many participants; 4 when --run is omitted.")
|
|
19
|
+
// The older spelling of --count, hidden and noted on stderr (renamed-options.ts).
|
|
20
|
+
.addOption(new Option("--sims <count>").hideHelp())
|
|
19
21
|
.option("--scorer <path>", "Terminal/computer-use/shared-world labs only: repo-relative adopter scorer module (.mjs). Overrides review.scorer.ref. Executable code: review it as code.")
|
|
20
22
|
.option("--run-id <id>", "Explicit run id for deterministic fixture tests; refused when that run already exists.")
|
|
21
23
|
.option("--cwd <path>", "Target project directory.", ".")
|
|
@@ -54,7 +56,8 @@ export function registerWatchCommand(parent, io) {
|
|
|
54
56
|
].join("\n"))
|
|
55
57
|
.action((labArg, options, command) => handleWatch(io, labArg, options, command));
|
|
56
58
|
}
|
|
57
|
-
async function handleWatch(io, labArg,
|
|
59
|
+
async function handleWatch(io, labArg, parsed, command) {
|
|
60
|
+
const options = { ...parsed, count: countOption(io, parsed) };
|
|
58
61
|
const lab = options.lab ?? labArg;
|
|
59
62
|
if (options.lab !== undefined && labArg !== undefined) {
|
|
60
63
|
refuseWatch(command, io, options.cwd, {
|
|
@@ -151,7 +154,6 @@ async function watchLab(io, command, lab, options) {
|
|
|
151
154
|
port: options.port,
|
|
152
155
|
...(options.runId === undefined ? {} : { runId: options.runId }),
|
|
153
156
|
...(options.scorer === undefined ? {} : { scorer: options.scorer }),
|
|
154
|
-
...(options.sims === undefined ? {} : { sims: options.sims }),
|
|
155
157
|
...(options.expose === undefined ? {} : { expose: options.expose }),
|
|
156
158
|
...(options.tunnel === undefined ? {} : { tunnel: options.tunnel }),
|
|
157
159
|
...(options.tunnelDomain === undefined ? {} : { tunnelDomain: options.tunnelDomain }),
|
|
@@ -164,21 +166,21 @@ async function watchLab(io, command, lab, options) {
|
|
|
164
166
|
},
|
|
165
167
|
});
|
|
166
168
|
}
|
|
167
|
-
/** Without a lab, watch shows existing evidence (`--run`) or a fresh synthetic run (`--
|
|
169
|
+
/** Without a lab, watch shows existing evidence (`--run`) or a fresh synthetic run (`--count`). */
|
|
168
170
|
function resolveWatchTarget(options, command) {
|
|
169
171
|
const runOptionSource = typeof command.getOptionValueSource === "function"
|
|
170
172
|
? command.getOptionValueSource("run")
|
|
171
173
|
: undefined;
|
|
172
174
|
const runWasOmitted = runOptionSource === undefined || runOptionSource === "default";
|
|
173
|
-
const participantCount = options.
|
|
175
|
+
const participantCount = options.count === undefined ? undefined : parsePositiveInteger(options.count);
|
|
174
176
|
const port = parseObserverPort(options.port);
|
|
175
|
-
if (
|
|
176
|
-
return { code: "HUMANISH_INVALID_SIM_COUNT", message: "--
|
|
177
|
+
if (participantCount === null) {
|
|
178
|
+
return { code: "HUMANISH_INVALID_SIM_COUNT", message: "--count must be a positive integer." };
|
|
177
179
|
}
|
|
178
|
-
if (!runWasOmitted &&
|
|
180
|
+
if (!runWasOmitted && participantCount !== undefined) {
|
|
179
181
|
return {
|
|
180
182
|
code: "HUMANISH_WATCH_OPTION_CONFLICT",
|
|
181
|
-
message: "Use either --run to watch existing evidence or --
|
|
183
|
+
message: "Use either --run to watch existing evidence or --count to start a fresh run, not both.",
|
|
182
184
|
};
|
|
183
185
|
}
|
|
184
186
|
if (!runWasOmitted && options.runId !== undefined) {
|
package/dist/cli/doctor.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type KeyResolutionDeps } from "../keys/key-resolution.js";
|
|
2
2
|
import { type DetectLocalAgentsOptions } from "../actors/local-agent/cli.js";
|
|
3
|
+
import { type LabSetupCheckArgs } from "../lab/doctor.js";
|
|
3
4
|
declare const DOCTOR_SCHEMA = "humanish.doctor-result.v1";
|
|
4
5
|
export interface DoctorResult {
|
|
5
6
|
schema: typeof DOCTOR_SCHEMA;
|
|
@@ -35,5 +36,7 @@ export declare function doctor(cwdInput: string, options?: {
|
|
|
35
36
|
localAgents?: DetectLocalAgentsOptions;
|
|
36
37
|
/** Where the key probe looks for vendor stores; tests point it at a temp home. */
|
|
37
38
|
keyDeps?: KeyResolutionDeps;
|
|
39
|
+
/** The hosted Codex participant's operator handshake; tests replace it. */
|
|
40
|
+
codexParticipantReadiness?: LabSetupCheckArgs["codexParticipantReadiness"];
|
|
38
41
|
}): Promise<DoctorResult>;
|
|
39
42
|
export {};
|