humanish 0.107.0 → 0.108.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +22 -17
- package/CHANGELOG.md +14 -0
- package/CONTEXT.md +51 -44
- package/README.md +145 -172
- package/SECURITY.md +16 -26
- package/TELEMETRY.md +8 -6
- package/dist/actors/affordance.d.ts +4 -4
- package/dist/actors/affordance.js +12 -12
- package/dist/actors/agent-session.d.ts +2 -2
- package/dist/actors/agent-session.js +7 -7
- package/dist/actors/codex/app-server-actor-trace.d.ts +1 -1
- package/dist/actors/codex/app-server-actor-trace.js +1 -1
- package/dist/actors/codex/app-server-ui.js +1 -1
- package/dist/actors/codex/codex-admission.d.ts +91 -0
- package/dist/actors/codex/codex-admission.js +150 -0
- package/dist/actors/codex/restricted-executable.d.ts +4 -4
- package/dist/actors/codex/restricted-executable.js +8 -8
- package/dist/actors/codex/restricted-launch.d.ts +2 -1
- package/dist/actors/codex/restricted-launch.js +1 -1
- package/dist/actors/codex/restricted-participant.js +8 -6
- package/dist/actors/codex/restricted-policy.d.ts +2 -2
- package/dist/actors/codex/restricted-policy.js +2 -2
- package/dist/actors/codex/restricted-session.d.ts +2 -2
- package/dist/actors/codex/restricted-session.js +10 -5
- package/dist/actors/computer-use/actor.d.ts +16 -16
- package/dist/actors/computer-use/actor.js +2 -2
- package/dist/actors/computer-use/admission-limit.d.ts +1 -1
- package/dist/actors/computer-use/admission-limit.js +1 -1
- package/dist/actors/computer-use/loop/actions.d.ts +3 -3
- package/dist/actors/computer-use/loop/actions.js +10 -10
- package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
- package/dist/actors/computer-use/loop/backstop.js +14 -12
- package/dist/actors/computer-use/loop/ending.d.ts +5 -5
- package/dist/actors/computer-use/loop/ending.js +7 -7
- package/dist/actors/computer-use/loop/observation.d.ts +2 -2
- package/dist/actors/computer-use/loop/observation.js +9 -9
- package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
- package/dist/actors/computer-use/loop/provider-call.js +1 -1
- package/dist/actors/computer-use/loop/session.js +3 -3
- package/dist/actors/computer-use/loop/spend.d.ts +1 -1
- package/dist/actors/computer-use/loop/spend.js +1 -1
- package/dist/actors/computer-use/loop/trace.js +9 -8
- package/dist/actors/computer-use/loop/types.d.ts +25 -23
- package/dist/actors/computer-use/loop/usage.js +2 -2
- package/dist/actors/computer-use/openai-context.d.ts +37 -0
- package/dist/actors/computer-use/openai-context.js +214 -0
- package/dist/actors/computer-use/openai-provider.d.ts +11 -8
- package/dist/actors/computer-use/openai-provider.js +45 -34
- package/dist/actors/computer-use/openai-requests.d.ts +36 -10
- package/dist/actors/computer-use/openai-requests.js +82 -15
- package/dist/actors/computer-use/openai-wire.d.ts +19 -7
- package/dist/actors/computer-use/openai-wire.js +36 -34
- package/dist/actors/contract.d.ts +78 -43
- package/dist/actors/contract.js +29 -23
- package/dist/actors/local-agent/claude-session.d.ts +1 -1
- package/dist/actors/local-agent/claude-session.js +10 -9
- package/dist/actors/local-agent/cli.d.ts +8 -6
- package/dist/actors/local-agent/cli.js +24 -28
- package/dist/actors/local-agent/readiness.d.ts +2 -2
- package/dist/actors/local-agent/readiness.js +4 -4
- package/dist/actors/reasoning-effort.js +6 -6
- package/dist/actors/registry.d.ts +10 -10
- package/dist/actors/registry.js +18 -17
- package/dist/actors/scripted-browser/actor.d.ts +8 -8
- package/dist/actors/scripted-browser/actor.js +16 -16
- package/dist/actors/scripted-browser/browser-command.js +1 -1
- package/dist/actors/scripted-browser/steps.js +1 -1
- package/dist/actors/scripted-browser/types.d.ts +1 -1
- package/dist/actors/stop-conditions.d.ts +1 -1
- package/dist/analysis/codex-config.d.ts +6 -2
- package/dist/analysis/codex-config.js +22 -14
- package/dist/analysis/service.js +5 -5
- package/dist/cli/commands/analyze.js +19 -16
- package/dist/cli/commands/codex.js +9 -9
- package/dist/cli/commands/comms.js +54 -33
- package/dist/cli/commands/feedback.js +20 -21
- package/dist/cli/commands/lab-format.d.ts +5 -4
- package/dist/cli/commands/lab-format.js +35 -23
- package/dist/cli/commands/lab-route-computer-use.js +6 -7
- package/dist/cli/commands/lab-route-preview.js +4 -3
- package/dist/cli/commands/lab-route-shared-world.js +3 -3
- package/dist/cli/commands/lab-run.js +10 -11
- package/dist/cli/commands/lab-scorer.d.ts +2 -2
- package/dist/cli/commands/lab-scorer.js +1 -1
- package/dist/cli/commands/migrate.d.ts +4 -0
- package/dist/cli/commands/migrate.js +65 -0
- package/dist/cli/commands/observe.js +147 -108
- package/dist/cli/commands/run-command.d.ts +10 -0
- package/dist/cli/commands/run-command.js +85 -0
- package/dist/cli/commands/runs.js +137 -138
- package/dist/cli/commands/setup.d.ts +2 -2
- package/dist/cli/commands/setup.js +26 -21
- package/dist/cli/commands/study.d.ts +3 -0
- package/dist/cli/commands/study.js +182 -0
- package/dist/cli/commands/tui.d.ts +4 -4
- package/dist/cli/commands/tui.js +21 -21
- package/dist/cli/commands/watch.js +60 -75
- package/dist/cli/deprecations.d.ts +18 -0
- package/dist/cli/deprecations.js +48 -0
- package/dist/cli/doctor.d.ts +15 -5
- package/dist/cli/doctor.js +103 -48
- package/dist/cli/first-run-path.d.ts +12 -10
- package/dist/cli/first-run-path.js +30 -28
- package/dist/cli/io.d.ts +41 -6
- package/dist/cli/io.js +97 -22
- package/dist/cli/observer-follow.d.ts +2 -2
- package/dist/cli/observer-follow.js +5 -6
- package/dist/cli/orientation.d.ts +6 -3
- package/dist/cli/orientation.js +43 -39
- package/dist/cli/product-sentence.d.ts +6 -0
- package/dist/cli/product-sentence.js +6 -0
- package/dist/cli/program.d.ts +6 -1
- package/dist/cli/program.js +109 -40
- package/dist/cli/telemetry.d.ts +15 -15
- package/dist/cli/telemetry.js +48 -40
- package/dist/cli.js +1 -1
- package/dist/comms/capture-surface.d.ts +13 -12
- package/dist/comms/capture-surface.js +23 -22
- package/dist/comms/catch-host.d.ts +7 -7
- package/dist/comms/catch-host.js +14 -14
- package/dist/comms/email-catch.d.ts +3 -3
- package/dist/comms/email-catch.js +8 -8
- package/dist/comms/external-evidence.js +2 -2
- package/dist/comms/extract.js +2 -2
- package/dist/comms/fake-inbox.d.ts +2 -2
- package/dist/comms/fake-inbox.js +2 -2
- package/dist/comms/receiving-render.d.ts +1 -1
- package/dist/comms/receiving-render.js +2 -2
- package/dist/comms/sandbox-catch-script.d.ts +6 -6
- package/dist/comms/sandbox-catch-script.js +6 -6
- package/dist/comms/sandbox-catch.d.ts +36 -37
- package/dist/comms/sandbox-catch.js +34 -35
- package/dist/comms/setup.js +42 -8
- package/dist/comms/thread-evidence.d.ts +1 -1
- package/dist/comms/thread-evidence.js +6 -6
- package/dist/comms/types.d.ts +6 -6
- package/dist/comms/types.js +3 -3
- package/dist/evidence/frame-signature.d.ts +1 -1
- package/dist/evidence/frame-signature.js +4 -4
- package/dist/evidence/redaction.d.ts +3 -3
- package/dist/evidence/redaction.js +4 -4
- package/dist/feedback/draft.js +36 -78
- package/dist/feedback/export-bundle.js +1 -1
- package/dist/feedback/export.d.ts +5 -1
- package/dist/feedback/export.js +7 -8
- package/dist/feedback/feedback.d.ts +2 -2
- package/dist/feedback/feedback.js +21 -3
- package/dist/guest/chromium-text.js +2 -2
- package/dist/guest/desktop-native.d.ts +1 -1
- package/dist/guest/runtime.js +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.js +8 -6
- package/dist/keys/key-resolution.d.ts +5 -5
- package/dist/keys/key-resolution.js +23 -23
- package/dist/lab/adapter-extension.d.ts +7 -7
- package/dist/lab/adapter-extension.js +13 -36
- package/dist/lab/adapter-scorer-loader.d.ts +7 -7
- package/dist/lab/adapter-scorer-loader.js +32 -32
- package/dist/lab/composition-rules.js +42 -42
- package/dist/lab/config.js +65 -25
- package/dist/lab/deprecated-fields.d.ts +10 -0
- package/dist/lab/deprecated-fields.js +24 -0
- package/dist/lab/device-presets.d.ts +8 -8
- package/dist/lab/device-presets.js +11 -11
- package/dist/lab/discover.d.ts +13 -9
- package/dist/lab/discover.js +117 -57
- package/dist/lab/doctor.d.ts +10 -3
- package/dist/lab/doctor.js +47 -9
- package/dist/lab/init-templates.js +147 -147
- package/dist/lab/init.d.ts +1 -1
- package/dist/lab/init.js +41 -9
- package/dist/lab/keys.d.ts +2 -0
- package/dist/lab/keys.js +42 -8
- package/dist/lab/lab-deps.d.ts +7 -12
- package/dist/lab/parse/actors.js +9 -9
- package/dist/lab/parse/comms.js +5 -5
- package/dist/lab/parse/execution.js +13 -13
- package/dist/lab/parse/study-v3.d.ts +23 -0
- package/dist/lab/parse/study-v3.js +259 -0
- package/dist/lab/parse/subject-state.d.ts +7 -7
- package/dist/lab/parse/subject-state.js +16 -16
- package/dist/lab/parse/subject.js +28 -28
- package/dist/lab/parse/values.d.ts +1 -1
- package/dist/lab/parse/values.js +3 -3
- package/dist/lab/persona-resolve.d.ts +4 -4
- package/dist/lab/persona-resolve.js +4 -4
- package/dist/lab/plan-participants.d.ts +2 -2
- package/dist/lab/plan-types.d.ts +4 -4
- package/dist/lab/plan.d.ts +1 -7
- package/dist/lab/plan.js +10 -41
- package/dist/lab/preflight-probes.js +11 -11
- package/dist/lab/preflight-result.d.ts +2 -1
- package/dist/lab/preflight-result.js +5 -4
- package/dist/lab/preflight.d.ts +7 -5
- package/dist/lab/preflight.js +5 -5
- package/dist/lab/routing.d.ts +31 -25
- package/dist/lab/routing.js +60 -29
- package/dist/lab/run-lab-events.d.ts +0 -3
- package/dist/lab/run-lab-events.js +0 -6
- package/dist/lab/run-lab-homes.d.ts +22 -10
- package/dist/lab/run-lab-homes.js +5 -1
- package/dist/lab/run-lab-options.d.ts +1 -1
- package/dist/lab/run-lab-options.js +16 -13
- package/dist/lab/summary.d.ts +7 -6
- package/dist/lab/summary.js +10 -10
- package/dist/lab/tasks.d.ts +15 -15
- package/dist/lab/tasks.js +14 -14
- package/dist/lab/types.d.ts +101 -95
- package/dist/lab/types.js +2 -0
- package/dist/lab/validation.d.ts +13 -13
- package/dist/lab/validation.js +44 -42
- package/dist/lab/warnings.d.ts +10 -0
- package/dist/lab/warnings.js +61 -33
- package/dist/library-aliases.d.ts +56 -0
- package/dist/library-aliases.js +22 -0
- package/dist/observer/artifact.d.ts +1 -1
- package/dist/observer/artifact.js +6 -6
- package/dist/observer/data.d.ts +6 -6
- package/dist/observer/data.js +5 -4
- package/dist/observer/exposure.d.ts +1 -1
- package/dist/observer/exposure.js +11 -11
- package/dist/observer/http.js +1 -1
- package/dist/observer/library.d.ts +1 -1
- package/dist/observer/library.js +4 -2
- package/dist/observer/listen.js +5 -4
- package/dist/observer/render.d.ts +1 -1
- package/dist/observer/render.js +10 -5
- package/dist/observer/run-routes.d.ts +3 -3
- package/dist/observer/run-routes.js +1 -1
- package/dist/observer/serve.js +7 -3
- package/dist/observer/tunnel.js +1 -1
- package/dist/observer-app.html +4 -4
- package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
- package/dist/routes/computer-use/bundle-parts.js +15 -15
- package/dist/routes/computer-use/bundle.js +3 -3
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/comms.js +14 -14
- package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +4 -3
- package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
- package/dist/routes/computer-use/e2b-desktop/prepare.js +7 -7
- package/dist/routes/computer-use/e2b-desktop/start.js +9 -8
- package/dist/routes/computer-use/e2b-desktop/teardown.js +5 -4
- package/dist/routes/computer-use/external-comms.d.ts +1 -1
- package/dist/routes/computer-use/external-comms.js +1 -1
- package/dist/routes/computer-use/fanout-bundle.js +18 -18
- package/dist/routes/computer-use/fanout-records.js +10 -11
- package/dist/routes/computer-use/live-flush.d.ts +1 -1
- package/dist/routes/computer-use/live-flush.js +6 -6
- package/dist/routes/computer-use/live-phase.d.ts +4 -2
- package/dist/routes/computer-use/live-phase.js +6 -6
- package/dist/routes/computer-use/local-vm.js +1 -1
- package/dist/routes/computer-use/participant-desktop.d.ts +4 -4
- package/dist/routes/computer-use/participant-desktop.js +4 -4
- package/dist/routes/computer-use/participant-execution.d.ts +4 -4
- package/dist/routes/computer-use/participant-execution.js +9 -9
- package/dist/routes/computer-use/participant-model.d.ts +6 -0
- package/dist/routes/computer-use/participant-model.js +31 -13
- package/dist/routes/computer-use/participant-prompt.d.ts +11 -11
- package/dist/routes/computer-use/participant-prompt.js +6 -6
- package/dist/routes/computer-use/participant-runs.d.ts +7 -7
- package/dist/routes/computer-use/participant-runs.js +13 -13
- package/dist/routes/computer-use/plan.js +22 -22
- package/dist/routes/computer-use/preflight.js +21 -21
- package/dist/routes/computer-use/rerun-selection.js +1 -1
- package/dist/routes/computer-use/result.js +11 -11
- package/dist/routes/computer-use/route.d.ts +2 -1
- package/dist/routes/computer-use/route.js +15 -14
- package/dist/routes/computer-use/self-report.d.ts +7 -7
- package/dist/routes/computer-use/self-report.js +31 -31
- package/dist/routes/computer-use/setup.d.ts +1 -1
- package/dist/routes/computer-use/setup.js +17 -18
- package/dist/routes/computer-use/single-bundle.d.ts +7 -7
- package/dist/routes/computer-use/single-bundle.js +28 -30
- package/dist/routes/computer-use/subject-projection.d.ts +1 -1
- package/dist/routes/computer-use/subject-projection.js +6 -6
- package/dist/routes/computer-use/types.d.ts +40 -42
- package/dist/routes/computer-use/types.js +10 -10
- package/dist/routes/preview.d.ts +8 -2
- package/dist/routes/preview.js +8 -4
- package/dist/routes/scripted/bundle.d.ts +2 -2
- package/dist/routes/scripted/bundle.js +13 -12
- package/dist/routes/scripted/plan.d.ts +1 -1
- package/dist/routes/scripted/plan.js +9 -9
- package/dist/routes/scripted/result.js +5 -5
- package/dist/routes/scripted/route.js +5 -6
- package/dist/routes/scripted/scenario.js +2 -2
- package/dist/routes/scripted/setup.js +7 -7
- package/dist/routes/scripted/subject.js +1 -1
- package/dist/routes/scripted/surface-records.js +3 -3
- package/dist/routes/scripted/types.d.ts +3 -5
- package/dist/routes/scripted/types.js +1 -1
- package/dist/routes/shared-world/bundle-records.js +9 -8
- package/dist/routes/shared-world/bundle.d.ts +5 -5
- package/dist/routes/shared-world/bundle.js +40 -38
- package/dist/routes/shared-world/checkpoints.d.ts +1 -1
- package/dist/routes/shared-world/checkpoints.js +1 -1
- package/dist/routes/shared-world/comms.d.ts +5 -5
- package/dist/routes/shared-world/comms.js +14 -14
- package/dist/routes/shared-world/external-public.d.ts +4 -3
- package/dist/routes/shared-world/external-public.js +16 -12
- package/dist/routes/shared-world/handoff.d.ts +7 -6
- package/dist/routes/shared-world/handoff.js +65 -57
- package/dist/routes/shared-world/lobby-code.d.ts +2 -2
- package/dist/routes/shared-world/lobby-code.js +9 -9
- package/dist/routes/shared-world/participant-specs.d.ts +7 -6
- package/dist/routes/shared-world/participant-specs.js +31 -24
- package/dist/routes/shared-world/plan.js +7 -7
- package/dist/routes/shared-world/provenance.d.ts +2 -2
- package/dist/routes/shared-world/provenance.js +2 -2
- package/dist/routes/shared-world/provisioned.js +14 -13
- package/dist/routes/shared-world/result.js +20 -21
- package/dist/routes/shared-world/route.js +23 -22
- package/dist/routes/shared-world/setup.d.ts +3 -3
- package/dist/routes/shared-world/setup.js +4 -4
- package/dist/routes/shared-world/types.d.ts +30 -28
- package/dist/routes/shared-world/types.js +4 -4
- package/dist/routes/terminal/adapter.d.ts +3 -3
- package/dist/routes/terminal/adapter.js +5 -5
- package/dist/routes/terminal/bundle.d.ts +3 -3
- package/dist/routes/terminal/bundle.js +22 -21
- package/dist/routes/terminal/credentials.d.ts +4 -4
- package/dist/routes/terminal/credentials.js +7 -7
- package/dist/routes/terminal/dry-run.js +4 -4
- package/dist/routes/terminal/encoding.js +2 -2
- package/dist/routes/terminal/ledger.d.ts +3 -3
- package/dist/routes/terminal/ledger.js +14 -14
- package/dist/routes/terminal/live-finish.js +3 -3
- package/dist/routes/terminal/live-sandbox.js +12 -13
- package/dist/routes/terminal/persona.js +1 -1
- package/dist/routes/terminal/plan.js +11 -11
- package/dist/routes/terminal/recorder.js +2 -2
- package/dist/routes/terminal/result.js +8 -8
- package/dist/routes/terminal/route.js +6 -7
- package/dist/routes/terminal/sandbox.d.ts +1 -1
- package/dist/routes/terminal/sandbox.js +1 -1
- package/dist/routes/terminal/session.js +8 -7
- package/dist/routes/terminal/token-usage.d.ts +1 -1
- package/dist/routes/terminal/token-usage.js +7 -8
- package/dist/routes/terminal/trace.d.ts +2 -2
- package/dist/routes/terminal/trace.js +2 -2
- package/dist/routes/terminal/types.d.ts +26 -28
- package/dist/routes/terminal/types.js +3 -3
- package/dist/run/bundle-shape.js +3 -3
- package/dist/run/bundle.d.ts +46 -46
- package/dist/run/bundle.js +2 -1
- package/dist/run/cost-summary.js +3 -3
- package/dist/run/costs.js +7 -1
- package/dist/run/detail.d.ts +6 -6
- package/dist/run/detail.js +4 -4
- package/dist/run/dry-run-inputs.js +1 -1
- package/dist/run/dry-run.js +18 -18
- package/dist/run/judge.d.ts +19 -13
- package/dist/run/judge.js +18 -8
- package/dist/run/paths.d.ts +1 -1
- package/dist/run/paths.js +1 -1
- package/dist/run/pricing.d.ts +11 -6
- package/dist/run/pricing.js +20 -13
- package/dist/run/projection.d.ts +14 -14
- package/dist/run/projection.js +15 -15
- package/dist/run/reclaim.js +2 -2
- package/dist/run/results.d.ts +5 -5
- package/dist/run/run-index.d.ts +8 -6
- package/dist/run/run-index.js +15 -16
- package/dist/run/run-not-found.d.ts +5 -0
- package/dist/run/run-not-found.js +15 -0
- package/dist/run/run.d.ts +5 -4
- package/dist/run/run.js +1 -1
- package/dist/run/sandbox-receipts.d.ts +2 -2
- package/dist/run/sandbox-receipts.js +3 -3
- package/dist/run/shared-world-evidence.d.ts +36 -35
- package/dist/run/shared-world-evidence.js +4 -4
- package/dist/run/shared-world-shape.d.ts +1 -1
- package/dist/run/shared-world-shape.js +6 -6
- package/dist/run/stats.d.ts +12 -6
- package/dist/run/stats.js +116 -58
- package/dist/run/status.d.ts +8 -29
- package/dist/run/status.js +5 -27
- package/dist/run/stored-runs.js +2 -1
- package/dist/run/stream-shape.js +1 -1
- package/dist/run/streams.d.ts +6 -6
- package/dist/run/study-provenance.d.ts +47 -0
- package/dist/run/study-provenance.js +63 -0
- package/dist/run/study-result.d.ts +16 -0
- package/dist/run/study-result.js +9 -0
- package/dist/run/text.d.ts +2 -0
- package/dist/run/text.js +4 -0
- package/dist/run-lab.d.ts +7 -7
- package/dist/run-lab.js +1 -3
- package/dist/study/convert.d.ts +33 -0
- package/dist/study/convert.js +432 -0
- package/dist/study/field-paths.d.ts +12 -0
- package/dist/study/field-paths.js +126 -0
- package/dist/study/files.d.ts +26 -0
- package/dist/study/files.js +43 -0
- package/dist/study/migrate.d.ts +48 -0
- package/dist/study/migrate.js +408 -0
- package/dist/study/owned-files.d.ts +38 -0
- package/dist/study/owned-files.js +182 -0
- package/dist/subject/clone.d.ts +1 -1
- package/dist/subject/desktop-cli.d.ts +1 -1
- package/dist/subject/desktop-cli.js +2 -2
- package/dist/subject/local-tree-archive.js +1 -1
- package/dist/subject/local-tree.d.ts +1 -1
- package/dist/subject/node-bootstrap.js +1 -1
- package/dist/subject/runtime.js +8 -9
- package/dist/subject/serve.d.ts +1 -1
- package/dist/subject/serve.js +3 -3
- package/dist/subject/state.d.ts +1 -1
- package/dist/subject/steps.d.ts +5 -5
- package/dist/subject/steps.js +4 -4
- package/dist/substrates/command-failure.d.ts +3 -3
- package/dist/substrates/command-failure.js +3 -3
- package/dist/substrates/detached.d.ts +6 -6
- package/dist/substrates/detached.js +7 -7
- package/dist/substrates/e2b/cdp-probe.d.ts +9 -9
- package/dist/substrates/e2b/cdp-probe.js +14 -17
- package/dist/substrates/e2b/desktop-browser.d.ts +2 -2
- package/dist/substrates/e2b/desktop-browser.js +8 -8
- package/dist/substrates/e2b/desktop-cdp.d.ts +9 -9
- package/dist/substrates/e2b/desktop-cdp.js +8 -8
- package/dist/substrates/e2b/desktop-executor.d.ts +1 -1
- package/dist/substrates/e2b/desktop-executor.js +1 -1
- package/dist/substrates/e2b/desktop-geometry.d.ts +3 -3
- package/dist/substrates/e2b/desktop-geometry.js +7 -7
- package/dist/substrates/e2b/desktop-media.d.ts +1 -1
- package/dist/substrates/e2b/desktop-media.js +1 -1
- package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
- package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
- package/dist/substrates/e2b/sandbox.d.ts +1 -1
- package/dist/substrates/e2b/sandbox.js +1 -1
- package/dist/substrates/e2b/sdk.d.ts +11 -11
- package/dist/substrates/e2b/sdk.js +6 -6
- package/dist/tui/actions.d.ts +1 -1
- package/dist/tui/actions.js +13 -13
- package/dist/tui/contract.d.ts +16 -16
- package/dist/tui/contract.js +10 -10
- package/dist/tui/launch.d.ts +4 -4
- package/dist/tui/launch.js +18 -19
- package/dist/tui/project.js +5 -5
- package/dist/tui-app.js +82 -82
- package/dist/verify/actor.d.ts +8 -8
- package/dist/verify/actor.js +36 -36
- package/dist/verify/artifacts.d.ts +2 -2
- package/dist/verify/artifacts.js +3 -3
- package/dist/verify/context-growth.d.ts +9 -0
- package/dist/verify/context-growth.js +62 -0
- package/dist/verify/costs.d.ts +6 -6
- package/dist/verify/costs.js +8 -8
- package/dist/verify/shared-world-concurrent.d.ts +2 -2
- package/dist/verify/shared-world-concurrent.js +79 -76
- package/dist/verify/shared-world.d.ts +2 -2
- package/dist/verify/shared-world.js +16 -16
- package/dist/verify/subject.d.ts +4 -4
- package/dist/verify/subject.js +18 -18
- package/dist/verify/verify.js +92 -43
- package/docs/README.md +25 -32
- package/docs/architecture/actor-contract.md +56 -87
- package/docs/architecture/desktop-sessions.md +7 -7
- package/docs/architecture/external-public-shared-world.md +61 -59
- package/docs/architecture/github-feedback-loop.md +1 -4
- package/docs/architecture/guest-desktop.md +2 -2
- package/docs/architecture/observer.md +34 -34
- package/docs/architecture/restricted-codex-analysis.md +34 -28
- package/docs/architecture/serve.md +34 -37
- package/docs/architecture/state-driven-executor.md +55 -58
- package/docs/architecture/task-protocol-support.md +5 -5
- package/docs/architecture/terminal-product-route.md +67 -107
- package/docs/contracts/README.md +24 -0
- package/docs/contracts/adapter-admission.md +3 -3
- package/docs/contracts/adapter-fixtures.md +2 -5
- package/docs/contracts/core.md +1 -3
- package/docs/contracts/errors.md +62 -0
- package/docs/contracts/feedback.md +8 -9
- package/docs/contracts/policy.md +7 -12
- package/docs/contracts/run-bundle.md +45 -44
- package/docs/contracts/schemas.md +421 -362
- package/docs/contracts/study-analysis.md +3 -3
- package/docs/contracts/study-costs.md +11 -7
- package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
- package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
- package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
- package/docs/principles/actor-fidelity.md +4 -4
- package/docs/principles/engineering.md +3 -3
- package/docs/principles/invariants-and-defaults.md +38 -38
- package/docs/principles/self-driving-harness.md +1 -5
- package/docs/principles/three-roles.md +1 -1
- package/docs/product/automatic-analysis.md +7 -7
- package/examples/participant/README.md +5 -5
- package/examples/participant/run.mjs +11 -10
- package/examples/scorer/README.md +3 -3
- package/examples/scorer/run.mjs +11 -12
- package/package.json +16 -17
- package/skills/humanish/SKILL.md +60 -58
- package/skills/humanish/agents/openai.yaml +1 -1
- package/AGENTS.md +0 -99
- package/CONTRIBUTING.md +0 -148
- package/dist/actors/codex/qualified-versions.d.ts +0 -72
- package/dist/actors/codex/qualified-versions.js +0 -132
- package/dist/cli/commands/lab.d.ts +0 -3
- package/dist/cli/commands/lab.js +0 -199
- package/dist/cli/renamed-options.d.ts +0 -11
- package/dist/cli/renamed-options.js +0 -18
- package/dist/observer/static.d.ts +0 -39
- package/dist/observer/static.js +0 -369
- package/docs/architecture/comms-inbox.md +0 -122
- package/docs/architecture/desktop-recording.md +0 -80
- package/docs/architecture/local-browser-runtime.md +0 -178
- package/docs/architecture/observer-review.md +0 -144
- package/docs/architecture/participant-media.md +0 -90
- package/docs/architecture/project-layout.md +0 -62
- package/docs/architecture/real-email-receiving.md +0 -136
- package/docs/assets/humanish-drawdb-hero.png +0 -0
- package/docs/assets/humanish-observer-hero.png +0 -0
- package/docs/goals/current.md +0 -207
- package/docs/product/lobby-trivia-3player-external-public.md +0 -77
- package/docs/product/open-source-install-experience.md +0 -240
- package/docs/ramp/README.md +0 -295
- package/docs/release/open-source-readiness.md +0 -222
- package/docs/release/public-readiness-standard.md +0 -210
- package/docs/roadmap/world-class-open-source-v0.md +0 -311
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// File operations for humanish migrate that never replace or delete a file the run did not create.
|
|
2
|
+
// A new name is taken with an exclusive create or link(), which fail when the name is in use. A
|
|
3
|
+
// file is removed by renaming it to a random name first and checking it there, so a file saved over
|
|
4
|
+
// the name in the meantime keeps it.
|
|
5
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
6
|
+
import { constants } from "node:fs";
|
|
7
|
+
import { lstat, mkdir, open, readFile, rename, unlink } from "node:fs/promises";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { isNodeError } from "../run/type-guards.js";
|
|
10
|
+
export function sha256(bytes) {
|
|
11
|
+
return createHash("sha256").update(bytes).digest("hex");
|
|
12
|
+
}
|
|
13
|
+
// A source must be a single-link regular file. A file this run wrote may briefly have two links
|
|
14
|
+
// while a move is committed, so `ours` relaxes that.
|
|
15
|
+
export async function fileIdentity(absolutePath, ours = false) {
|
|
16
|
+
const stats = await lstat(absolutePath, { bigint: true });
|
|
17
|
+
if (!stats.isFile() || (!ours && stats.nlink !== 1n))
|
|
18
|
+
throw new Error("not a single-link regular file");
|
|
19
|
+
return {
|
|
20
|
+
dev: stats.dev,
|
|
21
|
+
ino: stats.ino,
|
|
22
|
+
size: stats.size,
|
|
23
|
+
sha256: sha256(await readFile(absolutePath)),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function sameFile(left, right) {
|
|
27
|
+
return (left.dev === right.dev &&
|
|
28
|
+
left.ino === right.ino &&
|
|
29
|
+
left.size === right.size &&
|
|
30
|
+
left.sha256 === right.sha256);
|
|
31
|
+
}
|
|
32
|
+
// Walk a directory below the project root one segment at a time, refusing a symbolic link or a
|
|
33
|
+
// non-directory. `create` makes missing segments and records each one it made.
|
|
34
|
+
export async function bindDirectory(root, relativeDir, created) {
|
|
35
|
+
let current = root;
|
|
36
|
+
for (const segment of relativeDir.split(path.sep).filter(Boolean)) {
|
|
37
|
+
current = path.join(current, segment);
|
|
38
|
+
let stats;
|
|
39
|
+
try {
|
|
40
|
+
stats = await lstat(current, { bigint: true });
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
if (!(isNodeError(error) && error.code === "ENOENT") || created === undefined) {
|
|
44
|
+
if (isNodeError(error) && error.code === "ENOENT")
|
|
45
|
+
return undefined;
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
await mkdir(current, { mode: 0o755 });
|
|
49
|
+
created.push(current);
|
|
50
|
+
stats = await lstat(current, { bigint: true });
|
|
51
|
+
}
|
|
52
|
+
if (stats.isSymbolicLink() || !stats.isDirectory())
|
|
53
|
+
throw new Error(`${path.relative(root, current)} is not a plain directory`);
|
|
54
|
+
}
|
|
55
|
+
const stats = await lstat(current, { bigint: true });
|
|
56
|
+
return { physicalPath: current, dev: stats.dev, ino: stats.ino };
|
|
57
|
+
}
|
|
58
|
+
export async function assertDirectory(directory, root) {
|
|
59
|
+
const again = await bindDirectory(root, path.relative(root, directory.physicalPath));
|
|
60
|
+
if (again === undefined || again.dev !== directory.dev || again.ino !== directory.ino)
|
|
61
|
+
throw new Error(`${path.relative(root, directory.physicalPath)} changed`);
|
|
62
|
+
}
|
|
63
|
+
export async function exists(absolutePath) {
|
|
64
|
+
try {
|
|
65
|
+
await lstat(absolutePath);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (isNodeError(error) && error.code === "ENOENT")
|
|
70
|
+
return false;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Create a file exclusively and write it. Its inode is recorded the moment the create succeeds, so
|
|
75
|
+
// a failed write is still known to be this run's and a taken name never is. The bytes are read back
|
|
76
|
+
// through the same descriptor, so the identity recorded is this file's, whatever holds the name.
|
|
77
|
+
export async function writeOwned(owned, bytes, mode) {
|
|
78
|
+
const data = Buffer.from(bytes);
|
|
79
|
+
const handle = await open(owned.path, constants.O_CREAT | constants.O_EXCL | constants.O_RDWR | constants.O_NOFOLLOW, mode);
|
|
80
|
+
try {
|
|
81
|
+
const opened = await handle.stat({ bigint: true });
|
|
82
|
+
owned.inode = { dev: opened.dev, ino: opened.ino };
|
|
83
|
+
await handle.writeFile(data);
|
|
84
|
+
await handle.sync();
|
|
85
|
+
const stats = await handle.stat({ bigint: true });
|
|
86
|
+
const back = Buffer.alloc(Number(stats.size));
|
|
87
|
+
await handle.read(back, 0, back.length, 0);
|
|
88
|
+
owned.identity = { dev: stats.dev, ino: stats.ino, size: stats.size, sha256: sha256(back) };
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
await handle.close();
|
|
92
|
+
}
|
|
93
|
+
if (owned.identity.sha256 !== sha256(data))
|
|
94
|
+
throw new Error(`${path.basename(owned.path)} did not read back as written`);
|
|
95
|
+
}
|
|
96
|
+
// Remove the file at `file` only if `matches` says it is the expected one. The name is first renamed
|
|
97
|
+
// to a random one and the file checked there, so a file saved over the name in between is never
|
|
98
|
+
// deleted: it gets its name back, or keeps the random one. Returns the path kept, or undefined once
|
|
99
|
+
// the file is removed or was already gone.
|
|
100
|
+
export async function removeChecked(file, matches, linkFile) {
|
|
101
|
+
const aside = `${file}.migrate-${randomUUID()}.del`;
|
|
102
|
+
try {
|
|
103
|
+
await rename(file, aside);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
if (isNodeError(error) && error.code === "ENOENT")
|
|
107
|
+
return undefined;
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
const current = await fileIdentity(aside, true).catch(() => undefined);
|
|
111
|
+
if (current !== undefined && matches(current)) {
|
|
112
|
+
await unlink(aside);
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
return (await restoreName(aside, file, linkFile)) ? file : aside;
|
|
116
|
+
}
|
|
117
|
+
// Remove a file this run created if it still holds this run's bytes, or was cut short while being
|
|
118
|
+
// written. Returns the path kept, if any.
|
|
119
|
+
export async function removeOwned(owned, linkFile) {
|
|
120
|
+
const inode = owned.inode;
|
|
121
|
+
if (inode === undefined)
|
|
122
|
+
return undefined;
|
|
123
|
+
return removeChecked(owned.path, (current) => current.dev === inode.dev &&
|
|
124
|
+
current.ino === inode.ino &&
|
|
125
|
+
(owned.identity === undefined || sameFile(current, owned.identity)), linkFile);
|
|
126
|
+
}
|
|
127
|
+
// Hard links need filesystem support. Without it a file is created exclusively and read back.
|
|
128
|
+
export const NO_HARD_LINKS = new Set(["EPERM", "ENOTSUP", "EOPNOTSUPP", "EXDEV"]);
|
|
129
|
+
// Give the file at `from` the name `to` without replacing anything there: link() fails on a taken
|
|
130
|
+
// name, and so does the exclusive create a filesystem without hard links gets instead. True once
|
|
131
|
+
// `to` holds the file and `from` is gone. False when `to` was taken, or was replaced before `from`
|
|
132
|
+
// could go, which leaves `from` as the file's only name.
|
|
133
|
+
export async function restoreName(from, to, linkFile) {
|
|
134
|
+
let placed;
|
|
135
|
+
let copied;
|
|
136
|
+
let owned;
|
|
137
|
+
try {
|
|
138
|
+
await linkFile(from, to);
|
|
139
|
+
const stats = await lstat(from, { bigint: true });
|
|
140
|
+
placed = { dev: stats.dev, ino: stats.ino };
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
if (isNodeError(error) && error.code === "EEXIST")
|
|
144
|
+
return false;
|
|
145
|
+
if (!(isNodeError(error) && NO_HARD_LINKS.has(error.code ?? "")))
|
|
146
|
+
throw error;
|
|
147
|
+
// Without hard links the file is copied. What was copied is recorded, so an edit made to
|
|
148
|
+
// `from` during the copy keeps `from`.
|
|
149
|
+
const stats = await lstat(from, { bigint: true });
|
|
150
|
+
// Only a regular file is copied; anything else keeps the name it has.
|
|
151
|
+
if (!stats.isFile())
|
|
152
|
+
return false;
|
|
153
|
+
const bytes = await readFile(from);
|
|
154
|
+
copied = { dev: stats.dev, ino: stats.ino, size: BigInt(bytes.length), sha256: sha256(bytes) };
|
|
155
|
+
const copy = { path: to };
|
|
156
|
+
try {
|
|
157
|
+
await writeOwned(copy, bytes, Number(stats.mode & 511n));
|
|
158
|
+
}
|
|
159
|
+
catch (copyError) {
|
|
160
|
+
if (copy.inode === undefined && isNodeError(copyError) && copyError.code === "EEXIST")
|
|
161
|
+
return false;
|
|
162
|
+
if (copy.inode !== undefined)
|
|
163
|
+
await removeOwned(copy, linkFile).catch(() => undefined);
|
|
164
|
+
throw copyError;
|
|
165
|
+
}
|
|
166
|
+
placed = copy.inode;
|
|
167
|
+
owned = copy;
|
|
168
|
+
}
|
|
169
|
+
const now = await lstat(to, { bigint: true }).catch(() => undefined);
|
|
170
|
+
if (now === undefined || now.dev !== placed.dev || now.ino !== placed.ino)
|
|
171
|
+
return false;
|
|
172
|
+
if (copied === undefined) {
|
|
173
|
+
await unlink(from);
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
const expected = copied;
|
|
177
|
+
if ((await removeChecked(from, (current) => sameFile(current, expected), linkFile)) === undefined)
|
|
178
|
+
return true;
|
|
179
|
+
// `from` changed during the copy: it stays, and the stale copy goes.
|
|
180
|
+
await removeOwned(owned, linkFile).catch(() => undefined);
|
|
181
|
+
return false;
|
|
182
|
+
}
|
package/dist/subject/clone.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export declare function provisionCloneSubject(shell: Shell, args: {
|
|
|
25
25
|
state?: LabSubjectState;
|
|
26
26
|
hasGithubToken: boolean;
|
|
27
27
|
requestTimeoutMs: number;
|
|
28
|
-
/** Literal scrubber for known provisioned values, applied to log tails
|
|
28
|
+
/** Literal scrubber for known provisioned values, applied to log tails pre-truncation. */
|
|
29
29
|
scrub: (text: string) => string;
|
|
30
30
|
/** Called the moment the cloned commit resolves, so provenance survives later failures. */
|
|
31
31
|
onCommit?: (commit: string) => void;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Shell } from "../substrates/shell.js";
|
|
2
2
|
import { type SubjectPhaseEvent } from "./steps.js";
|
|
3
3
|
/**
|
|
4
|
-
* Prepare a CLI study's runtime and, only when declared, its product
|
|
4
|
+
* Prepare a CLI study's runtime and, only when declared, its product.
|
|
5
5
|
*
|
|
6
6
|
* The install runs unkeyed and before the session starts, for the same reason the clone route
|
|
7
7
|
* provisions its subject first: what is being studied begins when the participant looks at the
|
|
@@ -4,7 +4,7 @@ import { NODE_BOOTSTRAP_COMMAND, NODE_BOOTSTRAP_TIMEOUT_MS } from "./node-bootst
|
|
|
4
4
|
import { runDetachedStep } from "../substrates/detached.js";
|
|
5
5
|
import { emitPhaseCompleted, emitPhaseStarted, INSTALL_TIMEOUT_MS, } from "./steps.js";
|
|
6
6
|
/**
|
|
7
|
-
* Prepare a CLI study's runtime and, only when declared, its product
|
|
7
|
+
* Prepare a CLI study's runtime and, only when declared, its product.
|
|
8
8
|
*
|
|
9
9
|
* The install runs unkeyed and before the session starts, for the same reason the clone route
|
|
10
10
|
* provisions its subject first: what is being studied begins when the participant looks at the
|
|
@@ -44,7 +44,7 @@ export async function provisionDesktopCli(shell, args) {
|
|
|
44
44
|
if (!result.ok) {
|
|
45
45
|
// Fail closed: a participant handed a desktop where the product is not installed would produce
|
|
46
46
|
// a transcript about a missing command, and that finding belongs to the harness, not the tool.
|
|
47
|
-
// The tail rides along, scrubbed before truncation like every other provisioning failure
|
|
47
|
+
// The tail rides along, scrubbed before truncation like every other provisioning failure. A
|
|
48
48
|
// bare "install failed" is unactionable to whoever wrote the command.
|
|
49
49
|
throw new Error(args.scrub(`desktop-cli install failed for "${args.product}" (${result.timedOut ? "timed out" : `exit ${result.exitCode ?? "?"}`}): ${failureTail(args.scrub(result.logTail))}`));
|
|
50
50
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// that cannot happen: enumerateLocalTree() builds one entries array, and both
|
|
9
9
|
// the hash and the tar file list are derived from that same array.
|
|
10
10
|
//
|
|
11
|
-
// See docs/goals/local-tree-subject/goal.md ("Packing design") for the full
|
|
11
|
+
// See docs/history/goals/local-tree-subject/goal.md ("Packing design") for the full
|
|
12
12
|
// contract implemented here. Node builtins only, no npm dependencies.
|
|
13
13
|
import { execFileSync } from "node:child_process";
|
|
14
14
|
import { createHash } from "node:crypto";
|
|
@@ -18,7 +18,7 @@ export declare function provisionLocalTreeSubject(shell: Shell, args: {
|
|
|
18
18
|
/** Declared subject state (seed steps; external declaration is provenance-only). */
|
|
19
19
|
state?: LabSubjectState;
|
|
20
20
|
requestTimeoutMs: number;
|
|
21
|
-
/** Literal scrubber for known provisioned values, applied to log tails
|
|
21
|
+
/** Literal scrubber for known provisioned values, applied to log tails pre-truncation. */
|
|
22
22
|
scrub: (text: string) => string;
|
|
23
23
|
/** Called the moment each state step finishes, success or failure. */
|
|
24
24
|
onStateStep?: (record: RunSubjectStateStepRecord) => void;
|
|
@@ -54,7 +54,7 @@ export const NODE_BOOTSTRAP_COMMAND = [
|
|
|
54
54
|
"for executable in node npm npx; do",
|
|
55
55
|
` sudo -n ln -sfn "$node_target/bin/$executable" "/usr/local/bin/$executable"`,
|
|
56
56
|
"done",
|
|
57
|
-
// Keep global product executables on the existing ordinary/sudo `PATH
|
|
57
|
+
// Keep global product executables on the existing ordinary/sudo `PATH`. The new
|
|
58
58
|
// versioned distribution is the only config we modify; no user/global npmrc or profile.
|
|
59
59
|
`sudo -n "$node_target/bin/node" -e '${NODE_NPM_PREFIX_SCRIPT}' "$node_target/lib/node_modules/npm/npmrc"`,
|
|
60
60
|
"hash -r",
|
package/dist/subject/runtime.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
// Provide the runtime a subject's serve pipeline needs, instead of failing at exit 127
|
|
1
|
+
// Provide the runtime a subject's serve pipeline needs, instead of failing at exit 127.
|
|
2
2
|
//
|
|
3
|
-
// The stock E2B `desktop` template ships python3 and curl but no Node.
|
|
4
|
-
//
|
|
5
|
-
// for
|
|
6
|
-
//
|
|
7
|
-
// `pnpm: command not found` after a sandbox had been created and paid for.
|
|
3
|
+
// The stock E2B `desktop` template ships python3 and curl but no Node. So the in-sandbox comms
|
|
4
|
+
// catch runs on python3, the terminal route bootstraps Node explicitly, and this module provides
|
|
5
|
+
// Node for the computer-use clone/local-tree route. Without it, any study whose `serve.install`
|
|
6
|
+
// runs npm or pnpm dies with `pnpm: command not found` after its sandbox is created and paid for.
|
|
8
7
|
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
8
|
+
// That failure is invisible up front: `lab inspect` is clean, the plan prints normally, the sandbox
|
|
9
|
+
// provisions, and the first signal is a shell exit code attributed to "subject install failed".
|
|
11
10
|
// Nobody can debug that from the outside.
|
|
12
11
|
//
|
|
13
12
|
// The harness provides the runtime instead of warning about it. An adopter writing a lab for a Node app should not have to
|
|
14
|
-
// know which binaries the template happens to carry
|
|
13
|
+
// know which binaries the template happens to carry. That is the harness's job, and the terminal
|
|
15
14
|
// route already treats it that way. Detection is conservative and the bootstrap is skipped whenever
|
|
16
15
|
// a runtime is already present, so a custom template that ships Node pays nothing.
|
|
17
16
|
/** Package managers and runtimes whose absence on the stock template breaks a serve pipeline. */
|
package/dist/subject/serve.d.ts
CHANGED
|
@@ -25,7 +25,7 @@ export declare function runSubjectServePipeline(shell: Shell, args: {
|
|
|
25
25
|
/** Declared subject state (seed steps; external declaration is provenance-only). */
|
|
26
26
|
state?: LabSubjectState;
|
|
27
27
|
requestTimeoutMs: number;
|
|
28
|
-
/** Literal scrubber for known provisioned values, applied to log tails
|
|
28
|
+
/** Literal scrubber for known provisioned values, applied to log tails pre-truncation. */
|
|
29
29
|
scrub: (text: string) => string;
|
|
30
30
|
/** Called the moment each state step finishes, success or failure. */
|
|
31
31
|
onStateStep?: (record: RunSubjectStateStepRecord) => void;
|
package/dist/subject/serve.js
CHANGED
|
@@ -8,7 +8,7 @@ import { emitPhaseCompleted, emitPhaseStarted, INSTALL_TIMEOUT_MS, isoNow, SUBJE
|
|
|
8
8
|
const BUILD_TIMEOUT_MS = 10 * 60_000;
|
|
9
9
|
const DEFAULT_READY_TIMEOUT_MS = 180_000;
|
|
10
10
|
/**
|
|
11
|
-
* Run a provisioning step and, when it fails with an exit code, run it once more
|
|
11
|
+
* Run a provisioning step and, when it fails with an exit code, run it once more: a
|
|
12
12
|
* transient network error inside `npm install` is the common case. A timeout is not retried: its
|
|
13
13
|
* budget is already spent, and a second wait would double it. The retry runs under its own step
|
|
14
14
|
* name so both logs stay.
|
|
@@ -121,7 +121,7 @@ export async function runSubjectServePipeline(shell, args) {
|
|
|
121
121
|
await refresh();
|
|
122
122
|
}
|
|
123
123
|
/**
|
|
124
|
-
* Provide the runtime the pipeline needs before running it
|
|
124
|
+
* Provide the runtime the pipeline needs before running it. The stock desktop template
|
|
125
125
|
* ships python3 and curl but no Node. Probe first, so a template that ships its own Node pays
|
|
126
126
|
* nothing.
|
|
127
127
|
*/
|
|
@@ -187,7 +187,7 @@ async function installSubject(step, command) {
|
|
|
187
187
|
? "subject install failed twice"
|
|
188
188
|
: "subject install failed");
|
|
189
189
|
if (!install.ok) {
|
|
190
|
-
// Lead with the line a person can act on; npm's own trace follows it
|
|
190
|
+
// Lead with the line a person can act on; npm's own trace follows it.
|
|
191
191
|
const headline = install.timedOut
|
|
192
192
|
? `subject install timed out after ${step.serve.installTimeoutMs ?? INSTALL_TIMEOUT_MS}ms`
|
|
193
193
|
: install.attempts === 2
|
package/dist/subject/state.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export declare function commandDigestOf(command: string): string;
|
|
|
14
14
|
export declare function runStateSteps(shell: Shell, when: LabStateStepWhen, args: {
|
|
15
15
|
state?: LabSubjectState;
|
|
16
16
|
requestTimeoutMs: number;
|
|
17
|
-
/** Literal scrubber for known provisioned values, applied to log tails
|
|
17
|
+
/** Literal scrubber for known provisioned values, applied to log tails pre-truncation. */
|
|
18
18
|
scrub: (text: string) => string;
|
|
19
19
|
onStateStep?: (record: RunSubjectStateStepRecord) => void;
|
|
20
20
|
onPhase?: (event: SubjectPhaseEvent) => void;
|
package/dist/subject/steps.d.ts
CHANGED
|
@@ -25,13 +25,13 @@ export declare function emitPhaseStarted(onPhase: ((event: SubjectPhaseEvent) =>
|
|
|
25
25
|
/** Emit the matching phase-completed event: always carries ok and durationMs (>= 0). */
|
|
26
26
|
export declare function emitPhaseCompleted(onPhase: ((event: SubjectPhaseEvent) => void) | undefined, now: () => number, startedAt: number, phase: string, ok: boolean, message: string): void;
|
|
27
27
|
/** Default phase-boundary sink (stderr): one line per event, prefixed with the participant id
|
|
28
|
-
* only when
|
|
29
|
-
*
|
|
28
|
+
* only when the run has more than one participant. A single participant still gets every line:
|
|
29
|
+
* a silent clone, install, build and ready boot is the bug this event stream exists to close.
|
|
30
30
|
* Overridable via LabDeps.subjectPhaseSink so deterministic tests capture instead of writing to
|
|
31
31
|
* the real stderr. */
|
|
32
|
-
export declare function defaultSubjectPhaseSink(event: SubjectPhaseEvent,
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
export declare function defaultSubjectPhaseSink(event: SubjectPhaseEvent, participant: {
|
|
33
|
+
readonly id: string;
|
|
34
|
+
readonly count: number;
|
|
35
35
|
}): void;
|
|
36
36
|
/** The shared-world subject's phase line: one shared plane, so no participant prefix. */
|
|
37
37
|
export declare function defaultSharedWorldPhaseSink(event: SubjectPhaseEvent): void;
|
package/dist/subject/steps.js
CHANGED
|
@@ -23,13 +23,13 @@ export function emitPhaseCompleted(onPhase, now, startedAt, phase, ok, message)
|
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
25
|
/** Default phase-boundary sink (stderr): one line per event, prefixed with the participant id
|
|
26
|
-
* only when
|
|
27
|
-
*
|
|
26
|
+
* only when the run has more than one participant. A single participant still gets every line:
|
|
27
|
+
* a silent clone, install, build and ready boot is the bug this event stream exists to close.
|
|
28
28
|
* Overridable via LabDeps.subjectPhaseSink so deterministic tests capture instead of writing to
|
|
29
29
|
* the real stderr. */
|
|
30
|
-
export function defaultSubjectPhaseSink(event,
|
|
30
|
+
export function defaultSubjectPhaseSink(event, participant) {
|
|
31
31
|
const durationSuffix = event.durationMs === undefined ? "" : ` (${event.durationMs}ms)`;
|
|
32
|
-
const prefix =
|
|
32
|
+
const prefix = participant.count > 1 ? `humanish computer-use [${participant.id}]` : "humanish computer-use";
|
|
33
33
|
process.stderr.write(`${prefix}: ${event.message}${durationSuffix}\n`);
|
|
34
34
|
}
|
|
35
35
|
/** The shared-world subject's phase line: one shared plane, so no participant prefix. */
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* True when `error` is (structurally) the @e2b/desktop CommandExitError: a
|
|
3
|
-
* non-zero substrate command exit that the real Sandbox surfaces as a
|
|
3
|
+
* non-zero substrate command exit that the real Sandbox surfaces as a throw.
|
|
4
4
|
* Matches either the SDK class name (`name === "CommandExitError"`) or any object
|
|
5
5
|
* carrying a numeric `exitCode` (the same field `commandFailureInfo` reads, so a
|
|
6
6
|
* structural fake is covered without importing the SDK class).
|
|
7
7
|
*
|
|
8
|
-
* Deliberately conservative
|
|
8
|
+
* Deliberately conservative: it is the recoverability predicate the CUA loop uses
|
|
9
9
|
* to skip a single failed desktop action instead of ending the whole run: it must
|
|
10
|
-
*
|
|
10
|
+
* not match a deadline/abort control-flow signal (those subclass Error without a
|
|
11
11
|
* name override or an exitCode) or a generic Error with no exit signal, so only a
|
|
12
12
|
* genuine substrate-command failure is treated as recoverable.
|
|
13
13
|
*/
|
|
@@ -12,14 +12,14 @@
|
|
|
12
12
|
import { tailOf } from "./shell.js";
|
|
13
13
|
/**
|
|
14
14
|
* True when `error` is (structurally) the @e2b/desktop CommandExitError: a
|
|
15
|
-
* non-zero substrate command exit that the real Sandbox surfaces as a
|
|
15
|
+
* non-zero substrate command exit that the real Sandbox surfaces as a throw.
|
|
16
16
|
* Matches either the SDK class name (`name === "CommandExitError"`) or any object
|
|
17
17
|
* carrying a numeric `exitCode` (the same field `commandFailureInfo` reads, so a
|
|
18
18
|
* structural fake is covered without importing the SDK class).
|
|
19
19
|
*
|
|
20
|
-
* Deliberately conservative
|
|
20
|
+
* Deliberately conservative: it is the recoverability predicate the CUA loop uses
|
|
21
21
|
* to skip a single failed desktop action instead of ending the whole run: it must
|
|
22
|
-
*
|
|
22
|
+
* not match a deadline/abort control-flow signal (those subclass Error without a
|
|
23
23
|
* name override or an exitCode) or a generic Error with no exit signal, so only a
|
|
24
24
|
* genuine substrate-command failure is treated as recoverable.
|
|
25
25
|
*/
|
|
@@ -10,7 +10,7 @@ export declare function detachedTimersOf(options: DetachedTimers): DetachedTimer
|
|
|
10
10
|
export interface DetachedStepOptions extends DetachedTimers {
|
|
11
11
|
/** Short [a-z0-9-] label; names the script/status/log files under /tmp. */
|
|
12
12
|
name: string;
|
|
13
|
-
/** The shell command to run (the lab author's own command
|
|
13
|
+
/** The shell command to run (the lab author's own command: package.json-script trust). */
|
|
14
14
|
command: string;
|
|
15
15
|
cwd?: string;
|
|
16
16
|
/** Wall-clock budget for the step. */
|
|
@@ -22,19 +22,19 @@ export interface DetachedStepResult {
|
|
|
22
22
|
ok: boolean;
|
|
23
23
|
exitCode?: number;
|
|
24
24
|
timedOut: boolean;
|
|
25
|
-
/** Capped,
|
|
25
|
+
/** Capped, unredacted log tail; redact before persisting. */
|
|
26
26
|
logTail: string;
|
|
27
27
|
}
|
|
28
|
-
/** Read the capped log tail for a step (raw
|
|
28
|
+
/** Read the capped log tail for a step (raw; caller redacts). */
|
|
29
29
|
export declare function readDetachedLog(shell: Shell, name: string, requestTimeoutMs?: number): Promise<string>;
|
|
30
30
|
/**
|
|
31
|
-
* Run a
|
|
31
|
+
* Run a bounded step (install/build) detached, polling its atomic status file until it
|
|
32
32
|
* exits or the budget runs out. On timeout the process group is killed and the log tail is
|
|
33
33
|
* still captured so failures stay diagnosable.
|
|
34
34
|
*/
|
|
35
35
|
export declare function runDetachedStep(shell: Shell, options: DetachedStepOptions): Promise<DetachedStepResult>;
|
|
36
36
|
/**
|
|
37
|
-
* Launch a
|
|
37
|
+
* Launch a long-lived process (the subject's server) fully detached and return immediately.
|
|
38
38
|
* No status polling: liveness is the caller's readiness probe, and reclamation belongs to
|
|
39
39
|
* the sandbox lifecycle (create with kill-on-timeout).
|
|
40
40
|
*/
|
|
@@ -45,7 +45,7 @@ export declare function startDetachedProcess(shell: Shell, options: {
|
|
|
45
45
|
requestTimeoutMs?: number;
|
|
46
46
|
}): Promise<void>;
|
|
47
47
|
/**
|
|
48
|
-
* Poll a URL from
|
|
48
|
+
* Poll a URL from inside the sandbox until it answers 2xx/3xx or the budget runs out.
|
|
49
49
|
* Returns true when the subject is ready.
|
|
50
50
|
*/
|
|
51
51
|
export declare function probeUrl(shell: Shell, url: string, options: {
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
// Detached process management over a Shell, the primitive behind serving a subject app in the
|
|
2
2
|
// sandbox. A foreground command hits its deadline on long-running work, so long work runs detached:
|
|
3
3
|
//
|
|
4
|
-
// - Scripts are written via `writeFile`, never heredocs
|
|
4
|
+
// - Scripts are written via `writeFile`, never heredocs, which eliminates the
|
|
5
5
|
// sentinel-collision bug class (a command line that equals the heredoc terminator) by
|
|
6
6
|
// construction.
|
|
7
|
-
// - Bounded steps (install/build) run detached with an
|
|
7
|
+
// - Bounded steps (install/build) run detached with an atomically-written status file
|
|
8
8
|
// (write tmp + mv), polled by short foreground commands; a timeout kills the process
|
|
9
9
|
// group and surfaces a capped log tail for the caller to redact and persist.
|
|
10
10
|
// - Long-lived steps (a dev/prod server) launch fully detached through `Shell.start`; the
|
|
11
11
|
// sandbox lifecycle (kill-on-timeout) owns their reclamation.
|
|
12
12
|
// - Readiness is an explicit curl probe against the declared URL.
|
|
13
13
|
//
|
|
14
|
-
// Log tails are returned
|
|
14
|
+
// Log tails are returned raw; callers must pass them through redaction before persisting
|
|
15
15
|
// (build output can echo env values and paths).
|
|
16
16
|
import { runOrThrow, shellQuote, throwOnExit } from "./shell.js";
|
|
17
17
|
const WORK_ROOT = "/tmp/humanish-subject";
|
|
@@ -62,14 +62,14 @@ async function writeAndLaunch(shell, name, command, cwd, requestTimeoutMs) {
|
|
|
62
62
|
await shell.writeFile(scriptPath, wrapperScript(name, command, cwd));
|
|
63
63
|
throwOnExit(await shell.start(`bash ${shellQuote(scriptPath)}`, { requestTimeoutMs }));
|
|
64
64
|
}
|
|
65
|
-
/** Read the capped log tail for a step (raw
|
|
65
|
+
/** Read the capped log tail for a step (raw; caller redacts). */
|
|
66
66
|
export async function readDetachedLog(shell, name, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {
|
|
67
67
|
assertName(name);
|
|
68
68
|
const result = await runOrThrow(shell, `tail -c ${LOG_TAIL_BYTES} ${shellQuote(`${stepDir(name)}/log.txt`)} 2>/dev/null || true`, { requestTimeoutMs });
|
|
69
69
|
return result.stdout;
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
* Run a
|
|
72
|
+
* Run a bounded step (install/build) detached, polling its atomic status file until it
|
|
73
73
|
* exits or the budget runs out. On timeout the process group is killed and the log tail is
|
|
74
74
|
* still captured so failures stay diagnosable.
|
|
75
75
|
*/
|
|
@@ -105,7 +105,7 @@ export async function runDetachedStep(shell, options) {
|
|
|
105
105
|
}
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
|
-
* Launch a
|
|
108
|
+
* Launch a long-lived process (the subject's server) fully detached and return immediately.
|
|
109
109
|
* No status polling: liveness is the caller's readiness probe, and reclamation belongs to
|
|
110
110
|
* the sandbox lifecycle (create with kill-on-timeout).
|
|
111
111
|
*/
|
|
@@ -113,7 +113,7 @@ export async function startDetachedProcess(shell, options) {
|
|
|
113
113
|
await writeAndLaunch(shell, options.name, options.command, options.cwd, options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS);
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
|
-
* Poll a URL from
|
|
116
|
+
* Poll a URL from inside the sandbox until it answers 2xx/3xx or the budget runs out.
|
|
117
117
|
* Returns true when the subject is ready.
|
|
118
118
|
*/
|
|
119
119
|
export async function probeUrl(shell, url, options) {
|
|
@@ -11,29 +11,29 @@ export interface ChromeCdpProbeArgs {
|
|
|
11
11
|
targetId?: string;
|
|
12
12
|
/**
|
|
13
13
|
* "pinned" (default): the launch-time target, for launch geometry and emulation attribution.
|
|
14
|
-
* "active": the tab the participant is driving
|
|
14
|
+
* "active": the tab the participant is driving now; Chrome's /json lists page
|
|
15
15
|
* targets most-recently-focused first. The state observer must follow the participant: a
|
|
16
|
-
* verification link that opens in a
|
|
16
|
+
* verification link that opens in a new tab left a pinned observer reading the old tab forever,
|
|
17
17
|
* so the observed URL never changed again and stopWhen/task criteria went blind (a live run's
|
|
18
|
-
* funnel read reach-dashboard 0/2 under a screenshot
|
|
18
|
+
* funnel read reach-dashboard 0/2 under a screenshot of the dashboard). Final geometry follows
|
|
19
19
|
* this target too: a closed launch tab is unavailable, and a background tab may report stale
|
|
20
20
|
* layout dimensions or zero outer bounds after navigation.
|
|
21
21
|
*/
|
|
22
22
|
prefer?: ChromeCdpPagePreference;
|
|
23
23
|
/**
|
|
24
24
|
* "state": url/title/text/scrollY. "geometry": outer window + CSS viewport. "port": resolution
|
|
25
|
-
* only. "emulate": apply mobile emulation
|
|
25
|
+
* only. "emulate": apply mobile emulation to the selected page and exit (the overrides that
|
|
26
26
|
* are session-scoped, UA / touch / DPR, lapse when the socket closes). "hold": the same over a browser-level
|
|
27
27
|
* socket, then stay attached until killed (how a participant keeps them for its whole life) and attach
|
|
28
28
|
* to every page target Chrome opens later, sending it the same overrides and a reload the moment
|
|
29
|
-
* it exists, never pausing it
|
|
29
|
+
* it exists, never pausing it. "fidelity": read
|
|
30
30
|
* back what the page reports about itself (UA, DPR, viewport, touch), the proof for the bundle.
|
|
31
31
|
*/
|
|
32
32
|
mode: "state" | "geometry" | "port" | "emulate" | "hold" | "fidelity";
|
|
33
33
|
/** For "emulate": what to apply. */
|
|
34
34
|
emulation?: ChromeMobileEmulationRequest;
|
|
35
35
|
}
|
|
36
|
-
/** Mobile emulation request
|
|
36
|
+
/** Mobile emulation request: the CDP Emulation domain applied to one page target. */
|
|
37
37
|
export interface ChromeMobileEmulationRequest {
|
|
38
38
|
width: number;
|
|
39
39
|
height: number;
|
|
@@ -82,9 +82,9 @@ export interface ChromeCdpProbeResult {
|
|
|
82
82
|
* headless Chrome).
|
|
83
83
|
*
|
|
84
84
|
* WebSocket is hand-rolled because python's stdlib has no client: one masked text frame out, frames
|
|
85
|
-
* in until the reply with id 1 arrives, 1.5 s budget, and
|
|
85
|
+
* in until the reply with id 1 arrives, 1.5 s budget, and no Origin header (Chrome refuses
|
|
86
86
|
* cross-origin DevTools sockets unless --remote-allow-origins is set; a header-less client is a
|
|
87
|
-
* local one). urllib is opened
|
|
87
|
+
* local one). urllib is opened without proxy handlers so a sandbox-wide http_proxy cannot redirect
|
|
88
88
|
* a loopback read.
|
|
89
89
|
*/
|
|
90
90
|
export declare const CHROME_CDP_PROBE_PY: string;
|
|
@@ -93,7 +93,7 @@ export declare function chromeCdpProbeCommand(args: ChromeCdpProbeArgs): string;
|
|
|
93
93
|
/**
|
|
94
94
|
* Narrow one probe's stdout. A parse failure is reported as unavailable with the reason, never as
|
|
95
95
|
* an empty success: the difference between "nothing to observe" and "could not observe" is the
|
|
96
|
-
* whole point
|
|
96
|
+
* whole point.
|
|
97
97
|
*/
|
|
98
98
|
export declare function parseChromeCdpProbeOutput(stdout: string | undefined): ChromeCdpProbeResult;
|
|
99
99
|
export {};
|