humanish 0.107.0 → 0.109.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +73 -69
- package/CHANGELOG.md +27 -0
- package/CONTEXT.md +51 -44
- package/README.md +148 -175
- package/SECURITY.md +16 -26
- package/TELEMETRY.md +8 -6
- package/dist/actors/affordance.d.ts +4 -4
- package/dist/actors/affordance.js +12 -12
- package/dist/actors/agent-session.d.ts +2 -2
- package/dist/actors/agent-session.js +7 -7
- package/dist/actors/codex/app-server-actor-trace.d.ts +1 -1
- package/dist/actors/codex/app-server-actor-trace.js +1 -1
- package/dist/actors/codex/app-server-trace.js +2 -1
- package/dist/actors/codex/app-server-ui.js +1 -1
- package/dist/actors/codex/codex-admission.d.ts +91 -0
- package/dist/actors/codex/codex-admission.js +150 -0
- package/dist/actors/codex/restricted-executable.d.ts +4 -4
- package/dist/actors/codex/restricted-executable.js +8 -8
- package/dist/actors/codex/restricted-launch.d.ts +2 -1
- package/dist/actors/codex/restricted-launch.js +1 -1
- package/dist/actors/codex/restricted-participant.js +20 -18
- package/dist/actors/codex/restricted-policy.d.ts +2 -2
- package/dist/actors/codex/restricted-policy.js +2 -2
- package/dist/actors/codex/restricted-session.d.ts +3 -3
- package/dist/actors/codex/restricted-session.js +10 -5
- package/dist/actors/computer-use/actor.d.ts +18 -18
- package/dist/actors/computer-use/actor.js +4 -4
- package/dist/actors/computer-use/admission-limit.d.ts +3 -3
- package/dist/actors/computer-use/admission-limit.js +4 -4
- package/dist/actors/computer-use/executor-error.d.ts +2 -2
- package/dist/actors/computer-use/executor-error.js +3 -3
- package/dist/actors/computer-use/loop/actions.d.ts +3 -3
- package/dist/actors/computer-use/loop/actions.js +15 -15
- package/dist/actors/computer-use/loop/backstop.d.ts +3 -3
- package/dist/actors/computer-use/loop/backstop.js +14 -12
- package/dist/actors/computer-use/loop/debrief.js +2 -2
- package/dist/actors/computer-use/loop/ending.d.ts +6 -6
- package/dist/actors/computer-use/loop/ending.js +18 -17
- package/dist/actors/computer-use/loop/observation.d.ts +2 -2
- package/dist/actors/computer-use/loop/observation.js +15 -14
- package/dist/actors/computer-use/loop/provider-call.d.ts +1 -1
- package/dist/actors/computer-use/loop/provider-call.js +12 -12
- package/dist/actors/computer-use/loop/session.d.ts +4 -4
- package/dist/actors/computer-use/loop/session.js +4 -4
- package/dist/actors/computer-use/loop/spend.d.ts +1 -1
- package/dist/actors/computer-use/loop/spend.js +1 -1
- package/dist/actors/computer-use/loop/trace.js +11 -9
- package/dist/actors/computer-use/loop/types.d.ts +47 -45
- package/dist/actors/computer-use/loop/usage.d.ts +2 -2
- package/dist/actors/computer-use/loop/usage.js +2 -2
- package/dist/actors/computer-use/loop.d.ts +6 -1
- package/dist/actors/computer-use/loop.js +26 -4
- package/dist/actors/computer-use/openai-context.d.ts +37 -0
- package/dist/actors/computer-use/openai-context.js +214 -0
- package/dist/actors/computer-use/openai-provider.d.ts +13 -10
- package/dist/actors/computer-use/openai-provider.js +52 -41
- package/dist/actors/computer-use/openai-requests.d.ts +36 -10
- package/dist/actors/computer-use/openai-requests.js +82 -15
- package/dist/actors/computer-use/openai-wire.d.ts +19 -7
- package/dist/actors/computer-use/openai-wire.js +36 -34
- package/dist/actors/computer-use/provider-error.d.ts +4 -4
- package/dist/actors/computer-use/provider-error.js +6 -6
- package/dist/actors/contract.d.ts +82 -47
- package/dist/actors/contract.js +30 -24
- package/dist/actors/local-agent/claude-session.d.ts +1 -1
- package/dist/actors/local-agent/claude-session.js +13 -12
- package/dist/actors/local-agent/cli.d.ts +9 -7
- package/dist/actors/local-agent/cli.js +24 -28
- package/dist/actors/local-agent/readiness.d.ts +2 -2
- package/dist/actors/local-agent/readiness.js +4 -4
- package/dist/actors/reasoning-effort.js +8 -8
- package/dist/actors/registry.d.ts +12 -12
- package/dist/actors/registry.js +21 -20
- package/dist/actors/scripted-browser/actor.d.ts +10 -10
- package/dist/actors/scripted-browser/actor.js +17 -17
- package/dist/actors/scripted-browser/browser-command.js +1 -1
- package/dist/actors/scripted-browser/steps.js +1 -1
- package/dist/actors/scripted-browser/types.d.ts +1 -1
- package/dist/actors/stop-conditions.d.ts +1 -1
- package/dist/analysis/automatic-completion.d.ts +7 -7
- package/dist/analysis/automatic-completion.js +1 -1
- package/dist/analysis/automatic-config.d.ts +6 -6
- package/dist/analysis/automatic-config.js +1 -1
- package/dist/analysis/codex-config.d.ts +6 -2
- package/dist/analysis/codex-config.js +22 -14
- package/dist/analysis/execute.d.ts +1 -1
- package/dist/analysis/execute.js +1 -1
- package/dist/analysis/service.js +5 -5
- package/dist/analysis/types.d.ts +6 -0
- package/dist/browser-control/client.js +16 -16
- package/dist/browser-control/dispatcher.js +4 -4
- package/dist/browser-control/protocol.js +14 -14
- package/dist/browser-control/recording-transfer.js +4 -4
- package/dist/browser-control/transport.js +7 -7
- package/dist/cli/commands/analysis-signals.d.ts +2 -2
- package/dist/cli/commands/analyze.js +19 -16
- package/dist/cli/commands/codex.js +9 -9
- package/dist/cli/commands/comms.js +48 -35
- package/dist/cli/commands/feedback.js +20 -21
- package/dist/cli/commands/migrate.d.ts +4 -0
- package/dist/cli/commands/migrate.js +65 -0
- package/dist/cli/commands/observe.d.ts +0 -1
- package/dist/cli/commands/observe.js +136 -112
- package/dist/cli/commands/run-command.d.ts +10 -0
- package/dist/cli/commands/run-command.js +85 -0
- package/dist/cli/commands/runs.js +136 -139
- package/dist/cli/commands/setup.d.ts +2 -2
- package/dist/cli/commands/setup.js +27 -24
- package/dist/cli/commands/study-format.d.ts +9 -0
- package/dist/cli/commands/{lab-format.js → study-format.js} +39 -27
- package/dist/cli/commands/{lab-route-computer-use.d.ts → study-route-computer-use.d.ts} +6 -6
- package/dist/cli/commands/{lab-route-computer-use.js → study-route-computer-use.js} +17 -18
- package/dist/cli/commands/{lab-route-open.d.ts → study-route-open.d.ts} +4 -4
- package/dist/cli/commands/{lab-route-open.js → study-route-open.js} +2 -2
- package/dist/cli/commands/{lab-route-preview.d.ts → study-route-preview.d.ts} +7 -7
- package/dist/cli/commands/{lab-route-preview.js → study-route-preview.js} +7 -6
- package/dist/cli/commands/study-route-run.d.ts +19 -0
- package/dist/cli/commands/{lab-route-run.js → study-route-run.js} +6 -6
- package/dist/cli/commands/study-route-scripted.d.ts +17 -0
- package/dist/cli/commands/{lab-route-scripted.js → study-route-scripted.js} +4 -4
- package/dist/cli/commands/{lab-route-shared-world.d.ts → study-route-shared-world.d.ts} +5 -5
- package/dist/cli/commands/{lab-route-shared-world.js → study-route-shared-world.js} +10 -10
- package/dist/cli/commands/study-route-terminal.d.ts +17 -0
- package/dist/cli/commands/{lab-route-terminal.js → study-route-terminal.js} +4 -4
- package/dist/cli/commands/study-run.d.ts +9 -0
- package/dist/cli/commands/{lab-run.js → study-run.js} +44 -45
- package/dist/cli/commands/{lab-scorer.d.ts → study-scorer.d.ts} +7 -7
- package/dist/cli/commands/{lab-scorer.js → study-scorer.js} +2 -2
- package/dist/cli/commands/study.d.ts +3 -0
- package/dist/cli/commands/study.js +146 -0
- package/dist/cli/commands/tui.d.ts +4 -4
- package/dist/cli/commands/tui.js +31 -31
- package/dist/cli/commands/watch.js +71 -121
- package/dist/cli/deprecations.d.ts +6 -0
- package/dist/cli/deprecations.js +18 -0
- package/dist/cli/doctor.d.ts +18 -8
- package/dist/cli/doctor.js +114 -59
- package/dist/cli/first-run-path.d.ts +15 -13
- package/dist/cli/first-run-path.js +35 -33
- package/dist/cli/io.d.ts +44 -9
- package/dist/cli/io.js +98 -23
- package/dist/cli/observer-follow.d.ts +3 -3
- package/dist/cli/observer-follow.js +6 -7
- package/dist/cli/orientation.d.ts +10 -7
- package/dist/cli/orientation.js +89 -47
- package/dist/cli/product-sentence.d.ts +6 -0
- package/dist/cli/product-sentence.js +6 -0
- package/dist/cli/program.d.ts +6 -1
- package/dist/cli/program.js +111 -43
- package/dist/cli/telemetry.d.ts +16 -16
- package/dist/cli/telemetry.js +46 -44
- package/dist/cli.js +1 -1
- package/dist/comms/capture-surface.d.ts +13 -12
- package/dist/comms/capture-surface.js +23 -22
- package/dist/comms/catch-host.d.ts +7 -7
- package/dist/comms/catch-host.js +17 -17
- package/dist/comms/connections.d.ts +1 -1
- package/dist/comms/connections.js +2 -2
- package/dist/comms/email-catch.d.ts +3 -3
- package/dist/comms/email-catch.js +8 -8
- package/dist/comms/external-evidence.d.ts +5 -5
- package/dist/comms/external-evidence.js +5 -4
- package/dist/comms/extract.js +2 -2
- package/dist/comms/fake-inbox.d.ts +3 -3
- package/dist/comms/fake-inbox.js +3 -3
- package/dist/comms/receiving-render.d.ts +1 -1
- package/dist/comms/receiving-render.js +2 -2
- package/dist/comms/receiving-runtime.d.ts +4 -4
- package/dist/comms/sandbox-catch-script.d.ts +6 -6
- package/dist/comms/sandbox-catch-script.js +6 -6
- package/dist/comms/sandbox-catch.d.ts +38 -39
- package/dist/comms/sandbox-catch.js +36 -37
- package/dist/comms/setup.d.ts +2 -2
- package/dist/comms/setup.js +56 -25
- package/dist/comms/thread-evidence.d.ts +1 -1
- package/dist/comms/thread-evidence.js +6 -6
- package/dist/comms/types.d.ts +6 -6
- package/dist/comms/types.js +3 -3
- package/dist/evidence/frame-signature.d.ts +1 -1
- package/dist/evidence/frame-signature.js +4 -4
- package/dist/evidence/redaction.d.ts +3 -3
- package/dist/evidence/redaction.js +4 -4
- package/dist/feedback/draft.js +38 -80
- package/dist/feedback/export-bundle.js +1 -1
- package/dist/feedback/export.d.ts +5 -1
- package/dist/feedback/export.js +10 -10
- package/dist/feedback/feedback.d.ts +2 -2
- package/dist/feedback/feedback.js +21 -3
- package/dist/feedback/proof.d.ts +1 -1
- package/dist/feedback/proof.js +2 -2
- package/dist/guest/bootstrap.js +6 -6
- package/dist/guest/browser-tools.js +8 -8
- package/dist/guest/chromium-text.js +19 -19
- package/dist/guest/desktop-executor.d.ts +2 -2
- package/dist/guest/desktop-executor.js +20 -20
- package/dist/guest/desktop-keys.js +4 -4
- package/dist/guest/desktop-media.d.ts +2 -2
- package/dist/guest/desktop-media.js +16 -16
- package/dist/guest/desktop-native.d.ts +1 -1
- package/dist/guest/desktop-native.js +10 -10
- package/dist/guest/runtime-desktop.js +2 -2
- package/dist/guest/runtime-processes.d.ts +2 -2
- package/dist/guest/runtime-processes.js +2 -2
- package/dist/guest/runtime.js +6 -6
- package/dist/index.d.ts +14 -14
- package/dist/index.js +8 -8
- package/dist/keys/key-resolution.d.ts +5 -5
- package/dist/keys/key-resolution.js +23 -23
- package/dist/observer/artifact.d.ts +2 -2
- package/dist/observer/artifact.js +7 -7
- package/dist/observer/data.d.ts +6 -6
- package/dist/observer/data.js +5 -4
- package/dist/observer/exposure.d.ts +1 -1
- package/dist/observer/exposure.js +11 -11
- package/dist/observer/http.js +1 -1
- package/dist/observer/library.d.ts +3 -1
- package/dist/observer/library.js +8 -3
- package/dist/observer/listen.js +5 -4
- package/dist/observer/render.d.ts +1 -1
- package/dist/observer/render.js +17 -6
- package/dist/observer/run-routes.d.ts +4 -3
- package/dist/observer/run-routes.js +38 -13
- package/dist/observer/serve.d.ts +1 -1
- package/dist/observer/serve.js +7 -3
- package/dist/observer/tunnel.js +1 -1
- package/dist/observer-app.html +4 -4
- package/dist/routes/computer-use/bundle-parts.d.ts +9 -9
- package/dist/routes/computer-use/bundle-parts.js +18 -17
- package/dist/routes/computer-use/bundle.d.ts +2 -2
- package/dist/routes/computer-use/bundle.js +10 -9
- package/dist/routes/computer-use/e2b-desktop/comms.d.ts +6 -6
- package/dist/routes/computer-use/e2b-desktop/comms.js +18 -17
- package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -4
- package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +5 -4
- package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -10
- package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +1 -1
- package/dist/routes/computer-use/e2b-desktop/prepare.js +10 -10
- package/dist/routes/computer-use/e2b-desktop/start.js +7 -7
- package/dist/routes/computer-use/e2b-desktop/state.d.ts +2 -2
- package/dist/routes/computer-use/e2b-desktop/teardown.js +2 -2
- package/dist/routes/computer-use/external-comms.d.ts +4 -4
- package/dist/routes/computer-use/external-comms.js +1 -1
- package/dist/routes/computer-use/fanout-bundle.js +27 -26
- package/dist/routes/computer-use/fanout-records.js +12 -13
- package/dist/routes/computer-use/live-flush.d.ts +4 -4
- package/dist/routes/computer-use/live-flush.js +6 -6
- package/dist/routes/computer-use/live-phase.d.ts +5 -4
- package/dist/routes/computer-use/live-phase.js +8 -8
- package/dist/routes/computer-use/local-tree-pack.d.ts +5 -5
- package/dist/routes/computer-use/local-tree-pack.js +1 -1
- package/dist/routes/computer-use/local-vm.d.ts +8 -8
- package/dist/routes/computer-use/local-vm.js +3 -3
- package/dist/routes/computer-use/participant-desktop.d.ts +7 -7
- package/dist/routes/computer-use/participant-desktop.js +5 -5
- package/dist/routes/computer-use/participant-execution.d.ts +4 -4
- package/dist/routes/computer-use/participant-execution.js +10 -10
- package/dist/routes/computer-use/participant-model.d.ts +6 -0
- package/dist/routes/computer-use/participant-model.js +33 -15
- package/dist/routes/computer-use/participant-prompt.d.ts +15 -15
- package/dist/routes/computer-use/participant-prompt.js +9 -9
- package/dist/routes/computer-use/participant-runs.d.ts +16 -16
- package/dist/routes/computer-use/participant-runs.js +26 -25
- package/dist/routes/computer-use/plan.d.ts +12 -12
- package/dist/routes/computer-use/plan.js +42 -42
- package/dist/routes/computer-use/preflight.d.ts +5 -5
- package/dist/routes/computer-use/preflight.js +25 -25
- package/dist/routes/computer-use/rerun-selection.d.ts +1 -1
- package/dist/routes/computer-use/rerun-selection.js +4 -3
- package/dist/routes/computer-use/result.d.ts +4 -4
- package/dist/routes/computer-use/result.js +22 -21
- package/dist/routes/computer-use/route.d.ts +12 -11
- package/dist/routes/computer-use/route.js +31 -30
- package/dist/routes/computer-use/self-report.d.ts +7 -7
- package/dist/routes/computer-use/self-report.js +32 -32
- package/dist/routes/computer-use/setup.d.ts +23 -23
- package/dist/routes/computer-use/setup.js +28 -29
- package/dist/routes/computer-use/single-bundle.d.ts +11 -11
- package/dist/routes/computer-use/single-bundle.js +40 -41
- package/dist/routes/computer-use/subject-projection.d.ts +4 -4
- package/dist/routes/computer-use/subject-projection.js +6 -6
- package/dist/routes/computer-use/types.d.ts +71 -73
- package/dist/routes/computer-use/types.js +12 -12
- package/dist/routes/preview.d.ts +13 -7
- package/dist/routes/preview.js +11 -7
- package/dist/routes/scripted/bundle.d.ts +7 -7
- package/dist/routes/scripted/bundle.js +20 -18
- package/dist/routes/scripted/plan.d.ts +8 -8
- package/dist/routes/scripted/plan.js +13 -13
- package/dist/routes/scripted/result.d.ts +3 -3
- package/dist/routes/scripted/result.js +13 -13
- package/dist/routes/scripted/route.d.ts +9 -9
- package/dist/routes/scripted/route.js +15 -16
- package/dist/routes/scripted/scenario.d.ts +1 -1
- package/dist/routes/scripted/scenario.js +5 -5
- package/dist/routes/scripted/setup.d.ts +6 -6
- package/dist/routes/scripted/setup.js +8 -8
- package/dist/routes/scripted/subject.d.ts +5 -5
- package/dist/routes/scripted/subject.js +4 -4
- package/dist/routes/scripted/surface-records.d.ts +1 -1
- package/dist/routes/scripted/surface-records.js +4 -4
- package/dist/routes/scripted/surface-sessions.d.ts +3 -3
- package/dist/routes/scripted/types.d.ts +18 -20
- package/dist/routes/scripted/types.js +2 -2
- package/dist/routes/shared-world/bundle-records.js +11 -10
- package/dist/routes/shared-world/bundle.d.ts +5 -5
- package/dist/routes/shared-world/bundle.js +46 -43
- package/dist/routes/shared-world/checkpoints.d.ts +4 -4
- package/dist/routes/shared-world/checkpoints.js +2 -2
- package/dist/routes/shared-world/comms.d.ts +14 -14
- package/dist/routes/shared-world/comms.js +19 -18
- package/dist/routes/shared-world/external-public.d.ts +4 -3
- package/dist/routes/shared-world/external-public.js +16 -12
- package/dist/routes/shared-world/handoff.d.ts +7 -6
- package/dist/routes/shared-world/handoff.js +65 -57
- package/dist/routes/shared-world/lobby-code.d.ts +2 -2
- package/dist/routes/shared-world/lobby-code.js +9 -9
- package/dist/routes/shared-world/participant-specs.d.ts +10 -9
- package/dist/routes/shared-world/participant-specs.js +38 -31
- package/dist/routes/shared-world/plan.d.ts +9 -9
- package/dist/routes/shared-world/plan.js +16 -16
- package/dist/routes/shared-world/provenance.d.ts +2 -2
- package/dist/routes/shared-world/provenance.js +2 -2
- package/dist/routes/shared-world/provisioned.d.ts +8 -8
- package/dist/routes/shared-world/provisioned.js +18 -17
- package/dist/routes/shared-world/result.d.ts +6 -6
- package/dist/routes/shared-world/result.js +29 -29
- package/dist/routes/shared-world/route.d.ts +11 -11
- package/dist/routes/shared-world/route.js +40 -39
- package/dist/routes/shared-world/setup.d.ts +16 -16
- package/dist/routes/shared-world/setup.js +23 -23
- package/dist/routes/shared-world/types.d.ts +55 -53
- package/dist/routes/shared-world/types.js +4 -4
- package/dist/routes/terminal/adapter.d.ts +5 -5
- package/dist/routes/terminal/adapter.js +9 -9
- package/dist/routes/terminal/bundle.d.ts +13 -13
- package/dist/routes/terminal/bundle.js +28 -27
- package/dist/routes/terminal/credentials.d.ts +8 -8
- package/dist/routes/terminal/credentials.js +12 -12
- package/dist/routes/terminal/dry-run.d.ts +4 -4
- package/dist/routes/terminal/dry-run.js +12 -12
- package/dist/routes/terminal/encoding.js +2 -2
- package/dist/routes/terminal/ledger.d.ts +5 -5
- package/dist/routes/terminal/ledger.js +14 -14
- package/dist/routes/terminal/lifetime.d.ts +1 -1
- package/dist/routes/terminal/lifetime.js +1 -1
- package/dist/routes/terminal/live-finish.d.ts +2 -2
- package/dist/routes/terminal/live-finish.js +10 -10
- package/dist/routes/terminal/live-sandbox.d.ts +2 -2
- package/dist/routes/terminal/live-sandbox.js +15 -15
- package/dist/routes/terminal/participant-text.js +2 -1
- package/dist/routes/terminal/persona.d.ts +2 -2
- package/dist/routes/terminal/persona.js +3 -3
- package/dist/routes/terminal/plan.d.ts +7 -7
- package/dist/routes/terminal/plan.js +15 -15
- package/dist/routes/terminal/recorder.js +2 -2
- package/dist/routes/terminal/result.d.ts +5 -5
- package/dist/routes/terminal/result.js +14 -14
- package/dist/routes/terminal/route.d.ts +9 -9
- package/dist/routes/terminal/route.js +19 -20
- package/dist/routes/terminal/sandbox.d.ts +1 -1
- package/dist/routes/terminal/sandbox.js +1 -1
- package/dist/routes/terminal/session.d.ts +5 -5
- package/dist/routes/terminal/session.js +14 -13
- package/dist/routes/terminal/token-usage.d.ts +1 -1
- package/dist/routes/terminal/token-usage.js +7 -8
- package/dist/routes/terminal/trace.d.ts +4 -4
- package/dist/routes/terminal/trace.js +2 -2
- package/dist/routes/terminal/types.d.ts +48 -50
- package/dist/routes/terminal/types.js +5 -5
- package/dist/run/bundle-shape.js +3 -3
- package/dist/run/bundle.d.ts +49 -49
- package/dist/run/bundle.js +3 -2
- package/dist/run/cost-summary.js +3 -3
- package/dist/run/costs.d.ts +23 -0
- package/dist/run/costs.js +79 -44
- package/dist/run/detail.d.ts +6 -6
- package/dist/run/detail.js +4 -4
- package/dist/run/dry-run-inputs.d.ts +1 -1
- package/dist/run/dry-run-inputs.js +2 -2
- package/dist/run/dry-run.js +20 -20
- package/dist/run/judge.d.ts +19 -13
- package/dist/run/judge.js +18 -8
- package/dist/run/outcomes.d.ts +1 -1
- package/dist/run/participant.d.ts +1 -1
- package/dist/run/paths.d.ts +1 -1
- package/dist/run/paths.js +1 -1
- package/dist/run/preflight-receipts.js +1 -1
- package/dist/run/pricing.d.ts +11 -6
- package/dist/run/pricing.js +22 -15
- package/dist/run/projection.d.ts +46 -46
- package/dist/run/projection.js +57 -57
- package/dist/run/reclaim.d.ts +1 -1
- package/dist/run/reclaim.js +3 -3
- package/dist/run/results.d.ts +5 -5
- package/dist/run/run-cost.d.ts +53 -0
- package/dist/run/run-cost.js +105 -0
- package/dist/run/run-index-analysis.d.ts +15 -0
- package/dist/run/run-index-analysis.js +77 -0
- package/dist/run/run-index.d.ts +19 -7
- package/dist/run/run-index.js +77 -64
- package/dist/run/run-not-found.d.ts +5 -0
- package/dist/run/run-not-found.js +15 -0
- package/dist/run/run.d.ts +6 -5
- package/dist/run/run.js +3 -3
- package/dist/run/sandbox-receipts.d.ts +2 -2
- package/dist/run/sandbox-receipts.js +3 -3
- package/dist/run/shared-world-evidence.d.ts +37 -36
- package/dist/run/shared-world-evidence.js +4 -4
- package/dist/run/shared-world-shape.d.ts +1 -1
- package/dist/run/shared-world-shape.js +7 -7
- package/dist/run/stats.d.ts +14 -8
- package/dist/run/stats.js +121 -63
- package/dist/run/status.d.ts +16 -29
- package/dist/run/status.js +10 -29
- package/dist/run/stored-runs.js +2 -1
- package/dist/run/stream-shape.js +1 -1
- package/dist/run/streams.d.ts +7 -7
- package/dist/run/study-provenance.d.ts +49 -0
- package/dist/run/study-provenance.js +66 -0
- package/dist/run/study-result.d.ts +11 -0
- package/dist/run/study-result.js +9 -0
- package/dist/run/text.d.ts +2 -0
- package/dist/run/text.js +4 -0
- package/dist/run-study.d.ts +112 -0
- package/dist/{run-lab.js → run-study.js} +52 -47
- package/dist/{lab → study}/adapter-extension.d.ts +15 -27
- package/dist/{lab → study}/adapter-extension.js +10 -45
- package/dist/{lab → study}/adapter-scorer-loader.d.ts +17 -17
- package/dist/{lab → study}/adapter-scorer-loader.js +34 -34
- package/dist/study/composition-rules.d.ts +7 -0
- package/dist/{lab → study}/composition-rules.js +53 -53
- package/dist/study/config.d.ts +15 -0
- package/dist/{lab → study}/config.js +98 -41
- package/dist/study/convert.d.ts +33 -0
- package/dist/study/convert.js +432 -0
- package/dist/{lab → study}/device-presets.d.ts +10 -10
- package/dist/{lab → study}/device-presets.js +11 -11
- package/dist/study/discover.d.ts +75 -0
- package/dist/{lab → study}/discover.js +134 -95
- package/dist/{lab → study}/doctor.d.ts +19 -12
- package/dist/{lab → study}/doctor.js +58 -20
- package/dist/study/field-paths.d.ts +12 -0
- package/dist/study/field-paths.js +126 -0
- package/dist/study/files.d.ts +26 -0
- package/dist/study/files.js +44 -0
- package/dist/{lab → study}/init-templates.d.ts +2 -2
- package/dist/study/init-templates.js +421 -0
- package/dist/{lab → study}/init.d.ts +2 -2
- package/dist/{lab → study}/init.js +46 -11
- package/dist/study/keys.d.ts +4 -0
- package/dist/{lab → study}/keys.js +46 -12
- package/dist/study/migrate.d.ts +48 -0
- package/dist/study/migrate.js +408 -0
- package/dist/study/owned-files.d.ts +38 -0
- package/dist/study/owned-files.js +182 -0
- package/dist/{lab → study}/parse/actors.d.ts +5 -5
- package/dist/{lab → study}/parse/actors.js +14 -14
- package/dist/study/parse/comms.d.ts +12 -0
- package/dist/{lab → study}/parse/comms.js +5 -5
- package/dist/study/parse/execution.d.ts +19 -0
- package/dist/{lab → study}/parse/execution.js +13 -13
- package/dist/study/parse/study-v3.d.ts +21 -0
- package/dist/study/parse/study-v3.js +259 -0
- package/dist/study/parse/subject-state.d.ts +30 -0
- package/dist/{lab → study}/parse/subject-state.js +19 -19
- package/dist/{lab → study}/parse/subject.d.ts +3 -3
- package/dist/{lab → study}/parse/subject.js +34 -34
- package/dist/{lab → study}/parse/values.d.ts +3 -3
- package/dist/{lab → study}/parse/values.js +3 -3
- package/dist/{lab → study}/persona-resolve.d.ts +8 -8
- package/dist/{lab → study}/persona-resolve.js +6 -6
- package/dist/{lab → study}/plan-base.d.ts +7 -7
- package/dist/{lab → study}/plan-base.js +1 -1
- package/dist/{lab → study}/plan-participants.d.ts +12 -12
- package/dist/{lab → study}/plan-participants.js +4 -4
- package/dist/{lab → study}/plan-types.d.ts +31 -31
- package/dist/{lab → study}/plan-types.js +2 -2
- package/dist/study/plan.d.ts +13 -0
- package/dist/study/plan.js +101 -0
- package/dist/study/preflight-probes.d.ts +3 -0
- package/dist/{lab → study}/preflight-probes.js +20 -19
- package/dist/study/preflight-result.d.ts +8 -0
- package/dist/{lab → study}/preflight-result.js +5 -4
- package/dist/study/preflight.d.ts +94 -0
- package/dist/{lab → study}/preflight.js +12 -12
- package/dist/{lab → study}/requirements.d.ts +3 -3
- package/dist/{lab → study}/requirements.js +1 -1
- package/dist/study/route-inputs.d.ts +28 -0
- package/dist/{lab → study}/route-inputs.js +1 -1
- package/dist/{lab → study}/routing.d.ts +39 -33
- package/dist/{lab → study}/routing.js +60 -29
- package/dist/{lab/run-lab-events.d.ts → study/run-study-events.d.ts} +10 -13
- package/dist/{lab/run-lab-events.js → study/run-study-events.js} +3 -9
- package/dist/{lab/run-lab-homes.d.ts → study/run-study-homes.d.ts} +21 -18
- package/dist/{lab/run-lab-homes.js → study/run-study-homes.js} +1 -1
- package/dist/study/run-study-options.d.ts +28 -0
- package/dist/{lab/run-lab-options.js → study/run-study-options.js} +29 -25
- package/dist/{lab/lab-deps.d.ts → study/study-deps.d.ts} +8 -13
- package/dist/{lab/lab-deps.js → study/study-deps.js} +2 -2
- package/dist/{lab → study}/summary.d.ts +16 -15
- package/dist/{lab → study}/summary.js +21 -21
- package/dist/{lab → study}/tasks.d.ts +18 -18
- package/dist/{lab → study}/tasks.js +14 -14
- package/dist/{lab → study}/types.d.ts +202 -196
- package/dist/{lab → study}/types.js +3 -1
- package/dist/{lab → study}/validation.d.ts +27 -27
- package/dist/{lab → study}/validation.js +53 -51
- package/dist/study/warnings.d.ts +12 -0
- package/dist/{lab → study}/warnings.js +62 -34
- package/dist/subject/clone.d.ts +7 -7
- package/dist/subject/clone.js +2 -2
- package/dist/subject/desktop-cli.d.ts +1 -1
- package/dist/subject/desktop-cli.js +2 -2
- package/dist/subject/local-tree-archive.d.ts +2 -2
- package/dist/subject/local-tree-archive.js +4 -4
- package/dist/subject/local-tree.d.ts +4 -4
- package/dist/subject/node-bootstrap.js +1 -1
- package/dist/subject/runtime.js +9 -10
- package/dist/subject/serve.d.ts +5 -5
- package/dist/subject/serve.js +3 -3
- package/dist/subject/state.d.ts +4 -4
- package/dist/subject/state.js +1 -1
- package/dist/subject/steps.d.ts +6 -6
- package/dist/subject/steps.js +5 -5
- package/dist/substrates/command-failure.d.ts +3 -3
- package/dist/substrates/command-failure.js +3 -3
- package/dist/substrates/desktop-session.js +2 -2
- package/dist/substrates/detached.d.ts +6 -6
- package/dist/substrates/detached.js +7 -7
- package/dist/substrates/e2b/cdp-probe.d.ts +9 -9
- package/dist/substrates/e2b/cdp-probe.js +14 -17
- package/dist/substrates/e2b/desktop-browser.d.ts +6 -6
- package/dist/substrates/e2b/desktop-browser.js +9 -9
- package/dist/substrates/e2b/desktop-cdp.d.ts +10 -10
- package/dist/substrates/e2b/desktop-cdp.js +9 -9
- package/dist/substrates/e2b/desktop-executor.d.ts +2 -2
- package/dist/substrates/e2b/desktop-executor.js +13 -13
- package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
- package/dist/substrates/e2b/desktop-geometry.js +8 -8
- package/dist/substrates/e2b/desktop-media.d.ts +4 -4
- package/dist/substrates/e2b/desktop-media.js +1 -1
- package/dist/substrates/e2b/desktop-screenshot-cleanup.d.ts +3 -3
- package/dist/substrates/e2b/desktop-screenshot-cleanup.js +3 -3
- package/dist/substrates/e2b/lifetime.js +1 -1
- package/dist/substrates/e2b/sandbox.d.ts +4 -4
- package/dist/substrates/e2b/sandbox.js +2 -2
- package/dist/substrates/e2b/sdk.d.ts +12 -12
- package/dist/substrates/e2b/sdk.js +7 -7
- package/dist/substrates/local/runtime-config.d.ts +4 -4
- package/dist/substrates/local/runtime-config.js +4 -4
- package/dist/tui/actions.d.ts +1 -1
- package/dist/tui/actions.js +13 -13
- package/dist/tui/contract.d.ts +23 -23
- package/dist/tui/contract.js +11 -11
- package/dist/tui/launch.d.ts +7 -7
- package/dist/tui/launch.js +36 -31
- package/dist/tui/project.js +5 -5
- package/dist/tui-app.js +139 -139
- package/dist/verify/actor.d.ts +8 -8
- package/dist/verify/actor.js +36 -36
- package/dist/verify/artifacts.d.ts +2 -2
- package/dist/verify/artifacts.js +3 -3
- package/dist/verify/context-growth.d.ts +9 -0
- package/dist/verify/context-growth.js +62 -0
- package/dist/verify/costs.d.ts +6 -6
- package/dist/verify/costs.js +8 -8
- package/dist/verify/shared-world-concurrent.d.ts +2 -2
- package/dist/verify/shared-world-concurrent.js +79 -76
- package/dist/verify/shared-world.d.ts +2 -2
- package/dist/verify/shared-world.js +16 -16
- package/dist/verify/subject.d.ts +5 -5
- package/dist/verify/subject.js +19 -19
- package/dist/verify/verify.js +94 -44
- package/docs/README.md +25 -32
- package/docs/architecture/actor-contract.md +60 -91
- package/docs/architecture/browser-control.md +1 -1
- package/docs/architecture/desktop-sessions.md +7 -7
- package/docs/architecture/external-public-shared-world.md +68 -65
- package/docs/architecture/github-feedback-loop.md +2 -5
- package/docs/architecture/guest-desktop.md +2 -2
- package/docs/architecture/observer.md +34 -34
- package/docs/architecture/restricted-codex-analysis.md +34 -28
- package/docs/architecture/serve.md +34 -37
- package/docs/architecture/state-driven-executor.md +55 -58
- package/docs/architecture/task-protocol-support.md +6 -6
- package/docs/architecture/terminal-product-route.md +70 -110
- package/docs/contracts/README.md +24 -0
- package/docs/contracts/adapter-admission.md +3 -3
- package/docs/contracts/adapter-fixtures.md +4 -7
- package/docs/contracts/core.md +1 -3
- package/docs/contracts/errors.md +62 -0
- package/docs/contracts/feedback.md +8 -9
- package/docs/contracts/policy.md +7 -12
- package/docs/contracts/run-bundle.md +42 -44
- package/docs/contracts/schemas.md +446 -368
- package/docs/contracts/study-analysis.md +7 -4
- package/docs/contracts/study-costs.md +28 -9
- package/docs/decisions/0001-run-bundle-is-the-source-of-truth.md +1 -1
- package/docs/decisions/0002-observer-is-one-self-contained-file.md +2 -2
- package/docs/decisions/0003-contained-paths-and-cleanup-authority.md +3 -3
- package/docs/principles/actor-fidelity.md +4 -4
- package/docs/principles/engineering.md +3 -3
- package/docs/principles/invariants-and-defaults.md +38 -38
- package/docs/principles/self-driving-harness.md +1 -5
- package/docs/principles/three-roles.md +1 -1
- package/docs/product/automatic-analysis.md +7 -7
- package/examples/README.md +1 -1
- package/examples/participant/README.md +5 -5
- package/examples/participant/run.mjs +11 -10
- package/examples/scorer/README.md +3 -3
- package/examples/scorer/run.mjs +11 -12
- package/examples/scorer/scorer.mjs +3 -3
- package/package.json +16 -17
- package/skills/humanish/SKILL.md +64 -60
- package/skills/humanish/agents/openai.yaml +1 -1
- package/AGENTS.md +0 -99
- package/CONTRIBUTING.md +0 -148
- package/dist/actors/codex/qualified-versions.d.ts +0 -72
- package/dist/actors/codex/qualified-versions.js +0 -132
- package/dist/cli/commands/lab-format.d.ts +0 -8
- package/dist/cli/commands/lab-route-run.d.ts +0 -19
- package/dist/cli/commands/lab-route-scripted.d.ts +0 -17
- package/dist/cli/commands/lab-route-terminal.d.ts +0 -17
- package/dist/cli/commands/lab-run.d.ts +0 -9
- package/dist/cli/commands/lab.d.ts +0 -3
- package/dist/cli/commands/lab.js +0 -199
- package/dist/cli/renamed-options.d.ts +0 -11
- package/dist/cli/renamed-options.js +0 -18
- package/dist/lab/composition-rules.d.ts +0 -7
- package/dist/lab/config.d.ts +0 -7
- package/dist/lab/discover.d.ts +0 -65
- package/dist/lab/init-templates.js +0 -416
- package/dist/lab/keys.d.ts +0 -2
- package/dist/lab/parse/comms.d.ts +0 -12
- package/dist/lab/parse/execution.d.ts +0 -19
- package/dist/lab/parse/subject-state.d.ts +0 -30
- package/dist/lab/plan.d.ts +0 -19
- package/dist/lab/plan.js +0 -132
- package/dist/lab/preflight-probes.d.ts +0 -3
- package/dist/lab/preflight-result.d.ts +0 -7
- package/dist/lab/preflight.d.ts +0 -92
- package/dist/lab/route-inputs.d.ts +0 -28
- package/dist/lab/run-lab-options.d.ts +0 -28
- package/dist/lab/warnings.d.ts +0 -2
- package/dist/observer/static.d.ts +0 -39
- package/dist/observer/static.js +0 -369
- package/dist/run-lab.d.ts +0 -112
- package/docs/architecture/comms-inbox.md +0 -122
- package/docs/architecture/desktop-recording.md +0 -80
- package/docs/architecture/local-browser-runtime.md +0 -178
- package/docs/architecture/observer-review.md +0 -144
- package/docs/architecture/participant-media.md +0 -90
- package/docs/architecture/project-layout.md +0 -62
- package/docs/architecture/real-email-receiving.md +0 -136
- package/docs/assets/humanish-drawdb-hero.png +0 -0
- package/docs/assets/humanish-observer-hero.png +0 -0
- package/docs/goals/current.md +0 -207
- package/docs/product/lobby-trivia-3player-external-public.md +0 -77
- package/docs/product/open-source-install-experience.md +0 -240
- package/docs/ramp/README.md +0 -295
- package/docs/release/open-source-readiness.md +0 -222
- package/docs/release/public-readiness-standard.md +0 -210
- package/docs/roadmap/world-class-open-source-v0.md +0 -311
- /package/dist/{lab → study}/init-paths.d.ts +0 -0
- /package/dist/{lab → study}/init-paths.js +0 -0
- /package/dist/{lab → study}/init-plan.d.ts +0 -0
- /package/dist/{lab → study}/init-plan.js +0 -0
- /package/dist/{lab → study}/participant-assignment.d.ts +0 -0
- /package/dist/{lab → study}/participant-assignment.js +0 -0
- /package/dist/{lab → study}/persona.d.ts +0 -0
- /package/dist/{lab → study}/persona.js +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/** The accounting's analysis spend, or null when the run sent no analysis request. */
|
|
2
|
+
export function analysisCostOf(accounting) {
|
|
3
|
+
const requests = accounting.dispatched + accounting.unresolved;
|
|
4
|
+
if (requests === 0)
|
|
5
|
+
return null;
|
|
6
|
+
const historyWhole = accounting.warnings.every((warning) => warning === "ANALYSIS_HISTORY_NOT_RECORDED");
|
|
7
|
+
return {
|
|
8
|
+
requests,
|
|
9
|
+
estimatedUsd: accounting.estimatedUsd,
|
|
10
|
+
complete: accounting.unpriced === 0 && historyWhole,
|
|
11
|
+
providers: [...accounting.providers],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function runCost(subtotal, analysis) {
|
|
15
|
+
if (subtotal === null || subtotal === undefined)
|
|
16
|
+
return { run: null, analysis: null, total: null };
|
|
17
|
+
const run = {
|
|
18
|
+
usd: typeof subtotal.estimatedTotalUsd === "number" ? subtotal.estimatedTotalUsd : null,
|
|
19
|
+
complete: subtotal.fullyEstimated === undefined ? null : subtotal.fullyEstimated,
|
|
20
|
+
ratesAsOf: subtotal.ratesAsOf ?? null,
|
|
21
|
+
placeholder: subtotal.placeholder === true,
|
|
22
|
+
};
|
|
23
|
+
const spent = analysis ?? null;
|
|
24
|
+
const known = [run.usd, spent?.estimatedUsd].filter((usd) => typeof usd === "number");
|
|
25
|
+
if (known.length === 0)
|
|
26
|
+
return { run, analysis: spent, total: null };
|
|
27
|
+
const lowerBound = run.usd === null || run.complete === false || spent?.complete === false;
|
|
28
|
+
return {
|
|
29
|
+
run,
|
|
30
|
+
analysis: spent,
|
|
31
|
+
total: {
|
|
32
|
+
usd: round6(known.reduce((sum, usd) => sum + usd, 0)),
|
|
33
|
+
complete: lowerBound ? false : run.complete,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A run index entry's cost: its participants-and-desktops figure, complete or a lower bound when
|
|
39
|
+
* the status record says which, plus its analyses.
|
|
40
|
+
*/
|
|
41
|
+
export function indexedRunCost(entry) {
|
|
42
|
+
return runCost({
|
|
43
|
+
estimatedTotalUsd: entry.estimatedCostUsd ?? null,
|
|
44
|
+
...(entry.estimatedCostComplete === undefined
|
|
45
|
+
? {}
|
|
46
|
+
: { fullyEstimated: entry.estimatedCostComplete }),
|
|
47
|
+
}, entry.analysisCost);
|
|
48
|
+
}
|
|
49
|
+
/** Six decimals, as the run cost summary rounds, so sums of small estimates do not drift. */
|
|
50
|
+
function round6(value) {
|
|
51
|
+
return Math.round(value * 1e6) / 1e6;
|
|
52
|
+
}
|
|
53
|
+
/** An estimate, saying so when some of the spend has no price and is not in it. */
|
|
54
|
+
function estimateText(usd, complete) {
|
|
55
|
+
return `est. ~$${usd.toFixed(2)}${complete === false ? " plus unpriced usage" : ""}`;
|
|
56
|
+
}
|
|
57
|
+
function analysesNoun(requests) {
|
|
58
|
+
return requests === 1 ? "analysis" : `${requests} analyses`;
|
|
59
|
+
}
|
|
60
|
+
function billedBy(providers) {
|
|
61
|
+
const names = providers.map((provider) => provider === "openai" ? "OpenAI API key" : "Codex account");
|
|
62
|
+
return names.length === 0 ? "" : ` (${names.join(" and ")})`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The cost as separate parts: participants and desktops, then the analysis and the total when the
|
|
66
|
+
* run sent an analysis request. Empty when the run has no cost summary.
|
|
67
|
+
*/
|
|
68
|
+
export function runCostParts(cost) {
|
|
69
|
+
if (cost.run === null)
|
|
70
|
+
return [];
|
|
71
|
+
const rates = `rates as of ${cost.run.ratesAsOf}${cost.run.placeholder ? ", placeholder" : ""}`;
|
|
72
|
+
const parts = [
|
|
73
|
+
cost.run.usd === null
|
|
74
|
+
? "Participants + desktops: cost not estimated"
|
|
75
|
+
: `Participants + desktops: ${estimateText(cost.run.usd, cost.run.complete)} (${rates})`,
|
|
76
|
+
];
|
|
77
|
+
const analysis = cost.analysis;
|
|
78
|
+
if (analysis === null)
|
|
79
|
+
return parts;
|
|
80
|
+
const noun = analysesNoun(analysis.requests);
|
|
81
|
+
const label = noun.charAt(0).toUpperCase() + noun.slice(1);
|
|
82
|
+
if (analysis.estimatedUsd === null)
|
|
83
|
+
parts.push(analysis.providers.length === 1 && analysis.providers[0] === "codex"
|
|
84
|
+
? `${label}: Codex account, dollar cost unknown`
|
|
85
|
+
: `${label}: cost not estimated${billedBy(analysis.providers)}`);
|
|
86
|
+
else
|
|
87
|
+
parts.push(`${label}: ${estimateText(analysis.estimatedUsd, analysis.complete)}${billedBy(analysis.providers)}`);
|
|
88
|
+
if (cost.total !== null)
|
|
89
|
+
parts.push(`Total: ${estimateText(cost.total.usd, cost.total.complete)}`);
|
|
90
|
+
return parts;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* The cost in one short label for a list row: the total, and how many analyses it includes.
|
|
94
|
+
* Undefined when the run has no cost summary.
|
|
95
|
+
*/
|
|
96
|
+
export function runCostLabel(cost) {
|
|
97
|
+
if (cost.run === null)
|
|
98
|
+
return undefined;
|
|
99
|
+
const amount = cost.total === null
|
|
100
|
+
? "cost not estimated"
|
|
101
|
+
: `~$${cost.total.usd.toFixed(2)} est.${cost.total.complete === false ? " plus unpriced usage" : ""}`;
|
|
102
|
+
return cost.analysis === null
|
|
103
|
+
? amount
|
|
104
|
+
: `${amount}, with ${analysesNoun(cost.analysis.requests)}`;
|
|
105
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type RunAnalysisCost } from "./run-cost.js";
|
|
2
|
+
/** Per-run analysis costs, keyed on their fingerprint. Nothing here is authoritative. */
|
|
3
|
+
export declare class AnalysisCostCache {
|
|
4
|
+
private readonly slots;
|
|
5
|
+
get(runId: string, fingerprint: string): {
|
|
6
|
+
cost: RunAnalysisCost | undefined;
|
|
7
|
+
} | undefined;
|
|
8
|
+
set(runId: string, fingerprint: string, cost: RunAnalysisCost | undefined): void;
|
|
9
|
+
retain(keep: Set<string>): void;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* The run's analysis spend for its index entry, read with the same reader stats uses. Undefined
|
|
13
|
+
* when the run sent no analysis request or its run directory cannot be bound.
|
|
14
|
+
*/
|
|
15
|
+
export declare function readIndexedAnalysisCost(cwd: string, runId: string, cache: AnalysisCostCache | undefined): Promise<RunAnalysisCost | undefined>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { readdir, stat } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { AUTOMATIC_ANALYSIS_DIRECTORY } from "../analysis/job.js";
|
|
4
|
+
import { ANALYSIS_DIRECTORY, ANALYSIS_EXECUTION_DIRECTORY } from "../analysis/store.js";
|
|
5
|
+
import { readAnalysisAccounting } from "./costs.js";
|
|
6
|
+
import { bindExistingRunArtifactPaths } from "./paths.js";
|
|
7
|
+
import { analysisCostOf } from "./run-cost.js";
|
|
8
|
+
// A run's analysis is written after its status record and bundle are final, so the index keys a
|
|
9
|
+
// run's analysis cost on a fingerprint of the analysis directories, not on the status record. A
|
|
10
|
+
// receipt lands inside an attempt directory that already exists, which changes that directory's
|
|
11
|
+
// mtime and not its parent's, so each attempt directory is part of the fingerprint.
|
|
12
|
+
/** Stat signatures of everything an analysis write changes; null when the run has no analysis. */
|
|
13
|
+
async function analysisFingerprint(runDir) {
|
|
14
|
+
const signatures = [];
|
|
15
|
+
for (const directory of [ANALYSIS_EXECUTION_DIRECTORY, ANALYSIS_DIRECTORY]) {
|
|
16
|
+
const root = path.join(runDir, directory);
|
|
17
|
+
const rootSignature = await signature(root);
|
|
18
|
+
if (rootSignature === null)
|
|
19
|
+
continue;
|
|
20
|
+
signatures.push(`${directory}:${rootSignature}`);
|
|
21
|
+
const children = await readdir(root).catch(() => []);
|
|
22
|
+
for (const child of children.sort((left, right) => left.localeCompare(right)))
|
|
23
|
+
signatures.push(`${directory}/${child}:${await signature(path.join(root, child))}`);
|
|
24
|
+
}
|
|
25
|
+
const job = await signature(path.join(runDir, AUTOMATIC_ANALYSIS_DIRECTORY, "job.json"));
|
|
26
|
+
if (job !== null)
|
|
27
|
+
signatures.push(`job:${job}`);
|
|
28
|
+
return signatures.length === 0 ? null : signatures.join("|");
|
|
29
|
+
}
|
|
30
|
+
async function signature(file) {
|
|
31
|
+
try {
|
|
32
|
+
const stats = await stat(file);
|
|
33
|
+
return `${Number(stats.ino)}:${stats.mtimeMs}:${stats.ctimeMs}:${stats.size}`;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Per-run analysis costs, keyed on their fingerprint. Nothing here is authoritative. */
|
|
40
|
+
export class AnalysisCostCache {
|
|
41
|
+
slots = new Map();
|
|
42
|
+
get(runId, fingerprint) {
|
|
43
|
+
const slot = this.slots.get(runId);
|
|
44
|
+
return slot?.fingerprint === fingerprint ? { cost: slot.cost } : undefined;
|
|
45
|
+
}
|
|
46
|
+
set(runId, fingerprint, cost) {
|
|
47
|
+
this.slots.set(runId, { fingerprint, cost });
|
|
48
|
+
}
|
|
49
|
+
retain(keep) {
|
|
50
|
+
for (const runId of this.slots.keys())
|
|
51
|
+
if (!keep.has(runId))
|
|
52
|
+
this.slots.delete(runId);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The run's analysis spend for its index entry, read with the same reader stats uses. Undefined
|
|
57
|
+
* when the run sent no analysis request or its run directory cannot be bound.
|
|
58
|
+
*/
|
|
59
|
+
export async function readIndexedAnalysisCost(cwd, runId, cache) {
|
|
60
|
+
const fingerprint = await analysisFingerprint(path.join(cwd, ".humanish", "runs", runId));
|
|
61
|
+
if (fingerprint === null)
|
|
62
|
+
return undefined;
|
|
63
|
+
const cached = cache?.get(runId, fingerprint);
|
|
64
|
+
if (cached !== undefined)
|
|
65
|
+
return cached.cost;
|
|
66
|
+
let prepared;
|
|
67
|
+
try {
|
|
68
|
+
prepared = await bindExistingRunArtifactPaths(cwd, runId);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Not cached: a directory that cannot be bound now may bind on the next refresh.
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
const cost = analysisCostOf(await readAnalysisAccounting(prepared)) ?? undefined;
|
|
75
|
+
cache?.set(runId, fingerprint, cost);
|
|
76
|
+
return cost;
|
|
77
|
+
}
|
package/dist/run/run-index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AnalysisCostCache } from "./run-index-analysis.js";
|
|
2
|
+
import type { RunAnalysisCost } from "./run-cost.js";
|
|
3
|
+
import { type RunLiveness, type RunStatusRecord } from "./status.js";
|
|
4
|
+
import { type RunStudyProvenance } from "./study-provenance.js";
|
|
2
5
|
declare const RUN_INDEX_SCHEMA = "humanish.run-index.v1";
|
|
3
6
|
export interface RunIndexEntry {
|
|
4
7
|
runId: string;
|
|
@@ -12,7 +15,7 @@ export interface RunIndexEntry {
|
|
|
12
15
|
* one run's record carries that pid.
|
|
13
16
|
*/
|
|
14
17
|
pid?: number;
|
|
15
|
-
|
|
18
|
+
study?: RunStudyProvenance;
|
|
16
19
|
startedAt?: string;
|
|
17
20
|
updatedAt?: string;
|
|
18
21
|
completedAt?: string;
|
|
@@ -22,8 +25,13 @@ export interface RunIndexEntry {
|
|
|
22
25
|
reachedGoal: number;
|
|
23
26
|
reportedFriction?: number;
|
|
24
27
|
};
|
|
28
|
+
/** Participants and desktops only; analysis bills separately and is in `analysisCost`. */
|
|
25
29
|
estimatedCostUsd?: number | null;
|
|
26
|
-
/**
|
|
30
|
+
/** False when that figure is a lower bound; absent when unknown (a status record before 0.109). */
|
|
31
|
+
estimatedCostComplete?: boolean;
|
|
32
|
+
/** The run's analysis requests, every attempt counted once; absent when it sent none. */
|
|
33
|
+
analysisCost?: RunAnalysisCost;
|
|
34
|
+
/** Wall-clock span when both ends are known; used for per-study medians. */
|
|
27
35
|
durationMs?: number;
|
|
28
36
|
}
|
|
29
37
|
export interface RunIndexResult {
|
|
@@ -31,7 +39,7 @@ export interface RunIndexResult {
|
|
|
31
39
|
cwd: string;
|
|
32
40
|
/** Newest first, by the best timestamp each entry has. */
|
|
33
41
|
runs: RunIndexEntry[];
|
|
34
|
-
/** Directories that could not be read at all, by name
|
|
42
|
+
/** Directories that could not be read at all, by name: surfaced, never silently dropped. */
|
|
35
43
|
unreadable: string[];
|
|
36
44
|
}
|
|
37
45
|
/** What a cached entry was derived from, so a changed file invalidates exactly that entry. */
|
|
@@ -48,6 +56,8 @@ interface CacheKey {
|
|
|
48
56
|
*/
|
|
49
57
|
export declare class RunIndexCache {
|
|
50
58
|
private readonly slots;
|
|
59
|
+
/** Analysis costs, keyed on their own fingerprint: analysis lands after the status record. */
|
|
60
|
+
readonly analysis: AnalysisCostCache;
|
|
51
61
|
get(runId: string, key: CacheKey): RunIndexEntry | undefined;
|
|
52
62
|
set(runId: string, key: CacheKey, entry: RunIndexEntry): void;
|
|
53
63
|
/** Drop entries for runs that no longer exist, so a long-lived surface cannot leak. */
|
|
@@ -59,7 +69,8 @@ interface BundleFacts {
|
|
|
59
69
|
runId?: string;
|
|
60
70
|
mode?: string;
|
|
61
71
|
createdAt?: string;
|
|
62
|
-
|
|
72
|
+
study?: unknown;
|
|
73
|
+
lab?: unknown;
|
|
63
74
|
persona?: {
|
|
64
75
|
source?: string;
|
|
65
76
|
};
|
|
@@ -79,6 +90,7 @@ interface BundleFacts {
|
|
|
79
90
|
};
|
|
80
91
|
cost?: {
|
|
81
92
|
estimatedTotalUsd?: number | null;
|
|
93
|
+
fullyEstimated?: unknown;
|
|
82
94
|
};
|
|
83
95
|
}
|
|
84
96
|
/**
|
|
@@ -95,8 +107,8 @@ export interface ReadRunIndexOptions {
|
|
|
95
107
|
cache?: RunIndexCache;
|
|
96
108
|
/** Injectable clock, so liveness classification is reproducible in tests. */
|
|
97
109
|
nowMs?: number;
|
|
98
|
-
/** Cap the number of runs returned (newest first). The full directory is still enumerated
|
|
99
|
-
*
|
|
110
|
+
/** Cap the number of runs returned (newest first). The full directory is still enumerated;
|
|
111
|
+
* the cap limits reads, and the count reflects what was read. */
|
|
100
112
|
limit?: number;
|
|
101
113
|
}
|
|
102
114
|
/**
|
package/dist/run/run-index.js
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
// The run index
|
|
1
|
+
// The run index: list and classify every run in a project without parsing bundles.
|
|
2
2
|
//
|
|
3
|
-
// The existing `listRuns` walks each run tree
|
|
3
|
+
// The existing `listRuns` walks each run tree, screenshots included, validating symlinks and
|
|
4
4
|
// then parses each `run.json`: measured 197ms cold / 152ms warm at 25 runs. That is fine for a
|
|
5
5
|
// command that prints once and exits, and much too hot for a surface that refreshes on a cadence
|
|
6
6
|
// over SSH. This module reads the small `status.json` record each run now writes (586 bytes beside
|
|
7
7
|
// a 92KB bundle) and caches per-run entries keyed on the stat of the file each was derived from.
|
|
8
8
|
//
|
|
9
|
-
//
|
|
9
|
+
// Rules, unchanged from the record itself:
|
|
10
10
|
// - `run.json` is the evidence-of-record. Every field here is a projection for listing and
|
|
11
11
|
// classification; nothing here is a claim about what a participant did.
|
|
12
12
|
// - A run with no status record is not assumed finished. It is classified from what is on disk:
|
|
13
|
-
// a bundle means finished, receipts without a bundle mean interrupted. That is the
|
|
14
|
-
// reading of a run whose process died
|
|
13
|
+
// a bundle means finished, receipts without a bundle mean interrupted. That is the
|
|
14
|
+
// reading of a run whose process died (and, before this contract existed, of every run).
|
|
15
15
|
// - One unreadable run directory degrades that run, never the listing.
|
|
16
16
|
import { readdir, readFile, stat } from "node:fs/promises";
|
|
17
17
|
import path from "node:path";
|
|
18
|
-
import {
|
|
18
|
+
import { AnalysisCostCache, readIndexedAnalysisCost } from "./run-index-analysis.js";
|
|
19
|
+
import { RUN_STATUS_FILE, classifyRunStatus, isRunStatusRecord, } from "./status.js";
|
|
20
|
+
import { studyProvenanceOf } from "./study-provenance.js";
|
|
19
21
|
import { RUN_BUNDLE_FILE } from "./bundle.js";
|
|
20
22
|
const RUN_INDEX_SCHEMA = "humanish.run-index.v1";
|
|
21
23
|
/**
|
|
@@ -25,6 +27,8 @@ const RUN_INDEX_SCHEMA = "humanish.run-index.v1";
|
|
|
25
27
|
*/
|
|
26
28
|
export class RunIndexCache {
|
|
27
29
|
slots = new Map();
|
|
30
|
+
/** Analysis costs, keyed on their own fingerprint: analysis lands after the status record. */
|
|
31
|
+
analysis = new AnalysisCostCache();
|
|
28
32
|
get(runId, key) {
|
|
29
33
|
const slot = this.slots.get(runId);
|
|
30
34
|
if (slot === undefined)
|
|
@@ -45,6 +49,7 @@ export class RunIndexCache {
|
|
|
45
49
|
if (!keep.has(runId))
|
|
46
50
|
this.slots.delete(runId);
|
|
47
51
|
}
|
|
52
|
+
this.analysis.retain(keep);
|
|
48
53
|
}
|
|
49
54
|
get size() {
|
|
50
55
|
return this.slots.size;
|
|
@@ -78,7 +83,7 @@ function entryFromStatus(record, nowMs) {
|
|
|
78
83
|
liveness: classifyRunStatus(record, nowMs),
|
|
79
84
|
mode: record.mode,
|
|
80
85
|
...(typeof record.pid === "number" ? { pid: record.pid } : {}),
|
|
81
|
-
...(record
|
|
86
|
+
...studyEntry(studyProvenanceOf(record)),
|
|
82
87
|
startedAt: record.startedAt,
|
|
83
88
|
updatedAt: record.updatedAt,
|
|
84
89
|
...(record.completedAt === undefined ? {} : { completedAt: record.completedAt }),
|
|
@@ -89,6 +94,9 @@ function entryFromStatus(record, nowMs) {
|
|
|
89
94
|
...(record.outcome?.estimatedCostUsd === undefined
|
|
90
95
|
? {}
|
|
91
96
|
: { estimatedCostUsd: record.outcome.estimatedCostUsd }),
|
|
97
|
+
...(typeof record.outcome?.estimatedCostComplete === "boolean"
|
|
98
|
+
? { estimatedCostComplete: record.outcome.estimatedCostComplete }
|
|
99
|
+
: {}),
|
|
92
100
|
...(Number.isFinite(started) && Number.isFinite(ended) ? { durationMs: ended - started } : {}),
|
|
93
101
|
};
|
|
94
102
|
}
|
|
@@ -98,9 +106,9 @@ function usableStatusRecord(raw, runId) {
|
|
|
98
106
|
}
|
|
99
107
|
/**
|
|
100
108
|
* The bundle-only reading, for a run with no usable status record. A bundle on disk usually means
|
|
101
|
-
* the run reached its final write. But a live run now flushes an
|
|
109
|
+
* the run reached its final write. But a live run now flushes an in-progress bundle as it goes (so
|
|
102
110
|
* anything asking what a participant is doing has something to read), and that bundle marks its
|
|
103
|
-
* simulations `running`. With no status record there is no freshness to judge, and the
|
|
111
|
+
* simulations `running`. With no status record there is no freshness to judge, and the
|
|
104
112
|
* reading of "it started, and nothing here says it finished" is interrupted, not finished.
|
|
105
113
|
*/
|
|
106
114
|
function bundleLiveness(bundle) {
|
|
@@ -117,18 +125,16 @@ export function runLiveness(runId, status, bundle, nowMs) {
|
|
|
117
125
|
? { liveness: classifyRunStatus(status, nowMs), record: status }
|
|
118
126
|
: { liveness: bundleLiveness(bundle) };
|
|
119
127
|
}
|
|
128
|
+
function studyEntry(study) {
|
|
129
|
+
return study === undefined ? {} : { study };
|
|
130
|
+
}
|
|
120
131
|
function entryFromBundle(runId, bundle) {
|
|
121
|
-
const legacyLabId = bundle.lab === undefined ? inferLegacyLabId(bundle) : undefined;
|
|
122
132
|
return {
|
|
123
133
|
runId,
|
|
124
134
|
derivedFrom: "bundle",
|
|
125
135
|
liveness: bundleLiveness(bundle),
|
|
126
136
|
...(bundle.mode === "dry-run" || bundle.mode === "live" ? { mode: bundle.mode } : {}),
|
|
127
|
-
...(bundle
|
|
128
|
-
? { lab: bundle.lab }
|
|
129
|
-
: legacyLabId === undefined
|
|
130
|
-
? {}
|
|
131
|
-
: { lab: { id: legacyLabId } }),
|
|
137
|
+
...studyEntry(studyProvenanceOf(bundle)),
|
|
132
138
|
...(bundle.createdAt === undefined ? {} : { startedAt: bundle.createdAt }),
|
|
133
139
|
...(bundle.review?.verdict === undefined ? {} : { verdict: bundle.review.verdict }),
|
|
134
140
|
...(bundle.review?.participants === undefined
|
|
@@ -137,6 +143,9 @@ function entryFromBundle(runId, bundle) {
|
|
|
137
143
|
...(bundle.cost?.estimatedTotalUsd === undefined
|
|
138
144
|
? {}
|
|
139
145
|
: { estimatedCostUsd: bundle.cost.estimatedTotalUsd }),
|
|
146
|
+
...(typeof bundle.cost?.fullyEstimated === "boolean"
|
|
147
|
+
? { estimatedCostComplete: bundle.cost.fullyEstimated }
|
|
148
|
+
: {}),
|
|
140
149
|
};
|
|
141
150
|
}
|
|
142
151
|
/**
|
|
@@ -160,58 +169,15 @@ export async function readRunIndex(cwdInput, options = {}) {
|
|
|
160
169
|
const runs = [];
|
|
161
170
|
const unreadable = [];
|
|
162
171
|
for (const runId of runIds) {
|
|
163
|
-
const
|
|
164
|
-
|
|
165
|
-
const bundleFile = path.join(runDir, RUN_BUNDLE_FILE);
|
|
166
|
-
// Cheapest source first: the status record. Its stat is the cache key, so a live run whose
|
|
167
|
-
// record ticks every 5s re-reads 586 bytes and nothing else.
|
|
168
|
-
const statusKey = await statKey(statusFile);
|
|
169
|
-
if (statusKey !== null) {
|
|
170
|
-
const cached = cache?.get(runId, statusKey);
|
|
171
|
-
if (cached !== undefined) {
|
|
172
|
-
// A running record's liveness is time-dependent, so it is recomputed even on a cache hit:
|
|
173
|
-
// an unchanged record can still have gone stale. An ended record (finished or
|
|
174
|
-
// interrupted, both with completedAt) keeps the liveness it was cached with.
|
|
175
|
-
runs.push(cached.derivedFrom === "status" &&
|
|
176
|
-
cached.updatedAt !== undefined &&
|
|
177
|
-
cached.completedAt === undefined
|
|
178
|
-
? {
|
|
179
|
-
...cached,
|
|
180
|
-
liveness: classifyRunStatus({ state: "running", updatedAt: cached.updatedAt }, nowMs),
|
|
181
|
-
}
|
|
182
|
-
: cached);
|
|
183
|
-
continue;
|
|
184
|
-
}
|
|
185
|
-
const raw = await readJson(statusFile);
|
|
186
|
-
if (usableStatusRecord(raw, runId)) {
|
|
187
|
-
const entry = entryFromStatus(raw, nowMs);
|
|
188
|
-
cache?.set(runId, statusKey, entry);
|
|
189
|
-
runs.push(entry);
|
|
190
|
-
continue;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
// No usable status record: fall back to the bundle. This is every run written before the
|
|
194
|
-
// contract existed, and it is why an old project still lists correctly.
|
|
195
|
-
const bundleKey = await statKey(bundleFile);
|
|
196
|
-
if (bundleKey !== null) {
|
|
197
|
-
const cached = cache?.get(runId, bundleKey);
|
|
198
|
-
if (cached !== undefined) {
|
|
199
|
-
runs.push(cached);
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
|
-
const raw = await readJson(bundleFile);
|
|
203
|
-
if (raw !== null && typeof raw === "object") {
|
|
204
|
-
const entry = entryFromBundle(runId, raw);
|
|
205
|
-
cache?.set(runId, bundleKey, entry);
|
|
206
|
-
runs.push(entry);
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
172
|
+
const entry = await readEntry(runId, path.join(runsRoot, runId), cache, nowMs);
|
|
173
|
+
if (entry === "unreadable") {
|
|
209
174
|
unreadable.push(runId);
|
|
210
175
|
continue;
|
|
211
176
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
177
|
+
const analysisCost = entry.derivedFrom === "directory"
|
|
178
|
+
? undefined
|
|
179
|
+
: await readIndexedAnalysisCost(cwd, runId, cache?.analysis);
|
|
180
|
+
runs.push(analysisCost === undefined ? entry : { ...entry, analysisCost });
|
|
215
181
|
}
|
|
216
182
|
cache?.retain(runIds);
|
|
217
183
|
runs.sort((left, right) => sortKey(right) - sortKey(left));
|
|
@@ -222,6 +188,53 @@ export async function readRunIndex(cwdInput, options = {}) {
|
|
|
222
188
|
unreadable,
|
|
223
189
|
};
|
|
224
190
|
}
|
|
191
|
+
/** One run's entry, cheapest source first, or "unreadable" when its bundle cannot be parsed. */
|
|
192
|
+
async function readEntry(runId, runDir, cache, nowMs) {
|
|
193
|
+
const statusFile = path.join(runDir, RUN_STATUS_FILE);
|
|
194
|
+
const bundleFile = path.join(runDir, RUN_BUNDLE_FILE);
|
|
195
|
+
// Cheapest source first: the status record. Its stat is the cache key, so a live run whose
|
|
196
|
+
// record ticks every 5s re-reads 586 bytes and nothing else.
|
|
197
|
+
const statusKey = await statKey(statusFile);
|
|
198
|
+
if (statusKey !== null) {
|
|
199
|
+
const cached = cache?.get(runId, statusKey);
|
|
200
|
+
if (cached !== undefined) {
|
|
201
|
+
// A running record's liveness is time-dependent, so it is recomputed even on a cache hit:
|
|
202
|
+
// an unchanged record can still have gone stale. An ended record (finished or
|
|
203
|
+
// interrupted, both with completedAt) keeps the liveness it was cached with.
|
|
204
|
+
return cached.derivedFrom === "status" &&
|
|
205
|
+
cached.updatedAt !== undefined &&
|
|
206
|
+
cached.completedAt === undefined
|
|
207
|
+
? {
|
|
208
|
+
...cached,
|
|
209
|
+
liveness: classifyRunStatus({ state: "running", updatedAt: cached.updatedAt }, nowMs),
|
|
210
|
+
}
|
|
211
|
+
: cached;
|
|
212
|
+
}
|
|
213
|
+
const raw = await readJson(statusFile);
|
|
214
|
+
if (usableStatusRecord(raw, runId)) {
|
|
215
|
+
const entry = entryFromStatus(raw, nowMs);
|
|
216
|
+
cache?.set(runId, statusKey, entry);
|
|
217
|
+
return entry;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
// No usable status record: fall back to the bundle. This is every run written before the
|
|
221
|
+
// contract existed, and it is why an old project still lists correctly.
|
|
222
|
+
const bundleKey = await statKey(bundleFile);
|
|
223
|
+
if (bundleKey !== null) {
|
|
224
|
+
const cached = cache?.get(runId, bundleKey);
|
|
225
|
+
if (cached !== undefined)
|
|
226
|
+
return cached;
|
|
227
|
+
const raw = await readJson(bundleFile);
|
|
228
|
+
if (raw === null || typeof raw !== "object")
|
|
229
|
+
return "unreadable";
|
|
230
|
+
const entry = entryFromBundle(runId, raw);
|
|
231
|
+
cache?.set(runId, bundleKey, entry);
|
|
232
|
+
return entry;
|
|
233
|
+
}
|
|
234
|
+
// Neither record nor bundle: receipts without an outcome. That is precisely an interrupted
|
|
235
|
+
// run (the shape a dropped connection leaves), and saying so is more useful than hiding it.
|
|
236
|
+
return { runId, derivedFrom: "directory", liveness: "interrupted" };
|
|
237
|
+
}
|
|
225
238
|
/** Newest-first ordering: the most recent thing known about a run, else its id's own timestamp. */
|
|
226
239
|
function sortKey(entry) {
|
|
227
240
|
for (const candidate of [entry.completedAt, entry.updatedAt, entry.startedAt]) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The message for a run that is not there: how to start one when the project has no runs, or how
|
|
3
|
+
* to list them when it has. Only the runs directory's entry names are read.
|
|
4
|
+
*/
|
|
5
|
+
export declare function runNotFoundMessage(cwdInput: string, runInput: string): Promise<string>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { resolveRunsRoot } from "./paths.js";
|
|
4
|
+
/**
|
|
5
|
+
* The message for a run that is not there: how to start one when the project has no runs, or how
|
|
6
|
+
* to list them when it has. Only the runs directory's entry names are read.
|
|
7
|
+
*/
|
|
8
|
+
export async function runNotFoundMessage(cwdInput, runInput) {
|
|
9
|
+
const cwd = path.resolve(cwdInput);
|
|
10
|
+
const entries = await readdir(resolveRunsRoot(cwd)).catch(() => []);
|
|
11
|
+
const hasRun = entries.some((name) => !name.startsWith(".") && !name.endsWith(".json"));
|
|
12
|
+
return hasRun
|
|
13
|
+
? `No run ${runInput}; humanish runs lists them.`
|
|
14
|
+
: `No runs in ${cwd} yet; start one with humanish run first-run.`;
|
|
15
|
+
}
|
package/dist/run/run.d.ts
CHANGED
|
@@ -2,7 +2,8 @@ import { renderObserver, type ObserverResult } from "../observer/render.js";
|
|
|
2
2
|
import { type RunBundle } from "./bundle.js";
|
|
3
3
|
import type { ExecutionOutcome } from "./judge.js";
|
|
4
4
|
import { type PreparedRunArtifactPaths, type RunIdInUse } from "./paths.js";
|
|
5
|
-
import { type
|
|
5
|
+
import { type RunStatusHandle } from "./status.js";
|
|
6
|
+
import type { RunStudyProvenance } from "./study-provenance.js";
|
|
6
7
|
interface StartRunOptions {
|
|
7
8
|
/** Project directory, in the form the route resolved it. */
|
|
8
9
|
cwd: string;
|
|
@@ -10,10 +11,10 @@ interface StartRunOptions {
|
|
|
10
11
|
runId?: string | undefined;
|
|
11
12
|
mintRunId: () => string;
|
|
12
13
|
mode: "dry-run" | "live";
|
|
13
|
-
|
|
14
|
+
study?: RunStudyProvenance | undefined;
|
|
14
15
|
/** review.md for the published bundle. */
|
|
15
16
|
renderReview: (bundle: RunBundle) => string;
|
|
16
|
-
/** Used by `FinishedRun.renderObserver`; `render` is the `
|
|
17
|
+
/** Used by `FinishedRun.renderObserver`; `render` is the `StudyDeps.renderObserver` seam. */
|
|
17
18
|
observer?: {
|
|
18
19
|
open: boolean;
|
|
19
20
|
render?: typeof renderObserver | undefined;
|
|
@@ -25,8 +26,8 @@ interface Run {
|
|
|
25
26
|
readonly runId: string;
|
|
26
27
|
readonly createdAt: string;
|
|
27
28
|
readonly mode: "dry-run" | "live";
|
|
28
|
-
/** The manifest the run came from
|
|
29
|
-
readonly
|
|
29
|
+
/** The manifest the run came from; bundleHead copies it into the bundle. */
|
|
30
|
+
readonly study?: RunStudyProvenance;
|
|
30
31
|
/** Routes write their evidence files through these and hand them to participants. */
|
|
31
32
|
readonly paths: PreparedRunArtifactPaths;
|
|
32
33
|
/**
|
package/dist/run/run.js
CHANGED
|
@@ -9,7 +9,7 @@ import {} from "./results.js";
|
|
|
9
9
|
import { createRunArtifactPaths, validatePreparedRunArtifactPaths, } from "./paths.js";
|
|
10
10
|
import { registerActiveRun } from "./active-runs.js";
|
|
11
11
|
import { writeContainedOutputFile, writePreparedRunLatestPointer } from "./contained-output.js";
|
|
12
|
-
import { beginRunStatus, runStatusOutcome
|
|
12
|
+
import { beginRunStatus, runStatusOutcome } from "./status.js";
|
|
13
13
|
/** An entry point called in a state that does not admit it. */
|
|
14
14
|
class RunLifecycleError extends Error {
|
|
15
15
|
name = "RunLifecycleError";
|
|
@@ -88,7 +88,7 @@ export async function runScope(fn) {
|
|
|
88
88
|
const created = await createRunArtifactPaths(options.cwd, runId);
|
|
89
89
|
if (!created.ok)
|
|
90
90
|
return created;
|
|
91
|
-
// beginRunStatus reads only the mode and the
|
|
91
|
+
// beginRunStatus reads only the mode and the study provenance from the run's options.
|
|
92
92
|
status = beginRunStatus(created.paths, { ...options, runId });
|
|
93
93
|
// Registered before the first write lands: a signal while it is still settling reaches
|
|
94
94
|
// the handle, whose interrupt queues behind that write.
|
|
@@ -156,7 +156,7 @@ export async function runScope(fn) {
|
|
|
156
156
|
runId,
|
|
157
157
|
createdAt,
|
|
158
158
|
mode: options.mode,
|
|
159
|
-
...(options.
|
|
159
|
+
...(options.study === undefined ? {} : { study: options.study }),
|
|
160
160
|
paths,
|
|
161
161
|
writeSnapshot(bundle) {
|
|
162
162
|
if (closed)
|
|
@@ -9,7 +9,7 @@ export interface SandboxReceipt {
|
|
|
9
9
|
/** Who allocated the sandbox. Receipts written before this field existed have none. */
|
|
10
10
|
provider?: SandboxProviderId;
|
|
11
11
|
sandboxId: string;
|
|
12
|
-
/** The create-time sandbox TTL (ms), when known
|
|
12
|
+
/** The create-time sandbox TTL (ms), when known: how long the server-side backstop runs. */
|
|
13
13
|
timeoutMs?: number;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
@@ -22,7 +22,7 @@ export interface ParsedSandboxReceipt extends Omit<SandboxReceipt, "provider"> {
|
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Append one receipt. Best-effort by design: the receipt exists to protect the run, so a failed
|
|
25
|
-
* receipt write must never fail the participant
|
|
25
|
+
* receipt write must never fail the participant. The only cost of a miss is that `reclaim` cannot see
|
|
26
26
|
* this id and the TTL backstop covers it instead. Containment is the same prepare step every
|
|
27
27
|
* artifact write uses; append (not atomic-replace) keeps racing participants' receipts intact.
|
|
28
28
|
*/
|
|
@@ -6,7 +6,7 @@ import { prepareContainedOutputFile } from "./contained-output.js";
|
|
|
6
6
|
export const SANDBOX_RECEIPTS_ARTIFACT = "sandbox-receipts.ndjson";
|
|
7
7
|
/**
|
|
8
8
|
* Append one receipt. Best-effort by design: the receipt exists to protect the run, so a failed
|
|
9
|
-
* receipt write must never fail the participant
|
|
9
|
+
* receipt write must never fail the participant. The only cost of a miss is that `reclaim` cannot see
|
|
10
10
|
* this id and the TTL backstop covers it instead. Containment is the same prepare step every
|
|
11
11
|
* artifact write uses; append (not atomic-replace) keeps racing participants' receipts intact.
|
|
12
12
|
*/
|
|
@@ -16,7 +16,7 @@ export async function appendSandboxReceipt(root, receipt) {
|
|
|
16
16
|
await appendFile(filePath, `${JSON.stringify(receipt)}\n`, "utf8");
|
|
17
17
|
}
|
|
18
18
|
catch {
|
|
19
|
-
// Swallowed on purpose
|
|
19
|
+
// Swallowed on purpose; see the contract above.
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
/** Parse a receipts file leniently: a torn final line (crash mid-append) drops, valid lines keep. */
|
|
@@ -42,7 +42,7 @@ export function parseSandboxReceipts(text) {
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
catch {
|
|
45
|
-
// torn line
|
|
45
|
+
// A torn line: skip it.
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
return receipts;
|