@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,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { FlowPredicateSchema, Verified } from '@reticlehq/core';
|
|
3
|
-
import { DANGEROUS_ACTION_CONFIRM_ARG, ReticleCommand, QueryBy, } from '@reticlehq/core';
|
|
1
|
+
import { SECRET_FIELD_ARG, SECRET_NAME_ARG, secretKeyForFill, secretValue, } from './fields/flow-secret-field.js';
|
|
2
|
+
import { EventType, FlowPredicateSchema, MUTATING_METHODS, Verified, isDevToolingUrl, pathOf, } from '@reticlehq/core';
|
|
3
|
+
import { DANGEROUS_ACTION_CONFIRM_ARG, DOCUMENT_ANCHOR_ROLE, ReticleCommand, QueryBy, isGlobalPressCall, } from '@reticlehq/core';
|
|
4
4
|
import { ReticleTool, invokedFlowMissing } from '@reticlehq/core';
|
|
5
5
|
import { formatStepAddress } from 'open-verification';
|
|
6
6
|
import { refFor } from './flow-anchor.js';
|
|
@@ -44,11 +44,13 @@ export function queryRefs(result) {
|
|
|
44
44
|
export function replayActionArgs(value, confirmDangerous = false, field) {
|
|
45
45
|
const args = { ...asRecord(value) };
|
|
46
46
|
delete args[DANGEROUS_ACTION_CONFIRM_ARG];
|
|
47
|
+
const key = field === undefined ? undefined : secretKeyForFill(args, field);
|
|
47
48
|
delete args[SECRET_NAME_ARG];
|
|
49
|
+
delete args[SECRET_FIELD_ARG];
|
|
48
50
|
if (confirmDangerous)
|
|
49
51
|
args[DANGEROUS_ACTION_CONFIRM_ARG] = true;
|
|
50
|
-
if (
|
|
51
|
-
const supplied = secretValue(
|
|
52
|
+
if (key !== undefined) {
|
|
53
|
+
const supplied = secretValue(key, process.env);
|
|
52
54
|
if (supplied !== undefined && supplied.length > 0)
|
|
53
55
|
args['value'] = supplied;
|
|
54
56
|
}
|
|
@@ -82,14 +84,26 @@ function sourceFromResult(res) {
|
|
|
82
84
|
* Pathname rather than the whole url, because that is what `startPath` is compared against and what
|
|
83
85
|
* a hash-routed app makes meaningless in the document location — see routeOfEvent.
|
|
84
86
|
*/
|
|
85
|
-
export
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
export { pathOf };
|
|
88
|
+
/**
|
|
89
|
+
* Did the app send a write request in this window? A step that did is saved `writes: true`, so a
|
|
90
|
+
* replay does not repeat it unasked. The dev server's own traffic is not the app's.
|
|
91
|
+
*/
|
|
92
|
+
export function wroteIn(events) {
|
|
93
|
+
return events.some((event) => {
|
|
94
|
+
if (EventType.NET_REQUEST !== event.type)
|
|
95
|
+
return false;
|
|
96
|
+
const method = asString(event.data['method'])?.toUpperCase() ?? '';
|
|
97
|
+
return MUTATING_METHODS.includes(method) && !isDevToolingUrl(asString(event.data['url']));
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
/** `wroteIn` over a session's window, best-effort: the record must never fail the drive it records. */
|
|
101
|
+
export function wroteSince(session, since) {
|
|
88
102
|
try {
|
|
89
|
-
return
|
|
103
|
+
return wroteIn(session.eventsSince(since));
|
|
90
104
|
}
|
|
91
105
|
catch {
|
|
92
|
-
return
|
|
106
|
+
return false;
|
|
93
107
|
}
|
|
94
108
|
}
|
|
95
109
|
/** What a saved flow could not keep, and the fix. See RecordedStep.unkeptExpect. */
|
|
@@ -106,7 +120,9 @@ export function captureAct(recordings, args, res,
|
|
|
106
120
|
/** Where this step ran, so the ambient tape can be cut into journeys. See RecordedStep.route. */
|
|
107
121
|
route,
|
|
108
122
|
/** The session that acted: only recordings it started take the step. */
|
|
109
|
-
session
|
|
123
|
+
session,
|
|
124
|
+
/** The act's window sent a write request; see `wroteIn`. */
|
|
125
|
+
wrote = false) {
|
|
110
126
|
// NO `active()` gate. `RecordingStore.capture` opens the AMBIENT tape on its first step, and that
|
|
111
127
|
// branch was unreachable from here: this returned early whenever nothing was open, and the only
|
|
112
128
|
// thing that opened anything was `reticle_record { action: "start" }`. So the comment on `capture`
|
|
@@ -116,6 +132,10 @@ session) {
|
|
|
116
132
|
// That is the whole supply of regression tests this product could have had for free: few saved
|
|
117
133
|
// flows are mutation-testable and few steps declare a consequence, and a drive that is never
|
|
118
134
|
// recorded cannot contribute to either.
|
|
135
|
+
// A click on Reticle's own panel (the HUD exposed) is not a step of the app's journey: saved, the
|
|
136
|
+
// app's flow pressed Run Harness on replay, a paid drive, under an intent that never named it.
|
|
137
|
+
if (true === asRecord(res)['reticleUi'])
|
|
138
|
+
return;
|
|
119
139
|
const step = compileActStep(args, res);
|
|
120
140
|
// Keep the assertion the agent actually made. `act_and_wait { until }` IS the agent saying what
|
|
121
141
|
// success means — the large majority of calls carry one — and dropping it produced a flow graded
|
|
@@ -132,6 +152,8 @@ session) {
|
|
|
132
152
|
const intent = asString(args['intent'])?.trim();
|
|
133
153
|
if (intent !== undefined && intent.length > 0)
|
|
134
154
|
step.intent = intent;
|
|
155
|
+
if (wrote)
|
|
156
|
+
step.writes = true;
|
|
135
157
|
recordings.capture(step, route, session);
|
|
136
158
|
}
|
|
137
159
|
/**
|
|
@@ -140,9 +162,11 @@ session) {
|
|
|
140
162
|
* a regression test asserting something never once observed to hold because of the action. The
|
|
141
163
|
* action itself is always recorded: it happened, and replay needs it to reach the next step.
|
|
142
164
|
*/
|
|
143
|
-
export function captureVerdictedAct(recordings, args, res, route, verified, session
|
|
165
|
+
export function captureVerdictedAct(recordings, args, res, route, verified, session,
|
|
166
|
+
/** The act's window sent a write request; see `wroteIn`. */
|
|
167
|
+
wrote = false) {
|
|
144
168
|
const { until: _until, predicate: _predicate, ...unproved } = args;
|
|
145
|
-
captureAct(recordings, Verified.YES === verified ? args : unproved, res, route, session);
|
|
169
|
+
captureAct(recordings, Verified.YES === verified ? args : unproved, res, route, session, wrote);
|
|
146
170
|
}
|
|
147
171
|
/** Fold a PASSING standalone assertion into the step it proved. See RecordingStore.attachExpect. */
|
|
148
172
|
export function captureAssertion(recordings, raw, session) {
|
|
@@ -205,9 +229,31 @@ function explicitTimeoutMs(args) {
|
|
|
205
229
|
* perfectly stable anchor.
|
|
206
230
|
*/
|
|
207
231
|
function compileAnchorArgs(r, ref, action, actArgs) {
|
|
232
|
+
const compiled = anchorArgs(r, ref, action, actArgs);
|
|
233
|
+
// The SDK says the target holds a secret (a password input, whatever its label). Carried beside
|
|
234
|
+
// the anchor so the saved flow redacts the fill by what the field IS, not by what it is called.
|
|
235
|
+
if (true === r['secret'])
|
|
236
|
+
compiled.args[SECRET_FIELD_ARG] = true;
|
|
237
|
+
return compiled;
|
|
238
|
+
}
|
|
239
|
+
function anchorArgs(r, ref, action, actArgs) {
|
|
240
|
+
// A document-key press with no ref ran live against no element (act-target resolves it to the
|
|
241
|
+
// document), so there is nothing to anchor and nothing missing. It used to fall through to the
|
|
242
|
+
// ref-bound branch with an empty ref, which saved as the degraded placeholder and drifted on every
|
|
243
|
+
// replay with "add a data-testid", on a step that has no element to add one to (#1559).
|
|
244
|
+
if (0 === ref.length && isGlobalPressCall({ action, args: actArgs })) {
|
|
245
|
+
return {
|
|
246
|
+
args: { by: QueryBy.ROLE, value: DOCUMENT_ANCHOR_ROLE, action, args: actArgs },
|
|
247
|
+
stable: true,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
208
250
|
const testid = asString(r['testid']);
|
|
209
251
|
const source = sourceFromResult(r);
|
|
210
|
-
|
|
252
|
+
// Several elements carry this test id, so a replay would take the first: anchor on role and name
|
|
253
|
+
// when the element has them, else keep the test id and say how many share it.
|
|
254
|
+
const testidOf = 'number' === typeof r['testidOf'] && 1 < r['testidOf'] ? r['testidOf'] : undefined;
|
|
255
|
+
const named = asString(r['role']) !== undefined && asString(r['name']) !== undefined;
|
|
256
|
+
if (testid !== undefined && !(testidOf !== undefined && named)) {
|
|
211
257
|
// The testid anchors the step; source rides along purely so a failure can name a file. Carrying
|
|
212
258
|
// both was the point of separating anchor from provenance at capture time.
|
|
213
259
|
const testidArgs = {
|
|
@@ -218,6 +264,8 @@ function compileAnchorArgs(r, ref, action, actArgs) {
|
|
|
218
264
|
};
|
|
219
265
|
if (source !== undefined)
|
|
220
266
|
testidArgs['source'] = source;
|
|
267
|
+
if (testidOf !== undefined)
|
|
268
|
+
testidArgs['of'] = testidOf;
|
|
221
269
|
return { args: testidArgs, stable: true };
|
|
222
270
|
}
|
|
223
271
|
// Role + NAME before component: a component/source anchor names the JSX site, so every row's copy
|
|
@@ -264,7 +312,10 @@ export function compileSequenceStep(args, res) {
|
|
|
264
312
|
? asRecord(res)['steps']
|
|
265
313
|
: [];
|
|
266
314
|
let stable = inputSteps.length > 0;
|
|
267
|
-
const subSteps = inputSteps.
|
|
315
|
+
const subSteps = inputSteps.flatMap((raw, i) => {
|
|
316
|
+
// A step on Reticle's own panel is not a step of the app's journey, as for a single act.
|
|
317
|
+
if (true === asRecord(resolved[i])['reticleUi'])
|
|
318
|
+
return [];
|
|
268
319
|
const step = asRecord(raw);
|
|
269
320
|
const compiled = compileAnchorArgs(asRecord(resolved[i]), asString(step['ref']) ?? '', asString(step['action']) ?? '', replayActionArgs(step['args']));
|
|
270
321
|
if (!compiled.stable)
|
|
@@ -273,7 +324,7 @@ export function compileSequenceStep(args, res) {
|
|
|
273
324
|
// one batch, but what each step CLAIMED is per step -- folding them together would let one
|
|
274
325
|
// signal answer for every click in the journey.
|
|
275
326
|
const expect = enforceableExpect(step['expect']);
|
|
276
|
-
return expect === undefined ? compiled.args : { ...compiled.args, expect };
|
|
327
|
+
return [expect === undefined ? compiled.args : { ...compiled.args, expect }];
|
|
277
328
|
});
|
|
278
329
|
const timeoutMs = explicitTimeoutMs(args);
|
|
279
330
|
return {
|
|
@@ -294,6 +345,9 @@ export function compileSequenceStep(args, res) {
|
|
|
294
345
|
* the first of them.
|
|
295
346
|
*/
|
|
296
347
|
async function resolveRef(session, step) {
|
|
348
|
+
// Dispatched the way it ran live: at the document, with no ref. See compileAnchorArgs.
|
|
349
|
+
if (isDocumentPress(step))
|
|
350
|
+
return { ref: '' };
|
|
297
351
|
const by = asString(step.by);
|
|
298
352
|
const value = asString(step.value);
|
|
299
353
|
if (by === QueryBy.TESTID && value !== undefined) {
|
|
@@ -354,6 +408,19 @@ async function resolveRef(session, step) {
|
|
|
354
408
|
}
|
|
355
409
|
return { ref, note: 'replayed by stale ref (not portable across sessions)' };
|
|
356
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* A compiled step that presses a document key at no element (#1559).
|
|
413
|
+
*
|
|
414
|
+
* Both halves are required. The anchor alone is not enough, because a hand-edited `role: document`
|
|
415
|
+
* on a click would then dispatch that click at nothing; and the press alone is not enough, because a
|
|
416
|
+
* recorded Escape aimed at a named element keeps that element.
|
|
417
|
+
*/
|
|
418
|
+
export function isDocumentPress(step) {
|
|
419
|
+
return (QueryBy.ROLE === step['by'] &&
|
|
420
|
+
DOCUMENT_ANCHOR_ROLE === step['value'] &&
|
|
421
|
+
undefined === step['name'] &&
|
|
422
|
+
isGlobalPressCall({ action: step['action'], args: step['args'] }));
|
|
423
|
+
}
|
|
357
424
|
/** Re-execute every step of a compiled program in order, stopping at the first failure. */
|
|
358
425
|
export async function replayProgram(session, program, confirmDangerous = false,
|
|
359
426
|
/**
|
|
@@ -19,7 +19,7 @@ import { withFileLock } from '../../../memory/project/file-lock.js';
|
|
|
19
19
|
*/
|
|
20
20
|
const AssertionTiersFileSchema = z.object({
|
|
21
21
|
version: z.literal(1),
|
|
22
|
-
flows: z.record(z.object({
|
|
22
|
+
flows: z.record(z.string(), z.object({
|
|
23
23
|
steps: z.array(z.object({ step: z.number(), expect: z.unknown().optional() })),
|
|
24
24
|
/** Source files this flow covered when it last passed — lets the gate scope DELETION findings to
|
|
25
25
|
* the files that actually changed, instead of flagging every intentionally-removed flow. */
|
|
@@ -33,6 +33,15 @@ interface Coverage {
|
|
|
33
33
|
}
|
|
34
34
|
/** The gate's outcome when the project has recorded no flows at all — not a pass, and not a failure. */
|
|
35
35
|
export declare const NO_FLOWS = "no_flows";
|
|
36
|
+
/**
|
|
37
|
+
* How to get a first flow, in calls that work on every tool surface (#1547).
|
|
38
|
+
*
|
|
39
|
+
* `reticle_record` and `reticle_flow_save` are not on the default surface, so naming them bare sent
|
|
40
|
+
* an agent looking for tools it did not have, and it stopped. A journey driven with
|
|
41
|
+
* `reticle_act_and_wait` and an `until` is saved as a flow when the session ends, so that leads;
|
|
42
|
+
* recording by hand goes through `reticle_run`, which every surface advertises.
|
|
43
|
+
*/
|
|
44
|
+
export declare const RECORD_A_FLOW: string;
|
|
36
45
|
/** The gate's flow-coverage line. `pct` and `outcome` are mutually exclusive by construction. */
|
|
37
46
|
interface FlowCoverageReport {
|
|
38
47
|
covered: number;
|
|
@@ -6,6 +6,17 @@
|
|
|
6
6
|
*/
|
|
7
7
|
/** The gate's outcome when the project has recorded no flows at all — not a pass, and not a failure. */
|
|
8
8
|
export const NO_FLOWS = 'no_flows';
|
|
9
|
+
/**
|
|
10
|
+
* How to get a first flow, in calls that work on every tool surface (#1547).
|
|
11
|
+
*
|
|
12
|
+
* `reticle_record` and `reticle_flow_save` are not on the default surface, so naming them bare sent
|
|
13
|
+
* an agent looking for tools it did not have, and it stopped. A journey driven with
|
|
14
|
+
* `reticle_act_and_wait` and an `until` is saved as a flow when the session ends, so that leads;
|
|
15
|
+
* recording by hand goes through `reticle_run`, which every surface advertises.
|
|
16
|
+
*/
|
|
17
|
+
export const RECORD_A_FLOW = 'Drive a journey with reticle_act_and_wait and an `until`: it is saved as a flow when the session ends. ' +
|
|
18
|
+
'Or record one by hand with reticle_run { tool: "reticle_record", args: { action: "start" } }, then ' +
|
|
19
|
+
'reticle_run { tool: "reticle_flow_save", args: { flowName } }.';
|
|
9
20
|
/**
|
|
10
21
|
* What to do about it, since the empty state is otherwise indistinguishable from success.
|
|
11
22
|
*
|
|
@@ -13,7 +24,7 @@ export const NO_FLOWS = 'no_flows';
|
|
|
13
24
|
* that errors is a second dead end on top of the first (see suggested-commands-exist.test.ts). Same
|
|
14
25
|
* wording as the empty-suite verdict, which is the same situation reached from `reticle verify`.
|
|
15
26
|
*/
|
|
16
|
-
const NO_FLOWS_NOTE =
|
|
27
|
+
const NO_FLOWS_NOTE = `no flows recorded — nothing was checked. ${RECORD_A_FLOW}`;
|
|
17
28
|
/**
|
|
18
29
|
* Report flow coverage so that an EMPTY suite cannot be read as a passing one.
|
|
19
30
|
*
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which flows a suite run replays, resolved against the store.
|
|
3
|
+
*
|
|
4
|
+
* Shared by the MCP tool and the `reticle verify` command so the two cannot disagree about what a
|
|
5
|
+
* selection means.
|
|
6
|
+
*
|
|
7
|
+
* Lives beside the flow store rather than under `suite/` on purpose: it needs `flowsForSession`, and
|
|
8
|
+
* from `suite/` that import made `suite` and `flows` need EACH OTHER -- a mutual pair, which the
|
|
9
|
+
* reach guard forbids growing because two directories that need each other cannot be read, moved or
|
|
10
|
+
* tested apart. Here it adds no edge at all: `flows` reaching itself is nothing, and `cli -> flows`
|
|
11
|
+
* already existed. The pure rule lives in core (`selectFlows`); this is the part that has to read
|
|
12
|
+
* the files, because a label lives in one and `list` returns only names.
|
|
13
|
+
*/
|
|
14
|
+
import { type FlowFile } from '@reticlehq/core';
|
|
1
15
|
import type { ProjectTarget } from '../../memory/project/session-root.js';
|
|
2
16
|
import type { ToolDeps } from '../../surface/tools/tool-kit.js';
|
|
3
17
|
/**
|
|
@@ -14,6 +28,8 @@ export declare function resolveSuiteSelection(deps: ToolDeps, target: ProjectTar
|
|
|
14
28
|
run: string[];
|
|
15
29
|
quarantined: string[];
|
|
16
30
|
unmatched: string[];
|
|
31
|
+
/** Flows held back by `skipWrites`: replaying them would send their write requests again. */
|
|
32
|
+
writing?: string[];
|
|
17
33
|
/** Flows in a dependency cycle — none of them ran. */
|
|
18
34
|
cycles?: string[];
|
|
19
35
|
/** A flow whose prerequisite is not in this run, so it did not run either. */
|
|
@@ -30,3 +46,12 @@ export declare function resolveSuiteSelection(deps: ToolDeps, target: ProjectTar
|
|
|
30
46
|
*/
|
|
31
47
|
knownRoutes: string[];
|
|
32
48
|
}>;
|
|
49
|
+
/** The flows a replay would change real data with: a step sent, or expects, a write request. */
|
|
50
|
+
export declare function writingFlows(flows: readonly FlowFile[]): string[];
|
|
51
|
+
/** How the refusal of an unknown flow name opens: the error table recognizes it by these words. */
|
|
52
|
+
export declare const UNKNOWN_FLOW_OPENING = "No saved flow is named";
|
|
53
|
+
/**
|
|
54
|
+
* The refusal for flow names no saved flow carries, or `undefined` when every name is known. Names
|
|
55
|
+
* the flows that do exist, so the typo can be fixed in the next call.
|
|
56
|
+
*/
|
|
57
|
+
export declare function unknownFlowRefusal(wanted: readonly string[], known: readonly string[]): Error | undefined;
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
import { FLOW_FILE_VERSION, orderFlows, selectFlows } from '@reticlehq/core';
|
|
15
15
|
import { flowsForSession } from './flow-store-for-session.js';
|
|
16
|
+
import { readyForReplay, replayability } from './flow-replayable.js';
|
|
16
17
|
/**
|
|
17
18
|
* Resolve what a suite run should replay, and what it is holding back.
|
|
18
19
|
*
|
|
@@ -55,23 +56,29 @@ export async function resolveSuiteSelection(deps, target, args) {
|
|
|
55
56
|
...(0 === wantedLabels.length ? {} : { labels: wantedLabels }),
|
|
56
57
|
});
|
|
57
58
|
/*
|
|
58
|
-
* A name
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* a typo has no other way of surfacing -- ask for `@smoek` and, without this, a suite of zero
|
|
63
|
-
* flows reports a clean pass.
|
|
59
|
+
* A name no saved flow carries is refused before anything runs. It used to be ATTEMPTED, so a
|
|
60
|
+
* typo became a failed check and a failed run on the dashboard, with "check the element state" as
|
|
61
|
+
* the advice. `unmatched` still reports labels, where a typo has no other way of surfacing -- ask
|
|
62
|
+
* for `@smoek` and, without it, a suite of zero flows reports a clean pass.
|
|
64
63
|
*/
|
|
65
|
-
const
|
|
64
|
+
const unknown = unknownFlowRefusal(wantedNames, names);
|
|
65
|
+
if (unknown !== undefined)
|
|
66
|
+
throw unknown;
|
|
66
67
|
/*
|
|
67
68
|
* Ordered AFTER selection, so a prerequisite filtered out by a label is reported rather than
|
|
68
69
|
* silently pulled back in. A flow whose `login` was excluded does not run: failing it here would
|
|
69
70
|
* produce a failure about the wrong thing, and quietly adding `login` back would run a flow the
|
|
70
71
|
* caller did not ask for.
|
|
71
72
|
*/
|
|
72
|
-
|
|
73
|
+
/*
|
|
74
|
+
* A certify run must not change real data. A flow whose step sent a write request when it was
|
|
75
|
+
* recorded (or whose expect names one) is held back and named, never replayed, when asked.
|
|
76
|
+
*/
|
|
77
|
+
const writing = true === args['skipWrites'] ? writingFlows(chosen.run) : [];
|
|
78
|
+
const ordered = orderFlows(chosen.run.filter((flow) => !writing.includes(flow.name)));
|
|
73
79
|
return {
|
|
74
|
-
run:
|
|
80
|
+
run: ordered.run.map((flow) => flow.name),
|
|
81
|
+
...(0 === writing.length ? {} : { writing }),
|
|
75
82
|
quarantined: chosen.quarantined,
|
|
76
83
|
unmatched: chosen.unmatched.filter((entry) => !wantedNames.includes(entry)),
|
|
77
84
|
...(0 === ordered.cycles.length ? {} : { cycles: ordered.cycles }),
|
|
@@ -83,3 +90,28 @@ export async function resolveSuiteSelection(deps, target, args) {
|
|
|
83
90
|
],
|
|
84
91
|
};
|
|
85
92
|
}
|
|
93
|
+
/** The flows a replay would change real data with: a step sent, or expects, a write request. */
|
|
94
|
+
export function writingFlows(flows) {
|
|
95
|
+
return flows
|
|
96
|
+
.filter((flow) => true === replayability(readyForReplay(flow)).writes)
|
|
97
|
+
.map((flow) => flow.name);
|
|
98
|
+
}
|
|
99
|
+
/** How the refusal of an unknown flow name opens: the error table recognizes it by these words. */
|
|
100
|
+
export const UNKNOWN_FLOW_OPENING = 'No saved flow is named';
|
|
101
|
+
/** How many saved flow names a refusal lists before it says how many more there are. */
|
|
102
|
+
const KNOWN_SHOWN = 10;
|
|
103
|
+
/**
|
|
104
|
+
* The refusal for flow names no saved flow carries, or `undefined` when every name is known. Names
|
|
105
|
+
* the flows that do exist, so the typo can be fixed in the next call.
|
|
106
|
+
*/
|
|
107
|
+
export function unknownFlowRefusal(wanted, known) {
|
|
108
|
+
const missing = wanted.filter((name) => !known.includes(name));
|
|
109
|
+
if (0 === missing.length)
|
|
110
|
+
return undefined;
|
|
111
|
+
const asked = missing.map((name) => `"${name}"`).join(', ');
|
|
112
|
+
const more = known.length - KNOWN_SHOWN;
|
|
113
|
+
const saved = 0 === known.length
|
|
114
|
+
? 'No flows are saved for this project yet: drive the journey once and it is saved.'
|
|
115
|
+
: `Saved flows: ${known.slice(0, KNOWN_SHOWN).join(', ')}${more > 0 ? `, and ${String(more)} more (reticle_flow {action:"list"})` : ''}.`;
|
|
116
|
+
return new Error(`${UNKNOWN_FLOW_OPENING} ${asked}, so nothing ran. ${saved}`);
|
|
117
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* True when git answers that it does not ignore `path`, so a checkout gets the file from git. False
|
|
3
|
+
* when git ignores it, and when git cannot answer. Asked once for each path in this process. `path`
|
|
4
|
+
* need not exist yet.
|
|
5
|
+
*/
|
|
6
|
+
export declare function gitTracks(path: string): boolean;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether git gives a checkout a path, or ignores it. One `git check-ignore` for each path.
|
|
3
|
+
*/
|
|
4
|
+
import { spawnSync } from 'node:child_process';
|
|
5
|
+
import { existsSync } from 'node:fs';
|
|
6
|
+
import { dirname } from 'node:path';
|
|
7
|
+
/** Exit status of `git check-ignore` for a path that git does not ignore. */
|
|
8
|
+
const CHECK_IGNORE_NOT_IGNORED = 1;
|
|
9
|
+
const GIT_TIMEOUT_MS = 2_000;
|
|
10
|
+
const tracked = new Map();
|
|
11
|
+
/**
|
|
12
|
+
* True when git answers that it does not ignore `path`, so a checkout gets the file from git. False
|
|
13
|
+
* when git ignores it, and when git cannot answer. Asked once for each path in this process. `path`
|
|
14
|
+
* need not exist yet.
|
|
15
|
+
*/
|
|
16
|
+
export function gitTracks(path) {
|
|
17
|
+
const known = tracked.get(path);
|
|
18
|
+
if (known !== undefined)
|
|
19
|
+
return known;
|
|
20
|
+
const result = spawnSync('git', ['check-ignore', '-q', path], {
|
|
21
|
+
cwd: existingAncestor(path),
|
|
22
|
+
stdio: 'ignore',
|
|
23
|
+
timeout: GIT_TIMEOUT_MS,
|
|
24
|
+
windowsHide: true,
|
|
25
|
+
});
|
|
26
|
+
const answer = CHECK_IGNORE_NOT_IGNORED === result.status;
|
|
27
|
+
tracked.set(path, answer);
|
|
28
|
+
return answer;
|
|
29
|
+
}
|
|
30
|
+
/** `path`, or the nearest directory above it that exists: git needs a real working directory. */
|
|
31
|
+
function existingAncestor(path) {
|
|
32
|
+
let dir = dirname(path);
|
|
33
|
+
while (!existsSync(dir) && dirname(dir) !== dir)
|
|
34
|
+
dir = dirname(dir);
|
|
35
|
+
return dir;
|
|
36
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { ProjectCloud } from './cloud-config.js';
|
|
2
|
+
export declare const BackgroundSyncState: {
|
|
3
|
+
readonly ON: "on";
|
|
4
|
+
readonly OPTED_OUT: "opted-out";
|
|
5
|
+
readonly UNLINKED: "unlinked";
|
|
6
|
+
readonly SIGNED_OUT: "signed-out";
|
|
7
|
+
/** The platform refused the credential (401/403). Stays stopped until the sign-in changes. */
|
|
8
|
+
readonly REFUSED: "refused";
|
|
9
|
+
};
|
|
10
|
+
export type BackgroundSyncState = (typeof BackgroundSyncState)[keyof typeof BackgroundSyncState];
|
|
11
|
+
export interface BackgroundSyncGate {
|
|
12
|
+
state: BackgroundSyncState;
|
|
13
|
+
/** In words a person can act on. */
|
|
14
|
+
why: string;
|
|
15
|
+
/** Who is sending, when it is ON: a new value after a new sign-in or a new key. */
|
|
16
|
+
credential?: string;
|
|
17
|
+
}
|
|
18
|
+
/** May the daemon send this root's work now? Reads the disk, never the network. */
|
|
19
|
+
export declare function backgroundSyncGate(input: {
|
|
20
|
+
reticleRoot: string;
|
|
21
|
+
cloud: ProjectCloud;
|
|
22
|
+
env: NodeJS.ProcessEnv;
|
|
23
|
+
/** The signed-in session's token for that address, or undefined. */
|
|
24
|
+
signedIn: (url: string) => string | undefined;
|
|
25
|
+
}): BackgroundSyncGate;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the daemon's background sync may send a project's work.
|
|
3
|
+
*
|
|
4
|
+
* The daemon sends without anybody asking, so it sends only when every one of these holds:
|
|
5
|
+
*
|
|
6
|
+
* - Nobody switched it off: `RETICLE_BACKGROUND_SYNC=0` on the machine, `"backgroundSync": false`
|
|
7
|
+
* in the project's `.reticle.json`.
|
|
8
|
+
* - The project is LINKED, by its own `.reticle/cloud.json`. The address comes from that link and
|
|
9
|
+
* nowhere else. An environment address is never used: a repository's `.env` that named the
|
|
10
|
+
* hosted service once sent another app's runs to the wrong workspace.
|
|
11
|
+
* - Somebody is signed in to that address, and this machine holds a key for the link. `reticle
|
|
12
|
+
* logout` stops it on the next tick; `reticle login` starts it again. OR the link's key is
|
|
13
|
+
* `RETICLE_API_KEY` from the environment, which is how CI runs: a committed `cloud.json`, a key
|
|
14
|
+
* kept as a secret, and nobody to sign in. The address still comes from the link, and
|
|
15
|
+
* `resolveProjectCloud` uses the environment's key only when it is for that address.
|
|
16
|
+
*
|
|
17
|
+
* `reticle sync` stays the explicit way to send now, and none of this applies to it.
|
|
18
|
+
*/
|
|
19
|
+
import { dirname } from 'node:path';
|
|
20
|
+
import { ReticleEnv, apiKeyFrom } from '@reticlehq/core';
|
|
21
|
+
import { projectSetting } from '../intent/record-request.js';
|
|
22
|
+
export const BackgroundSyncState = {
|
|
23
|
+
ON: 'on',
|
|
24
|
+
OPTED_OUT: 'opted-out',
|
|
25
|
+
UNLINKED: 'unlinked',
|
|
26
|
+
SIGNED_OUT: 'signed-out',
|
|
27
|
+
/** The platform refused the credential (401/403). Stays stopped until the sign-in changes. */
|
|
28
|
+
REFUSED: 'refused',
|
|
29
|
+
};
|
|
30
|
+
const OFF_VALUES = new Set(['0', 'false', 'off', 'no']);
|
|
31
|
+
const BACKGROUND_SYNC_SETTING = 'backgroundSync';
|
|
32
|
+
/** May the daemon send this root's work now? Reads the disk, never the network. */
|
|
33
|
+
export function backgroundSyncGate(input) {
|
|
34
|
+
const { reticleRoot, cloud, env, signedIn } = input;
|
|
35
|
+
if (OFF_VALUES.has((env[ReticleEnv.BACKGROUND_SYNC] ?? '').toLowerCase())) {
|
|
36
|
+
return {
|
|
37
|
+
state: BackgroundSyncState.OPTED_OUT,
|
|
38
|
+
why: `off on this machine (${ReticleEnv.BACKGROUND_SYNC})`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
if (false === projectSetting(dirname(reticleRoot), BACKGROUND_SYNC_SETTING)) {
|
|
42
|
+
return {
|
|
43
|
+
state: BackgroundSyncState.OPTED_OUT,
|
|
44
|
+
why: `off in this project ("${BACKGROUND_SYNC_SETTING}": false in .reticle.json)`,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
// `link` is set only from the project's own link file; an environment key leaves it unset.
|
|
48
|
+
if (cloud.link === undefined) {
|
|
49
|
+
return {
|
|
50
|
+
state: BackgroundSyncState.UNLINKED,
|
|
51
|
+
why: 'this project is not linked: run `reticle connect`',
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
if (null === cloud.config) {
|
|
55
|
+
return {
|
|
56
|
+
state: BackgroundSyncState.SIGNED_OUT,
|
|
57
|
+
why: cloud.reason ?? 'no key for this link: run `reticle connect`',
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
if (cloud.config.apiKey === apiKeyFrom(env)) {
|
|
61
|
+
return {
|
|
62
|
+
state: BackgroundSyncState.ON,
|
|
63
|
+
why: `sends to ${cloud.config.url} with ${ReticleEnv.API_KEY}`,
|
|
64
|
+
credential: cloud.config.apiKey,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const token = signedIn(cloud.config.url);
|
|
68
|
+
if (token === undefined) {
|
|
69
|
+
return {
|
|
70
|
+
state: BackgroundSyncState.SIGNED_OUT,
|
|
71
|
+
why: `nobody is signed in to ${cloud.config.url}: run \`reticle connect --url ${cloud.config.url}\``,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
state: BackgroundSyncState.ON,
|
|
76
|
+
why: `sends to ${cloud.config.url}`,
|
|
77
|
+
credential: `${cloud.config.apiKey}\u0000${token}`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type FileSystemPort } from '../project/fs/fs-port.js';
|
|
2
2
|
import { type CloudConfig } from './cloud-sync.js';
|
|
3
3
|
/** `<reticleRoot>/cloud.json` — the project's cloud binding + sync policy (non-secret). */
|
|
4
4
|
/** Re-exported so the existing importers keep working; the string itself lives in core. */
|
|
@@ -31,6 +31,17 @@ interface SyncPolicy {
|
|
|
31
31
|
* a project that keeps its runs local has not agreed to send pictures of its pages either.
|
|
32
32
|
*/
|
|
33
33
|
screenshots: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Push the frames filmed between steps (about one a second while Reticle drives a tab), which the
|
|
36
|
+
* dashboard plays as the run's video. Follows `screenshots` when the link does not say.
|
|
37
|
+
*/
|
|
38
|
+
video: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Upload the episode log (every tool call and its whole result). Never a default and never
|
|
41
|
+
* inherited from another switch: only `"episodes": true` here, and even then only to a workspace
|
|
42
|
+
* that consented to share its data. See `episodesMaySync`.
|
|
43
|
+
*/
|
|
44
|
+
episodes?: boolean;
|
|
34
45
|
}
|
|
35
46
|
/** Where a verification actually executes. Reserved for the hosted-runner path; default local. */
|
|
36
47
|
export declare const VerifyMode: {
|