@reticlehq/server 3.9.0 → 3.10.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/SKILL.md +13 -12
- package/dist/command/cli/adhoc-suite.js +2 -0
- package/dist/command/cli/adhoc-verdict.d.ts +2 -43
- package/dist/command/cli/adhoc-verdict.js +50 -187
- package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
- package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
- package/dist/command/cli/cli-doctor.js +1 -1
- package/dist/command/cli/cli-flow-commands.js +2 -9
- package/dist/command/cli/cli-kill.js +1 -1
- package/dist/command/cli/cli-parse-compare.d.ts +22 -0
- package/dist/command/cli/cli-parse-compare.js +75 -0
- package/dist/command/cli/cli-parse-grade.d.ts +36 -0
- package/dist/command/cli/cli-parse-grade.js +75 -0
- package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
- package/dist/command/cli/cli-parse-grammar.js +18 -20
- package/dist/command/cli/cli-parse-verify.d.ts +10 -0
- package/dist/command/cli/cli-parse-verify.js +63 -14
- package/dist/command/cli/cli-parse.d.ts +17 -15
- package/dist/command/cli/cli-parse.js +44 -27
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +29 -20
- package/dist/command/cli/cli-usage.js +58 -29
- package/dist/command/cli/cli-verify.d.ts +11 -2
- package/dist/command/cli/cli-verify.js +27 -8
- package/dist/command/cli/cloud-cli.js +2 -119
- package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
- package/dist/command/cli/daemon-link/daemon-client.js +205 -0
- package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
- package/dist/command/cli/doctor-repairs.js +1 -1
- package/dist/command/cli/ensure-daemon.d.ts +26 -0
- package/dist/command/cli/ensure-daemon.js +57 -0
- package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
- package/dist/command/cli/finished-run/grade-command.js +180 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +1 -1
- package/dist/command/cli/ports/port-holder.d.ts +9 -0
- package/dist/command/cli/ports/port-holder.js +27 -3
- package/dist/command/cli/status/status-lines.d.ts +1 -0
- package/dist/command/cli/status/status-lines.js +22 -0
- package/dist/command/cli/status-fields.d.ts +5 -1
- package/dist/command/cli/status-fields.js +7 -3
- package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
- package/dist/command/cli/two-builds/compare-command.js +314 -0
- package/dist/command/cli/verify-against.d.ts +61 -0
- package/dist/command/cli/verify-against.js +187 -0
- package/dist/command/cli/verify-no-session.d.ts +2 -0
- package/dist/command/cli/verify-no-session.js +13 -0
- package/dist/command/cli/verify-results.d.ts +35 -2
- package/dist/command/cli/verify-results.js +76 -10
- package/dist/command/cli.js +46 -41
- package/dist/command/daemon/daemon-resolve.d.ts +8 -1
- package/dist/command/daemon/daemon-resolve.js +27 -1
- package/dist/command/daemon/daemon.d.ts +12 -1
- package/dist/command/daemon/daemon.js +35 -4
- package/dist/command/daemon/lifetime/death-cause.js +21 -2
- package/dist/command/daemon/lifetime/heartbeat.js +7 -2
- package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
- package/dist/command/daemon/lifetime/startup-failure.js +62 -0
- package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
- package/dist/command/setup/bringup/dev-server-files.js +17 -0
- package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
- package/dist/command/setup/bringup/static-page-server.js +43 -9
- package/dist/command/setup/init/init-runtime.js +6 -0
- package/dist/command/setup/node-effects.d.ts +3 -2
- package/dist/command/setup/node-effects.js +9 -3
- package/dist/command/setup/remaining-steps.d.ts +8 -0
- package/dist/command/setup/remaining-steps.js +10 -0
- package/dist/command/setup/run-setup.d.ts +2 -0
- package/dist/command/setup/run-setup.js +9 -1
- package/dist/command/setup/setup-command.js +6 -3
- package/dist/command/update/updater.js +6 -0
- package/dist/command/version/version-skew.js +1 -1
- package/dist/features/compare/action-plan.d.ts +260 -0
- package/dist/features/compare/action-plan.js +543 -0
- package/dist/features/compare/behaviour-compare.d.ts +24 -0
- package/dist/features/compare/behaviour-compare.js +85 -0
- package/dist/features/compare/behaviour-diff.d.ts +97 -0
- package/dist/features/compare/behaviour-diff.js +202 -0
- package/dist/features/compare/behaviour-report.d.ts +40 -0
- package/dist/features/compare/behaviour-report.js +128 -0
- package/dist/features/compare/build-readings.d.ts +106 -0
- package/dist/features/compare/build-readings.js +250 -0
- package/dist/features/compare/compare-diff.d.ts +62 -0
- package/dist/features/compare/compare-diff.js +177 -0
- package/dist/features/compare/compare-report-html.d.ts +6 -0
- package/dist/features/compare/compare-report-html.js +102 -0
- package/dist/features/compare/compare-report.d.ts +15 -0
- package/dist/features/compare/compare-report.js +73 -0
- package/dist/features/compare/compare-run.d.ts +60 -0
- package/dist/features/compare/compare-run.js +123 -0
- package/dist/features/compare/outside/effect-lines.d.ts +26 -0
- package/dist/features/compare/outside/effect-lines.js +103 -0
- package/dist/features/compare/outside/state-sources.d.ts +76 -0
- package/dist/features/compare/outside/state-sources.js +164 -0
- package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
- package/dist/features/compare/outside/value-dictionary.js +227 -0
- package/dist/features/compare/visible-content.d.ts +20 -0
- package/dist/features/compare/visible-content.js +125 -0
- package/dist/features/crawl/crawl-empty.js +2 -1
- package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
- package/dist/features/crawl/crawl-exhaustive.js +138 -0
- package/dist/features/crawl/crawl-tools.d.ts +9 -2
- package/dist/features/crawl/crawl-tools.js +28 -12
- package/dist/features/crawl/crawl.d.ts +8 -9
- package/dist/features/crawl/crawl.js +61 -65
- package/dist/features/exhaust/app-coverage.d.ts +5 -1
- package/dist/features/exhaust/app-coverage.js +3 -1
- package/dist/features/exhaust/code-coverage.js +8 -4
- package/dist/features/exhaust/edge-cases.d.ts +133 -0
- package/dist/features/exhaust/edge-cases.js +310 -0
- package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
- package/dist/features/exhaust/edges/edge-drive.js +364 -0
- package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
- package/dist/features/exhaust/edges/edge-run.js +169 -0
- package/dist/features/exhaust/explorer.d.ts +87 -14
- package/dist/features/exhaust/explorer.js +159 -25
- package/dist/features/exhaust/failure-branches.d.ts +5 -0
- package/dist/features/exhaust/failure-branches.js +29 -11
- package/dist/features/exhaust/invariants.d.ts +112 -0
- package/dist/features/exhaust/invariants.js +188 -0
- package/dist/features/exhaust/ledger.d.ts +68 -0
- package/dist/features/exhaust/ledger.js +121 -13
- package/dist/features/exhaust/session-fold.d.ts +10 -0
- package/dist/features/exhaust/session-fold.js +46 -3
- package/dist/features/exhaust/session-port.d.ts +3 -1
- package/dist/features/exhaust/session-port.js +97 -28
- package/dist/features/grade/grade-answer.d.ts +99 -0
- package/dist/features/grade/grade-answer.js +112 -0
- package/dist/features/grade/grade-noise.d.ts +27 -0
- package/dist/features/grade/grade-noise.js +55 -0
- package/dist/features/grade/grade-renumber.d.ts +12 -0
- package/dist/features/grade/grade-renumber.js +86 -0
- package/dist/features/grade/grade-state.d.ts +50 -0
- package/dist/features/grade/grade-state.js +93 -0
- package/dist/features/grade/grade-suggest.d.ts +33 -0
- package/dist/features/grade/grade-suggest.js +98 -0
- package/dist/features/visual/visual-tools.js +66 -19
- package/dist/index.js +7 -4
- package/dist/judgement/capsule/causal-summary.js +9 -2
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
- package/dist/judgement/runs/reticle-runner.js +16 -2
- package/dist/judgement/runs/runner-port.d.ts +2 -0
- package/dist/judgement/runs/runner-port.js +23 -5
- package/dist/language/flows/affected-tools.d.ts +1 -1
- package/dist/language/flows/affected-tools.js +49 -30
- package/dist/language/flows/change/git-changed.d.ts +2 -1
- package/dist/language/flows/change/git-changed.js +19 -2
- package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
- package/dist/language/flows/fields/flow-secret-field.js +77 -21
- package/dist/language/flows/flow-anchor.d.ts +60 -2
- package/dist/language/flows/flow-anchor.js +125 -20
- package/dist/language/flows/flow-classify.d.ts +20 -0
- package/dist/language/flows/flow-classify.js +90 -12
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +25 -1
- package/dist/language/flows/flow-journey.d.ts +38 -4
- package/dist/language/flows/flow-journey.js +138 -8
- package/dist/language/flows/flow-replay-run.d.ts +0 -16
- package/dist/language/flows/flow-replay-run.js +76 -14
- package/dist/language/flows/flow-replay-types.d.ts +4 -2
- package/dist/language/flows/flow-replay.d.ts +19 -1
- package/dist/language/flows/flow-replay.js +169 -52
- package/dist/language/flows/flow-replayable.js +7 -1
- package/dist/language/flows/flow-start-path.d.ts +34 -5
- package/dist/language/flows/flow-start-path.js +202 -15
- package/dist/language/flows/flow-step-runners.d.ts +14 -13
- package/dist/language/flows/flow-step-runners.js +184 -109
- package/dist/language/flows/flow-store-for-session.d.ts +26 -25
- package/dist/language/flows/flow-store-for-session.js +44 -0
- package/dist/language/flows/flow-tools.js +46 -33
- package/dist/language/flows/flows.js +176 -76
- package/dist/language/flows/recording/tape/recordings.d.ts +19 -3
- package/dist/language/flows/recording/tape/recordings.js +71 -5
- package/dist/language/flows/replay.d.ts +19 -5
- package/dist/language/flows/replay.js +99 -7
- package/dist/language/flows/steps/page-steps.d.ts +68 -0
- package/dist/language/flows/steps/page-steps.js +198 -0
- package/dist/language/flows/suite/sequential-run.d.ts +68 -0
- package/dist/language/flows/suite/sequential-run.js +96 -0
- package/dist/language/flows/verify-change-tools.js +26 -15
- package/dist/memory/cloud/background-sync.d.ts +13 -0
- package/dist/memory/cloud/background-sync.js +24 -3
- package/dist/memory/cloud/sync-daemon.js +26 -27
- package/dist/memory/journal/attach-journal.js +2 -1
- package/dist/memory/journal/drive-flow.d.ts +7 -0
- package/dist/memory/journal/drive-flow.js +44 -13
- package/dist/memory/journal/journal-recorder.d.ts +4 -2
- package/dist/memory/journal/session-journal.d.ts +7 -0
- package/dist/memory/journal/session-journal.js +58 -10
- package/dist/memory/project/root-claims.d.ts +9 -0
- package/dist/memory/project/root-claims.js +9 -4
- package/dist/portal/input/download-capture.d.ts +7 -0
- package/dist/portal/input/download-capture.js +92 -0
- package/dist/portal/input/network-detail.d.ts +6 -0
- package/dist/portal/input/network-detail.js +12 -1
- package/dist/portal/input/network-mock-tools.js +49 -13
- package/dist/portal/input/network-mock.d.ts +8 -0
- package/dist/portal/input/network-mock.js +28 -9
- package/dist/portal/input/page-capture.d.ts +24 -0
- package/dist/portal/input/page-capture.js +33 -0
- package/dist/portal/input/real-input.d.ts +22 -20
- package/dist/portal/input/real-input.js +41 -31
- package/dist/portal/input/viewport-tools.d.ts +8 -0
- package/dist/portal/input/viewport-tools.js +75 -18
- package/dist/portal/pool/browser-pool.d.ts +11 -29
- package/dist/portal/pool/browser-pool.js +35 -17
- package/dist/portal/pool/context-permissions.d.ts +17 -3
- package/dist/portal/pool/context-permissions.js +36 -5
- package/dist/portal/pool/determinism.d.ts +52 -0
- package/dist/portal/pool/determinism.js +259 -0
- package/dist/portal/pool/lease-emulation.d.ts +34 -1
- package/dist/portal/pool/lease-emulation.js +18 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
- package/dist/portal/pool/lease-marker-stamp.js +15 -1
- package/dist/portal/pool/lease-page-error.d.ts +44 -17
- package/dist/portal/pool/lease-page-error.js +147 -5
- package/dist/portal/pool/page-error-journal.d.ts +7 -1
- package/dist/portal/pool/page-error-journal.js +27 -0
- package/dist/portal/pool/playwright-launcher.js +51 -8
- package/dist/portal/pool/pool-contract.d.ts +27 -1
- package/dist/portal/pool/pool-lease.d.ts +36 -1
- package/dist/portal/pool/zero-install.d.ts +8 -0
- package/dist/portal/pool/zero-install.js +23 -1
- package/dist/portal/session/dev-server/dev-command.d.ts +7 -6
- package/dist/portal/session/dev-server/dev-command.js +61 -15
- package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
- package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
- package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
- package/dist/portal/session/dev-server/project-ports.js +62 -0
- package/dist/portal/session/facts/departed-network.d.ts +66 -0
- package/dist/portal/session/facts/departed-network.js +142 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
- package/dist/portal/session/no-session-diagnosis.js +67 -25
- package/dist/portal/session/no-session-next-action.d.ts +2 -0
- package/dist/portal/session/no-session-next-action.js +12 -3
- package/dist/portal/session/no-session-watch.d.ts +6 -0
- package/dist/portal/session/no-session-watch.js +38 -3
- package/dist/portal/session/serving-directory.d.ts +10 -0
- package/dist/portal/session/serving-directory.js +39 -8
- package/dist/portal/session/session-manager.d.ts +10 -0
- package/dist/portal/session/session-manager.js +174 -63
- package/dist/start-wiring.d.ts +2 -1
- package/dist/start-wiring.js +2 -1
- package/dist/surface/mcp/mcp.js +3 -2
- package/dist/surface/mcp/shared-params.d.ts +2 -0
- package/dist/surface/mcp/shared-params.js +31 -0
- package/dist/surface/tools/act/act-observation.d.ts +40 -2
- package/dist/surface/tools/act/act-observation.js +118 -12
- package/dist/surface/tools/act/act-preflight.js +1 -1
- package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
- package/dist/surface/tools/act/act-sequence-retry.js +61 -5
- package/dist/surface/tools/act/after-match.d.ts +4 -1
- package/dist/surface/tools/act/after-match.js +8 -1
- package/dist/surface/tools/act/already-true.js +1 -1
- package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
- package/dist/surface/tools/act/navigation/reload-result.js +25 -2
- package/dist/surface/tools/act/resolve-target.d.ts +15 -1
- package/dist/surface/tools/act/resolve-target.js +24 -1
- package/dist/surface/tools/act/sequence-grade.d.ts +12 -0
- package/dist/surface/tools/act/sequence-grade.js +37 -26
- package/dist/surface/tools/act/settle-in-flight.js +27 -15
- package/dist/surface/tools/act-command.d.ts +23 -0
- package/dist/surface/tools/act-command.js +50 -0
- package/dist/surface/tools/act-sequence-tool.js +78 -50
- package/dist/surface/tools/act-tools.d.ts +1 -13
- package/dist/surface/tools/act-tools.js +74 -86
- package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
- package/dist/surface/tools/agent/build-staleness.js +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +16 -37
- package/dist/surface/tools/browser-tools.js +12 -6
- package/dist/surface/tools/compare-tools.d.ts +11 -0
- package/dist/surface/tools/compare-tools.js +94 -0
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.js +9 -2
- package/dist/surface/tools/error-recovery.d.ts +12 -1
- package/dist/surface/tools/error-recovery.js +91 -21
- package/dist/surface/tools/explore-tools.js +1 -1
- package/dist/surface/tools/invoke-tool.js +3 -2
- package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
- package/dist/surface/tools/lease-coverage-tools.js +128 -0
- package/dist/surface/tools/lease-hint.d.ts +35 -1
- package/dist/surface/tools/lease-hint.js +42 -0
- package/dist/surface/tools/lease-readiness.d.ts +26 -0
- package/dist/surface/tools/lease-readiness.js +79 -0
- package/dist/surface/tools/lease-seed.d.ts +14 -1
- package/dist/surface/tools/lease-seed.js +35 -3
- package/dist/surface/tools/lease-tools.d.ts +3 -41
- package/dist/surface/tools/lease-tools.js +62 -110
- package/dist/surface/tools/lease-url-identity.d.ts +46 -0
- package/dist/surface/tools/lease-url-identity.js +97 -0
- package/dist/surface/tools/merge-tools.js +99 -2
- package/dist/surface/tools/merged-name-redirect.js +5 -1
- package/dist/surface/tools/observe-tools.js +15 -9
- package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
- package/dist/surface/tools/read/console-pre-attach.js +23 -0
- package/dist/surface/tools/read-tools.js +33 -30
- package/dist/surface/tools/real-input-attempt.d.ts +0 -8
- package/dist/surface/tools/real-input-attempt.js +143 -28
- package/dist/surface/tools/session-ports.d.ts +14 -0
- package/dist/surface/tools/session-ports.js +53 -0
- package/dist/surface/tools/tool-kit.d.ts +6 -0
- package/dist/surface/tools/tool-kit.js +2 -3
- package/dist/surface/tools/tool-surface.js +0 -1
- package/dist/surface/tools/tools.js +28 -5
- package/dist/surface/tools/type-spelling.d.ts +13 -0
- package/dist/surface/tools/type-spelling.js +36 -0
- package/dist/telemetry/agent-client.d.ts +6 -0
- package/dist/telemetry/agent-client.js +10 -0
- package/dist/telemetry/argument-shape.js +1 -0
- package/dist/telemetry/tool-refused.d.ts +6 -3
- package/dist/telemetry/tool-refused.js +8 -3
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +1 -1
- package/docs/capabilities.mdx +61 -1
- package/docs/cli/affected.mdx +9 -7
- package/docs/cli/cloud.mdx +3 -3
- package/docs/cli/compare.mdx +94 -0
- package/docs/cli/doctor.mdx +1 -1
- package/docs/cli/grade.mdx +97 -0
- package/docs/cli/license.mdx +9 -7
- package/docs/cli/restart.mdx +7 -5
- package/docs/cli/rollback.mdx +5 -5
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/update.mdx +2 -2
- package/docs/cli/verify.mdx +23 -1
- package/docs/cli.mdx +33 -23
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +1 -1
- package/docs/enterprise.md +2 -2
- package/docs/environment.mdx +1 -1
- package/docs/flows.md +11 -1
- package/docs/frameworks.mdx +9 -9
- package/docs/getting-started.md +1 -1
- package/docs/install-manual.mdx +1 -1
- package/docs/license-activation.mdx +3 -3
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages.mdx +1 -1
- package/docs/predicates.mdx +1 -1
- package/docs/quickstart.mdx +68 -49
- package/docs/skill-setup.md +1 -1
- package/docs/skill.md +14 -13
- package/docs/telemetry.md +2 -2
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/verify.mdx +4 -1
- package/docs/troubleshooting.mdx +1 -1
- package/docs/usage.md +17 -14
- package/package.json +13 -13
- package/dist/features/exhaust/exhaust-run.d.ts +0 -33
- package/dist/features/exhaust/exhaust-run.js +0 -82
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* nothing. A cause we hold positive evidence against is not printed at all.
|
|
19
19
|
*/
|
|
20
20
|
import { isLoopbackHostname, LeaseNotReadyReason } from '@reticlehq/core';
|
|
21
|
+
import { HeldLeaseReload } from './lease-readiness.js';
|
|
21
22
|
import { INIT_COMMAND } from '../../portal/session/no-session-next-action.js';
|
|
22
23
|
const NUXT = 'nuxt';
|
|
23
24
|
const PORT_DIFFERENTIAL = "The usual cause is a PORT MISMATCH: the app's SDK connects to the port it was BUILT with, so a " +
|
|
@@ -180,3 +181,44 @@ export function leaseReaderFailedHint(url, failure) {
|
|
|
180
181
|
: `The zero-install reader failed on ${url}: ${failure.cause}. ${LEASE_RELEASED_SENTENCE} ` +
|
|
181
182
|
'If the tab closed during setup, acquire again.';
|
|
182
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
* The answer for a held lease that is kept although its page did not connect (#1924). The tab is
|
|
186
|
+
* kept, because its context holds the cookies: a new context starts signed out. `reload` says
|
|
187
|
+
* whether its page loaded again; `cause` is why it did not connect, or why it did not load.
|
|
188
|
+
*/
|
|
189
|
+
export function keptLeaseAnswer(lease, pool, cause) {
|
|
190
|
+
const reloaded = lease.reload === HeldLeaseReload.RELOADED;
|
|
191
|
+
const what = reloaded
|
|
192
|
+
? 'Acquire loaded its page again, but the page did not connect.'
|
|
193
|
+
: `Acquire could not load ${lease.url} in it again: ${cause}`;
|
|
194
|
+
return {
|
|
195
|
+
sessionId: lease.sessionId,
|
|
196
|
+
url: lease.url,
|
|
197
|
+
ready: false,
|
|
198
|
+
notReadyReason: LeaseNotReadyReason.SDK_NEVER_DIALLED,
|
|
199
|
+
reused: true,
|
|
200
|
+
expiresInMs: pool.leaseTtlMs(),
|
|
201
|
+
leased: pool.activeCount(),
|
|
202
|
+
queued: pool.queuedCount(),
|
|
203
|
+
hint: `You already hold a lease on ${lease.origin}: ${lease.sessionId}. ${what} The tab and its ` +
|
|
204
|
+
'context are kept, so its cookies and sign-in are kept. A new context has no cookies: ' +
|
|
205
|
+
'release this lease first only if you want one, and pass seedStorage to start it signed in.' +
|
|
206
|
+
(reloaded ? ` ${cause}` : ' Acquire again when the app answers.'),
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Why a held lease's page did not load again, said from what the daemon can check: whether
|
|
211
|
+
* anything accepts a connection on the page's port. Only asked of a loopback URL, where the probe
|
|
212
|
+
* reaches the same server the browser does.
|
|
213
|
+
*/
|
|
214
|
+
export async function notLoadedCause(url, portAccepts) {
|
|
215
|
+
const target = URL.canParse(url) ? new URL(url) : undefined;
|
|
216
|
+
if (portAccepts === undefined || target === undefined || !isLoopbackHostname(target.hostname)) {
|
|
217
|
+
return 'the page did not load. The app may be restarting.';
|
|
218
|
+
}
|
|
219
|
+
const defaultPort = 'https:' === target.protocol ? '443' : '80';
|
|
220
|
+
const port = '' === target.port ? defaultPort : target.port;
|
|
221
|
+
return (await portAccepts(Number(port)).catch(() => false))
|
|
222
|
+
? `the server on port ${port} accepted the connection, but the page did not finish loading. It may still be compiling.`
|
|
223
|
+
: `nothing accepts connections on port ${port}. The app may be restarting.`;
|
|
224
|
+
}
|
|
@@ -111,4 +111,30 @@ export declare function moveReusedLease(tabUrl: () => string | undefined, reques
|
|
|
111
111
|
url: string;
|
|
112
112
|
arrived: boolean;
|
|
113
113
|
} | undefined>;
|
|
114
|
+
/** What loading a held lease's tab again found. */
|
|
115
|
+
export declare const HeldLeaseReload: {
|
|
116
|
+
/** Its tab had already registered, so nothing was loaded again. */
|
|
117
|
+
readonly REGISTERED: "registered";
|
|
118
|
+
/** The page loaded again. Its SDK may or may not have dialled in since. */
|
|
119
|
+
readonly RELOADED: "reloaded";
|
|
120
|
+
/** The page is still open, but it did not load: the server did not answer, or it timed out. */
|
|
121
|
+
readonly NOT_LOADED: "not-loaded";
|
|
122
|
+
/** The page is closed, or its context is gone. Nothing is left to keep. */
|
|
123
|
+
readonly GONE: "gone";
|
|
124
|
+
};
|
|
125
|
+
export type HeldLeaseReload = (typeof HeldLeaseReload)[keyof typeof HeldLeaseReload];
|
|
126
|
+
/**
|
|
127
|
+
* Load a held lease's tab again in its own context, and wait for its SDK to dial in (#1924).
|
|
128
|
+
*
|
|
129
|
+
* A held lease whose tab never registered used to be released, and a new context minted. That
|
|
130
|
+
* context has no cookies, so a tab the agent had signed in to was closed and replaced by a
|
|
131
|
+
* signed-out one, and the retry could not get the sign-in back. The context is the sign-in, so the
|
|
132
|
+
* retry keeps it and only loads the page again. The reader the first acquire injected is an init
|
|
133
|
+
* script of that page, so it runs again on the new document by itself.
|
|
134
|
+
*
|
|
135
|
+
* A navigation that fails is not a closed tab: a dev server that restarts refuses the connection
|
|
136
|
+
* for a moment, and the context with its cookies is still there. `isOpen` asks the page something,
|
|
137
|
+
* which tells the two apart. A tab that has registered already is left alone.
|
|
138
|
+
*/
|
|
139
|
+
export declare function reconnectHeldLease(goto: (timeoutMs: number) => Promise<boolean>, isOpen: () => Promise<boolean>, isLoading: () => Promise<boolean>, isRegistered: () => boolean, deadline: number, now: () => number): Promise<HeldLeaseReload>;
|
|
114
140
|
export {};
|
|
@@ -250,3 +250,82 @@ export async function moveReusedLease(tabUrl, requested, goto, now) {
|
|
|
250
250
|
}
|
|
251
251
|
return { navigated: true, url: requested, arrived: pageOf(tabUrl()) === target };
|
|
252
252
|
}
|
|
253
|
+
/** What loading a held lease's tab again found. */
|
|
254
|
+
export const HeldLeaseReload = {
|
|
255
|
+
/** Its tab had already registered, so nothing was loaded again. */
|
|
256
|
+
REGISTERED: 'registered',
|
|
257
|
+
/** The page loaded again. Its SDK may or may not have dialled in since. */
|
|
258
|
+
RELOADED: 'reloaded',
|
|
259
|
+
/** The page is still open, but it did not load: the server did not answer, or it timed out. */
|
|
260
|
+
NOT_LOADED: 'not-loaded',
|
|
261
|
+
/** The page is closed, or its context is gone. Nothing is left to keep. */
|
|
262
|
+
GONE: 'gone',
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* Load a held lease's tab again in its own context, and wait for its SDK to dial in (#1924).
|
|
266
|
+
*
|
|
267
|
+
* A held lease whose tab never registered used to be released, and a new context minted. That
|
|
268
|
+
* context has no cookies, so a tab the agent had signed in to was closed and replaced by a
|
|
269
|
+
* signed-out one, and the retry could not get the sign-in back. The context is the sign-in, so the
|
|
270
|
+
* retry keeps it and only loads the page again. The reader the first acquire injected is an init
|
|
271
|
+
* script of that page, so it runs again on the new document by itself.
|
|
272
|
+
*
|
|
273
|
+
* A navigation that fails is not a closed tab: a dev server that restarts refuses the connection
|
|
274
|
+
* for a moment, and the context with its cookies is still there. `isOpen` asks the page something,
|
|
275
|
+
* which tells the two apart. A tab that has registered already is left alone.
|
|
276
|
+
*/
|
|
277
|
+
export async function reconnectHeldLease(goto, isOpen, isLoading, isRegistered, deadline, now) {
|
|
278
|
+
if (isRegistered()) {
|
|
279
|
+
return HeldLeaseReload.REGISTERED;
|
|
280
|
+
}
|
|
281
|
+
// Bounded by the acquire's own deadline. Playwright reads a timeout of 0 as "none", so at least
|
|
282
|
+
// 1 ms; and raced too, because a frozen page can hold the navigation past its own timeout.
|
|
283
|
+
const budget = Math.max(1, deadline - now());
|
|
284
|
+
const went = await answerWithin(Promise.resolve(budget).then(goto), budget + HELD_PAGE_ANSWER_MS, false);
|
|
285
|
+
if (!went) {
|
|
286
|
+
return (await pageStillOpen(isOpen)) ? HeldLeaseReload.NOT_LOADED : HeldLeaseReload.GONE;
|
|
287
|
+
}
|
|
288
|
+
const loading = () => answerWithin(isLoading(), HELD_PAGE_ANSWER_MS, false);
|
|
289
|
+
await connectOrInject({ isLoading: loading }, isRegistered, connectWaitUntil(deadline, now));
|
|
290
|
+
return HeldLeaseReload.RELOADED;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* How long one question to a held page may take. A page that answers does so in milliseconds; a
|
|
294
|
+
* frozen one (a script in an endless loop) never does, and must not hold the acquire with it.
|
|
295
|
+
*/
|
|
296
|
+
const HELD_PAGE_ANSWER_MS = 250;
|
|
297
|
+
/** `work`'s answer, or `fallback` when it rejects or has not answered within `ms`. */
|
|
298
|
+
async function answerWithin(work, ms, fallback) {
|
|
299
|
+
let timer;
|
|
300
|
+
const late = new Promise((resolve) => {
|
|
301
|
+
timer = setTimeout(() => {
|
|
302
|
+
resolve(fallback);
|
|
303
|
+
}, ms);
|
|
304
|
+
});
|
|
305
|
+
try {
|
|
306
|
+
return await Promise.race([work.catch(() => fallback), late]);
|
|
307
|
+
}
|
|
308
|
+
finally {
|
|
309
|
+
clearTimeout(timer);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
/** How many times a page whose navigation failed is asked whether it is still there. */
|
|
313
|
+
const OPEN_PROBE_ATTEMPTS = 3;
|
|
314
|
+
/**
|
|
315
|
+
* Whether a page still answers, after a navigation on it failed.
|
|
316
|
+
*
|
|
317
|
+
* Asked more than once, because the first question right after a failed navigation is often lost
|
|
318
|
+
* ("Execution context was destroyed") on a page that is still open, and the next one is answered.
|
|
319
|
+
* A closed page, or a page whose context is closed, refuses every time. A frozen page never answers,
|
|
320
|
+
* so each question is bounded, and it reads as gone.
|
|
321
|
+
*/
|
|
322
|
+
async function pageStillOpen(isOpen) {
|
|
323
|
+
for (let attempt = 0; attempt < OPEN_PROBE_ATTEMPTS; attempt++) {
|
|
324
|
+
const asked = Promise.resolve().then(isOpen);
|
|
325
|
+
if (await answerWithin(asked, HELD_PAGE_ANSWER_MS, false)) {
|
|
326
|
+
return true;
|
|
327
|
+
}
|
|
328
|
+
await sleep(LEASE_READY_POLL_MS);
|
|
329
|
+
}
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
@@ -24,6 +24,11 @@ export declare const NAV_CERT_REFUSED: string;
|
|
|
24
24
|
export declare const NAV_FAILED_QUESTION = "is the app running there?";
|
|
25
25
|
/** What a lease navigation that ran out of time tells the caller to do. */
|
|
26
26
|
export declare const NAV_TIMEOUT_ADVICE: string;
|
|
27
|
+
/**
|
|
28
|
+
* What a lease navigation that ran out of time tells the caller when the server accepted the
|
|
29
|
+
* connection: it is running and most likely compiling the route, so starting it again is wrong (#2005).
|
|
30
|
+
*/
|
|
31
|
+
export declare const NAV_COMPILING_ADVICE: string;
|
|
27
32
|
/**
|
|
28
33
|
* The sentence for a lease whose first navigation failed.
|
|
29
34
|
*
|
|
@@ -35,7 +40,15 @@ export declare const NAV_TIMEOUT_ADVICE: string;
|
|
|
35
40
|
* hunting for a dev server that is up instead of retrying, so the timeout sentence names both
|
|
36
41
|
* cases and leads with the retry.
|
|
37
42
|
*/
|
|
38
|
-
export declare function navFailureMessage(url: string, err: unknown, seed?: SeedStorage): string;
|
|
43
|
+
export declare function navFailureMessage(url: string, err: unknown, seed?: SeedStorage, serverAccepted?: boolean): string;
|
|
44
|
+
/**
|
|
45
|
+
* Whether the server behind a timed-out lease navigation accepted a connection.
|
|
46
|
+
*
|
|
47
|
+
* Only asked after a timeout and only of a loopback URL: the port probe reaches `localhost`, so a
|
|
48
|
+
* remote host would be answered by whatever listens locally on the same port. Never rejects; any
|
|
49
|
+
* doubt is `false`, which keeps the generic timeout advice.
|
|
50
|
+
*/
|
|
51
|
+
export declare function serverAcceptedAfterTimeout(url: string, err: unknown, seed: SeedStorage | undefined, portAccepts: ((port: number) => Promise<boolean>) | undefined): Promise<boolean>;
|
|
39
52
|
/** Whether a path is a sign-in page, by its name: `/login`, `/signin`, `/auth/login` and similar. */
|
|
40
53
|
export declare const isAuthPath: (pathname: string) => boolean;
|
|
41
54
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Seeded storage for a lease, and the errors a lease's navigation throws: what a caller may see of
|
|
3
3
|
* them without seeing the secrets it seeded. Split from lease-tools.ts, which crossed the line cap.
|
|
4
4
|
*/
|
|
5
|
-
import { REDACTED_VALUE, scrubKnownSecrets } from '@reticlehq/core';
|
|
5
|
+
import { isLoopbackHostname, REDACTED_VALUE, scrubKnownSecrets, } from '@reticlehq/core';
|
|
6
6
|
function redactExactValue(text, value) {
|
|
7
7
|
if (0 === value.length)
|
|
8
8
|
return text;
|
|
@@ -95,6 +95,12 @@ export const NAV_FAILED_QUESTION = 'is the app running there?';
|
|
|
95
95
|
/** What a lease navigation that ran out of time tells the caller to do. */
|
|
96
96
|
export const NAV_TIMEOUT_ADVICE = 'If the app is running, a dev server compiling a route for the first time can take longer than ' +
|
|
97
97
|
'that: retry the acquire. If it is not running, start it first.';
|
|
98
|
+
/**
|
|
99
|
+
* What a lease navigation that ran out of time tells the caller when the server accepted the
|
|
100
|
+
* connection: it is running and most likely compiling the route, so starting it again is wrong (#2005).
|
|
101
|
+
*/
|
|
102
|
+
export const NAV_COMPILING_ADVICE = 'The server accepted the connection, so it is running and is probably still compiling this ' +
|
|
103
|
+
'route: wait a few seconds, then acquire the lease again. Do not start another dev server.';
|
|
98
104
|
/** Lead of the timeout sentence, before the budget ("within 30 s", or "in time" when unknown). */
|
|
99
105
|
const NAV_TIMEOUT_LEAD = 'the page did not finish loading';
|
|
100
106
|
const NAV_TIMEOUT_UNKNOWN_BUDGET = 'in time';
|
|
@@ -111,7 +117,7 @@ const PLAYWRIGHT_TIMEOUT = /Timeout (\d+)ms exceeded/;
|
|
|
111
117
|
* hunting for a dev server that is up instead of retrying, so the timeout sentence names both
|
|
112
118
|
* cases and leads with the retry.
|
|
113
119
|
*/
|
|
114
|
-
export function navFailureMessage(url, err, seed) {
|
|
120
|
+
export function navFailureMessage(url, err, seed, serverAccepted = false) {
|
|
115
121
|
const reason = cleanNavError(err, seed);
|
|
116
122
|
// A certificate the browser refused is not an app that is down: the server answered, with a cert
|
|
117
123
|
// no CA here vouches for (a self-signed or mkcert dev certificate). Asking "is the app running?"
|
|
@@ -125,7 +131,33 @@ export function navFailureMessage(url, err, seed) {
|
|
|
125
131
|
const within = budgetMs === undefined
|
|
126
132
|
? NAV_TIMEOUT_UNKNOWN_BUDGET
|
|
127
133
|
: `within ${String(Number(budgetMs) / 1000)} s`;
|
|
128
|
-
|
|
134
|
+
const advice = serverAccepted ? NAV_COMPILING_ADVICE : NAV_TIMEOUT_ADVICE;
|
|
135
|
+
return `could not open ${url} — ${NAV_TIMEOUT_LEAD} ${within} (${reason}). ${advice}`;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Whether the server behind a timed-out lease navigation accepted a connection.
|
|
139
|
+
*
|
|
140
|
+
* Only asked after a timeout and only of a loopback URL: the port probe reaches `localhost`, so a
|
|
141
|
+
* remote host would be answered by whatever listens locally on the same port. Never rejects; any
|
|
142
|
+
* doubt is `false`, which keeps the generic timeout advice.
|
|
143
|
+
*/
|
|
144
|
+
export async function serverAcceptedAfterTimeout(url, err, seed, portAccepts) {
|
|
145
|
+
if (portAccepts === undefined || NAV_TIMED_OUT !== cleanNavError(err, seed)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
let parsed;
|
|
149
|
+
try {
|
|
150
|
+
parsed = new URL(url);
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
if (!isLoopbackHostname(parsed.hostname)) {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
const defaultPort = 'https:' === parsed.protocol ? 443 : 80;
|
|
159
|
+
const port = '' === parsed.port ? defaultPort : Number(parsed.port);
|
|
160
|
+
return portAccepts(port).catch(() => false);
|
|
129
161
|
}
|
|
130
162
|
/** Whether a path is a sign-in page, by its name: `/login`, `/signin`, `/auth/login` and similar. */
|
|
131
163
|
export const isAuthPath = (pathname) => /(?:^|\/)(?:login|signin|sign-in|auth\/login|auth\/signin|session\/new)(?:$|\/)/i.test(pathname);
|
|
@@ -10,50 +10,11 @@
|
|
|
10
10
|
* Attach-only: the pool drives a browser against an already-running dev server — it never starts one.
|
|
11
11
|
*/
|
|
12
12
|
import { type SeedStorage } from '@reticlehq/core';
|
|
13
|
-
import { HudVisibility } from '@reticlehq/core';
|
|
14
13
|
import { type ToolDef, type ToolDeps } from './tool-kit.js';
|
|
15
14
|
import { type BrowserPool } from '../../portal/pool/browser-pool.js';
|
|
16
15
|
export { sessionMutationPort, sessionPerturbationPort, suiteFixturePort, suiteFixtureSeed, } from './session-ports.js';
|
|
17
|
-
|
|
18
|
-
* Append Reticle identity params (__reticle_session, optional __reticle_project) to a URL so the app's own SDK
|
|
19
|
-
* adopts them on connect. Pure; falls back to plain concatenation if the URL can't be parsed.
|
|
20
|
-
*/
|
|
21
|
-
export declare function appendReticleParams(url: string, session: string, projectId?: string, hud?: HudVisibility): string;
|
|
16
|
+
export { appendReticleParams, carryReticleIdentity, resolveLeasedSessionId, } from './lease-url-identity.js';
|
|
22
17
|
export { cleanNavError, evaluateSeedPrecondition, scrubSeedFromError } from './lease-seed.js';
|
|
23
|
-
/**
|
|
24
|
-
* The session a lease's tab actually registered as, or undefined while nothing has.
|
|
25
|
-
*
|
|
26
|
-
* Normally that is the lease id: `appendReticleParams` stamps `__reticle_session` on the URL and the
|
|
27
|
-
* SDK adopts it. An app that passes an explicit `session` to `connect()` keeps its own name instead,
|
|
28
|
-
* which is legitimate — a single-app fixture does it deliberately so a battery can address it by a
|
|
29
|
-
* known id. Matching on the lease id alone could never see those tabs, so the lease reported
|
|
30
|
-
* `ready: false` and a hint blaming a port mismatch while the session was connected and driveable.
|
|
31
|
-
*
|
|
32
|
-
* The URL marker is the evidence, and it is what makes this safe: two concurrent leases on one origin
|
|
33
|
-
* carry different markers, so neither can adopt the other's tab. Parsed rather than substring-matched,
|
|
34
|
-
* so `lease-abc` cannot claim `lease-abcdef`.
|
|
35
|
-
*/
|
|
36
|
-
export declare function resolveLeasedSessionId(sessions: {
|
|
37
|
-
get: (id: string) => unknown;
|
|
38
|
-
all: () => {
|
|
39
|
-
id: string;
|
|
40
|
-
url?: string;
|
|
41
|
-
}[];
|
|
42
|
-
}, leaseId: string): string | undefined;
|
|
43
|
-
/**
|
|
44
|
-
* Carry a claimed identity across a navigation.
|
|
45
|
-
*
|
|
46
|
-
* A LEASED tab is addressed by `__reticle_session` in its URL: that param is how the pool finds the
|
|
47
|
-
* context it opened, and — since succession was tightened — it is also the ONLY thing that lets the
|
|
48
|
-
* reconnecting document inherit the lease. `reticle_navigate` sent the caller's raw URL, so the very
|
|
49
|
-
* first navigation stripped the marker, the tab re-announced as an ordinary anonymous session, and
|
|
50
|
-
* the lease was orphaned: "no sessions are connected at all", with a browser window still open on
|
|
51
|
-
* screen. A leased browser that cannot survive being navigated is not a usable one.
|
|
52
|
-
*
|
|
53
|
-
* A tab that claims nothing is left exactly as it was — this must never bolt Reticle's params onto
|
|
54
|
-
* a human's own URL.
|
|
55
|
-
*/
|
|
56
|
-
export declare function carryReticleIdentity(fromUrl: string | undefined, toUrl: string): string;
|
|
57
18
|
/**
|
|
58
19
|
* Acquire a leased, SDK-connected context for a caller that is not the lease TOOL (the parallel suite).
|
|
59
20
|
* Returns the session id plus its release; the caller must release in a finally so a crashed flow never
|
|
@@ -63,6 +24,7 @@ export declare function acquireLeasedSession(pool: {
|
|
|
63
24
|
acquire: (url: string, opts: {
|
|
64
25
|
sessionId: string;
|
|
65
26
|
seedStorage?: SeedStorage;
|
|
27
|
+
ignoreHTTPSErrors?: boolean;
|
|
66
28
|
}) => Promise<{
|
|
67
29
|
sessionId: string;
|
|
68
30
|
release: () => Promise<void>;
|
|
@@ -83,7 +45,7 @@ export declare function acquireLeasedSession(pool: {
|
|
|
83
45
|
id: string;
|
|
84
46
|
url?: string;
|
|
85
47
|
}[];
|
|
86
|
-
}, url: string, projectId?: string, seedStorage?: SeedStorage): Promise<{
|
|
48
|
+
}, url: string, projectId?: string, seedStorage?: SeedStorage, ignoreHTTPSErrors?: boolean): Promise<{
|
|
87
49
|
sessionId: string;
|
|
88
50
|
release: () => Promise<void>;
|
|
89
51
|
}>;
|