@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type FlowFile, type FlowReplayResult } from '@reticlehq/core';
|
|
2
|
+
import { type VerificationRunInput } from './artifact/build-verification-run.js';
|
|
2
3
|
import { type ProjectTarget } from '../../memory/project/session-root.js';
|
|
3
4
|
import type { ToolDeps } from '../../surface/tools/tool-kit.js';
|
|
4
5
|
/** A replay plus the wall-clock time it took — the shape the verify handler already collects. */
|
|
@@ -11,8 +12,8 @@ export interface TimedReplay {
|
|
|
11
12
|
/** The MCP client name `reticle verify` (the command line, CI's path) connects to a daemon as. */
|
|
12
13
|
export declare const CLI_CLIENT_NAME = "reticle-cli";
|
|
13
14
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* unaffected. Returns the runId (for logging/tests); undefined if nothing was produced (empty suite).
|
|
15
|
+
* Who ran the command line, and why. On a CI runner it is the pipeline; anywhere else it is the
|
|
16
|
+
* person who holds the key, so the cloud credits them and the run does not read as CI.
|
|
17
17
|
*/
|
|
18
|
+
export declare function cliRunAuthor(env: NodeJS.ProcessEnv): Pick<VerificationRunInput, 'agent' | 'trigger'>;
|
|
18
19
|
export declare function persistAndSyncVerificationRun(deps: ToolDeps, timed: TimedReplay[], target: ProjectTarget): Promise<string | undefined>;
|
|
@@ -10,29 +10,42 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { callerClientName } from '../../hooks/coding-agents.js';
|
|
12
12
|
import { currentDrivenBy } from '../../hooks/driven-by.js';
|
|
13
|
-
import { RunAgentKind, RunFramework, RunProfile, RunTrigger, asRunId, } from '@reticlehq/core';
|
|
13
|
+
import { RunAgentKind, RunFramework, RunProfile, RunTrigger, RunFlowStatus, Verified, asRunId, } from '@reticlehq/core';
|
|
14
14
|
import { homedir } from 'node:os';
|
|
15
15
|
import { buildVerificationRun, } from './artifact/build-verification-run.js';
|
|
16
16
|
import { mapReplayToFlowResult } from './artifact/replay-mapping.js';
|
|
17
|
+
import { runLedger } from './run-ledger.js';
|
|
17
18
|
import { defaultRunId } from './default-run-id.js';
|
|
18
19
|
import { currentShotRun } from './default-run-id.js';
|
|
19
20
|
import { RunStore } from './artifact/run-store.js';
|
|
20
21
|
import { cloudFetch, syncRunToCloud, SyncOutcome } from '../../memory/cloud/cloud-sync.js';
|
|
21
22
|
import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
|
|
22
23
|
import { log } from '../../log.js';
|
|
24
|
+
import { isCiEnv } from '../../telemetry/automation-hint.js';
|
|
23
25
|
import { rootForTarget } from '../../memory/project/session-root.js';
|
|
24
26
|
/** The author of record when no MCP peer introduced itself — a CLI run, or a client that skipped the handshake. */
|
|
25
27
|
const RETICLE_MCP_AGENT_ID = 'reticle-mcp';
|
|
26
28
|
/** The MCP client name `reticle verify` (the command line, CI's path) connects to a daemon as. */
|
|
27
29
|
export const CLI_CLIENT_NAME = 'reticle-cli';
|
|
28
30
|
/**
|
|
29
|
-
* Who ran
|
|
30
|
-
*
|
|
31
|
-
* minted the key, while the path that boots its own daemon said pipeline.
|
|
31
|
+
* Who ran the command line, and why. On a CI runner it is the pipeline; anywhere else it is the
|
|
32
|
+
* person who holds the key, so the cloud credits them and the run does not read as CI.
|
|
32
33
|
*/
|
|
34
|
+
export function cliRunAuthor(env) {
|
|
35
|
+
return isCiEnv(env)
|
|
36
|
+
? {
|
|
37
|
+
agent: { id: CLI_CLIENT_NAME, kind: RunAgentKind.OEM_PIPELINE },
|
|
38
|
+
trigger: { kind: RunTrigger.OEM },
|
|
39
|
+
}
|
|
40
|
+
: {
|
|
41
|
+
agent: { id: CLI_CLIENT_NAME, kind: RunAgentKind.HUMAN },
|
|
42
|
+
trigger: { kind: RunTrigger.MANUAL },
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/** Who ran a suite, and why: the command line by `cliRunAuthor`, any other client as a coding agent. */
|
|
33
46
|
function agentAndTrigger(client) {
|
|
34
47
|
return CLI_CLIENT_NAME === client
|
|
35
|
-
?
|
|
48
|
+
? cliRunAuthor(process.env)
|
|
36
49
|
: {
|
|
37
50
|
agent: { id: client ?? RETICLE_MCP_AGENT_ID, kind: RunAgentKind.CODING_AGENT },
|
|
38
51
|
trigger: { kind: RunTrigger.MANUAL },
|
|
@@ -73,6 +86,13 @@ projectName) {
|
|
|
73
86
|
* tool — a disk or network failure is logged and swallowed so the verdict the agent asked for is
|
|
74
87
|
* unaffected. Returns the runId (for logging/tests); undefined if nothing was produced (empty suite).
|
|
75
88
|
*/
|
|
89
|
+
/** A replay's verdict, decided as its run decides it: a green that proved nothing is undecided. */
|
|
90
|
+
function replayVerified(replay, durationMs) {
|
|
91
|
+
const status = mapReplayToFlowResult(replay, durationMs).status;
|
|
92
|
+
if (RunFlowStatus.PASS === status)
|
|
93
|
+
return Verified.YES;
|
|
94
|
+
return RunFlowStatus.FAIL === status ? Verified.NO : Verified.UNKNOWN;
|
|
95
|
+
}
|
|
76
96
|
export async function persistAndSyncVerificationRun(deps, timed, target) {
|
|
77
97
|
const { projectId } = target;
|
|
78
98
|
if (0 === timed.length)
|
|
@@ -81,6 +101,8 @@ export async function persistAndSyncVerificationRun(deps, timed, target) {
|
|
|
81
101
|
// it was a second row ("Passed · Flow replay · Your agent") beside the plan run it belonged to.
|
|
82
102
|
if (currentDrivenBy() !== undefined)
|
|
83
103
|
return undefined;
|
|
104
|
+
for (const t of timed)
|
|
105
|
+
runLedger.replayed(t.replay.name, replayVerified(t.replay, t.durationMs));
|
|
84
106
|
let run;
|
|
85
107
|
// The project the suite ran for, not the directory the daemon was started in. Both halves below
|
|
86
108
|
// take it: the artifact `reticle_run` reads back through `sessionRoot`, and the cloud link that
|
|
@@ -4,6 +4,7 @@ import { loadNamedFlows, resolveChangedFiles } from '../../command/cli/cli-flow-
|
|
|
4
4
|
import { projectDirFor } from '../../memory/project/session-root.js';
|
|
5
5
|
import { sessionRoot, sessionProjectId } from '../../memory/project/session-root.js';
|
|
6
6
|
import { affectedSavedFlows } from './change/flow-sources.js';
|
|
7
|
+
import { RECORD_A_FLOW } from './suite/coverage.js';
|
|
7
8
|
/**
|
|
8
9
|
* `reticle_affected` — which saved flows must re-verify for a set of changed files.
|
|
9
10
|
*
|
|
@@ -67,7 +68,7 @@ export const AFFECTED_TOOLS = [
|
|
|
67
68
|
changed.failed
|
|
68
69
|
? `could not read the diff for \`${String(since)}\`, so NOTHING was compared and this result proves nothing: ${changed.reason ?? 'git failed'}`
|
|
69
70
|
: 0 === flows.length
|
|
70
|
-
?
|
|
71
|
+
? `no saved flows exist yet, so nothing COULD be affected. ${RECORD_A_FLOW}`
|
|
71
72
|
: 0 === changedFiles.length
|
|
72
73
|
? since === undefined && 0 === files.length
|
|
73
74
|
? 'no files were given and no `since` ref was passed, so nothing was compared — pass the files you edited, or a git ref'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AnnotationErrorCode, AnnotationKind, AnnotationTarget, COMPILED_PREDICATE_PREFIX, flowExpectHasConsequence, flowExpectIsPresenceOnly, PredicateKind, } from '@reticlehq/core';
|
|
1
|
+
import { AnnotationErrorCode, AnnotationKind, AnnotationTarget, COMPILED_PREDICATE_PREFIX, flowExpectHasConsequence, flowExpectIsPresenceOnly, PredicateKind, SettledChannel, } from '@reticlehq/core';
|
|
2
2
|
/**
|
|
3
3
|
* The PURE compiler at the heart of the annotation facet. A structured annotation +
|
|
4
4
|
* the current captured-step count → an AnnotateOutcome (a result envelope + the patch to apply to
|
|
@@ -39,7 +39,12 @@ function netPredicate(net) {
|
|
|
39
39
|
if (net.count === undefined)
|
|
40
40
|
return clause;
|
|
41
41
|
clause.count = net.count;
|
|
42
|
-
|
|
42
|
+
// The gate waits on the NETWORK: DOM churn from an animation held a request check open until it
|
|
43
|
+
// timed out, a flaky red on a loaded machine.
|
|
44
|
+
return {
|
|
45
|
+
kind: PredicateKind.ALL_OF,
|
|
46
|
+
predicates: [{ kind: PredicateKind.SETTLED, channel: SettledChannel.NETWORK }, clause],
|
|
47
|
+
};
|
|
43
48
|
}
|
|
44
49
|
export function compileAnnotation(a, stepCount) {
|
|
45
50
|
switch (a.kind) {
|
|
@@ -112,7 +117,7 @@ export function compileAnnotation(a, stepCount) {
|
|
|
112
117
|
if (a.console !== undefined) {
|
|
113
118
|
return flowSuccess(a, {
|
|
114
119
|
kind: PredicateKind.CONSOLE,
|
|
115
|
-
|
|
120
|
+
level: a.console.level ?? 'error',
|
|
116
121
|
...(a.console.absent === undefined ? {} : { absent: a.console.absent }),
|
|
117
122
|
});
|
|
118
123
|
}
|
|
@@ -85,7 +85,7 @@ export const ANNOTATE_TOOLS = [
|
|
|
85
85
|
.optional()
|
|
86
86
|
.describe('Treat statePath as an INVARIANT that must still hold AFTER the action settles (a blast-radius "this unrelated path must not have moved" check), not a condition to wait for. Without it a wait-until-true read passes before an over-reaching side-effect lands.'),
|
|
87
87
|
dataMatches: z
|
|
88
|
-
.record(z.unknown())
|
|
88
|
+
.record(z.string(), z.unknown())
|
|
89
89
|
.optional()
|
|
90
90
|
.describe('Key/value pairs the signal payload must match (assert-signal only).'),
|
|
91
91
|
net: z
|
|
@@ -16,6 +16,14 @@ export interface AffectedResult {
|
|
|
16
16
|
/** Of the affected, which were included only because their provenance is unknown (fail-safe). */
|
|
17
17
|
unknownProvenance: string[];
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* The one rule for "this changed file is that flow source": paths are compared by normalized suffix,
|
|
21
|
+
* so a repo-root-relative change (`web/src/app.ts`) matches a package-relative stamp (`src/app.ts`)
|
|
22
|
+
* and an absolute stamp, and vice-versa. Everything that asks whether a flow touches a file uses it,
|
|
23
|
+
* so "affected" and "stale" can never disagree about which files belong to a flow.
|
|
24
|
+
*/
|
|
25
|
+
export declare function pathsMatch(a: string, b: string): boolean;
|
|
26
|
+
export declare function sourceMatchesChange(source: string, changedFiles: readonly string[]): boolean;
|
|
19
27
|
/**
|
|
20
28
|
* Which flows are affected by a set of changed files. Deterministic; a flow with no sources manifest is
|
|
21
29
|
* always affected (fail-safe). `changedFiles` and flow sources are matched by normalized path suffix so
|
|
@@ -5,9 +5,26 @@
|
|
|
5
5
|
* (recorded before source stamping, or un-stampable) is `unknown` — and unknown always means affected, never
|
|
6
6
|
* silently skipped: the loop fails safe toward re-verifying.
|
|
7
7
|
*/
|
|
8
|
-
/** Normalize a path for comparison — strip a leading./ and any file:line suffix. */
|
|
8
|
+
/** Normalize a path for comparison — use `/` separators, strip a leading ./ and any file:line suffix. */
|
|
9
9
|
function normalize(path) {
|
|
10
|
-
return path
|
|
10
|
+
return path
|
|
11
|
+
.replace(/\\/g, '/')
|
|
12
|
+
.replace(/^\.\//, '')
|
|
13
|
+
.replace(/:\d+(:\d+)?$/, '');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The one rule for "this changed file is that flow source": paths are compared by normalized suffix,
|
|
17
|
+
* so a repo-root-relative change (`web/src/app.ts`) matches a package-relative stamp (`src/app.ts`)
|
|
18
|
+
* and an absolute stamp, and vice-versa. Everything that asks whether a flow touches a file uses it,
|
|
19
|
+
* so "affected" and "stale" can never disagree about which files belong to a flow.
|
|
20
|
+
*/
|
|
21
|
+
export function pathsMatch(a, b) {
|
|
22
|
+
const x = normalize(a);
|
|
23
|
+
const y = normalize(b);
|
|
24
|
+
return x === y || x.endsWith(`/${y}`) || y.endsWith(`/${x}`);
|
|
25
|
+
}
|
|
26
|
+
export function sourceMatchesChange(source, changedFiles) {
|
|
27
|
+
return changedFiles.some((c) => pathsMatch(c, source));
|
|
11
28
|
}
|
|
12
29
|
/**
|
|
13
30
|
* Which flows are affected by a set of changed files. Deterministic; a flow with no sources manifest is
|
|
@@ -15,11 +32,7 @@ function normalize(path) {
|
|
|
15
32
|
* a repo-relative change matches an absolute stamp and vice-versa.
|
|
16
33
|
*/
|
|
17
34
|
export function affectedFlows(flows, changedFiles) {
|
|
18
|
-
const
|
|
19
|
-
const matchesChange = (source) => {
|
|
20
|
-
const s = normalize(source);
|
|
21
|
-
return changed.some((c) => c === s || c.endsWith(`/${s}`) || s.endsWith(`/${c}`));
|
|
22
|
-
};
|
|
35
|
+
const matchesChange = (source) => sourceMatchesChange(source, changedFiles);
|
|
23
36
|
const affected = [];
|
|
24
37
|
const unknownProvenance = [];
|
|
25
38
|
for (const flow of flows) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { AnchorKind, DriftReason, isConsequenceDrift, ReplayStatus, unreachedRoutes, SuiteIsolation, } from '@reticlehq/core';
|
|
2
|
+
import { replayability, Replayable } from './flow-replayable.js';
|
|
2
3
|
import { classifyFlowAssertions, FlowAssertionGrade } from './flow-classify.js';
|
|
3
4
|
import { SUCCESS_STEP_TOOL } from './flow-success.js';
|
|
5
|
+
import { RECORD_A_FLOW } from './suite/coverage.js';
|
|
4
6
|
/**
|
|
5
7
|
* Turn a replay result into the autonomy DECISION envelope — the judgement a human reviewer used to
|
|
6
8
|
* make, expressed so a coding agent can act on it without one. Pure: no IO, no clock.
|
|
@@ -43,7 +45,7 @@ const INTENT_BROKEN_PREFIX = 'NO LONGER TRUE: ';
|
|
|
43
45
|
* Never an intent derived from step names: a guessed goal reads as the product owner's words and an
|
|
44
46
|
* agent will act on it. The same rule as the source pointer — absence stays honest.
|
|
45
47
|
*/
|
|
46
|
-
const NO_INTENT_ON_PASS = 'no intent declared, so this proves the steps ran, not what they were for — declare one with reticle_intent.';
|
|
48
|
+
const NO_INTENT_ON_PASS = 'no intent declared, so this proves the steps ran, not what they were for — declare one with reticle_run { tool: "reticle_intent" }.';
|
|
47
49
|
const NO_INTENT_ON_FAIL = 'no intent declared, so this names the mechanism, not the stakes.';
|
|
48
50
|
/** `<intent> — <mechanical>`, or the mechanical sentence plus the honest absence. */
|
|
49
51
|
function withIntent(mechanical, statement) {
|
|
@@ -215,7 +217,7 @@ invoked = new Map()) {
|
|
|
215
217
|
if (flow === undefined)
|
|
216
218
|
return undefined;
|
|
217
219
|
if (0 === flow.steps.length) {
|
|
218
|
-
return 'the flow has no steps — it replays green whatever the app does. Record it again, or add steps with reticle_annotate.';
|
|
220
|
+
return 'the flow has no steps — it replays green whatever the app does. Record it again, or add steps with reticle_run { tool: "reticle_annotate" }.';
|
|
219
221
|
}
|
|
220
222
|
const c = classifyFlowAssertions(flow, invoked);
|
|
221
223
|
if (c.grade !== FlowAssertionGrade.ASSERTION_FREE)
|
|
@@ -339,7 +341,7 @@ isolation) {
|
|
|
339
341
|
? ''
|
|
340
342
|
: ` — ${String(unreached.length)} known route(s) never opened: ${unreached.join(', ')}`;
|
|
341
343
|
const summary = 0 === total
|
|
342
|
-
?
|
|
344
|
+
? `no flows to verify — nothing was checked. ${RECORD_A_FLOW}`
|
|
343
345
|
: 0 === failed
|
|
344
346
|
? 0 === unverifiable.length
|
|
345
347
|
? `all ${total} flow${1 === total ? '' : 's'} pass`
|
|
@@ -356,18 +358,31 @@ isolation) {
|
|
|
356
358
|
const sharedState = SuiteIsolation.SHARED_SESSION === isolation && total > 1
|
|
357
359
|
? ' — these flows shared one session and ran in order, so a pass here may rest on state an earlier flow left behind; replay with `parallel` to give each its own context'
|
|
358
360
|
: '';
|
|
361
|
+
const notAsSaved = runs.flatMap(({ replay, flow }) => {
|
|
362
|
+
if (flow === undefined)
|
|
363
|
+
return [];
|
|
364
|
+
const report = replayability(flow);
|
|
365
|
+
return Replayable.YES === report.status && report.writes === undefined
|
|
366
|
+
? []
|
|
367
|
+
: [{ flow: replay.name, ...report }];
|
|
368
|
+
});
|
|
369
|
+
const notReplayable = notAsSaved.filter((row) => Replayable.YES !== row.status);
|
|
370
|
+
const asSaved = 0 === notReplayable.length
|
|
371
|
+
? ''
|
|
372
|
+
: ` — ${String(notReplayable.length)} of ${String(total)} flows are not replayable as saved (${notReplayable.map((row) => row.flow).join(', ')}): a drift there is the flow, not the app`;
|
|
359
373
|
return {
|
|
360
374
|
status,
|
|
361
375
|
total,
|
|
362
376
|
passed,
|
|
363
377
|
failed,
|
|
364
|
-
summary: summary + silentSteps + neverOpened + disagreed + sharedState,
|
|
378
|
+
summary: summary + silentSteps + neverOpened + disagreed + sharedState + asSaved,
|
|
365
379
|
failures,
|
|
366
380
|
...(isolation === undefined ? {} : { isolation }),
|
|
367
381
|
...(unverifiable.length > 0 ? { unverifiable } : {}),
|
|
368
382
|
...(coverage === undefined ? {} : { coverage }),
|
|
369
383
|
...(0 === unreached.length ? {} : { unreached }),
|
|
370
384
|
...(0 === contradictions.length ? {} : { contradictions }),
|
|
385
|
+
...(0 === notAsSaved.length ? {} : { replayability: notAsSaved }),
|
|
371
386
|
};
|
|
372
387
|
}
|
|
373
388
|
/**
|
|
@@ -24,6 +24,11 @@ export declare function anchorFieldName(anchor: FlowAnchor): string | undefined;
|
|
|
24
24
|
export declare const REDACTED_FILL = "<redacted: supply at replay>";
|
|
25
25
|
/** The arg a saved redacted fill names its variable in. Dropped before the step reaches the page. */
|
|
26
26
|
export declare const SECRET_NAME_ARG = "secret";
|
|
27
|
+
/**
|
|
28
|
+
* The arg a RECORDED step carries when the SDK said its target holds a secret. Recorder-internal:
|
|
29
|
+
* it decides redaction at save and never reaches the saved flow.
|
|
30
|
+
*/
|
|
31
|
+
export declare const SECRET_FIELD_ARG = "secretField";
|
|
27
32
|
/**
|
|
28
33
|
* The environment variable that supplies one redacted field.
|
|
29
34
|
*
|
|
@@ -45,6 +50,10 @@ export declare const callSecretsArg: z.ZodOptional<z.ZodRecord<z.ZodString, z.Zo
|
|
|
45
50
|
* daemon's environment.
|
|
46
51
|
*/
|
|
47
52
|
export declare function secretValue(envKey: string, env: Record<string, string | undefined>): string | undefined;
|
|
53
|
+
/** The field's own saved variable name, or its original key for legacy and invalid metadata. */
|
|
54
|
+
export declare function secretKeyForFill(args: Record<string, unknown> | undefined, field: string): string | undefined;
|
|
55
|
+
/** Allocate recorded fills' names while preserving legacy placeholders and existing suffixes. */
|
|
56
|
+
export declare function withDistinctSecretKeys(flow: FlowFile): FlowFile;
|
|
48
57
|
/** One field a flow needs supplied, and the variable that supplies it. */
|
|
49
58
|
export interface UnsuppliedSecret {
|
|
50
59
|
field: string;
|
|
@@ -32,6 +32,11 @@ export function anchorFieldName(anchor) {
|
|
|
32
32
|
export const REDACTED_FILL = '<redacted: supply at replay>';
|
|
33
33
|
/** The arg a saved redacted fill names its variable in. Dropped before the step reaches the page. */
|
|
34
34
|
export const SECRET_NAME_ARG = 'secret';
|
|
35
|
+
/**
|
|
36
|
+
* The arg a RECORDED step carries when the SDK said its target holds a secret. Recorder-internal:
|
|
37
|
+
* it decides redaction at save and never reaches the saved flow.
|
|
38
|
+
*/
|
|
39
|
+
export const SECRET_FIELD_ARG = 'secretField';
|
|
35
40
|
/** The prefix every secret's variable carries. */
|
|
36
41
|
const SECRET_ENV_PREFIX = 'RETICLE_SECRET_';
|
|
37
42
|
/**
|
|
@@ -50,7 +55,7 @@ export const secretEnvKey = (field) => `${SECRET_ENV_PREFIX}${field.replace(/[^a
|
|
|
50
55
|
/** The schema of that argument, shared by every tool that replays a flow. */
|
|
51
56
|
export { CALL_SECRETS_ARG };
|
|
52
57
|
export const callSecretsArg = z
|
|
53
|
-
.record(z.string())
|
|
58
|
+
.record(z.string(), z.string())
|
|
54
59
|
.optional()
|
|
55
60
|
.describe('Redacted fields\' values, this call only, never kept: { "auth-password": "…" }');
|
|
56
61
|
/**
|
|
@@ -64,6 +69,63 @@ export function secretValue(envKey, env) {
|
|
|
64
69
|
}
|
|
65
70
|
return env[envKey];
|
|
66
71
|
}
|
|
72
|
+
const SECRET_OCCURRENCE = /^(?:[2-9]|[1-9][0-9]+)$/;
|
|
73
|
+
/** The field's own saved variable name, or its original key for legacy and invalid metadata. */
|
|
74
|
+
export function secretKeyForFill(args, field) {
|
|
75
|
+
if (args?.['value'] !== REDACTED_FILL)
|
|
76
|
+
return undefined;
|
|
77
|
+
const named = args[SECRET_NAME_ARG];
|
|
78
|
+
const base = secretEnvKey(field);
|
|
79
|
+
// A flow can supply this field's occurrence, never an unrelated environment variable.
|
|
80
|
+
return 'string' === typeof named &&
|
|
81
|
+
named.startsWith(`${base}_`) &&
|
|
82
|
+
SECRET_OCCURRENCE.test(named.slice(base.length + 1))
|
|
83
|
+
? named
|
|
84
|
+
: base;
|
|
85
|
+
}
|
|
86
|
+
function* secretSteps(steps) {
|
|
87
|
+
for (const step of steps) {
|
|
88
|
+
yield step;
|
|
89
|
+
if (step.steps !== undefined)
|
|
90
|
+
yield* secretSteps(step.steps);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/** Allocate recorded fills' names while preserving legacy placeholders and existing suffixes. */
|
|
94
|
+
export function withDistinctSecretKeys(flow) {
|
|
95
|
+
const reserved = new Set();
|
|
96
|
+
const used = new Set();
|
|
97
|
+
for (const step of secretSteps(flow.steps)) {
|
|
98
|
+
const field = anchorFieldName(step.anchor);
|
|
99
|
+
if (field === undefined)
|
|
100
|
+
continue;
|
|
101
|
+
const key = secretKeyForFill(step.args, field);
|
|
102
|
+
if (key === undefined)
|
|
103
|
+
continue;
|
|
104
|
+
reserved.add(key);
|
|
105
|
+
if (key !== secretEnvKey(field) || step.args?.[SECRET_NAME_ARG] === undefined)
|
|
106
|
+
used.add(key);
|
|
107
|
+
}
|
|
108
|
+
const assign = (step) => {
|
|
109
|
+
let out = step;
|
|
110
|
+
const field = anchorFieldName(step.anchor);
|
|
111
|
+
if (field !== undefined &&
|
|
112
|
+
step.args?.['value'] === REDACTED_FILL &&
|
|
113
|
+
step.args[SECRET_NAME_ARG] === secretEnvKey(field)) {
|
|
114
|
+
const base = secretEnvKey(field);
|
|
115
|
+
let key = base;
|
|
116
|
+
let occurrence = 2;
|
|
117
|
+
while (used.has(key) || (key !== base && reserved.has(key))) {
|
|
118
|
+
key = `${base}_${occurrence}`;
|
|
119
|
+
occurrence += 1;
|
|
120
|
+
}
|
|
121
|
+
used.add(key);
|
|
122
|
+
if (key !== base)
|
|
123
|
+
out = { ...step, args: { ...step.args, [SECRET_NAME_ARG]: key } };
|
|
124
|
+
}
|
|
125
|
+
return step.steps === undefined ? out : { ...out, steps: step.steps.map(assign) };
|
|
126
|
+
};
|
|
127
|
+
return { ...flow, steps: flow.steps.map(assign) };
|
|
128
|
+
}
|
|
67
129
|
/**
|
|
68
130
|
* Every credential this flow will replay as the literal placeholder.
|
|
69
131
|
*
|
|
@@ -79,13 +141,13 @@ export function secretValue(envKey, env) {
|
|
|
79
141
|
export function unsuppliedSecrets(flow, env) {
|
|
80
142
|
const out = [];
|
|
81
143
|
const seen = new Set();
|
|
82
|
-
for (const step of flow.steps ?? []) {
|
|
83
|
-
if (REDACTED_FILL !== step.args?.['value'])
|
|
84
|
-
continue;
|
|
144
|
+
for (const step of secretSteps(flow.steps ?? [])) {
|
|
85
145
|
const field = anchorFieldName(step.anchor);
|
|
86
146
|
if (field === undefined)
|
|
87
147
|
continue;
|
|
88
|
-
const envKey =
|
|
148
|
+
const envKey = secretKeyForFill(step.args, field);
|
|
149
|
+
if (envKey === undefined)
|
|
150
|
+
continue;
|
|
89
151
|
const supplied = secretValue(envKey, env);
|
|
90
152
|
if (supplied !== undefined && supplied.length > 0)
|
|
91
153
|
continue;
|
|
@@ -101,6 +101,11 @@ export declare function reresolved(anchor: FlowAnchor, refs: readonly string[]):
|
|
|
101
101
|
* consequence did not hold.
|
|
102
102
|
*/
|
|
103
103
|
export declare function expectElementDrift(value: string, hint: QueryEmptyHint | undefined): Drift;
|
|
104
|
+
/** One look, no settling: for an anchor that may legitimately not be on the page yet. */
|
|
105
|
+
export declare function queryOnce(session: FlowReplaySession, queryArgs: Record<string, unknown>): Promise<{
|
|
106
|
+
refs: string[];
|
|
107
|
+
hint?: QueryEmptyHint;
|
|
108
|
+
}>;
|
|
104
109
|
export declare function resolveQuery(session: FlowReplaySession, queryArgs: Record<string, unknown>, sleep: Sleep, now?: () => number): Promise<{
|
|
105
110
|
refs: string[];
|
|
106
111
|
hint?: QueryEmptyHint;
|
|
@@ -309,6 +309,10 @@ async function settleTick(session, sleep) {
|
|
|
309
309
|
unsubscribe?.();
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
|
+
/** One look, no settling: for an anchor that may legitimately not be on the page yet. */
|
|
313
|
+
export async function queryOnce(session, queryArgs) {
|
|
314
|
+
return readQuery(await session.command(ReticleCommand.QUERY, queryArgs));
|
|
315
|
+
}
|
|
312
316
|
export async function resolveQuery(session, queryArgs, sleep, now = Date.now) {
|
|
313
317
|
let last = readQuery(await session.command(ReticleCommand.QUERY, queryArgs));
|
|
314
318
|
const deadline = now() + ANCHOR_SETTLE_BUDGET_MS;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Contradiction, FlowStepResult } from '@reticlehq/core';
|
|
1
|
+
import type { Contradiction, FlowStep, FlowStepResult, Predicate } from '@reticlehq/core';
|
|
2
2
|
/** Cross-step findings belong to no single step; -1 is the address the suite verdict already uses. */
|
|
3
3
|
export declare const CROSS_STEP_INDEX = -1;
|
|
4
4
|
/**
|
|
@@ -13,3 +13,9 @@ export declare const CROSS_STEP_INDEX = -1;
|
|
|
13
13
|
* Exported for its own test: the subtraction is the whole rule, and it is pure.
|
|
14
14
|
*/
|
|
15
15
|
export declare function crossStepOnly(whole: readonly Contradiction[], steps: readonly FlowStepResult[]): Contradiction[];
|
|
16
|
+
/**
|
|
17
|
+
* Every consequence the flow declared, sub-steps included. The whole-span pass judges the same
|
|
18
|
+
* window the steps did, so a failure a step expected is expected here too. Without it, the per-step
|
|
19
|
+
* pass dropped the declared failure and this pass reported it again as a cross-step finding.
|
|
20
|
+
*/
|
|
21
|
+
export declare function declaredIn(steps: readonly FlowStep[]): Predicate[];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { flattenSteps } from './flow-classify.js';
|
|
1
2
|
/** A contradiction's identity for de-duplication: the rule that fired, and the evidence it fired on. */
|
|
2
3
|
function contradictionId(found) {
|
|
3
4
|
return `${found.kind}|${found.detail}`;
|
|
@@ -19,3 +20,11 @@ export function crossStepOnly(whole, steps) {
|
|
|
19
20
|
const seen = new Set(steps.flatMap((step) => (step.contradictions ?? []).map(contradictionId)));
|
|
20
21
|
return whole.filter((found) => !seen.has(contradictionId(found)));
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Every consequence the flow declared, sub-steps included. The whole-span pass judges the same
|
|
25
|
+
* window the steps did, so a failure a step expected is expected here too. Without it, the per-step
|
|
26
|
+
* pass dropped the declared failure and this pass reported it again as a cross-step finding.
|
|
27
|
+
*/
|
|
28
|
+
export function declaredIn(steps) {
|
|
29
|
+
return flattenSteps(steps).flatMap((step) => (step.expect === undefined ? [] : [step.expect]));
|
|
30
|
+
}
|
|
@@ -11,15 +11,12 @@
|
|
|
11
11
|
* re-save writes the canonical shape. A kind a saved flow cannot enforce is refused, not stripped
|
|
12
12
|
* to an empty expect that would grade asserted-while-unchecked.
|
|
13
13
|
*/
|
|
14
|
-
import { FlowExpectSchema, FlowPredicateSchema, READABLE_FLOW_VERSIONS, FlowErrorCode, FlowFileSchema, } from '@reticlehq/core';
|
|
14
|
+
import { FlowExpectSchema, FlowPredicateSchema, READABLE_FLOW_VERSIONS, FlowErrorCode, FlowFileSchema, isPlainRecord as isRecord, } from '@reticlehq/core';
|
|
15
15
|
export const FlowParseNote = {
|
|
16
16
|
NOT_JSON: 'flow file is not valid JSON — fix the syntax or regenerate it with reticle_flow_save',
|
|
17
17
|
MALFORMED: 'flow file is malformed — fix or regenerate it with reticle_flow_save',
|
|
18
18
|
UNSUPPORTED_SHAPE: 'valid JSON, unsupported expect shape',
|
|
19
19
|
};
|
|
20
|
-
function isRecord(value) {
|
|
21
|
-
return 'object' === typeof value && null !== value && !Array.isArray(value);
|
|
22
|
-
}
|
|
23
20
|
/**
|
|
24
21
|
* Flatten `signal: { name, count }` into the on-disk fields. Other channels already match FlowExpect.
|
|
25
22
|
* Leave a signal object with no name alone so the schema failure can name the key.
|
|
@@ -127,15 +124,22 @@ export function coerceFlowFileExpects(raw) {
|
|
|
127
124
|
* The issues a union rejection buries.
|
|
128
125
|
*
|
|
129
126
|
* `expect` accepts a predicate OR a v1 expect, and zod reports a union failure as one
|
|
130
|
-
* `invalid_union` issue whose branch errors live inside `
|
|
127
|
+
* `invalid_union` issue whose branch errors live inside `errors`, with paths relative to the union. The one that matters is the
|
|
131
128
|
* v1 branch's `unrecognized_keys` — the misspelled field. Without this the file was still correctly
|
|
132
129
|
* REFUSED and the message said only "malformed", which sends the author back to hunt a
|
|
133
130
|
* one-character typo we had already identified.
|
|
134
131
|
*/
|
|
135
132
|
function flatten(issues) {
|
|
136
|
-
return issues.flatMap((issue) =>
|
|
137
|
-
|
|
138
|
-
|
|
133
|
+
return issues.flatMap((issue) => {
|
|
134
|
+
if ('invalid_union' !== issue.code) {
|
|
135
|
+
return [issue];
|
|
136
|
+
}
|
|
137
|
+
const branches = issue.errors.flat().map((inner) => ({
|
|
138
|
+
...inner,
|
|
139
|
+
path: [...issue.path, ...inner.path],
|
|
140
|
+
}));
|
|
141
|
+
return [issue, ...flatten(branches)];
|
|
142
|
+
});
|
|
139
143
|
}
|
|
140
144
|
export function describeFlowZodFailure(error) {
|
|
141
145
|
const all = flatten(error.issues);
|
|
@@ -148,12 +152,13 @@ export function describeFlowZodFailure(error) {
|
|
|
148
152
|
* top-level `invalid_union` says only "malformed", which is true and useless.
|
|
149
153
|
*/
|
|
150
154
|
const named = (one) => {
|
|
151
|
-
// NOT the discriminator complaint. `
|
|
155
|
+
// NOT the discriminator complaint. An `invalid_union` with a `discriminator` on `expect.kind` is the
|
|
152
156
|
// PREDICATE branch objecting that a v1 expect has no `kind` — which is true of every v1 expect
|
|
153
157
|
// ever written and tells the author nothing. The useful issue is the one from the branch they
|
|
154
158
|
// were actually writing.
|
|
155
|
-
if ('
|
|
159
|
+
if ('invalid_union' === one.code && undefined !== one.discriminator) {
|
|
156
160
|
return false;
|
|
161
|
+
}
|
|
157
162
|
return (('steps' === one.path[0] && 'expect' === one.path[2] && one.path.length > 3) ||
|
|
158
163
|
('success' === one.path[0] && one.path.length > 1));
|
|
159
164
|
};
|
|
@@ -12,7 +12,9 @@ import { classifyFlowAssertions } from './flow-classify.js';
|
|
|
12
12
|
*
|
|
13
13
|
* Nothing here derives an intent from step names. A flow that declares none reports that it declares
|
|
14
14
|
* none — a guessed intent puts words in the product owner's mouth and an agent will act on them,
|
|
15
|
-
* which is strictly worse than the honest absence.
|
|
15
|
+
* which is strictly worse than the honest absence. An auto-saved drive does carry a sentence built
|
|
16
|
+
* from its expects (`intentDerived`), so a reader can tell what it checks; it never enters the
|
|
17
|
+
* ledger, and the flow still reports that it declares no intent.
|
|
16
18
|
*/
|
|
17
19
|
/** Namespaced so a flow-declared intent never collides with one an agent declared by hand. */
|
|
18
20
|
const FLOW_INTENT_ID_PREFIX = 'flow:';
|
|
@@ -35,6 +37,9 @@ export function flowReplayVerdictId(flowName, at) {
|
|
|
35
37
|
function intentIdOf(flow) {
|
|
36
38
|
if (flow.intentId !== undefined)
|
|
37
39
|
return flow.intentId;
|
|
40
|
+
// A sentence built from the steps names the flow; it is not a goal, so it declares nothing.
|
|
41
|
+
if (true === flow.intentDerived)
|
|
42
|
+
return undefined;
|
|
38
43
|
// TRIMMED, not merely defined. `intent: " "` satisfied `!== undefined` and silenced the gap, so
|
|
39
44
|
// a flow whose stated goal is whitespace looked identical on disk to one somebody thought about.
|
|
40
45
|
//
|
|
@@ -58,3 +58,11 @@ export declare function establishedState(flow: FlowFile): readonly Predicate[];
|
|
|
58
58
|
* tab on `?tab=summary` as already at `?tab=wrap`.
|
|
59
59
|
*/
|
|
60
60
|
export declare function samePath(observed: string, expected: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* How long replay waits for the start page: the first step's budget when that is longer.
|
|
63
|
+
*
|
|
64
|
+
* A dev server that compiles a route on its first visit can take longer than the floor, and the
|
|
65
|
+
* flow then ended as unverifiable with nothing run. A step the caller let wait 15 s for its
|
|
66
|
+
* consequence can also wait 15 s for its page.
|
|
67
|
+
*/
|
|
68
|
+
export declare function startPathBudgetMs(flow: FlowFile): number;
|
|
@@ -137,3 +137,16 @@ export function samePath(observed, expected) {
|
|
|
137
137
|
const comparable = expected.includes('?') ? observed : withoutQuery(observed);
|
|
138
138
|
return trimmed(comparable) === trimmed(expected);
|
|
139
139
|
}
|
|
140
|
+
/** The least time replay waits for the SDK to reconnect on the start page. */
|
|
141
|
+
const START_PATH_ARRIVAL_TIMEOUT_MS = 5_000;
|
|
142
|
+
/**
|
|
143
|
+
* How long replay waits for the start page: the first step's budget when that is longer.
|
|
144
|
+
*
|
|
145
|
+
* A dev server that compiles a route on its first visit can take longer than the floor, and the
|
|
146
|
+
* flow then ended as unverifiable with nothing run. A step the caller let wait 15 s for its
|
|
147
|
+
* consequence can also wait 15 s for its page.
|
|
148
|
+
*/
|
|
149
|
+
export function startPathBudgetMs(flow) {
|
|
150
|
+
const first = flow.steps[0]?.timeoutMs ?? flow.signalTimeoutMs ?? 0;
|
|
151
|
+
return Math.max(START_PATH_ARRIVAL_TIMEOUT_MS, first);
|
|
152
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a flow needs from the live session to run in a leased context, and what it reports when the
|
|
3
|
+
* lease never came up.
|
|
4
|
+
*/
|
|
5
|
+
import { type FlowReplayResult } from '@reticlehq/core';
|
|
6
|
+
import type { ToolDeps } from '../../surface/tools/tool-kit.js';
|
|
7
|
+
/**
|
|
8
|
+
* The URL a leased context should open: the app's ORIGIN, not the live tab's current location.
|
|
9
|
+
*
|
|
10
|
+
* The live tab drifts — every replay navigates it — so using its full URL made each lease start wherever
|
|
11
|
+
* the previous run happened to finish (observed: leases opening /deployments and failing to find the
|
|
12
|
+
* login control that only exists at the root). A lease must be a FRESH visit to a deterministic entry
|
|
13
|
+
* point; flows that need another page carry their own startPath.
|
|
14
|
+
*/
|
|
15
|
+
export declare function leasableAppUrl(deps: ToolDeps, sessionId: string | undefined): string | undefined;
|
|
16
|
+
/**
|
|
17
|
+
* The live session's own URL — what the fixture port must be looked up by.
|
|
18
|
+
*
|
|
19
|
+
* NOT `leasableAppUrl`. That returns an ORIGIN, and the input provider finds a page by comparing
|
|
20
|
+
* full URLs, so an origin matched no page: `suiteFixtureSeed` answered `undefined` on every run and
|
|
21
|
+
* every leased flow booted cold while the code read as if it were seeded. Silent, because every
|
|
22
|
+
* refusal on that path is deliberately silent — a fixture is an optimisation, and a suite must not
|
|
23
|
+
* die when one is unavailable.
|
|
24
|
+
*/
|
|
25
|
+
export declare function sessionUrlOf(deps: ToolDeps, sessionId: string | undefined): string | undefined;
|
|
26
|
+
/** A flow whose leased context never came up is a suite ERROR, never a silent pass. */
|
|
27
|
+
export declare function leaseFailureReplay(name: string, error: string | undefined): FlowReplayResult;
|