@reticlehq/server 3.7.0 → 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +59 -68
- package/bin/reticle.js +9 -2
- package/dist/command/cli/adhoc-suite.js +1 -1
- package/dist/command/cli/adhoc-verdict.d.ts +12 -0
- package/dist/command/cli/adhoc-verdict.js +62 -4
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +5 -1
- package/dist/command/cli/auth/cloud-session.d.ts +11 -19
- package/dist/command/cli/auth/cloud-session.js +23 -0
- package/dist/command/cli/auth/device-flow.d.ts +3 -37
- package/dist/command/cli/cli-doctor.js +66 -21
- package/dist/command/cli/cli-flow-commands.js +53 -11
- package/dist/command/cli/cli-kill.d.ts +8 -0
- package/dist/command/cli/cli-kill.js +43 -3
- package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
- package/dist/command/cli/cli-parse-feedback.js +13 -1
- package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
- package/dist/command/cli/cli-parse-grammar.js +1 -6
- package/dist/command/cli/cli-parse-serve.d.ts +24 -0
- package/dist/command/cli/cli-parse-serve.js +124 -0
- package/dist/command/cli/cli-parse.d.ts +12 -11
- package/dist/command/cli/cli-parse.js +100 -123
- package/dist/command/cli/cli-usage.d.ts +0 -11
- package/dist/command/cli/cli-usage.js +43 -16
- package/dist/command/cli/cli-verify.d.ts +1 -1
- package/dist/command/cli/cli-verify.js +29 -14
- package/dist/command/cli/cloud-cli.js +27 -9
- package/dist/command/cli/cloud-kit.js +3 -3
- package/dist/command/cli/cloud-link.d.ts +1 -20
- package/dist/command/cli/cloud-link.js +2 -0
- package/dist/command/cli/cloud-login.d.ts +6 -2
- package/dist/command/cli/cloud-login.js +13 -41
- package/dist/command/cli/config/checkout.d.ts +10 -0
- package/dist/command/cli/config/checkout.js +78 -0
- package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
- package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
- package/dist/command/cli/doctor/doctor-rows.js +4 -0
- package/dist/command/cli/drive/drive-attach.d.ts +5 -0
- package/dist/command/cli/drive/drive-attach.js +21 -1
- package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
- package/dist/command/cli/hook/codex-transcript.js +224 -0
- package/dist/command/cli/hook/episode-structure.d.ts +24 -0
- package/dist/command/cli/hook/episode-structure.js +138 -0
- package/dist/command/cli/hook/hook-command.d.ts +9 -0
- package/dist/command/cli/hook/hook-command.js +211 -0
- package/dist/command/cli/hook/hook-fast.d.ts +31 -0
- package/dist/command/cli/hook/hook-fast.js +136 -0
- package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
- package/dist/command/cli/hook/prompt-hook.js +199 -0
- package/dist/command/cli/hook/tool-hook.d.ts +21 -0
- package/dist/command/cli/hook/tool-hook.js +259 -0
- package/dist/command/cli/launch/cli-launch.d.ts +2 -0
- package/dist/command/cli/launch/cli-launch.js +22 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
- package/dist/command/cli/mcp-command.d.ts +9 -0
- package/dist/command/cli/mcp-command.js +127 -41
- package/dist/command/cli/open-navigate.d.ts +43 -0
- package/dist/command/cli/open-navigate.js +85 -0
- package/dist/command/cli/ports/port-holder.d.ts +16 -4
- package/dist/command/cli/ports/port-holder.js +58 -12
- package/dist/command/cli/ports/resolve/cli-port.js +18 -2
- package/dist/command/cli/project-name.d.ts +1 -7
- package/dist/command/cli/project-name.js +1 -0
- package/dist/command/cli/report-command.d.ts +8 -2
- package/dist/command/cli/report-command.js +95 -18
- package/dist/command/cli/status-fields.d.ts +9 -2
- package/dist/command/cli/status-fields.js +148 -4
- package/dist/command/cli/try-command.d.ts +3 -4
- package/dist/command/cli/try-command.js +6 -11
- package/dist/command/cli/verify-results.d.ts +4 -1
- package/dist/command/cli/verify-results.js +3 -1
- package/dist/command/cli.d.ts +1 -7
- package/dist/command/cli.js +79 -160
- package/dist/command/daemon/daemon-resilience.d.ts +6 -1
- package/dist/command/daemon/daemon-resilience.js +31 -18
- package/dist/command/daemon/daemon.d.ts +11 -0
- package/dist/command/daemon/daemon.js +70 -2
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
- package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
- package/dist/command/daemon/wake-decision.js +4 -2
- package/dist/command/daemon/win32-escape.d.ts +32 -0
- package/dist/command/daemon/win32-escape.js +119 -0
- package/dist/command/setup/agent-configs.d.ts +9 -0
- package/dist/command/setup/agent-configs.js +9 -0
- package/dist/command/setup/auto-approve.d.ts +10 -3
- package/dist/command/setup/auto-approve.js +51 -3
- package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
- package/dist/command/setup/bringup/dev-server-wait.js +5 -1
- package/dist/command/setup/bringup/ensure-daemon.js +4 -7
- package/dist/command/setup/init/init-host.js +6 -0
- package/dist/command/setup/init/init-port.js +5 -4
- package/dist/command/setup/init/init-runtime.js +7 -1
- package/dist/command/setup/node-effects.d.ts +8 -0
- package/dist/command/setup/node-effects.js +36 -4
- package/dist/command/setup/probe/dev-port.d.ts +26 -0
- package/dist/command/setup/probe/dev-port.js +117 -0
- package/dist/command/setup/probe/page-probe.d.ts +1 -1
- package/dist/command/setup/probe/page-probe.js +11 -3
- package/dist/command/setup/remaining-steps.d.ts +0 -7
- package/dist/command/setup/remaining-steps.js +3 -2
- package/dist/command/setup/run-setup.d.ts +11 -0
- package/dist/command/setup/run-setup.js +33 -5
- package/dist/command/setup/setup-command.d.ts +2 -0
- package/dist/command/setup/setup-command.js +22 -4
- package/dist/command/update/updater.d.ts +1 -6
- package/dist/command/update/updater.js +4 -5
- package/dist/command/update/version-seen.d.ts +24 -0
- package/dist/command/update/version-seen.js +65 -0
- package/dist/command/version/peer-announce.d.ts +9 -1
- package/dist/command/version/peer-announce.js +25 -2
- package/dist/command/version/sdk-fix.d.ts +5 -6
- package/dist/command/version/sdk-fix.js +17 -32
- package/dist/command/version/version-skew.d.ts +16 -1
- package/dist/command/version/version-skew.js +84 -10
- package/dist/features/crawl/crawl-tools.js +2 -2
- package/dist/features/crawl/crawl.js +2 -0
- package/dist/features/exhaust/ledger.d.ts +15 -96
- package/dist/features/exhaust/ledger.js +3 -3
- package/dist/features/harness/drive-runs.d.ts +28 -4
- package/dist/features/harness/drive-runs.js +99 -7
- package/dist/features/harness/drivers.d.ts +1 -1
- package/dist/features/harness/drivers.js +1 -1
- package/dist/features/harness/harness.d.ts +5 -0
- package/dist/features/harness/harness.js +24 -12
- package/dist/features/harness/platform/platform-drives.d.ts +7 -1
- package/dist/features/harness/platform/platform-drives.js +12 -7
- package/dist/features/harness/platform/refusal.d.ts +1 -1
- package/dist/features/harness/platform/refusal.js +4 -4
- package/dist/features/harness/platform/remote-drive.js +70 -28
- package/dist/features/harness/platform/server-driver.js +22 -1
- package/dist/features/harness/platform-config.d.ts +1 -10
- package/dist/features/harness/platform-config.js +0 -20
- package/dist/features/license/license.d.ts +2 -14
- package/dist/features/visual/step-shots.d.ts +33 -1
- package/dist/features/visual/step-shots.js +155 -1
- package/dist/features/visual/visual-tools.js +12 -4
- package/dist/hooks/coding-agents.d.ts +6 -0
- package/dist/hooks/coding-agents.js +24 -3
- package/dist/hooks/episode-stamp.d.ts +32 -0
- package/dist/hooks/episode-stamp.js +61 -0
- package/dist/hooks/hook-commands.js +19 -9
- package/dist/index.d.ts +5 -1
- package/dist/index.js +66 -24
- package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
- package/dist/judgement/app-graph/journal-steps.js +92 -0
- package/dist/judgement/capsule/capsule-store.d.ts +2 -39
- package/dist/judgement/domain/domain-model.js +1 -10
- package/dist/judgement/domain/domain-tools.js +4 -2
- package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
- package/dist/judgement/runs/artifact/run-store.js +153 -28
- package/dist/judgement/runs/default-run-id.d.ts +3 -1
- package/dist/judgement/runs/default-run-id.js +15 -3
- package/dist/judgement/runs/drive-run.d.ts +3 -3
- package/dist/judgement/runs/drive-run.js +11 -7
- package/dist/judgement/runs/run-ledger.d.ts +21 -0
- package/dist/judgement/runs/run-ledger.js +143 -0
- package/dist/judgement/runs/runner-port.d.ts +1 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +4 -3
- package/dist/judgement/runs/verification-sync.js +27 -5
- package/dist/language/flows/affected-tools.js +2 -1
- package/dist/language/flows/annotate-notes/annotate.js +8 -3
- package/dist/language/flows/annotate-tools.js +1 -1
- package/dist/language/flows/change/affected.d.ts +8 -0
- package/dist/language/flows/change/affected.js +20 -7
- package/dist/language/flows/decision.js +19 -4
- package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
- package/dist/language/flows/fields/flow-secret-field.js +67 -5
- package/dist/language/flows/flow-anchor.d.ts +5 -0
- package/dist/language/flows/flow-anchor.js +4 -0
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +9 -0
- package/dist/language/flows/flow-expect-grammar.js +15 -10
- package/dist/language/flows/flow-intent.js +6 -1
- package/dist/language/flows/flow-journey.d.ts +8 -0
- package/dist/language/flows/flow-journey.js +13 -0
- package/dist/language/flows/flow-lease.d.ts +27 -0
- package/dist/language/flows/flow-lease.js +59 -0
- package/dist/language/flows/flow-replay-run.d.ts +1 -87
- package/dist/language/flows/flow-replay-run.js +111 -310
- package/dist/language/flows/flow-replay.js +21 -19
- package/dist/language/flows/flow-replayable.d.ts +38 -0
- package/dist/language/flows/flow-replayable.js +179 -0
- package/dist/language/flows/flow-start-path.d.ts +108 -0
- package/dist/language/flows/flow-start-path.js +313 -0
- package/dist/language/flows/flow-step-runners.d.ts +23 -2
- package/dist/language/flows/flow-step-runners.js +191 -32
- package/dist/language/flows/flow-store-for-session.d.ts +8 -1
- package/dist/language/flows/flow-store-for-session.js +6 -0
- package/dist/language/flows/flow-tools.d.ts +2 -23
- package/dist/language/flows/flow-tools.js +63 -113
- package/dist/language/flows/flows.d.ts +4 -6
- package/dist/language/flows/flows.js +90 -15
- package/dist/language/flows/heal-run.d.ts +10 -4
- package/dist/language/flows/heal-run.js +26 -9
- package/dist/language/flows/recording/flake.d.ts +3 -27
- package/dist/language/flows/recording/flake.js +1 -1
- package/dist/language/flows/recording/recording-backtrack.js +1 -4
- package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
- package/dist/language/flows/recording/tape/recordings.js +9 -3
- package/dist/language/flows/replay.d.ts +25 -5
- package/dist/language/flows/replay.js +83 -16
- package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
- package/dist/language/flows/suite/coverage.d.ts +9 -0
- package/dist/language/flows/suite/coverage.js +12 -1
- package/dist/language/flows/suite-selection.d.ts +25 -0
- package/dist/language/flows/suite-selection.js +41 -9
- package/dist/machine/git-tracks.d.ts +6 -0
- package/dist/machine/git-tracks.js +36 -0
- package/dist/memory/cloud/background-sync.d.ts +25 -0
- package/dist/memory/cloud/background-sync.js +79 -0
- package/dist/memory/cloud/cloud-config.d.ts +12 -1
- package/dist/memory/cloud/cloud-config.js +39 -13
- package/dist/memory/cloud/cloud-sync.d.ts +3 -24
- package/dist/memory/cloud/cloud-sync.js +5 -2
- package/dist/memory/cloud/harness-config.d.ts +0 -7
- package/dist/memory/cloud/memory-scope.d.ts +19 -0
- package/dist/memory/cloud/memory-scope.js +48 -0
- package/dist/memory/cloud/sync-answer.d.ts +43 -0
- package/dist/memory/cloud/sync-answer.js +42 -0
- package/dist/memory/cloud/sync-cycle.d.ts +40 -10
- package/dist/memory/cloud/sync-cycle.js +97 -144
- package/dist/memory/cloud/sync-daemon.d.ts +50 -3
- package/dist/memory/cloud/sync-daemon.js +473 -83
- package/dist/memory/cloud/sync-describe.d.ts +28 -0
- package/dist/memory/cloud/sync-describe.js +92 -0
- package/dist/memory/cloud/sync-disk.d.ts +9 -1
- package/dist/memory/cloud/sync-disk.js +137 -33
- package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
- package/dist/memory/cloud/sync-flow-versions.js +42 -0
- package/dist/memory/impact/impact-store.js +32 -15
- package/dist/memory/intent/intent-shard.d.ts +41 -266
- package/dist/memory/intent/intent-tools.js +20 -61
- package/dist/memory/intent/record-request.d.ts +27 -0
- package/dist/memory/intent/record-request.js +88 -0
- package/dist/memory/intent/settled-words.js +9 -1
- package/dist/memory/journal/drive-flow.d.ts +3 -0
- package/dist/memory/journal/drive-flow.js +11 -41
- package/dist/memory/journal/envelope-store.js +1 -1
- package/dist/memory/journal/envelope.d.ts +6 -154
- package/dist/memory/journal/episode-log.d.ts +107 -0
- package/dist/memory/journal/episode-log.js +302 -0
- package/dist/memory/journal/journal-recorder.d.ts +7 -0
- package/dist/memory/journal/journal-recorder.js +22 -9
- package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
- package/dist/memory/journal/on-disk/ambient-file.js +1 -1
- package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
- package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
- package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
- package/dist/memory/journal/self-observation.js +3 -1
- package/dist/memory/journal/session-end.js +23 -9
- package/dist/memory/journal/session-journal.js +39 -20
- package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
- package/dist/memory/project/artifact-root-resolver.js +68 -23
- package/dist/memory/project/artifact-root.d.ts +17 -3
- package/dist/memory/project/artifact-root.js +47 -9
- package/dist/memory/project/fs/fs-port.d.ts +5 -0
- package/dist/memory/project/fs/fs-port.js +13 -0
- package/dist/memory/project/learned-routes.d.ts +3 -4
- package/dist/memory/project/learned-routes.js +3 -11
- package/dist/memory/project/link-directory.js +5 -2
- package/dist/memory/project/root-claims.d.ts +3 -1
- package/dist/memory/project/root-claims.js +41 -7
- package/dist/memory/project/session-root.d.ts +1 -1
- package/dist/memory/project/session-root.js +1 -15
- package/dist/memory/project/sync-status.js +5 -6
- package/dist/memory/recall/memory-tools.js +2 -2
- package/dist/memory/recall/platform-memory.d.ts +3 -1
- package/dist/memory/recall/platform-memory.js +9 -1
- package/dist/memory/recall/project-memory.js +15 -19
- package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
- package/dist/portal/bridge/auth-failure-reason.js +19 -0
- package/dist/portal/bridge/bridge.d.ts +19 -4
- package/dist/portal/bridge/bridge.js +150 -177
- package/dist/portal/bridge/harness-request.d.ts +15 -0
- package/dist/portal/bridge/harness-request.js +19 -0
- package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
- package/dist/portal/bridge/origin/origin-follow.js +110 -0
- package/dist/portal/bridge/pairing-token.d.ts +6 -0
- package/dist/portal/bridge/pairing-token.js +47 -16
- package/dist/portal/bridge/protocol-skew.d.ts +27 -2
- package/dist/portal/bridge/protocol-skew.js +66 -2
- package/dist/portal/bridge/session-nonces.d.ts +46 -0
- package/dist/portal/bridge/session-nonces.js +72 -0
- package/dist/portal/input/viewport-tools.d.ts +31 -0
- package/dist/portal/input/viewport-tools.js +106 -15
- package/dist/portal/pool/bounded-close.d.ts +23 -0
- package/dist/portal/pool/bounded-close.js +38 -0
- package/dist/portal/pool/browser-pool.d.ts +44 -39
- package/dist/portal/pool/browser-pool.js +247 -95
- package/dist/portal/pool/context-permissions.d.ts +9 -1
- package/dist/portal/pool/context-permissions.js +26 -0
- package/dist/portal/pool/lease-emulation.d.ts +37 -0
- package/dist/portal/pool/lease-emulation.js +29 -0
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +74 -7
- package/dist/portal/pool/pool-contract.d.ts +23 -1
- package/dist/portal/pool/pool-lease.d.ts +128 -0
- package/dist/portal/pool/pool-lease.js +49 -0
- package/dist/portal/pool/zero-install.d.ts +8 -1
- package/dist/portal/pool/zero-install.js +24 -2
- package/dist/portal/production/production-activation.d.ts +136 -0
- package/dist/portal/production/production-activation.js +173 -0
- package/dist/portal/production/production-drive.d.ts +52 -0
- package/dist/portal/production/production-drive.js +301 -0
- package/dist/portal/production/production-hello.d.ts +23 -0
- package/dist/portal/production/production-hello.js +23 -0
- package/dist/portal/realm/web-realm.js +42 -15
- package/dist/portal/session/control-envelope.d.ts +1 -1
- package/dist/portal/session/dev-server/served-document.d.ts +0 -5
- package/dist/portal/session/dev-server/served-document.js +6 -8
- package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
- package/dist/portal/session/first-run-wiring.d.ts +3 -36
- package/dist/portal/session/first-run-wiring.js +10 -103
- package/dist/portal/session/live-control-tools.js +61 -19
- package/dist/portal/session/no-session-next-action.d.ts +11 -0
- package/dist/portal/session/no-session-next-action.js +40 -15
- package/dist/portal/session/no-session-watch.d.ts +7 -0
- package/dist/portal/session/no-session-watch.js +67 -23
- package/dist/portal/session/output-budget.d.ts +10 -0
- package/dist/portal/session/output-budget.js +16 -0
- package/dist/portal/session/presence/session-lease.d.ts +2 -0
- package/dist/portal/session/presence/session-lease.js +8 -0
- package/dist/portal/session/recorded-gaps.d.ts +15 -11
- package/dist/portal/session/recorded-gaps.js +39 -18
- package/dist/portal/session/serving-directory.d.ts +24 -2
- package/dist/portal/session/serving-directory.js +93 -5
- package/dist/portal/session/session-info.d.ts +26 -0
- package/dist/portal/session/session-info.js +20 -0
- package/dist/portal/session/session-manager.d.ts +35 -3
- package/dist/portal/session/session-manager.js +69 -14
- package/dist/portal/session/session-successor.js +1 -9
- package/dist/portal/session/session-tools.js +22 -4
- package/dist/portal/session/session.d.ts +10 -10
- package/dist/portal/session/session.js +37 -29
- package/dist/portal/session/zero-install-first-call.d.ts +7 -2
- package/dist/portal/session/zero-install-first-call.js +43 -20
- package/dist/start-wiring.d.ts +2 -2
- package/dist/start-wiring.js +17 -3
- package/dist/status-payload.d.ts +11 -1
- package/dist/status-payload.js +7 -1
- package/dist/surface/agent-presence-grace.d.ts +11 -0
- package/dist/surface/agent-presence-grace.js +34 -0
- package/dist/surface/http-server.d.ts +12 -1
- package/dist/surface/http-server.js +64 -15
- package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
- package/dist/surface/mcp/faults/mcp-outage.js +19 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
- package/dist/surface/mcp/mcp-proxy.js +194 -267
- package/dist/surface/mcp/mcp.d.ts +20 -3
- package/dist/surface/mcp/mcp.js +88 -25
- package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
- package/dist/surface/mcp/proxy/drive-calls.js +114 -5
- package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
- package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
- package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
- package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
- package/dist/surface/mcp/server-instructions.js +35 -16
- package/dist/surface/mcp/shared-params.d.ts +8 -0
- package/dist/surface/mcp/shared-params.js +15 -1
- package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
- package/dist/surface/mcp/sse-frame-parser.js +18 -0
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +13 -0
- package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
- package/dist/surface/mcp/tool-catalog-cache.js +14 -4
- package/dist/surface/tools/account-tool.d.ts +4 -3
- package/dist/surface/tools/account-tool.js +20 -31
- package/dist/surface/tools/act/act-danger.d.ts +2 -0
- package/dist/surface/tools/act/act-danger.js +41 -14
- package/dist/surface/tools/act/act-observation.d.ts +11 -0
- package/dist/surface/tools/act/act-observation.js +33 -0
- package/dist/surface/tools/act/act-preflight.js +10 -3
- package/dist/surface/tools/act/act-sequence-retry.js +2 -1
- package/dist/surface/tools/act/act-target.js +19 -5
- package/dist/surface/tools/act/durable.js +1 -1
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
- package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
- package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
- package/dist/surface/tools/act/unsettled-find.js +71 -0
- package/dist/surface/tools/act-sequence-tool.js +53 -24
- package/dist/surface/tools/act-tools.d.ts +2 -3
- package/dist/surface/tools/act-tools.js +49 -47
- package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
- package/dist/surface/tools/agent/for-the-agent.js +41 -3
- package/dist/surface/tools/assert/assert-grade.js +8 -3
- package/dist/surface/tools/assert/assert-verdict.js +4 -2
- package/dist/surface/tools/browser-tools.js +7 -4
- package/dist/surface/tools/chat-drives.js +50 -25
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.d.ts +8 -0
- package/dist/surface/tools/dynamic-tools.js +89 -34
- package/dist/surface/tools/empty-session-list.d.ts +18 -25
- package/dist/surface/tools/empty-session-list.js +67 -38
- package/dist/surface/tools/error-recovery.d.ts +17 -7
- package/dist/surface/tools/error-recovery.js +53 -20
- package/dist/surface/tools/explore-tools.d.ts +10 -0
- package/dist/surface/tools/explore-tools.js +72 -19
- package/dist/surface/tools/feedback-tools.js +23 -2
- package/dist/surface/tools/gap-novelty.d.ts +6 -0
- package/dist/surface/tools/gap-novelty.js +9 -0
- package/dist/surface/tools/gaps/capability-absences.js +4 -3
- package/dist/surface/tools/harness-explore.d.ts +1 -1
- package/dist/surface/tools/harness-explore.js +6 -4
- package/dist/surface/tools/harness-gate.d.ts +43 -21
- package/dist/surface/tools/harness-gate.js +55 -81
- package/dist/surface/tools/harness-script.d.ts +2 -0
- package/dist/surface/tools/harness-script.js +11 -6
- package/dist/surface/tools/harness-toolset.js +3 -4
- package/dist/surface/tools/invoke-tool.d.ts +0 -8
- package/dist/surface/tools/invoke-tool.js +164 -178
- package/dist/surface/tools/lease-hint.d.ts +9 -0
- package/dist/surface/tools/lease-hint.js +22 -3
- package/dist/surface/tools/lease-permissions.d.ts +1 -1
- package/dist/surface/tools/lease-readiness.d.ts +55 -0
- package/dist/surface/tools/lease-readiness.js +150 -2
- package/dist/surface/tools/lease-tools.d.ts +3 -75
- package/dist/surface/tools/lease-tools.js +124 -188
- package/dist/surface/tools/map-tools.d.ts +20 -0
- package/dist/surface/tools/map-tools.js +145 -0
- package/dist/surface/tools/merge-tools.js +11 -7
- package/dist/surface/tools/next-step.js +6 -3
- package/dist/surface/tools/observe-tools.js +46 -35
- package/dist/surface/tools/platform-moment.d.ts +3 -12
- package/dist/surface/tools/platform-moment.js +12 -24
- package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
- package/dist/surface/tools/read/complete-snapshot.js +13 -2
- package/dist/surface/tools/read/query-paginate.js +6 -0
- package/dist/surface/tools/read/query-shape.d.ts +9 -0
- package/dist/surface/tools/read/query-shape.js +15 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
- package/dist/surface/tools/read-tools.js +5 -5
- package/dist/surface/tools/real-input-attempt.d.ts +11 -0
- package/dist/surface/tools/real-input-attempt.js +206 -38
- package/dist/surface/tools/reconcile-tools.js +21 -8
- package/dist/surface/tools/reticle-result.d.ts +3 -0
- package/dist/surface/tools/reticle-result.js +8 -1
- package/dist/surface/tools/run-report.d.ts +22 -0
- package/dist/surface/tools/run-report.js +141 -0
- package/dist/surface/tools/session-ports.d.ts +57 -0
- package/dist/surface/tools/session-ports.js +102 -0
- package/dist/surface/tools/tool-kit.d.ts +58 -4
- package/dist/surface/tools/tool-kit.js +140 -6
- package/dist/surface/tools/tool-surface.d.ts +2 -0
- package/dist/surface/tools/tool-surface.js +45 -0
- package/dist/surface/tools/tools.js +49 -87
- package/dist/telemetry/automation-hint.d.ts +5 -0
- package/dist/telemetry/automation-hint.js +7 -0
- package/dist/telemetry/cli-telemetry.d.ts +22 -0
- package/dist/telemetry/cli-telemetry.js +80 -11
- package/dist/telemetry/daemon-telemetry.d.ts +3 -1
- package/dist/telemetry/daemon-telemetry.js +9 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +8 -3
- package/dist/telemetry/feedback.d.ts +1 -1
- package/dist/telemetry/feedback.js +51 -4
- package/dist/telemetry/harness-run.d.ts +3 -3
- package/dist/telemetry/harness-run.js +18 -7
- package/dist/telemetry/hud-events.d.ts +1 -1
- package/dist/telemetry/hud-metrics.d.ts +6 -3
- package/dist/telemetry/hud-metrics.js +20 -8
- package/dist/telemetry/install-source.js +1 -1
- package/dist/telemetry/mcp-connection.d.ts +1 -1
- package/dist/telemetry/mcp-connection.js +21 -2
- package/dist/telemetry/onboarding-firsts.d.ts +6 -1
- package/dist/telemetry/onboarding-firsts.js +41 -1
- package/dist/telemetry/proxy-telemetry.d.ts +42 -0
- package/dist/telemetry/proxy-telemetry.js +70 -1
- package/dist/telemetry/session-metrics.d.ts +1 -3
- package/dist/telemetry/session-metrics.js +16 -12
- package/dist/telemetry/telemetry.d.ts +9 -1
- package/dist/telemetry/telemetry.js +16 -1
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +7 -1
- package/dist/wire-journal.js +12 -2
- package/docs/README.md +4 -2
- package/docs/actions.mdx +7 -6
- package/docs/adapters.md +2 -1
- package/docs/agent-cheatsheet.md +19 -5
- package/docs/architecture.md +13 -10
- package/docs/autodrive.md +6 -5
- package/docs/benchmarks.md +2 -2
- package/docs/capabilities.mdx +1 -1
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +6 -6
- package/docs/cli/doctor.mdx +3 -1
- package/docs/cli/feedback.mdx +11 -7
- package/docs/cli/gate.mdx +1 -1
- package/docs/cli/help.mdx +1 -1
- package/docs/cli/init.mdx +20 -16
- package/docs/cli/mcp.mdx +5 -2
- package/docs/cli/open.mdx +5 -2
- package/docs/cli/report.mdx +1 -1
- package/docs/cli/restart.mdx +1 -1
- package/docs/cli/rollback.mdx +4 -4
- package/docs/cli/serve.mdx +7 -5
- package/docs/cli/setup.mdx +1 -1
- package/docs/cli/status.mdx +6 -2
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/telemetry.mdx +5 -1
- package/docs/cli/try.mdx +8 -8
- package/docs/cli/update.mdx +8 -5
- package/docs/cli/verify.mdx +12 -5
- package/docs/cli/version.mdx +1 -1
- package/docs/cli.mdx +10 -6
- package/docs/debugging.md +1 -1
- package/docs/deploy-checks.md +8 -6
- package/docs/desktop.mdx +14 -18
- package/docs/enterprise.md +6 -6
- package/docs/environment.mdx +5 -3
- package/docs/faq.mdx +9 -6
- package/docs/first-drive.md +19 -9
- package/docs/flows.md +3 -4
- package/docs/for-agents.md +1 -1
- package/docs/frameworks.mdx +34 -11
- package/docs/getting-started.md +46 -29
- package/docs/http-transport.md +2 -2
- package/docs/human-control.md +8 -8
- package/docs/index.mdx +2 -2
- package/docs/install-agentic.mdx +18 -19
- package/docs/install-manual.mdx +8 -4
- package/docs/integration-patterns.md +5 -5
- package/docs/multi-agent-testing.md +7 -5
- package/docs/packages/browser.mdx +34 -2
- package/docs/packages/core.mdx +2 -1
- package/docs/packages/electron.mdx +15 -3
- package/docs/packages/eslint-plugin.mdx +1 -1
- package/docs/packages/next.mdx +17 -5
- package/docs/packages/react.mdx +8 -1
- package/docs/packages/server.mdx +3 -3
- package/docs/packages/tauri.mdx +3 -3
- package/docs/packages/vite-plugin.mdx +1 -1
- package/docs/packages.mdx +19 -6
- package/docs/platform-integration.md +12 -4
- package/docs/predicates.mdx +18 -7
- package/docs/production-mode.md +108 -0
- package/docs/prompt-capture.md +99 -0
- package/docs/quickstart.mdx +14 -12
- package/docs/recipes.mdx +9 -8
- package/docs/required-checks.md +3 -2
- package/docs/skill-file.mdx +4 -3
- package/docs/skill-setup.md +2 -2
- package/docs/skill.md +62 -70
- package/docs/state-files.md +1 -0
- package/docs/state-management.mdx +11 -9
- package/docs/system-map.md +14 -13
- package/docs/telemetry.md +32 -24
- package/docs/testing.md +9 -5
- package/docs/tools/act-and-wait.mdx +17 -13
- package/docs/tools/act-sequence.mdx +40 -66
- package/docs/tools/act.mdx +7 -5
- package/docs/tools/assert.mdx +1 -1
- package/docs/tools/look.mdx +1 -1
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/network.mdx +13 -11
- package/docs/tools/overview.mdx +3 -3
- package/docs/tools/query.mdx +3 -3
- package/docs/tools/session-and-feedback.mdx +9 -6
- package/docs/tools/sessions.mdx +7 -0
- package/docs/tools/snapshot.mdx +9 -7
- package/docs/tools/tools-and-run.mdx +11 -10
- package/docs/tools/verify.mdx +1 -1
- package/docs/troubleshooting.mdx +21 -9
- package/docs/usage.md +58 -43
- package/docs/use-cases.mdx +2 -2
- package/docs/vs-chrome-devtools-mcp.mdx +5 -5
- package/docs/vs-playwright-mcp.mdx +5 -4
- package/docs/what-is-recorded.md +12 -7
- package/docs/what-is-reticle.mdx +2 -2
- package/docs/why-reticle.mdx +1 -1
- package/package.json +9 -12
- package/dist/command/dev/stale-issue-guard.d.ts +0 -34
- package/dist/command/dev/stale-issue-guard.js +0 -69
|
@@ -9,11 +9,10 @@
|
|
|
9
9
|
*
|
|
10
10
|
* Attach-only: the pool drives a browser against an already-running dev server — it never starts one.
|
|
11
11
|
*/
|
|
12
|
-
import
|
|
13
|
-
import { mutationPortFor } from '../../portal/input/network-mutation.js';
|
|
12
|
+
import * as production from '../../portal/production/production-activation.js';
|
|
14
13
|
import { z } from 'zod';
|
|
15
|
-
import { leaseNotConnectedHint } from './lease-hint.js';
|
|
16
|
-
import { probeLeaseAlive,
|
|
14
|
+
import { leaseNotConnectedHint, leaseReaderFailedHint, leaseStillLoadingHint, } from './lease-hint.js';
|
|
15
|
+
import { connectOrInject, moveReusedLease, notReadyReason, probeLeaseAlive, } from './lease-readiness.js';
|
|
17
16
|
import { probeSdkMarker } from './gaps/sdk-marker-probe.js';
|
|
18
17
|
import { observeWebDocument } from '../../portal/session/dev-server/served-document.js';
|
|
19
18
|
import { diagnoseObservedWebCsp } from '@reticlehq/init';
|
|
@@ -22,12 +21,15 @@ import { hasAnyAppConnectedBefore } from '../../memory/recall/prior/connection-m
|
|
|
22
21
|
import { AGENT_DRIVING_ELSEWHERE, AGENT_DRIVING_HERE_AGAIN, watchersToNotify, } from '../../portal/session/lease-visibility.js';
|
|
23
22
|
import { reticleStateHome } from '../../command/daemon/daemon.js';
|
|
24
23
|
import { claimArtifactRoot, dropArtifactRootClaim } from '../../memory/project/root-claims.js';
|
|
25
|
-
import { LeaseNotReadyReason, RETICLE_URL_PARAM, RETICLE_DEFAULT_PORT, SeedStorageSchema, } from '@reticlehq/core';
|
|
24
|
+
import { LeaseNotReadyReason, RETICLE_URL_PARAM, RETICLE_DEFAULT_PORT, SeedStorageSchema, originOf, } from '@reticlehq/core';
|
|
26
25
|
import { HudVisibility, ReticleTool, SESSION_HEALTH } from '@reticlehq/core';
|
|
27
26
|
import { HOST_STUB_NOTE } from './tool-kit.js';
|
|
27
|
+
import { PoolAtCapacityError } from '../../portal/pool/browser-pool.js';
|
|
28
28
|
import { asString } from '@reticlehq/core';
|
|
29
29
|
import { chromiumPreflightRefusal } from '../../command/cli/doctor/browser/chromium-hint.js';
|
|
30
30
|
import { LEASE_PERMISSIONS_ARG, hintOf, notificationReadBack, parseLeasePermissions, permissionRefusal, refuseRegrant, } from './lease-permissions.js';
|
|
31
|
+
import { LEASE_EMULATE_ARG, leaseEmulationOf } from '../../portal/input/viewport-tools.js';
|
|
32
|
+
export { sessionMutationPort, sessionPerturbationPort, suiteFixturePort, suiteFixtureSeed, } from './session-ports.js';
|
|
31
33
|
/**
|
|
32
34
|
* Everything the daemon already knows about why a leased tab might not have dialled in.
|
|
33
35
|
*
|
|
@@ -51,11 +53,13 @@ import { LEASE_PERMISSIONS_ARG, hintOf, notificationReadBack, parseLeasePermissi
|
|
|
51
53
|
*/
|
|
52
54
|
async function observedCspBlock(url, port) {
|
|
53
55
|
const document = await observeWebDocument(url);
|
|
54
|
-
if (document === undefined)
|
|
56
|
+
if (document === undefined) {
|
|
55
57
|
return undefined;
|
|
58
|
+
}
|
|
56
59
|
const refusesSocket = diagnoseObservedWebCsp(document, port).some((finding) => `${finding.problem} ${finding.fix}`.includes(CONNECT_SRC));
|
|
57
|
-
if (!refusesSocket)
|
|
60
|
+
if (!refusesSocket) {
|
|
58
61
|
return undefined;
|
|
62
|
+
}
|
|
59
63
|
const allow = `ws://localhost:${String(port)} ws://127.0.0.1:${String(port)}`;
|
|
60
64
|
return {
|
|
61
65
|
problem: `its ${CONNECT_SRC} does not allow ws://localhost:${String(port)}`,
|
|
@@ -81,15 +85,6 @@ async function leaseEvidence(deps, port, url) {
|
|
|
81
85
|
};
|
|
82
86
|
}
|
|
83
87
|
const POOL_UNAVAILABLE = 'browser pool unavailable — the lease tools need the daemon-managed pool (start Reticle via `reticle mcp`).';
|
|
84
|
-
/** The origin of a URL, or undefined when it does not parse. */
|
|
85
|
-
function originOf(url) {
|
|
86
|
-
try {
|
|
87
|
-
return new URL(url).origin;
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
return undefined;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
88
|
const ALREADY_HELD_LEASE = 'you already hold a lease on this origin';
|
|
94
89
|
function alreadyHeldHint(sessionId, origin) {
|
|
95
90
|
return (`${ALREADY_HELD_LEASE} (${origin}): ${sessionId} — reused it rather than opening a second ` +
|
|
@@ -108,8 +103,9 @@ export function appendReticleParams(url, session, projectId, hud) {
|
|
|
108
103
|
if (projectId !== undefined && projectId.length > 0) {
|
|
109
104
|
u.searchParams.set(RETICLE_URL_PARAM.PROJECT, projectId);
|
|
110
105
|
}
|
|
111
|
-
if (hud !== undefined)
|
|
106
|
+
if (hud !== undefined) {
|
|
112
107
|
u.searchParams.set(RETICLE_URL_PARAM.HUD, hud);
|
|
108
|
+
}
|
|
113
109
|
return u.toString();
|
|
114
110
|
}
|
|
115
111
|
catch {
|
|
@@ -143,8 +139,9 @@ function newLeaseId() {
|
|
|
143
139
|
* so `lease-abc` cannot claim `lease-abcdef`.
|
|
144
140
|
*/
|
|
145
141
|
export function resolveLeasedSessionId(sessions, leaseId) {
|
|
146
|
-
if (sessions.get(leaseId) !== undefined)
|
|
142
|
+
if (sessions.get(leaseId) !== undefined) {
|
|
147
143
|
return leaseId;
|
|
144
|
+
}
|
|
148
145
|
return sessions.all().find((s) => sessionParamOf(s.url) === leaseId)?.id;
|
|
149
146
|
}
|
|
150
147
|
/**
|
|
@@ -162,17 +159,20 @@ export function resolveLeasedSessionId(sessions, leaseId) {
|
|
|
162
159
|
*/
|
|
163
160
|
export function carryReticleIdentity(fromUrl, toUrl) {
|
|
164
161
|
const session = sessionParamOf(fromUrl);
|
|
165
|
-
if (session === undefined)
|
|
162
|
+
if (session === undefined) {
|
|
166
163
|
return toUrl;
|
|
164
|
+
}
|
|
167
165
|
// Already addressed (a caller passing the stamped URL back) — appending would be a no-op at best.
|
|
168
|
-
if (sessionParamOf(toUrl) !== undefined)
|
|
166
|
+
if (sessionParamOf(toUrl) !== undefined) {
|
|
169
167
|
return toUrl;
|
|
168
|
+
}
|
|
170
169
|
const projectId = projectParamOf(fromUrl);
|
|
171
170
|
return appendReticleParams(toUrl, session, projectId);
|
|
172
171
|
}
|
|
173
172
|
function projectParamOf(url) {
|
|
174
|
-
if (url === undefined)
|
|
173
|
+
if (url === undefined) {
|
|
175
174
|
return undefined;
|
|
175
|
+
}
|
|
176
176
|
try {
|
|
177
177
|
return new URL(url).searchParams.get(RETICLE_URL_PARAM.PROJECT) ?? undefined;
|
|
178
178
|
}
|
|
@@ -181,8 +181,9 @@ function projectParamOf(url) {
|
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
function sessionParamOf(url) {
|
|
184
|
-
if (url === undefined)
|
|
184
|
+
if (url === undefined) {
|
|
185
185
|
return undefined;
|
|
186
|
+
}
|
|
186
187
|
try {
|
|
187
188
|
return new URL(url).searchParams.get(RETICLE_URL_PARAM.SESSION) ?? undefined;
|
|
188
189
|
}
|
|
@@ -190,15 +191,6 @@ function sessionParamOf(url) {
|
|
|
190
191
|
return undefined;
|
|
191
192
|
}
|
|
192
193
|
}
|
|
193
|
-
const LEASE_READY_ATTEMPTS = 100;
|
|
194
|
-
const LEASE_READY_POLL_MS = 100;
|
|
195
|
-
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
196
|
-
/**
|
|
197
|
-
* Poll until the leased tab's SDK has actually registered on the bridge, so the sessionId we return
|
|
198
|
-
* is immediately usable (the page navigates first, then connects a moment later — without this wait
|
|
199
|
-
* an agent's very next call could race and hit "no connected session"). Returns whether it connected
|
|
200
|
-
* in time. `isConnected`, `sleeper`, and `attempts` are injected so this is fast to unit-test.
|
|
201
|
-
*/
|
|
202
194
|
/**
|
|
203
195
|
* Acquire a leased, SDK-connected context for a caller that is not the lease TOOL (the parallel suite).
|
|
204
196
|
* Returns the session id plus its release; the caller must release in a finally so a crashed flow never
|
|
@@ -224,8 +216,9 @@ export async function acquireLeasedSession(pool, sessions, url, projectId, seedS
|
|
|
224
216
|
registeredId = resolveLeasedSessionId(sessions, lease.sessionId);
|
|
225
217
|
return registeredId !== undefined;
|
|
226
218
|
});
|
|
227
|
-
if (registeredId !== undefined)
|
|
219
|
+
if (registeredId !== undefined) {
|
|
228
220
|
pool.alias?.(registeredId, lease.sessionId);
|
|
221
|
+
}
|
|
229
222
|
const effectiveId = registeredId ?? lease.sessionId;
|
|
230
223
|
if (seedStorage !== undefined) {
|
|
231
224
|
const session = sessions.get(effectiveId);
|
|
@@ -238,31 +231,6 @@ export async function acquireLeasedSession(pool, sessions, url, projectId, seedS
|
|
|
238
231
|
}
|
|
239
232
|
return { sessionId: effectiveId, release: () => lease.release() };
|
|
240
233
|
}
|
|
241
|
-
export async function waitForLeasedSession(isConnected, sleeper = sleep, attempts = LEASE_READY_ATTEMPTS, pollMs = LEASE_READY_POLL_MS) {
|
|
242
|
-
for (let i = 0; i < attempts; i++) {
|
|
243
|
-
if (isConnected())
|
|
244
|
-
return true;
|
|
245
|
-
await sleeper(pollMs);
|
|
246
|
-
}
|
|
247
|
-
return isConnected();
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Wait for the leased tab to connect; if its app never does, hand it the zero-install reader.
|
|
251
|
-
*
|
|
252
|
-
* The decision is taken HERE, by the daemon, on the one fact that settles it: no HELLO arrived. A
|
|
253
|
-
* timer inside the page cannot know that — an app can connect from a dynamic import that resolves
|
|
254
|
-
* after `load` — and a reader injected into a page whose app was about to connect would take its
|
|
255
|
-
* place and drop the app's own options. So an app that connected itself is never touched, and a page
|
|
256
|
-
* that stayed silent through the whole readiness wait is the one that gets a reader.
|
|
257
|
-
*/
|
|
258
|
-
export async function connectOrInject(lease, isConnected, wait = waitForLeasedSession) {
|
|
259
|
-
if (await wait(isConnected))
|
|
260
|
-
return { ready: true, zeroInstall: false };
|
|
261
|
-
if (true !== (await lease.injectReader?.()))
|
|
262
|
-
return { ready: false, zeroInstall: false };
|
|
263
|
-
const ready = await wait(isConnected);
|
|
264
|
-
return { ready, zeroInstall: ready };
|
|
265
|
-
}
|
|
266
234
|
/**
|
|
267
235
|
* Named on its own because `reticle drive <url>` runs it too.
|
|
268
236
|
*
|
|
@@ -280,11 +248,12 @@ export function hasOriginLock(origin) {
|
|
|
280
248
|
}
|
|
281
249
|
export const LEASE_ACQUIRE_TOOL = {
|
|
282
250
|
name: ReticleTool.LEASE_ACQUIRE,
|
|
283
|
-
description: 'Lease a fresh isolated browser context from the shared pool (shown or hidden as the daemon was started; `headed: true` forces a window) and navigate it to the app URL (the app must already be running; one with no Reticle SDK gets one supplied, reported as zeroInstall). If this origin is already leased and still connected, this returns THAT session rather than minting a second tab — a second acquire on the same origin poisons default session resolution. Returns the sessionId the leased tab registers — pass it to other tools. The pool keeps all leases in ONE browser and caps concurrency; if
|
|
251
|
+
description: 'Lease a fresh isolated browser context from the shared pool (shown or hidden as the daemon was started; `headed: true` forces a window) and navigate it to the app URL (the app must already be running; one with no Reticle SDK gets one supplied, reported as zeroInstall). If this origin is already leased and still connected, this returns THAT session rather than minting a second tab — a second acquire on the same origin poisons default session resolution. Returns the sessionId the leased tab registers — pass it to other tools. The pool keeps all leases in ONE browser and caps concurrency; if every slot is taken this is refused at once, naming the cap, rather than queued. Release with reticle_lease{action:"release"} when the flow is done. PREFER AN ALREADY-OPEN TAB: if reticle_sessions lists a non-leased session for this app, drive THAT instead — a lease is invisible to the person watching the app, whose HUD lives in their own tab, and a tab flagged hidden/throttled is often still driveable. Lease for isolation you actually need (a second identity, a clean context, parallel flows) or when driving the open tab has failed — this call answers with `preferExisting` when a live tab was available.',
|
|
284
252
|
inputSchema: {
|
|
285
253
|
url: z
|
|
286
254
|
.string()
|
|
287
|
-
.
|
|
255
|
+
.optional()
|
|
256
|
+
.describe('URL of the already-running app to drive (e.g. http://localhost:3000/dashboard). Omit it to lease the one dev server that runs in this project folder.'),
|
|
288
257
|
projectId: z
|
|
289
258
|
.string()
|
|
290
259
|
.optional()
|
|
@@ -307,10 +276,12 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
307
276
|
.optional()
|
|
308
277
|
.describe('How the HUD starts on the page: shown (default), hidden, or removed.'),
|
|
309
278
|
permissions: LEASE_PERMISSIONS_ARG,
|
|
279
|
+
emulate: LEASE_EMULATE_ARG,
|
|
280
|
+
production: production.PRODUCTION_LEASE_ARG,
|
|
310
281
|
root: z
|
|
311
282
|
.string()
|
|
312
283
|
.optional()
|
|
313
|
-
.describe("Absolute path of the .reticle folder this lease's runs belong in — the caller's project. Without it, the page's project id decides, and a page with none lands in ~/.reticle/unmatched, which nothing syncs."),
|
|
284
|
+
.describe("Absolute path of the .reticle folder this lease's runs belong in — the caller's project. The project folder itself is accepted when it contains a .reticle. Without it, the page's project id decides, and a page with none lands in ~/.reticle/unmatched, which nothing syncs."),
|
|
314
285
|
},
|
|
315
286
|
outputSchema: {
|
|
316
287
|
sessionId: z.string(),
|
|
@@ -331,9 +302,11 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
331
302
|
LeaseNotReadyReason.SDK_NEVER_DIALLED,
|
|
332
303
|
LeaseNotReadyReason.SDK_STOPPED_ANSWERING,
|
|
333
304
|
LeaseNotReadyReason.TAB_HIDDEN,
|
|
305
|
+
LeaseNotReadyReason.NOT_HTML_DOCUMENT,
|
|
306
|
+
LeaseNotReadyReason.READER_FAILED,
|
|
334
307
|
])
|
|
335
308
|
.optional()
|
|
336
|
-
.describe('Present only when ready is false. sdk_never_dialled ⇒ nothing connected within the wait, so check the install (the app may not embed @reticlehq/core). sdk_stopped_answering ⇒ an SDK did connect and has stopped replying, so the tab is wedged and needs recovering, not reinstalling. tab_hidden ⇒ the SDK answers but its tab is hidden, so timers and animations are throttled and nothing on it verifies; bring the tab to the front, or release and re-acquire.'),
|
|
309
|
+
.describe('Present only when ready is false. sdk_never_dialled ⇒ nothing connected within the wait, so check the install (the app may not embed @reticlehq/core), unless the hint says the page was still loading, in which case it is a slow first compile and checking reticle_session { action: "list" } shortly is the next step. sdk_stopped_answering ⇒ an SDK did connect and has stopped replying, so the tab is wedged and needs recovering, not reinstalling. tab_hidden ⇒ the SDK answers but its tab is hidden, so timers and animations are throttled and nothing on it verifies; bring the tab to the front, or release and re-acquire. not_html_document ⇒ the URL is not an HTML page (an `.svg`, for example), so acquire an HTML page of the app instead. reader_failed ⇒ the zero-install reader failed, for example because the tab closed during setup; the hint gives the cause. For both, the lease is already released.'),
|
|
337
310
|
expiresInMs: z
|
|
338
311
|
.number()
|
|
339
312
|
.describe('Milliseconds until this lease expires if untouched. Each tool call that targets this session resets the clock. Plan your work to finish or re-acquire before this runs out.'),
|
|
@@ -347,7 +320,12 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
347
320
|
.boolean()
|
|
348
321
|
.optional()
|
|
349
322
|
.describe('True when this acquire returned an existing live lease on the same origin rather than minting a second context.'),
|
|
323
|
+
navigated: z
|
|
324
|
+
.boolean()
|
|
325
|
+
.optional()
|
|
326
|
+
.describe('Present when a reused lease was on another page. True: its tab was moved to url. False: it could not be moved, and url is the page it is on.'),
|
|
350
327
|
hint: z.string().optional(),
|
|
328
|
+
production: production.PRODUCTION_LEASE_OUTPUT,
|
|
351
329
|
versionSkew: z
|
|
352
330
|
.string()
|
|
353
331
|
.optional()
|
|
@@ -357,11 +335,14 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
357
335
|
},
|
|
358
336
|
handler: async (deps, args) => {
|
|
359
337
|
const pool = deps.pool;
|
|
360
|
-
if (pool === undefined)
|
|
338
|
+
if (pool === undefined) {
|
|
361
339
|
throw new Error(POOL_UNAVAILABLE);
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
340
|
+
}
|
|
341
|
+
const given = asString(args['url']);
|
|
342
|
+
const url = given === undefined || 0 === given.length ? await deps.projectAppUrl?.() : given;
|
|
343
|
+
if (url === undefined) {
|
|
344
|
+
throw new Error('reticle_lease{action:"acquire"} requires a url: no single dev server runs in this project folder. Start the app, or pass the url it serves.');
|
|
345
|
+
}
|
|
365
346
|
// Preflight the browser before spending the round trip. Without it a missing Playwright Chromium
|
|
366
347
|
// only surfaces inside pool.acquire, where the launch failure is caught and reported as
|
|
367
348
|
// "could not open <url> — is the app running?" — sending the caller to debug an app that is
|
|
@@ -369,14 +350,16 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
369
350
|
// installed" so error-recovery routes it to the NO_POOL fix (install + drive a human tab).
|
|
370
351
|
if (deps.browserProbe !== undefined) {
|
|
371
352
|
const refusal = chromiumPreflightRefusal(await deps.browserProbe());
|
|
372
|
-
if (refusal !== undefined)
|
|
353
|
+
if (refusal !== undefined) {
|
|
373
354
|
throw new Error(refusal);
|
|
355
|
+
}
|
|
374
356
|
}
|
|
375
357
|
const projectId = asString(args['projectId']);
|
|
376
358
|
const root = asString(args['root']);
|
|
377
359
|
const headed = true === args['headed'];
|
|
378
360
|
const hud = Object.values(HudVisibility).find((v) => v === args['hud']);
|
|
379
|
-
const permissions = parseLeasePermissions(args['permissions']);
|
|
361
|
+
const permissions = production.leasePermissions(parseLeasePermissions(args['permissions']), args['production']);
|
|
362
|
+
const emulate = leaseEmulationOf(args['emulate']);
|
|
380
363
|
// The stub of the shell bindings, when the caller supplied one. Installed by the pool before
|
|
381
364
|
// the first navigation, so it is already defined when the app's first module runs.
|
|
382
365
|
const initScript = asString(args['initScript']);
|
|
@@ -395,6 +378,10 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
395
378
|
}
|
|
396
379
|
validatedSeed = parsed.data;
|
|
397
380
|
}
|
|
381
|
+
// Awaited only when asked: an extra tick here reorders concurrent acquires on the origin lock.
|
|
382
|
+
const activated = args['production'] === undefined
|
|
383
|
+
? undefined
|
|
384
|
+
: await production.activationFor(deps, args['production'], url, root);
|
|
398
385
|
// Sampled BEFORE acquiring: afterwards this lease is itself a session, and the point is to name
|
|
399
386
|
// a tab that already existed. A human's open tab is the one they can watch, so if one is here
|
|
400
387
|
// the agent should be told at the moment it is choosing — not after it has gone dark on them.
|
|
@@ -437,7 +424,12 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
437
424
|
const certMismatch = existing !== undefined &&
|
|
438
425
|
'boolean' === typeof certAsked &&
|
|
439
426
|
pool.ignoresHTTPSErrors(existing) !== certAsked;
|
|
440
|
-
|
|
427
|
+
// Emulation is set before the first paint, so a held lease is replaced like a seeded one.
|
|
428
|
+
if ((validatedSeed !== undefined ||
|
|
429
|
+
certMismatch ||
|
|
430
|
+
emulate !== undefined ||
|
|
431
|
+
activated !== undefined) &&
|
|
432
|
+
existing !== undefined) {
|
|
441
433
|
// Seeding or a different certificate setting asked for: release its own context so the new
|
|
442
434
|
// lease starts with what was asked.
|
|
443
435
|
await pool.release(existing);
|
|
@@ -463,16 +455,16 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
463
455
|
// old, or there may be none at all — `unresponsive` is set by past commands failing, and
|
|
464
456
|
// its own contract says absence means "answering, OR NOT ASKED YET". So the happy path of
|
|
465
457
|
// a first acquire pays nothing for this.
|
|
458
|
+
const tabUrl = () => deps.sessions.get(resolved)?.url;
|
|
459
|
+
const moved = await moveReusedLease(tabUrl, url, () => pool.gotoLease(existing, carryReticleIdentity(tabUrl(), url)), deps.now);
|
|
466
460
|
const reusedSession = deps.sessions.get(resolved);
|
|
467
|
-
const
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
: tabHidden(reusedSession)
|
|
471
|
-
? LeaseNotReadyReason.TAB_HIDDEN
|
|
472
|
-
: undefined;
|
|
461
|
+
const reuseReason = false === moved?.arrived
|
|
462
|
+
? LeaseNotReadyReason.SDK_NEVER_DIALLED
|
|
463
|
+
: notReadyReason(await probeLeaseAlive(reusedSession), reusedSession);
|
|
473
464
|
return {
|
|
474
465
|
sessionId: resolved,
|
|
475
|
-
url,
|
|
466
|
+
url: moved?.url ?? url,
|
|
467
|
+
...(moved === undefined ? {} : { navigated: moved.navigated }),
|
|
476
468
|
ready: reuseReason === undefined,
|
|
477
469
|
...(reuseReason === undefined ? {} : { notReadyReason: reuseReason }),
|
|
478
470
|
reused: true,
|
|
@@ -495,25 +487,34 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
495
487
|
}
|
|
496
488
|
const sessionId = newLeaseId();
|
|
497
489
|
// Before the page can dial in: the session is stamped with its root the moment it registers.
|
|
498
|
-
if (root !== undefined)
|
|
490
|
+
if (root !== undefined) {
|
|
499
491
|
claimArtifactRoot(sessionId, root);
|
|
500
|
-
|
|
492
|
+
}
|
|
493
|
+
const navUrl = appendReticleParams(activated?.url ?? url, sessionId, projectId, hud);
|
|
501
494
|
let lease;
|
|
502
495
|
try {
|
|
503
496
|
lease = await pool.acquire(navUrl, {
|
|
504
497
|
sessionId,
|
|
498
|
+
// An agent, or `reticle drive` behind it, is waiting on this answer and cannot see a queue:
|
|
499
|
+
// a full pool is said at once, not discovered as a 60 s silence (#1535).
|
|
500
|
+
whenFull: 'refuse',
|
|
505
501
|
...(headed ? { headed } : {}),
|
|
506
502
|
...(deps.attachId === undefined ? {} : { owner: deps.attachId }),
|
|
507
503
|
...(validatedSeed !== undefined ? { seedStorage: validatedSeed } : {}),
|
|
508
504
|
...(initScript !== undefined ? { initScript } : {}),
|
|
509
505
|
...(permissions !== undefined ? { permissions } : {}),
|
|
510
506
|
...(true === args['ignoreHTTPSErrors'] ? { ignoreHTTPSErrors: true } : {}),
|
|
507
|
+
...(emulate === undefined ? {} : { emulate }),
|
|
511
508
|
});
|
|
512
509
|
}
|
|
513
510
|
catch (err) {
|
|
511
|
+
if (err instanceof PoolAtCapacityError) {
|
|
512
|
+
throw err;
|
|
513
|
+
}
|
|
514
514
|
const refusal = permissionRefusal(err);
|
|
515
|
-
if (refusal !== undefined)
|
|
515
|
+
if (refusal !== undefined) {
|
|
516
516
|
throw refusal;
|
|
517
|
+
}
|
|
517
518
|
if (err instanceof Error && err.message.startsWith('Storage seeding failed')) {
|
|
518
519
|
throw new Error(scrubSeedFromError(err.message, validatedSeed));
|
|
519
520
|
}
|
|
@@ -525,7 +526,9 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
525
526
|
// Resolved rather than assumed: an app that names its own session registers under that name,
|
|
526
527
|
// and the id we hand back has to be the one the agent can actually drive.
|
|
527
528
|
let registeredId;
|
|
528
|
-
const
|
|
529
|
+
const waitStartedAt = Date.now();
|
|
530
|
+
const waited = await production.guardedForProduction(pool, lease, activated);
|
|
531
|
+
const { ready, zeroInstall, stillLoading, readerFailure } = await connectOrInject(waited, () => {
|
|
529
532
|
registeredId = resolveLeasedSessionId(deps.sessions, lease.sessionId);
|
|
530
533
|
return registeredId !== undefined;
|
|
531
534
|
});
|
|
@@ -533,8 +536,9 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
533
536
|
// under the id we are about to hand back, and the pool is keyed by the id it navigated with;
|
|
534
537
|
// without this the touches miss, the lease ages out despite continuous activity, and the
|
|
535
538
|
// reaper closes the context mid-flow. See BrowserPool.alias and #157.
|
|
536
|
-
if (registeredId !== undefined)
|
|
539
|
+
if (registeredId !== undefined) {
|
|
537
540
|
pool.alias(registeredId, lease.sessionId);
|
|
541
|
+
}
|
|
538
542
|
const effectiveSessionId = registeredId ?? lease.sessionId;
|
|
539
543
|
const session = deps.sessions.get(effectiveSessionId);
|
|
540
544
|
if (validatedSeed !== undefined && session !== undefined) {
|
|
@@ -543,16 +547,31 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
543
547
|
session.setPreconditionFailure?.(failureReason);
|
|
544
548
|
}
|
|
545
549
|
}
|
|
546
|
-
// The lease now exists, so any HUD a human is watching has just gone dark. Say so.
|
|
547
|
-
|
|
550
|
+
// The lease now exists, so any HUD a human is watching has just gone dark. Say so. A lease whose
|
|
551
|
+
// reader failed is already released, so there is nothing to say.
|
|
552
|
+
if (readerFailure === undefined) {
|
|
553
|
+
tellWatchers(deps, projectId, AGENT_DRIVING_ELSEWHERE);
|
|
554
|
+
}
|
|
548
555
|
// ready means the SDK dialled in — not that contracts match. Carry the skew warning on acquire
|
|
549
556
|
// so the agent does not learn it only after a CDP tool invents a closed page (#688).
|
|
550
|
-
const mintReason =
|
|
551
|
-
|
|
552
|
-
: tabHidden(session)
|
|
553
|
-
? LeaseNotReadyReason.TAB_HIDDEN
|
|
554
|
-
: undefined;
|
|
557
|
+
const mintReason = readerFailure?.reason ??
|
|
558
|
+
notReadyReason(ready, session, LeaseNotReadyReason.SDK_NEVER_DIALLED);
|
|
555
559
|
const versionSkew = registeredId === undefined ? undefined : deps.sessions.get(registeredId)?.versionSkew;
|
|
560
|
+
let notReadyHint;
|
|
561
|
+
if (!ready) {
|
|
562
|
+
if (readerFailure !== undefined) {
|
|
563
|
+
notReadyHint = leaseReaderFailedHint(url, readerFailure);
|
|
564
|
+
}
|
|
565
|
+
else if (true === stillLoading) {
|
|
566
|
+
notReadyHint = leaseStillLoadingHint(url, Date.now() - waitStartedAt);
|
|
567
|
+
}
|
|
568
|
+
else if (activated !== undefined) {
|
|
569
|
+
notReadyHint = production.notActivatedHint(url);
|
|
570
|
+
}
|
|
571
|
+
else {
|
|
572
|
+
notReadyHint = await notConnectedHint(deps, url, pool.dialFailureUrl?.(lease.sessionId));
|
|
573
|
+
}
|
|
574
|
+
}
|
|
556
575
|
return {
|
|
557
576
|
sessionId: registeredId ?? lease.sessionId,
|
|
558
577
|
url,
|
|
@@ -575,10 +594,9 @@ export const LEASE_ACQUIRE_TOOL = {
|
|
|
575
594
|
},
|
|
576
595
|
}),
|
|
577
596
|
...(versionSkew === undefined ? {} : { versionSkew }),
|
|
597
|
+
...production.summary(activated),
|
|
578
598
|
...(initScript === undefined ? {} : { hostStub: HOST_STUB_NOTE }),
|
|
579
|
-
...hintOf(ready
|
|
580
|
-
? undefined
|
|
581
|
-
: await notConnectedHint(deps, url, pool.dialFailureUrl?.(lease.sessionId)), ready ? await notificationReadBack(pool, lease.sessionId, permissions) : undefined),
|
|
599
|
+
...hintOf(notReadyHint, ready ? await notificationReadBack(pool, lease.sessionId, permissions) : undefined),
|
|
582
600
|
};
|
|
583
601
|
}
|
|
584
602
|
finally {
|
|
@@ -612,12 +630,19 @@ const LEASE_RELEASE_TOOL = {
|
|
|
612
630
|
},
|
|
613
631
|
handler: async (deps, args) => {
|
|
614
632
|
const pool = deps.pool;
|
|
615
|
-
if (pool === undefined)
|
|
633
|
+
if (pool === undefined) {
|
|
616
634
|
throw new Error(POOL_UNAVAILABLE);
|
|
635
|
+
}
|
|
617
636
|
const sessionId = asString(args['sessionId']);
|
|
618
637
|
if (sessionId === undefined || 0 === sessionId.length) {
|
|
619
638
|
throw new Error('reticle_lease{action:"release"} requires a sessionId');
|
|
620
639
|
}
|
|
640
|
+
// An id that holds no lease (a typo, or one that expired) answered `released: true`.
|
|
641
|
+
if (pool.leaseUrl(sessionId) === undefined) {
|
|
642
|
+
const held = pool.leasedSessionIds();
|
|
643
|
+
throw new Error(`reticle_lease{action:"release"}: no lease '${sessionId}' is held, so nothing was released. ` +
|
|
644
|
+
(0 === held.length ? 'No lease is held now.' : `Leases held now: ${held.join(', ')}.`));
|
|
645
|
+
}
|
|
621
646
|
return { released: true, leased: await releaseLease(deps, pool, sessionId) };
|
|
622
647
|
},
|
|
623
648
|
};
|
|
@@ -636,8 +661,9 @@ export async function releaseLease(deps, pool, sessionId) {
|
|
|
636
661
|
dropArtifactRootClaim(sessionId);
|
|
637
662
|
// Only once the LAST lease is gone. Announcing "live again" while another lease still drives
|
|
638
663
|
// would be a lie, and a HUD that says the wrong thing is worse than one that says nothing.
|
|
639
|
-
if (0 === pool.activeCount())
|
|
664
|
+
if (0 === pool.activeCount()) {
|
|
640
665
|
tellWatchers(deps, projectId, AGENT_DRIVING_HERE_AGAIN);
|
|
666
|
+
}
|
|
641
667
|
return pool.activeCount();
|
|
642
668
|
}
|
|
643
669
|
/**
|
|
@@ -665,11 +691,13 @@ const PREFER_EXISTING_NOTE = 'a non-leased tab for this app was already connecte
|
|
|
665
691
|
*/
|
|
666
692
|
function liveTabFor(deps, projectId, url) {
|
|
667
693
|
const pool = deps.pool;
|
|
668
|
-
if (pool === undefined)
|
|
694
|
+
if (pool === undefined) {
|
|
669
695
|
return undefined;
|
|
696
|
+
}
|
|
670
697
|
const wanted = originOf(url);
|
|
671
|
-
if (wanted === undefined)
|
|
698
|
+
if (wanted === undefined) {
|
|
672
699
|
return undefined;
|
|
700
|
+
}
|
|
673
701
|
try {
|
|
674
702
|
const candidates = deps.sessions
|
|
675
703
|
.all()
|
|
@@ -693,8 +721,9 @@ function liveTabFor(deps, projectId, url) {
|
|
|
693
721
|
*/
|
|
694
722
|
function tellWatchers(deps, projectId, text) {
|
|
695
723
|
const pool = deps.pool;
|
|
696
|
-
if (pool === undefined)
|
|
724
|
+
if (pool === undefined) {
|
|
697
725
|
return;
|
|
726
|
+
}
|
|
698
727
|
try {
|
|
699
728
|
const candidates = deps.sessions
|
|
700
729
|
.all()
|
|
@@ -708,96 +737,3 @@ function tellWatchers(deps, projectId, text) {
|
|
|
708
737
|
}
|
|
709
738
|
}
|
|
710
739
|
export const LEASE_TOOLS = [LEASE_ACQUIRE_TOOL, LEASE_RELEASE_TOOL];
|
|
711
|
-
/**
|
|
712
|
-
* The state a suite should boot its flows from: whatever the agent is already sitting in.
|
|
713
|
-
*
|
|
714
|
-
* This is the join the fixture work was building toward. A suite's flows each start from cold, so
|
|
715
|
-
* fifty of them prove the login works fifty times — and the flow that LOGS OUT leaves every flow
|
|
716
|
-
* after it signed out, which no navigation repairs, because the problem is not where the subject is
|
|
717
|
-
* but what it holds. A seed is applied to an isolated context BEFORE the first navigation, which is
|
|
718
|
-
* exactly and only when a fixture can work.
|
|
719
|
-
*
|
|
720
|
-
* Best-effort, deliberately. A fixture is an OPTIMISATION over running from cold, and running from
|
|
721
|
-
* cold is correct: a suite that refused to start because a cookie jar could not be read would have
|
|
722
|
-
* traded a slow answer for no answer. Every "no" here — no provider, no storage support, nothing
|
|
723
|
-
* driven, a browser that threw, nothing worth seeding — produces the same honest `undefined`, and
|
|
724
|
-
* the suite runs exactly as it did before any of this existed.
|
|
725
|
-
*/
|
|
726
|
-
export async function suiteFixtureSeed(realInput, appUrl) {
|
|
727
|
-
if (realInput === undefined)
|
|
728
|
-
return undefined;
|
|
729
|
-
try {
|
|
730
|
-
const port = await fixturePortFor(realInput, appUrl);
|
|
731
|
-
if (port === undefined)
|
|
732
|
-
return undefined;
|
|
733
|
-
return seedFromStorageState(await port.capture(), appUrl);
|
|
734
|
-
}
|
|
735
|
-
catch {
|
|
736
|
-
return undefined;
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
/**
|
|
740
|
-
* A way to make this session's page SLOW on purpose, or nothing.
|
|
741
|
-
*
|
|
742
|
-
* The third of these seams, for the same reason as the other two: a feature reaching into the input
|
|
743
|
-
* layer directly is a feature depending on a driver, and the boundary guard asks about it.
|
|
744
|
-
*
|
|
745
|
-
* Installs delays and NOTHING else. A rule that carried a status or a body would substitute a
|
|
746
|
-
* response the server never sent, and an app raced against invented data produces invented races —
|
|
747
|
-
* a fabricated defect handed to somebody at 3am, which is worse than finding nothing.
|
|
748
|
-
*/
|
|
749
|
-
export async function sessionPerturbationPort(realInput, appUrl) {
|
|
750
|
-
if (realInput === undefined || appUrl === undefined)
|
|
751
|
-
return undefined;
|
|
752
|
-
const setMocks = realInput.setMocks?.bind(realInput);
|
|
753
|
-
if (setMocks === undefined)
|
|
754
|
-
return undefined;
|
|
755
|
-
if (!(await realInput.isAvailableFor(appUrl)))
|
|
756
|
-
return undefined;
|
|
757
|
-
return {
|
|
758
|
-
slow: async (rules) => {
|
|
759
|
-
await setMocks(appUrl, [...rules]);
|
|
760
|
-
},
|
|
761
|
-
/** Clearing is the undo. A page left slowed is damage the next run inherits. */
|
|
762
|
-
clear: async () => {
|
|
763
|
-
await setMocks(appUrl, []);
|
|
764
|
-
},
|
|
765
|
-
};
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* Save/restore for this session's page, or nothing.
|
|
769
|
-
*
|
|
770
|
-
* The same job as `suiteFixtureSeed` next door, stopping one step earlier: that one captures and
|
|
771
|
-
* converts, this hands back the PORT so a caller can re-apply what it captured later. It lives here
|
|
772
|
-
* for the reason written above — a feature reaching into the input layer directly is a feature
|
|
773
|
-
* depending on a driver, and the boundary guard asks about it. It asked.
|
|
774
|
-
*/
|
|
775
|
-
export async function suiteFixturePort(realInput, appUrl) {
|
|
776
|
-
if (realInput === undefined || appUrl === undefined)
|
|
777
|
-
return undefined;
|
|
778
|
-
try {
|
|
779
|
-
return await fixturePortFor(realInput, appUrl);
|
|
780
|
-
}
|
|
781
|
-
catch {
|
|
782
|
-
return undefined;
|
|
783
|
-
}
|
|
784
|
-
}
|
|
785
|
-
/**
|
|
786
|
-
* A way to break this session's page, or nothing.
|
|
787
|
-
*
|
|
788
|
-
* Sits beside `suiteFixtureSeed` because it is the same shape of job: turning a provider capability
|
|
789
|
-
* into something a feature can use, on the one side of the graph that is allowed to know about both.
|
|
790
|
-
* A flow tool reaching into the input layer directly would be a feature depending on a driver, which
|
|
791
|
-
* is the reach the boundary guard exists to ask about.
|
|
792
|
-
*/
|
|
793
|
-
export async function sessionMutationPort(realInput, appUrl) {
|
|
794
|
-
if (realInput === undefined || appUrl === undefined)
|
|
795
|
-
return undefined;
|
|
796
|
-
try {
|
|
797
|
-
return await mutationPortFor(realInput, appUrl);
|
|
798
|
-
}
|
|
799
|
-
catch {
|
|
800
|
-
// A provider that cannot answer is the same answer as a provider that cannot break anything.
|
|
801
|
-
return undefined;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type AppMap, type JournalAction, type ReticleEvent } from '@reticlehq/core';
|
|
2
|
+
import { type ToolDef } from './tool-kit.js';
|
|
3
|
+
/** One session, as the fold reads it. */
|
|
4
|
+
export interface MapSession {
|
|
5
|
+
id: string;
|
|
6
|
+
actions: readonly JournalAction[];
|
|
7
|
+
events: readonly ReticleEvent[];
|
|
8
|
+
}
|
|
9
|
+
/** One screen on the map, with how much of it was pressed and proven. */
|
|
10
|
+
export interface MapScreen {
|
|
11
|
+
screen: string;
|
|
12
|
+
actions: number;
|
|
13
|
+
pressed: number;
|
|
14
|
+
proven: number;
|
|
15
|
+
}
|
|
16
|
+
/** The project's sessions folded into one graph; undefined when none pressed anything. */
|
|
17
|
+
export declare function graphOfSessions(sessions: readonly MapSession[]): AppMap | undefined;
|
|
18
|
+
/** Each screen with its actions counted: what is there, what was pressed, what held. */
|
|
19
|
+
export declare function screensOf(map: AppMap): MapScreen[];
|
|
20
|
+
export declare const MAP_TOOLS: ToolDef[];
|