@reticlehq/server 3.6.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +122 -123
- package/dist/command/cli/adhoc-suite.d.ts +14 -0
- package/dist/command/cli/adhoc-suite.js +42 -7
- package/dist/command/cli/adhoc-verdict.d.ts +18 -2
- package/dist/command/cli/adhoc-verdict.js +70 -6
- package/dist/command/cli/answers/gate-exit.d.ts +23 -0
- package/dist/command/cli/answers/gate-exit.js +45 -0
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +3 -1
- package/dist/command/cli/auth/device-flow.d.ts +13 -2
- package/dist/command/cli/auth/device-flow.js +17 -0
- package/dist/command/cli/cli-doctor.js +14 -0
- package/dist/command/cli/cli-flow-commands.d.ts +0 -11
- package/dist/command/cli/cli-flow-commands.js +28 -105
- package/dist/command/cli/cli-kill.js +3 -2
- package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
- package/dist/command/cli/cli-parse-grammar.js +75 -0
- package/dist/command/cli/cli-parse-verify.d.ts +2 -0
- package/dist/command/cli/cli-parse-verify.js +18 -0
- package/dist/command/cli/cli-parse.d.ts +19 -28
- package/dist/command/cli/cli-parse.js +82 -182
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +61 -9
- package/dist/command/cli/cli-usage.d.ts +33 -0
- package/dist/command/cli/cli-usage.js +287 -0
- package/dist/command/cli/cli-verify.d.ts +34 -4
- package/dist/command/cli/cli-verify.js +81 -12
- package/dist/command/cli/cloud-cli.d.ts +13 -0
- package/dist/command/cli/cloud-cli.js +145 -333
- package/dist/command/cli/cloud-kit.d.ts +12 -0
- package/dist/command/cli/cloud-kit.js +41 -2
- package/dist/command/cli/cloud-link.d.ts +57 -0
- package/dist/command/cli/cloud-link.js +308 -0
- package/dist/command/cli/cloud-login.d.ts +15 -1
- package/dist/command/cli/cloud-login.js +67 -13
- package/dist/command/cli/context-command.d.ts +1 -0
- package/dist/command/cli/context-command.js +33 -0
- package/dist/command/cli/daemon-start-options.d.ts +3 -0
- package/dist/command/cli/daemon-start-options.js +24 -3
- package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
- package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
- package/dist/command/cli/doctor/doctor-project-line.js +5 -4
- package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
- package/dist/command/cli/doctor/doctor-rows.js +6 -0
- package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
- package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
- package/dist/command/cli/known-regression.d.ts +13 -0
- package/dist/command/cli/known-regression.js +34 -0
- package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
- package/dist/command/cli/launch/sdk-version-match.js +25 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +11 -2
- package/dist/command/cli/mcp-command.d.ts +6 -0
- package/dist/command/cli/mcp-command.js +13 -5
- package/dist/command/cli/ports/port-holder.js +1 -1
- package/dist/command/cli/project-name.d.ts +29 -1
- package/dist/command/cli/project-name.js +107 -2
- package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
- package/dist/command/cli/setup-mcp-cli.js +29 -8
- package/dist/command/cli/status/status-lines.d.ts +1 -0
- package/dist/command/cli/status/status-lines.js +47 -2
- package/dist/command/cli/status/workspace-links.d.ts +10 -0
- package/dist/command/cli/status/workspace-links.js +29 -0
- package/dist/command/cli/try-command.d.ts +96 -0
- package/dist/command/cli/try-command.js +362 -0
- package/dist/command/cli/tutorial.d.ts +0 -100
- package/dist/command/cli/tutorial.js +0 -178
- package/dist/command/cli/verify-results.d.ts +19 -0
- package/dist/command/cli/verify-results.js +29 -0
- package/dist/command/cli-onboarding.d.ts +0 -11
- package/dist/command/cli-onboarding.js +0 -15
- package/dist/command/cli.d.ts +14 -0
- package/dist/command/cli.js +103 -83
- package/dist/command/daemon/daemon-resilience.js +4 -4
- package/dist/command/daemon/daemon-resolve.d.ts +9 -1
- package/dist/command/daemon/daemon-resolve.js +49 -10
- package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
- package/dist/command/setup/bringup/bridge-port.js +13 -3
- package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
- package/dist/command/setup/bringup/ensure-daemon.js +9 -2
- package/dist/command/setup/init/agent-restart.d.ts +23 -0
- package/dist/command/setup/init/agent-restart.js +28 -0
- package/dist/command/setup/init/init-port.d.ts +10 -1
- package/dist/command/setup/init/init-port.js +22 -2
- package/dist/command/setup/init/init-runtime.d.ts +12 -2
- package/dist/command/setup/init/init-runtime.js +96 -37
- package/dist/command/setup/node-effects.d.ts +2 -0
- package/dist/command/setup/node-effects.js +36 -8
- package/dist/command/setup/probe/existing-app.d.ts +12 -0
- package/dist/command/setup/probe/existing-app.js +14 -0
- package/dist/command/setup/remaining-steps.js +1 -1
- package/dist/command/setup/run-setup.d.ts +29 -9
- package/dist/command/setup/run-setup.js +34 -28
- package/dist/command/setup/setup-command.d.ts +23 -0
- package/dist/command/setup/setup-command.js +57 -4
- package/dist/command/setup/setup-mcp.js +25 -2
- package/dist/command/setup/tauri-signing.d.ts +19 -0
- package/dist/command/setup/tauri-signing.js +79 -0
- package/dist/command/setup/terminal/listeners.d.ts +10 -1
- package/dist/command/setup/terminal/listeners.js +37 -6
- package/dist/command/update/update-nudge.d.ts +9 -0
- package/dist/command/update/update-nudge.js +1 -1
- package/dist/command/update/updater.js +11 -15
- package/dist/command/version/version-nudge.js +3 -0
- package/dist/command/version/version-skew.d.ts +20 -1
- package/dist/command/version/version-skew.js +38 -2
- package/dist/features/crawl/crawl.js +14 -1
- package/dist/features/exhaust/ledger.d.ts +14 -14
- package/dist/features/harness/drive-report.d.ts +39 -5
- package/dist/features/harness/drive-report.js +271 -54
- package/dist/features/harness/drive-runs.d.ts +120 -0
- package/dist/features/harness/drive-runs.js +289 -0
- package/dist/features/harness/drivers.d.ts +1 -1
- package/dist/features/harness/drivers.js +1 -1
- package/dist/features/harness/explore/console-pages.d.ts +15 -0
- package/dist/features/harness/explore/console-pages.js +146 -0
- package/dist/features/harness/explore/disparity.d.ts +19 -0
- package/dist/features/harness/explore/disparity.js +71 -0
- package/dist/features/harness/explore/fake-app.d.ts +16 -0
- package/dist/features/harness/explore/fake-app.js +49 -0
- package/dist/features/harness/explore/goal-search.d.ts +26 -0
- package/dist/features/harness/explore/goal-search.js +144 -0
- package/dist/features/harness/explore/page-tree.d.ts +49 -0
- package/dist/features/harness/explore/page-tree.js +148 -0
- package/dist/features/harness/explore/site-map.d.ts +34 -0
- package/dist/features/harness/explore/site-map.js +150 -0
- package/dist/features/harness/goals.d.ts +68 -7
- package/dist/features/harness/goals.js +289 -36
- package/dist/features/harness/harness.d.ts +30 -1
- package/dist/features/harness/harness.js +141 -7
- package/dist/features/harness/platform/local-apps.d.ts +36 -3
- package/dist/features/harness/platform/local-apps.js +81 -5
- package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
- package/dist/features/harness/platform/persona-credentials.js +69 -0
- package/dist/features/harness/platform/platform-drives.d.ts +61 -0
- package/dist/features/harness/platform/platform-drives.js +114 -0
- package/dist/features/harness/platform/refusal.d.ts +52 -0
- package/dist/features/harness/platform/refusal.js +71 -0
- package/dist/features/harness/platform/remote-drive.d.ts +8 -2
- package/dist/features/harness/platform/remote-drive.js +22 -9
- package/dist/features/harness/platform/script.d.ts +57 -11
- package/dist/features/harness/platform/script.js +144 -12
- package/dist/features/harness/platform/server-driver.d.ts +17 -4
- package/dist/features/harness/platform/server-driver.js +29 -26
- package/dist/features/harness/platform-config.d.ts +38 -5
- package/dist/features/harness/platform-config.js +93 -8
- package/dist/features/harness/route-guess.d.ts +13 -0
- package/dist/features/harness/route-guess.js +49 -0
- package/dist/features/harness/script/script-run.d.ts +30 -1
- package/dist/features/harness/script/script-run.js +355 -48
- package/dist/features/license/license.d.ts +2 -2
- package/dist/features/visual/step-shots.d.ts +31 -0
- package/dist/features/visual/step-shots.js +231 -0
- package/dist/features/visual/visual-tools.js +22 -14
- package/dist/hooks/client-directory.d.ts +18 -0
- package/dist/hooks/client-directory.js +57 -0
- package/dist/hooks/coding-agents.d.ts +34 -0
- package/dist/hooks/coding-agents.js +117 -0
- package/dist/hooks/driven-by.d.ts +21 -2
- package/dist/hooks/driven-by.js +42 -2
- package/dist/hooks/hook-bus.d.ts +4 -0
- package/dist/hooks/hook-bus.js +18 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +26 -183
- package/dist/judgement/capsule/capsule-store.d.ts +2 -2
- package/dist/judgement/capsule/causal-summary.d.ts +15 -1
- package/dist/judgement/capsule/causal-summary.js +33 -0
- package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
- package/dist/judgement/runs/artifact/build-verification-run.js +20 -4
- package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
- package/dist/judgement/runs/artifact/gap-summary.js +12 -3
- package/dist/judgement/runs/artifact/replay-mapping.js +25 -9
- package/dist/judgement/runs/artifact/run-store.d.ts +13 -1
- package/dist/judgement/runs/artifact/run-store.js +175 -8
- package/dist/judgement/runs/context-tools.js +59 -1
- package/dist/judgement/runs/default-run-id.d.ts +3 -0
- package/dist/judgement/runs/default-run-id.js +16 -0
- package/dist/judgement/runs/drive-run.d.ts +53 -5
- package/dist/judgement/runs/drive-run.js +234 -20
- package/dist/judgement/runs/resume.d.ts +44 -0
- package/dist/judgement/runs/resume.js +137 -0
- package/dist/judgement/runs/reticle-runner.js +5 -2
- package/dist/judgement/runs/runner-port.d.ts +5 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +2 -0
- package/dist/judgement/runs/verification-sync.js +36 -15
- package/dist/language/flows/decision.js +2 -1
- package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
- package/dist/language/flows/fields/flow-secret-field.js +25 -2
- package/dist/language/flows/flow-anchor.d.ts +7 -2
- package/dist/language/flows/flow-anchor.js +10 -3
- package/dist/language/flows/flow-intent.d.ts +1 -0
- package/dist/language/flows/flow-journey.d.ts +6 -0
- package/dist/language/flows/flow-journey.js +20 -0
- package/dist/language/flows/flow-learning.d.ts +4 -0
- package/dist/language/flows/flow-learning.js +37 -3
- package/dist/language/flows/flow-replay-run.js +16 -18
- package/dist/language/flows/flow-replay-types.d.ts +1 -1
- package/dist/language/flows/flow-replay.d.ts +18 -1
- package/dist/language/flows/flow-replay.js +22 -7
- package/dist/language/flows/flow-result.d.ts +22 -1
- package/dist/language/flows/flow-result.js +47 -2
- package/dist/language/flows/flow-step-runners.d.ts +2 -0
- package/dist/language/flows/flow-step-runners.js +12 -6
- package/dist/language/flows/flow-store-for-session.js +5 -1
- package/dist/language/flows/flow-tools.d.ts +10 -0
- package/dist/language/flows/flow-tools.js +61 -62
- package/dist/language/flows/flows.d.ts +16 -1
- package/dist/language/flows/flows.js +69 -10
- package/dist/language/flows/narrow-write.d.ts +7 -0
- package/dist/language/flows/narrow-write.js +36 -1
- package/dist/language/flows/recording/recording-backtrack.js +14 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +29 -1
- package/dist/language/flows/recording/tape/recordings.js +60 -10
- package/dist/language/flows/replay.js +29 -6
- package/dist/language/flows/single-replay.d.ts +7 -0
- package/dist/language/flows/single-replay.js +26 -0
- package/dist/language/flows/verify-change-tools.d.ts +1 -0
- package/dist/language/flows/verify-change-tools.js +200 -193
- package/dist/memory/cloud/cloud-config.d.ts +10 -1
- package/dist/memory/cloud/cloud-config.js +19 -5
- package/dist/memory/cloud/cloud-sync.js +3 -3
- package/dist/memory/cloud/harness-config.d.ts +49 -0
- package/dist/memory/cloud/harness-config.js +16 -20
- package/dist/memory/cloud/memory-scope.d.ts +17 -0
- package/dist/memory/cloud/memory-scope.js +22 -0
- package/dist/memory/cloud/sync-cycle.d.ts +32 -4
- package/dist/memory/cloud/sync-cycle.js +113 -12
- package/dist/memory/cloud/sync-daemon.d.ts +11 -0
- package/dist/memory/cloud/sync-daemon.js +114 -4
- package/dist/memory/cloud/sync-disk.js +26 -2
- package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
- package/dist/memory/cloud/sync-screenshots.js +105 -0
- package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
- package/dist/memory/cloud/unsynced-roots.js +166 -0
- package/dist/memory/impact/account-watch.d.ts +16 -1
- package/dist/memory/impact/account-watch.js +26 -1
- package/dist/memory/impact/impact-store.d.ts +1 -4
- package/dist/memory/impact/impact-store.js +32 -42
- package/dist/memory/intent/inline-intent.d.ts +1 -0
- package/dist/memory/intent/intent-shard-store.js +16 -4
- package/dist/memory/intent/intent-shard.d.ts +12 -0
- package/dist/memory/intent/intent-store.d.ts +1 -0
- package/dist/memory/intent/intent-tools.js +42 -2
- package/dist/memory/intent/open-intents.d.ts +6 -0
- package/dist/memory/intent/open-intents.js +10 -1
- package/dist/memory/intent/settled-words.d.ts +24 -0
- package/dist/memory/intent/settled-words.js +130 -0
- package/dist/memory/journal/drive-flow.d.ts +16 -0
- package/dist/memory/journal/drive-flow.js +34 -2
- package/dist/memory/journal/drive-run-flush.d.ts +2 -0
- package/dist/memory/journal/drive-run-flush.js +20 -5
- package/dist/memory/journal/journal-recorder.js +46 -3
- package/dist/memory/journal/on-disk/retention.d.ts +5 -0
- package/dist/memory/journal/on-disk/retention.js +27 -2
- package/dist/memory/journal/on-disk/workspace-tiers.js +2 -0
- package/dist/memory/journal/session-end.d.ts +15 -1
- package/dist/memory/journal/session-end.js +38 -7
- package/dist/memory/project/artifact-root-resolver.js +33 -5
- package/dist/memory/project/artifact-root.d.ts +4 -3
- package/dist/memory/project/artifact-root.js +2 -2
- package/dist/memory/project/dir/reticle-dir.d.ts +14 -0
- package/dist/memory/project/dir/reticle-dir.js +23 -2
- package/dist/memory/project/link-directory.d.ts +15 -0
- package/dist/memory/project/link-directory.js +44 -0
- package/dist/memory/project/root-claims.d.ts +6 -0
- package/dist/memory/project/root-claims.js +39 -0
- package/dist/memory/project/session-root.d.ts +2 -0
- package/dist/memory/project/session-root.js +9 -1
- package/dist/memory/project/sync-status.d.ts +46 -0
- package/dist/memory/project/sync-status.js +135 -1
- package/dist/memory/recall/memory-tools.js +46 -3
- package/dist/memory/recall/platform-memory.d.ts +34 -0
- package/dist/memory/recall/platform-memory.js +139 -0
- package/dist/memory/recall/project-memory.js +36 -8
- package/dist/portal/bridge/bridge.d.ts +9 -5
- package/dist/portal/bridge/bridge.js +66 -23
- package/dist/portal/bridge/harness-request.d.ts +23 -0
- package/dist/portal/bridge/harness-request.js +27 -0
- package/dist/portal/bridge/wrong-path.d.ts +17 -0
- package/dist/portal/bridge/wrong-path.js +35 -0
- package/dist/portal/input/network-mock-tools.js +11 -2
- package/dist/portal/input/real-input.d.ts +2 -0
- package/dist/portal/input/real-input.js +13 -10
- package/dist/portal/pool/browser-pool.d.ts +48 -0
- package/dist/portal/pool/browser-pool.js +120 -2
- package/dist/portal/pool/context-permissions.d.ts +33 -0
- package/dist/portal/pool/context-permissions.js +33 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
- package/dist/portal/pool/lease-marker-stamp.js +49 -0
- package/dist/portal/pool/playwright-launcher.d.ts +27 -5
- package/dist/portal/pool/playwright-launcher.js +59 -14
- package/dist/portal/pool/pool-contract.d.ts +21 -1
- package/dist/portal/session/agent-link.d.ts +8 -0
- package/dist/portal/session/agent-link.js +17 -0
- package/dist/portal/session/command-payload.js +6 -1
- package/dist/portal/session/daemon-answers.d.ts +3 -3
- package/dist/portal/session/daemon-answers.js +4 -2
- package/dist/portal/session/dev-server/dev-command.d.ts +9 -0
- package/dist/portal/session/dev-server/dev-command.js +27 -1
- package/dist/portal/session/facts/observed-state.d.ts +16 -18
- package/dist/portal/session/facts/observed-state.js +46 -3
- package/dist/portal/session/human/live-control.d.ts +9 -2
- package/dist/portal/session/human/live-control.js +12 -3
- package/dist/portal/session/live-control-tools.js +82 -13
- package/dist/portal/session/narration-args.d.ts +5 -0
- package/dist/portal/session/narration-args.js +17 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +1 -1
- package/dist/portal/session/no-session-diagnosis.js +31 -9
- package/dist/portal/session/no-session-next-action.d.ts +20 -0
- package/dist/portal/session/no-session-next-action.js +134 -61
- package/dist/portal/session/no-session-watch.js +179 -22
- package/dist/portal/session/presence/session-lease.js +1 -1
- package/dist/portal/session/recorded-gaps.d.ts +97 -0
- package/dist/portal/session/recorded-gaps.js +251 -0
- package/dist/portal/session/session-health.d.ts +11 -0
- package/dist/portal/session/session-health.js +3 -1
- package/dist/portal/session/session-info.js +2 -1
- package/dist/portal/session/session-manager.d.ts +18 -0
- package/dist/portal/session/session-manager.js +54 -3
- package/dist/portal/session/session-successor.d.ts +8 -0
- package/dist/portal/session/session-successor.js +1 -1
- package/dist/portal/session/session.d.ts +15 -28
- package/dist/portal/session/session.js +60 -61
- package/dist/portal/session/timing/command-timeout.js +25 -1
- package/dist/portal/session/timing/wall-clock.d.ts +1 -1
- package/dist/portal/session/timing/wall-clock.js +1 -1
- package/dist/portal/session/zero-install-first-call.d.ts +31 -0
- package/dist/portal/session/zero-install-first-call.js +88 -0
- package/dist/start-options.d.ts +7 -1
- package/dist/start-wiring.d.ts +63 -0
- package/dist/start-wiring.js +169 -0
- package/dist/status-payload.d.ts +13 -1
- package/dist/status-payload.js +13 -1
- package/dist/surface/http-server.js +7 -1
- package/dist/surface/mcp/attach-memory.d.ts +1 -0
- package/dist/surface/mcp/attach-memory.js +12 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +4 -0
- package/dist/surface/mcp/mcp-proxy.js +29 -8
- package/dist/surface/mcp/mcp.d.ts +23 -0
- package/dist/surface/mcp/mcp.js +34 -4
- package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
- package/dist/surface/mcp/proxy/drive-calls.js +27 -0
- package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
- package/dist/surface/mcp/server-instructions.js +22 -14
- package/dist/surface/mcp/shared-params.js +1 -1
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +1 -0
- package/dist/surface/tools/account-tool.d.ts +22 -0
- package/dist/surface/tools/account-tool.js +157 -0
- package/dist/surface/tools/act/act-danger.d.ts +11 -0
- package/dist/surface/tools/act/act-danger.js +38 -1
- package/dist/surface/tools/act/act-observation.d.ts +33 -0
- package/dist/surface/tools/act/act-observation.js +57 -0
- package/dist/surface/tools/act/act-preflight.js +25 -2
- package/dist/surface/tools/act/act-target.js +8 -3
- package/dist/surface/tools/act/resolve-target.d.ts +1 -1
- package/dist/surface/tools/act/resolve-target.js +18 -3
- package/dist/surface/tools/act/screen-request.d.ts +34 -0
- package/dist/surface/tools/act/screen-request.js +113 -0
- package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
- package/dist/surface/tools/act/sequence-grade.js +13 -2
- package/dist/surface/tools/act-sequence-tool.js +136 -27
- package/dist/surface/tools/act-tools.d.ts +0 -9
- package/dist/surface/tools/act-tools.js +48 -34
- package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
- package/dist/surface/tools/agent/app-notes-learning.js +80 -0
- package/dist/surface/tools/agent/app-notes.d.ts +4 -0
- package/dist/surface/tools/agent/app-notes.js +48 -0
- package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
- package/dist/surface/tools/agent/build-staleness.js +62 -0
- package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
- package/dist/surface/tools/agent/compact-envelope.js +374 -0
- package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
- package/dist/surface/tools/agent/for-the-agent.js +44 -0
- package/dist/surface/tools/agent/notices.d.ts +50 -0
- package/dist/surface/tools/agent/notices.js +152 -0
- package/dist/surface/tools/agent/reteach.d.ts +11 -0
- package/dist/surface/tools/agent/reteach.js +50 -0
- package/dist/surface/tools/args/alias-args.d.ts +5 -0
- package/dist/surface/tools/args/alias-args.js +10 -0
- package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
- package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
- package/dist/surface/tools/assert/assert-source.d.ts +15 -0
- package/dist/surface/tools/assert/assert-source.js +40 -0
- package/dist/surface/tools/assert/assert-verdict.js +25 -15
- package/dist/surface/tools/browser-tools.js +43 -1
- package/dist/surface/tools/chat-drives.d.ts +75 -0
- package/dist/surface/tools/chat-drives.js +265 -21
- package/dist/surface/tools/coverage-tools.d.ts +2 -10
- package/dist/surface/tools/coverage-tools.js +2 -53
- package/dist/surface/tools/dynamic-tools.js +29 -1
- package/dist/surface/tools/empty-session-list.d.ts +10 -0
- package/dist/surface/tools/empty-session-list.js +45 -5
- package/dist/surface/tools/error-recovery.d.ts +8 -0
- package/dist/surface/tools/error-recovery.js +69 -5
- package/dist/surface/tools/explore-tools.d.ts +23 -2
- package/dist/surface/tools/explore-tools.js +377 -74
- package/dist/surface/tools/feedback-tools.d.ts +2 -3
- package/dist/surface/tools/feedback-tools.js +4 -3
- package/dist/surface/tools/gap-novelty.d.ts +3 -1
- package/dist/surface/tools/gap-novelty.js +8 -1
- package/dist/surface/tools/harness-explore.d.ts +52 -73
- package/dist/surface/tools/harness-explore.js +177 -146
- package/dist/surface/tools/harness-gate.d.ts +88 -0
- package/dist/surface/tools/harness-gate.js +235 -0
- package/dist/surface/tools/harness-hunt.d.ts +43 -0
- package/dist/surface/tools/harness-hunt.js +215 -0
- package/dist/surface/tools/harness-plan.d.ts +5 -0
- package/dist/surface/tools/harness-plan.js +7 -0
- package/dist/surface/tools/harness-script.d.ts +22 -0
- package/dist/surface/tools/harness-script.js +256 -38
- package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
- package/dist/surface/tools/harness-tab-guard.js +27 -0
- package/dist/surface/tools/harness-toolset.d.ts +8 -0
- package/dist/surface/tools/harness-toolset.js +27 -4
- package/dist/surface/tools/human-notes.d.ts +16 -0
- package/dist/surface/tools/human-notes.js +27 -0
- package/dist/surface/tools/invoke-tool.d.ts +5 -2
- package/dist/surface/tools/invoke-tool.js +220 -93
- package/dist/surface/tools/lease-hint.js +26 -5
- package/dist/surface/tools/lease-permissions.d.ts +33 -0
- package/dist/surface/tools/lease-permissions.js +73 -0
- package/dist/surface/tools/lease-readiness.d.ts +38 -0
- package/dist/surface/tools/lease-readiness.js +57 -0
- package/dist/surface/tools/lease-seed.d.ts +20 -0
- package/dist/surface/tools/lease-seed.js +45 -1
- package/dist/surface/tools/lease-tools.d.ts +10 -1
- package/dist/surface/tools/lease-tools.js +119 -69
- package/dist/surface/tools/live-call-text.js +2 -2
- package/dist/surface/tools/merge-tools.js +42 -2
- package/dist/surface/tools/merged-name-redirect.js +4 -0
- package/dist/surface/tools/next-step.d.ts +11 -1
- package/dist/surface/tools/next-step.js +73 -18
- package/dist/surface/tools/observe-tools.js +43 -5
- package/dist/surface/tools/platform-moment.d.ts +60 -0
- package/dist/surface/tools/platform-moment.js +132 -4
- package/dist/surface/tools/read-tools.js +65 -14
- package/dist/surface/tools/reticle-result.d.ts +120 -0
- package/dist/surface/tools/reticle-result.js +364 -0
- package/dist/surface/tools/tool-kit.d.ts +68 -2
- package/dist/surface/tools/tool-kit.js +73 -1
- package/dist/surface/tools/tools.js +25 -13
- package/dist/telemetry/account-envelope.d.ts +7 -0
- package/dist/telemetry/account-envelope.js +61 -0
- package/dist/telemetry/agent-client.d.ts +15 -0
- package/dist/telemetry/agent-client.js +57 -0
- package/dist/telemetry/app-instrumented.js +9 -2
- package/dist/telemetry/argument-shape.d.ts +7 -0
- package/dist/telemetry/argument-shape.js +86 -1
- package/dist/telemetry/automation-hint.d.ts +2 -3
- package/dist/telemetry/automation-hint.js +33 -8
- package/dist/telemetry/cli-telemetry.js +7 -2
- package/dist/telemetry/daemon-telemetry.js +3 -0
- package/dist/telemetry/error-fingerprint.d.ts +10 -1
- package/dist/telemetry/error-fingerprint.js +61 -5
- package/dist/telemetry/feedback-cli.d.ts +0 -13
- package/dist/telemetry/feedback-cli.js +0 -77
- package/dist/telemetry/feedback.d.ts +13 -0
- package/dist/telemetry/feedback.js +183 -17
- package/dist/telemetry/harness-run.d.ts +18 -0
- package/dist/telemetry/harness-run.js +80 -0
- package/dist/telemetry/hud-events.d.ts +16 -0
- package/dist/telemetry/hud-events.js +27 -0
- package/dist/telemetry/hud-metrics.d.ts +27 -6
- package/dist/telemetry/hud-metrics.js +99 -25
- package/dist/telemetry/init-telemetry.js +2 -2
- package/dist/telemetry/install-source.d.ts +13 -25
- package/dist/telemetry/install-source.js +44 -3
- package/dist/telemetry/mcp-connection.d.ts +0 -14
- package/dist/telemetry/mcp-connection.js +5 -1
- package/dist/telemetry/onboarding-firsts.d.ts +32 -0
- package/dist/telemetry/onboarding-firsts.js +81 -6
- package/dist/telemetry/platform-linked.d.ts +5 -0
- package/dist/telemetry/platform-linked.js +32 -0
- package/dist/telemetry/project-profile.js +5 -3
- package/dist/telemetry/proxy-telemetry.js +4 -1
- package/dist/telemetry/session-metrics.d.ts +15 -4
- package/dist/telemetry/session-metrics.js +88 -52
- package/dist/telemetry/telemetry.d.ts +26 -2
- package/dist/telemetry/telemetry.js +102 -21
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +12 -4
- package/dist/wire-journal.d.ts +2 -2
- package/dist/wire-journal.js +16 -5
- package/docs/README.md +2 -2
- package/docs/actions.mdx +6 -3
- package/docs/adapters.md +1 -1
- package/docs/agent-cheatsheet.md +24 -27
- package/docs/architecture.md +5 -5
- package/docs/autodrive.md +13 -12
- package/docs/benchmarks.md +5 -5
- package/docs/best-practices.mdx +27 -9
- package/docs/capabilities.mdx +14 -16
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +54 -75
- package/docs/cli/doctor.mdx +8 -3
- package/docs/cli/drive.mdx +12 -12
- package/docs/cli/feedback.mdx +3 -3
- package/docs/cli/gate.mdx +7 -2
- package/docs/cli/help.mdx +50 -55
- package/docs/cli/init.mdx +32 -15
- package/docs/cli/license.mdx +12 -8
- package/docs/cli/mcp.mdx +4 -4
- package/docs/cli/open.mdx +3 -3
- package/docs/cli/report.mdx +4 -2
- package/docs/cli/restart.mdx +2 -2
- package/docs/cli/rollback.mdx +14 -8
- package/docs/cli/serve.mdx +4 -4
- package/docs/cli/setup.mdx +23 -0
- package/docs/cli/status.mdx +13 -4
- package/docs/cli/stop.mdx +67 -8
- package/docs/cli/try.mdx +62 -0
- package/docs/cli/update.mdx +4 -3
- package/docs/cli/verify.mdx +17 -6
- package/docs/cli/version.mdx +3 -2
- package/docs/cli.mdx +110 -41
- package/docs/debugging.md +3 -3
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +5 -3
- package/docs/enterprise.md +11 -10
- package/docs/environment.mdx +5 -2
- package/docs/faq.mdx +3 -3
- package/docs/first-drive.md +5 -4
- package/docs/flows.md +35 -27
- package/docs/for-agents.md +4 -5
- package/docs/frameworks.mdx +32 -21
- package/docs/getting-started.md +66 -64
- package/docs/human-control.md +15 -14
- package/docs/index.mdx +15 -43
- package/docs/install-agentic.mdx +22 -37
- package/docs/install-manual.mdx +22 -12
- package/docs/instrumentation.mdx +5 -3
- package/docs/integration-patterns.md +7 -7
- package/docs/license-activation.mdx +1 -1
- package/docs/multi-agent-testing.md +24 -6
- package/docs/packages/babel-plugin.mdx +4 -2
- package/docs/packages/browser.mdx +16 -10
- package/docs/packages/core.mdx +12 -5
- package/docs/packages/electron.mdx +3 -2
- package/docs/packages/engine.mdx +1 -1
- package/docs/packages/eslint-plugin.mdx +18 -12
- package/docs/packages/next.mdx +8 -7
- package/docs/packages/open-verification.mdx +1 -1
- package/docs/packages/server.mdx +5 -5
- package/docs/packages/tauri.mdx +8 -8
- package/docs/packages/test.mdx +4 -10
- package/docs/packages/vite-plugin.mdx +11 -4
- package/docs/packages.mdx +11 -15
- package/docs/platform-integration.md +6 -5
- package/docs/predicates.mdx +40 -24
- package/docs/quickstart.mdx +58 -29
- package/docs/required-checks.md +8 -7
- package/docs/reticle-manual.md +15 -5
- package/docs/skill-file.mdx +17 -79
- package/docs/skill-setup.md +9 -9
- package/docs/skill.md +200 -0
- package/docs/system-map.md +7 -7
- package/docs/telemetry.md +22 -24
- package/docs/testing.md +4 -4
- package/docs/token-efficiency.md +12 -12
- package/docs/tools/act-and-wait.mdx +9 -2
- package/docs/tools/act-sequence.mdx +6 -7
- package/docs/tools/act.mdx +2 -2
- package/docs/tools/assert.mdx +18 -17
- package/docs/tools/console.mdx +9 -9
- package/docs/tools/inspect.mdx +16 -7
- package/docs/tools/look.mdx +24 -0
- package/docs/tools/navigate.mdx +5 -3
- package/docs/tools/network.mdx +2 -2
- package/docs/tools/observe.mdx +6 -6
- package/docs/tools/overview.mdx +34 -33
- package/docs/tools/query.mdx +5 -5
- package/docs/tools/session-and-feedback.mdx +13 -4
- package/docs/tools/sessions.mdx +8 -8
- package/docs/tools/snapshot.mdx +6 -5
- package/docs/tools/state.mdx +9 -9
- package/docs/tools/tools-and-run.mdx +26 -24
- package/docs/tools/verify.mdx +28 -0
- package/docs/tools/wait-for.mdx +8 -4
- package/docs/troubleshooting.mdx +21 -6
- package/docs/usage.md +51 -45
- package/docs/use-cases.mdx +3 -3
- package/docs/vs-chrome-devtools-mcp.mdx +9 -6
- package/docs/vs-playwright-mcp.mdx +3 -1
- package/docs/what-is-recorded.md +7 -5
- package/docs/what-is-reticle.mdx +2 -2
- package/docs/why-reticle.mdx +1 -1
- package/package.json +6 -5
- package/dist/command/cli/demo/demo-page.d.ts +0 -78
- package/dist/command/cli/demo/demo-page.js +0 -249
- package/dist/command/cli/demo/demo-run.d.ts +0 -38
- package/dist/command/cli/demo/demo-run.js +0 -138
- package/dist/judgement/hunt/hunt-report.d.ts +0 -49
- package/dist/judgement/hunt/hunt-report.js +0 -84
- package/dist/language/flows/buddy-status.d.ts +0 -25
- package/dist/language/flows/buddy-status.js +0 -32
- package/dist/language/flows/change/watch-batcher.d.ts +0 -18
- package/dist/language/flows/change/watch-batcher.js +0 -19
- package/dist/memory/cloud/harness-offer.d.ts +0 -44
- package/dist/memory/cloud/harness-offer.js +0 -145
- package/dist/surface/tools/feature-capture.d.ts +0 -151
- package/dist/surface/tools/feature-capture.js +0 -235
- package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
- package/dist/surface/tools/tool-hit-rate.js +0 -90
- package/dist/telemetry/harness-drive.d.ts +0 -4
- package/dist/telemetry/harness-drive.js +0 -35
- package/dist/telemetry/identify.d.ts +0 -22
- package/dist/telemetry/identify.js +0 -73
- package/docs/cli/capsules.mdx +0 -70
- package/docs/cli/hunt.mdx +0 -73
- package/docs/cli/identify.mdx +0 -76
- package/docs/cli/kill.mdx +0 -91
- package/docs/cli/watch.mdx +0 -62
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
* lighter per-flow RunRecord that feeds regression memory is synced separately in flow-replay-run.ts.
|
|
9
9
|
* Both are best-effort + opt-in: no creds → the artifact still lands on disk, nothing leaves the machine.
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { callerClientName } from '../../hooks/coding-agents.js';
|
|
12
|
+
import { currentDrivenBy } from '../../hooks/driven-by.js';
|
|
13
|
+
import { RunAgentKind, RunFramework, RunProfile, RunTrigger, asRunId, } from '@reticlehq/core';
|
|
13
14
|
import { homedir } from 'node:os';
|
|
14
15
|
import { buildVerificationRun, } from './artifact/build-verification-run.js';
|
|
15
16
|
import { mapReplayToFlowResult } from './artifact/replay-mapping.js';
|
|
16
17
|
import { defaultRunId } from './default-run-id.js';
|
|
18
|
+
import { currentShotRun } from './default-run-id.js';
|
|
17
19
|
import { RunStore } from './artifact/run-store.js';
|
|
18
20
|
import { cloudFetch, syncRunToCloud, SyncOutcome } from '../../memory/cloud/cloud-sync.js';
|
|
19
21
|
import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
|
|
@@ -21,29 +23,43 @@ import { log } from '../../log.js';
|
|
|
21
23
|
import { rootForTarget } from '../../memory/project/session-root.js';
|
|
22
24
|
/** The author of record when no MCP peer introduced itself — a CLI run, or a client that skipped the handshake. */
|
|
23
25
|
const RETICLE_MCP_AGENT_ID = 'reticle-mcp';
|
|
26
|
+
/** The MCP client name `reticle verify` (the command line, CI's path) connects to a daemon as. */
|
|
27
|
+
export const CLI_CLIENT_NAME = 'reticle-cli';
|
|
28
|
+
/**
|
|
29
|
+
* Who ran a suite, and why. The command line is the pipeline, whichever daemon replays for it:
|
|
30
|
+
* through a running daemon its runs read as a coding agent, trigger manual, credited to whoever
|
|
31
|
+
* minted the key, while the path that boots its own daemon said pipeline.
|
|
32
|
+
*/
|
|
33
|
+
function agentAndTrigger(client) {
|
|
34
|
+
return CLI_CLIENT_NAME === client
|
|
35
|
+
? { agent: { id: client, kind: RunAgentKind.OEM_PIPELINE }, trigger: { kind: RunTrigger.OEM } }
|
|
36
|
+
: {
|
|
37
|
+
agent: { id: client ?? RETICLE_MCP_AGENT_ID, kind: RunAgentKind.CODING_AGENT },
|
|
38
|
+
trigger: { kind: RunTrigger.MANUAL },
|
|
39
|
+
};
|
|
40
|
+
}
|
|
24
41
|
/** Assemble the ReticleVerificationRun artifact for a verify suite (pure — no IO). */
|
|
25
|
-
function assembleRun(deps, timed,
|
|
42
|
+
function assembleRun(deps, timed,
|
|
43
|
+
/** The dashboard project this checkout is linked to, else the session's own id. */
|
|
44
|
+
projectName) {
|
|
26
45
|
const flows = timed.map((t) => mapReplayToFlowResult(t.replay, t.durationMs, t.flow));
|
|
27
46
|
const input = {
|
|
28
|
-
|
|
47
|
+
// The run its replays' screenshots were filed under, when the verify minted one first.
|
|
48
|
+
runId: asRunId(currentShotRun() ?? defaultRunId()),
|
|
29
49
|
durationMs: flows.reduce((sum, f) => sum + f.durationMs, 0),
|
|
30
50
|
profile: RunProfile.DEV,
|
|
31
|
-
project: { name:
|
|
51
|
+
project: { name: projectName ?? 'reticle', framework: RunFramework.OTHER },
|
|
32
52
|
/*
|
|
33
53
|
* WHICH agent drove this, not merely THAT one did.
|
|
34
54
|
*
|
|
35
55
|
* This was hardcoded to 'reticle-mcp', so every run in every workspace claimed the same author.
|
|
36
56
|
* A dashboard built on it could say "an agent verified this" and never "Claude Code verified
|
|
37
57
|
* this, Cursor broke it" — which is the question a team actually has once more than one agent
|
|
38
|
-
* touches the repo. The name is the client's own claim from the MCP handshake
|
|
39
|
-
*
|
|
40
|
-
* admitting we do not know.
|
|
58
|
+
* touches the repo. The name is the client's own claim from the MCP handshake, for the call that
|
|
59
|
+
* ran this suite only; a plain CLI run, or a dashboard Re-verify no agent made, keeps the old id,
|
|
60
|
+
* because inventing a vendor there would be worse than admitting we do not know.
|
|
41
61
|
*/
|
|
42
|
-
|
|
43
|
-
id: mcpClientIdentity().name ?? RETICLE_MCP_AGENT_ID,
|
|
44
|
-
kind: RunAgentKind.CODING_AGENT,
|
|
45
|
-
},
|
|
46
|
-
trigger: { kind: RunTrigger.MANUAL },
|
|
62
|
+
...agentAndTrigger(callerClientName()),
|
|
47
63
|
changedFiles: [],
|
|
48
64
|
flows,
|
|
49
65
|
checks: [],
|
|
@@ -61,6 +77,10 @@ export async function persistAndSyncVerificationRun(deps, timed, target) {
|
|
|
61
77
|
const { projectId } = target;
|
|
62
78
|
if (0 === timed.length)
|
|
63
79
|
return undefined;
|
|
80
|
+
// A replay the Harness made inside its own drive is part of that drive's run: written on its own
|
|
81
|
+
// it was a second row ("Passed · Flow replay · Your agent") beside the plan run it belonged to.
|
|
82
|
+
if (currentDrivenBy() !== undefined)
|
|
83
|
+
return undefined;
|
|
64
84
|
let run;
|
|
65
85
|
// The project the suite ran for, not the directory the daemon was started in. Both halves below
|
|
66
86
|
// take it: the artifact `reticle_run` reads back through `sessionRoot`, and the cloud link that
|
|
@@ -68,8 +88,10 @@ export async function persistAndSyncVerificationRun(deps, timed, target) {
|
|
|
68
88
|
// a misrouted read silently meant "not attached" — and where it DID have one, the run was pushed
|
|
69
89
|
// to a dashboard belonging to whoever that checkout was linked to.
|
|
70
90
|
const root = rootForTarget(deps, target);
|
|
91
|
+
const cloud = await resolveProjectCloud(deps.fs, root, homedir(), process.env);
|
|
71
92
|
try {
|
|
72
|
-
|
|
93
|
+
// Named after the dashboard project the checkout is linked to: a Re-verify run read "reticle".
|
|
94
|
+
run = assembleRun(deps, timed, cloud.projectId ?? projectId);
|
|
73
95
|
await new RunStore(deps.fs, root).write(run);
|
|
74
96
|
}
|
|
75
97
|
catch (error) {
|
|
@@ -79,7 +101,6 @@ export async function persistAndSyncVerificationRun(deps, timed, target) {
|
|
|
79
101
|
return undefined;
|
|
80
102
|
}
|
|
81
103
|
// Per-project cloud: only push when THIS project has cloud attached AND its policy allows runs.
|
|
82
|
-
const cloud = await resolveProjectCloud(deps.fs, root, homedir(), process.env);
|
|
83
104
|
if (null === cloud.config || !cloud.policy.runs)
|
|
84
105
|
return run.runId; // not attached / runs disabled → local only
|
|
85
106
|
const result = await syncRunToCloud(run, cloud.config, cloudFetch);
|
|
@@ -165,7 +165,8 @@ invoked = new Map()) {
|
|
|
165
165
|
...(fix !== undefined ? { suggestedFix: fix } : {}),
|
|
166
166
|
nextAction: fix !== undefined
|
|
167
167
|
? `${fix}, or update the flow if the change was intended.`
|
|
168
|
-
: `inspect ${where ?? 'the step'} — the anchored element is
|
|
168
|
+
: `inspect ${where ?? 'the step'} — the anchored element is not on the page and nothing there looks like a rename. ` +
|
|
169
|
+
'If the replay began somewhere the recording did not (signed out, another route), record the steps that reach this one; otherwise rebind or update the flow.',
|
|
169
170
|
};
|
|
170
171
|
}
|
|
171
172
|
// status error: an action failed, or the success oracle was not satisfied (green-but-wrong).
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { type FlowAnchor, type FlowFile } from '@reticlehq/core';
|
|
3
|
+
import { CALL_SECRETS_ARG } from '../../../surface/tools/tool-kit.js';
|
|
2
4
|
/**
|
|
3
5
|
* What the anchor CALLS the field it points at.
|
|
4
6
|
*
|
|
@@ -20,6 +22,8 @@ export declare function anchorFieldName(anchor: FlowAnchor): string | undefined;
|
|
|
20
22
|
* reader what to do: the value belongs in the environment, not in a file they are about to commit.
|
|
21
23
|
*/
|
|
22
24
|
export declare const REDACTED_FILL = "<redacted: supply at replay>";
|
|
25
|
+
/** The arg a saved redacted fill names its variable in. Dropped before the step reaches the page. */
|
|
26
|
+
export declare const SECRET_NAME_ARG = "secret";
|
|
23
27
|
/**
|
|
24
28
|
* The environment variable that supplies one redacted field.
|
|
25
29
|
*
|
|
@@ -33,6 +37,14 @@ export declare const REDACTED_FILL = "<redacted: supply at replay>";
|
|
|
33
37
|
* saying it had to stay together.
|
|
34
38
|
*/
|
|
35
39
|
export declare const secretEnvKey: (field: string) => string;
|
|
40
|
+
/** The schema of that argument, shared by every tool that replays a flow. */
|
|
41
|
+
export { CALL_SECRETS_ARG };
|
|
42
|
+
export declare const callSecretsArg: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
43
|
+
/**
|
|
44
|
+
* One secret's value: supplied with this call (by field or by variable name), else from the
|
|
45
|
+
* daemon's environment.
|
|
46
|
+
*/
|
|
47
|
+
export declare function secretValue(envKey: string, env: Record<string, string | undefined>): string | undefined;
|
|
36
48
|
/** One field a flow needs supplied, and the variable that supplies it. */
|
|
37
49
|
export interface UnsuppliedSecret {
|
|
38
50
|
field: string;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
1
2
|
import { AnchorKind } from '@reticlehq/core';
|
|
3
|
+
import { CALL_SECRETS_ARG, callSecrets } from '../../../surface/tools/tool-kit.js';
|
|
2
4
|
/**
|
|
3
5
|
* What the anchor CALLS the field it points at.
|
|
4
6
|
*
|
|
@@ -28,6 +30,10 @@ export function anchorFieldName(anchor) {
|
|
|
28
30
|
* reader what to do: the value belongs in the environment, not in a file they are about to commit.
|
|
29
31
|
*/
|
|
30
32
|
export const REDACTED_FILL = '<redacted: supply at replay>';
|
|
33
|
+
/** The arg a saved redacted fill names its variable in. Dropped before the step reaches the page. */
|
|
34
|
+
export const SECRET_NAME_ARG = 'secret';
|
|
35
|
+
/** The prefix every secret's variable carries. */
|
|
36
|
+
const SECRET_ENV_PREFIX = 'RETICLE_SECRET_';
|
|
31
37
|
/**
|
|
32
38
|
* The environment variable that supplies one redacted field.
|
|
33
39
|
*
|
|
@@ -40,7 +46,24 @@ export const REDACTED_FILL = '<redacted: supply at replay>';
|
|
|
40
46
|
* rules must not be able to drift. It used to sit in `replay.ts`, one import away from the sentence
|
|
41
47
|
* saying it had to stay together.
|
|
42
48
|
*/
|
|
43
|
-
export const secretEnvKey = (field) =>
|
|
49
|
+
export const secretEnvKey = (field) => `${SECRET_ENV_PREFIX}${field.replace(/[^a-zA-Z0-9]+/g, '_').toUpperCase()}`;
|
|
50
|
+
/** The schema of that argument, shared by every tool that replays a flow. */
|
|
51
|
+
export { CALL_SECRETS_ARG };
|
|
52
|
+
export const callSecretsArg = z
|
|
53
|
+
.record(z.string())
|
|
54
|
+
.optional()
|
|
55
|
+
.describe('Redacted fields\' values, this call only, never kept: { "auth-password": "…" }');
|
|
56
|
+
/**
|
|
57
|
+
* One secret's value: supplied with this call (by field or by variable name), else from the
|
|
58
|
+
* daemon's environment.
|
|
59
|
+
*/
|
|
60
|
+
export function secretValue(envKey, env) {
|
|
61
|
+
for (const [key, value] of Object.entries(callSecrets() ?? {})) {
|
|
62
|
+
if (envKey === (key.startsWith(SECRET_ENV_PREFIX) ? key : secretEnvKey(key)))
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
return env[envKey];
|
|
66
|
+
}
|
|
44
67
|
/**
|
|
45
68
|
* Every credential this flow will replay as the literal placeholder.
|
|
46
69
|
*
|
|
@@ -63,7 +86,7 @@ export function unsuppliedSecrets(flow, env) {
|
|
|
63
86
|
if (field === undefined)
|
|
64
87
|
continue;
|
|
65
88
|
const envKey = secretEnvKey(field);
|
|
66
|
-
const supplied = env
|
|
89
|
+
const supplied = secretValue(envKey, env);
|
|
67
90
|
if (supplied !== undefined && supplied.length > 0)
|
|
68
91
|
continue;
|
|
69
92
|
if (seen.has(envKey))
|
|
@@ -16,8 +16,13 @@ import type { FlowReplaySession, Sleep } from './flow-replay-types.js';
|
|
|
16
16
|
export declare function editDistance(a: string, b: string): number;
|
|
17
17
|
/**
|
|
18
18
|
* The closest present testid to a missing one, by case-insensitive edit distance, ties broken
|
|
19
|
-
* by shortest length then lexically
|
|
20
|
-
*
|
|
19
|
+
* by shortest length then lexically — when it is close enough to be a rename. Null when nothing
|
|
20
|
+
* present is, so a drift record names a fix only when one plausibly exists.
|
|
21
|
+
*
|
|
22
|
+
* It used to name the closest survivor however far away it was. A replay that started signed out
|
|
23
|
+
* missed `compose-prompt` on the login screen and advised rebinding it to `login-submit`: eleven
|
|
24
|
+
* edits away, a different control on a different page, offered as the fix. Half the longer name is
|
|
25
|
+
* the ceiling — `chat-send` → `chat-submit` and `checkout-btn` → `checkout-button` stay in.
|
|
21
26
|
*/
|
|
22
27
|
export declare function nearestTestid(missing: string, present: string[]): string | null;
|
|
23
28
|
/**
|
|
@@ -35,8 +35,13 @@ export function editDistance(a, b) {
|
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
37
|
* The closest present testid to a missing one, by case-insensitive edit distance, ties broken
|
|
38
|
-
* by shortest length then lexically
|
|
39
|
-
*
|
|
38
|
+
* by shortest length then lexically — when it is close enough to be a rename. Null when nothing
|
|
39
|
+
* present is, so a drift record names a fix only when one plausibly exists.
|
|
40
|
+
*
|
|
41
|
+
* It used to name the closest survivor however far away it was. A replay that started signed out
|
|
42
|
+
* missed `compose-prompt` on the login screen and advised rebinding it to `login-submit`: eleven
|
|
43
|
+
* edits away, a different control on a different page, offered as the fix. Half the longer name is
|
|
44
|
+
* the ceiling — `chat-send` → `chat-submit` and `checkout-btn` → `checkout-button` stay in.
|
|
40
45
|
*/
|
|
41
46
|
export function nearestTestid(missing, present) {
|
|
42
47
|
let best = null;
|
|
@@ -53,7 +58,9 @@ export function nearestTestid(missing, present) {
|
|
|
53
58
|
bestDistance = distance;
|
|
54
59
|
}
|
|
55
60
|
}
|
|
56
|
-
|
|
61
|
+
if (null === best)
|
|
62
|
+
return null;
|
|
63
|
+
return bestDistance <= Math.max(missing.length, best.length) / 2 ? best : null;
|
|
57
64
|
}
|
|
58
65
|
/**
|
|
59
66
|
* Bounded settle for anchor re-resolution. A testid step queries the live DOM for the anchor; if a
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { type FlowFile, type FlowStep, type Predicate } from '@reticlehq/core';
|
|
2
2
|
/** A short, stable identity for a journey's shape: its start page and its steps. */
|
|
3
3
|
export declare function journeyFingerprint(flow: Pick<FlowFile, 'startPath' | 'steps'>): string;
|
|
4
|
+
/**
|
|
5
|
+
* Whether `shorter` is `longer` driven with steps left out: same start, and its steps appear in
|
|
6
|
+
* `longer` in the same order. A re-drive that retried a step, or stopped one short, is the same
|
|
7
|
+
* journey; two flows that share only a name and a page are not.
|
|
8
|
+
*/
|
|
9
|
+
export declare function withinJourney(longer: Pick<FlowFile, 'startPath' | 'steps'>, shorter: Pick<FlowFile, 'startPath' | 'steps'>): boolean;
|
|
4
10
|
/**
|
|
5
11
|
* Fold two copies of one journey into one file.
|
|
6
12
|
*
|
|
@@ -31,6 +31,26 @@ export function journeyFingerprint(flow) {
|
|
|
31
31
|
.digest('hex')
|
|
32
32
|
.slice(0, FINGERPRINT_LENGTH);
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Whether `shorter` is `longer` driven with steps left out: same start, and its steps appear in
|
|
36
|
+
* `longer` in the same order. A re-drive that retried a step, or stopped one short, is the same
|
|
37
|
+
* journey; two flows that share only a name and a page are not.
|
|
38
|
+
*/
|
|
39
|
+
export function withinJourney(longer, shorter) {
|
|
40
|
+
if ((longer.startPath ?? null) !== (shorter.startPath ?? null))
|
|
41
|
+
return false;
|
|
42
|
+
const shapes = longer.steps.map((step) => JSON.stringify(stepShape(step)));
|
|
43
|
+
let at = 0;
|
|
44
|
+
for (const step of shorter.steps) {
|
|
45
|
+
const wanted = JSON.stringify(stepShape(step));
|
|
46
|
+
while (at < shapes.length && shapes[at] !== wanted)
|
|
47
|
+
at += 1;
|
|
48
|
+
if (at === shapes.length)
|
|
49
|
+
return false;
|
|
50
|
+
at += 1;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
34
54
|
/** `kept` wins wherever it says something; `other` fills only what `kept` left unsaid. */
|
|
35
55
|
function fillStep(kept, other) {
|
|
36
56
|
if (other === undefined)
|
|
@@ -53,3 +53,7 @@ export declare function replayAndLearn(deps: ToolDeps,
|
|
|
53
53
|
args: Record<string, unknown>): Promise<FlowReplayResult>;
|
|
54
54
|
/** Write back the files a clean replay's anchors resolved to. Best-effort, as `persistLearning` is. */
|
|
55
55
|
export declare function persistSources(deps: ToolDeps, args: Record<string, unknown>, sources: Parameters<typeof withLearnedSources>[1]): Promise<void>;
|
|
56
|
+
/** A replay, under seeded perturbation when `seed` asks for one; the page is always put back. */
|
|
57
|
+
export declare function replaySeededOrNot(deps: ToolDeps, args: Record<string, unknown>,
|
|
58
|
+
/** Where the perturbation port finds the page: the app's origin. */
|
|
59
|
+
appUrl: string | undefined): Promise<FlowReplayResult>;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runSavedFlow } from '../../hooks/driven-by.js';
|
|
2
|
+
import { asNumber, asString, mutationTargetsFor, perturbationFor } from '@reticlehq/core';
|
|
3
|
+
import { sessionPerturbationPort } from '../../surface/tools/lease-tools.js';
|
|
2
4
|
import { flowsForSession } from './flow-store-for-session.js';
|
|
3
5
|
import { safeSessionTarget } from '../../memory/project/session-root.js';
|
|
4
6
|
import { replayNamedFlow } from './flow-replay-run.js';
|
|
@@ -73,10 +75,11 @@ export async function replayAndLearn(deps,
|
|
|
73
75
|
*/
|
|
74
76
|
args) {
|
|
75
77
|
let recorded;
|
|
76
|
-
|
|
78
|
+
// A saved flow's steps were asked for by whoever recorded it: no outward gate on them.
|
|
79
|
+
const result = await runSavedFlow(() => replayNamedFlow(deps, args, (session) => {
|
|
77
80
|
recorded = recordingSources(session);
|
|
78
81
|
return recorded.session;
|
|
79
|
-
});
|
|
82
|
+
}));
|
|
80
83
|
// Only a clean run teaches a file: a drifted step may have resolved to the wrong element.
|
|
81
84
|
if (result.status === ReplayStatus.OK && recorded !== undefined && recorded.sources.size > 0) {
|
|
82
85
|
await persistSources(deps, args, recorded.sources);
|
|
@@ -102,3 +105,34 @@ export async function persistSources(deps, args, sources) {
|
|
|
102
105
|
// Bookkeeping only.
|
|
103
106
|
}
|
|
104
107
|
}
|
|
108
|
+
/** A replay, under seeded perturbation when `seed` asks for one; the page is always put back. */
|
|
109
|
+
export async function replaySeededOrNot(deps, args,
|
|
110
|
+
/** Where the perturbation port finds the page: the app's origin. */
|
|
111
|
+
appUrl) {
|
|
112
|
+
const seed = asNumber(args['seed']);
|
|
113
|
+
if (seed === undefined)
|
|
114
|
+
return await replayAndLearn(deps, args);
|
|
115
|
+
/*
|
|
116
|
+
* The targets are the endpoints the FLOW declared it depends on, so the perturbation lands on
|
|
117
|
+
* traffic the flow claims to care about. No declared endpoints means nothing to slow, and the
|
|
118
|
+
* replay runs clean rather than pretending a seed did something. `finally` is not tidiness: a
|
|
119
|
+
* page left slowed is damage the NEXT run inherits, as a mystery.
|
|
120
|
+
*/
|
|
121
|
+
const target = targetOf(deps, args);
|
|
122
|
+
const loaded = await flowsForSession(deps, target)
|
|
123
|
+
.flows.load(asString(args['flowName']) ?? asString(args['flow']) ?? '', target.projectId)
|
|
124
|
+
.catch(() => null);
|
|
125
|
+
const targets = loaded !== null && loaded.ok ? mutationTargetsFor(loaded.value) : [];
|
|
126
|
+
const rules = perturbationFor(seed, targets);
|
|
127
|
+
const port = 0 === rules.length ? undefined : await sessionPerturbationPort(deps.realInput, appUrl);
|
|
128
|
+
if (port === undefined)
|
|
129
|
+
return replayAndLearn(deps, args);
|
|
130
|
+
try {
|
|
131
|
+
await port.slow(rules);
|
|
132
|
+
const replay = await runSavedFlow(() => replayNamedFlow(deps, args));
|
|
133
|
+
return { ...replay, perturbed: rules };
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
await port.clear().catch(() => undefined);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -4,7 +4,7 @@ import { EventType, FLOW_SIGNAL_TIMEOUT_MS, FlowErrorCode, RecordedFlowSchema, R
|
|
|
4
4
|
import { haltedFrom } from './recording/replay-halt.js';
|
|
5
5
|
import { establishedState, samePath } from './flow-journey.js';
|
|
6
6
|
import { asRecord, asString } from '@reticlehq/core';
|
|
7
|
-
import { routeOfEvent, routeOfUrl } from '@reticlehq/engine/question/predicate/predicate-route.js';
|
|
7
|
+
import { navigablePath, routeOfEvent, routeOfUrl, } from '@reticlehq/engine/question/predicate/predicate-route.js';
|
|
8
8
|
import { carryReticleIdentity } from '../../surface/tools/lease-tools.js';
|
|
9
9
|
import { partialStatus, replayFlow, replayWindow } from './flow-replay.js';
|
|
10
10
|
import { anchorPrecondition, anchorQueryArgs, staleTargetResult } from './flow-step-runners.js';
|
|
@@ -28,9 +28,10 @@ import { EnvelopeStore } from '../../memory/journal/envelope-store.js';
|
|
|
28
28
|
import { homedir } from 'node:os';
|
|
29
29
|
import { cloudFetch, syncRunRecordToCloud, SyncOutcome } from '../../memory/cloud/cloud-sync.js';
|
|
30
30
|
import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
|
|
31
|
-
import { memoryReadUrl, scopedMemoryEntries } from '../../memory/cloud/memory-scope.js';
|
|
31
|
+
import { memoryReadHeaders, memoryReadUrl, scopedMemoryEntries, } from '../../memory/cloud/memory-scope.js';
|
|
32
32
|
import { consultSubjectFor, selectConsulted } from './flow-memory-consult.js';
|
|
33
33
|
import { log } from '../../log.js';
|
|
34
|
+
import { replayStepShooter } from '../../features/visual/step-shots.js';
|
|
34
35
|
import { flowsForSession } from './flow-store-for-session.js';
|
|
35
36
|
import { projectForRoot } from '../../memory/project/project-for-root.js';
|
|
36
37
|
import { CROSS_STEP_INDEX, crossStepOnly } from './flow-cross-step.js';
|
|
@@ -46,7 +47,7 @@ export function latestRecordedFlow(events) {
|
|
|
46
47
|
return undefined;
|
|
47
48
|
}
|
|
48
49
|
export { flowErrorMessage } from './flow-result.js';
|
|
49
|
-
import { flowErrorMessage } from './flow-result.js';
|
|
50
|
+
import { flowErrorMessage, noteReplayCheck } from './flow-result.js';
|
|
50
51
|
/** Map the wire ReplayStatus onto the persisted RunStatus (ok→pass). */
|
|
51
52
|
function replayToRunStatus(status) {
|
|
52
53
|
switch (status) {
|
|
@@ -107,13 +108,14 @@ function currentPathOf(session) {
|
|
|
107
108
|
// query usually decides what the page renders, so a tab on `?tab=summary` would read as "already
|
|
108
109
|
// at `?tab=wrap`" and the replay would start on the wrong page with nothing saying so. Both sides
|
|
109
110
|
// carry it, which keeps a real difference visible and stops the false one.
|
|
111
|
+
// Reticle's own params dropped, as the recording drops them from `startPath` (#1411).
|
|
110
112
|
const observed = last === undefined ? undefined : routeOfEvent(last);
|
|
111
113
|
if (observed !== undefined)
|
|
112
|
-
return
|
|
114
|
+
return navigablePath(observed);
|
|
113
115
|
if (session.url === undefined)
|
|
114
116
|
return undefined;
|
|
115
117
|
const fromUrl = routeOfUrl(session.url);
|
|
116
|
-
return fromUrl === undefined ? undefined :
|
|
118
|
+
return fromUrl === undefined ? undefined : navigablePath(fromUrl);
|
|
117
119
|
}
|
|
118
120
|
/**
|
|
119
121
|
* Ask the project what it already knows about this flow.
|
|
@@ -132,11 +134,7 @@ async function consultProjectMemory(deps, flow, root) {
|
|
|
132
134
|
if (subject === undefined)
|
|
133
135
|
return undefined;
|
|
134
136
|
try {
|
|
135
|
-
// The APP's root, not the daemon's
|
|
136
|
-
// which for a user-scoped MCP registration is almost never the project being verified — so the
|
|
137
|
-
// link file it reads is the wrong one, or absent, and every project silently reads as
|
|
138
|
-
// "not attached". Same class of bug as the flow store resolving per daemon instead of per
|
|
139
|
-
// session, and it is invisible: the feature simply never appears.
|
|
137
|
+
// The APP's root, not the daemon's (wherever it was launched): its link file is this project's.
|
|
140
138
|
const cloud = await resolveProjectCloud(deps.fs, root, homedir(), process.env);
|
|
141
139
|
if (null === cloud.config || !cloud.policy.memory)
|
|
142
140
|
return undefined;
|
|
@@ -146,7 +144,7 @@ async function consultProjectMemory(deps, flow, root) {
|
|
|
146
144
|
const url = memoryReadUrl(cloud.config.url, { projectId: cloud.projectId, subject });
|
|
147
145
|
const res = await cloudFetch(url, {
|
|
148
146
|
method: 'GET',
|
|
149
|
-
headers:
|
|
147
|
+
headers: memoryReadHeaders(cloud.config.apiKey),
|
|
150
148
|
});
|
|
151
149
|
if (200 !== res.status)
|
|
152
150
|
return undefined;
|
|
@@ -574,8 +572,8 @@ observe = (s) => s) {
|
|
|
574
572
|
status: ReplayStatus.UNVERIFIABLE,
|
|
575
573
|
steps: [],
|
|
576
574
|
unverifiable: {
|
|
577
|
-
reason: `this flow fills a redacted field and nothing supplied it, so nothing ran and nothing ` +
|
|
578
|
-
`
|
|
575
|
+
reason: `this flow fills a redacted field and nothing supplied it, so nothing ran and nothing was ` +
|
|
576
|
+
`proved. Pass it with this call — secrets: { ${missing.map((each) => `"${each.field}": "…"`).join(', ')} } — or set ${names} where the daemon runs and restart it. Until then ` +
|
|
579
577
|
`the value typed would be the placeholder itself, and any failure after it would be ` +
|
|
580
578
|
`about this and not about the application.`,
|
|
581
579
|
},
|
|
@@ -613,6 +611,7 @@ observe = (s) => s) {
|
|
|
613
611
|
...(continueAt === undefined ? {} : { at: continueAt }),
|
|
614
612
|
// The HUD's replay chip, when the human pressed ▶. In-process only: an agent's arguments
|
|
615
613
|
// arrive as JSON and can never carry a function.
|
|
614
|
+
onStepResult: replayStepShooter(deps, session.id),
|
|
616
615
|
...('function' === typeof args['onStep']
|
|
617
616
|
? { onStep: args['onStep'] }
|
|
618
617
|
: {}),
|
|
@@ -624,7 +623,7 @@ observe = (s) => s) {
|
|
|
624
623
|
return lostDocumentResult(name, error);
|
|
625
624
|
}
|
|
626
625
|
// Only part of the journey was driven here: its steps were checked, nothing about the whole flow.
|
|
627
|
-
if (continueAt
|
|
626
|
+
if (0 < (continueAt ?? 0) || (to !== undefined && to < loaded.value.steps.length))
|
|
628
627
|
return { name, status: partialStatus(steps), steps };
|
|
629
628
|
// Computed HERE, before the synthetic success row is appended below: once that row is pushed,
|
|
630
629
|
// `steps.length` no longer counts only the flow's own steps and the arithmetic is wrong.
|
|
@@ -728,13 +727,12 @@ observe = (s) => s) {
|
|
|
728
727
|
result.halted = halted;
|
|
729
728
|
if (knows !== undefined)
|
|
730
729
|
result.knows = knows;
|
|
731
|
-
// A green that cannot go red is not a pass
|
|
732
|
-
// via this same function -- a single-flow caller saw a bare `ok` and had no way to learn the flow
|
|
733
|
-
// asserts nothing. Derived from the same helper on purpose: two copies of this judgement would
|
|
734
|
-
// drift, and the sibling tools would then disagree about the same flow.
|
|
730
|
+
// A green that cannot go red is not a pass: the same judgement `reticle_flow_verify` makes.
|
|
735
731
|
const cannotFail = status === ReplayStatus.OK ? unverifiableReason(loaded.value, invokedFlows) : undefined;
|
|
736
732
|
if (cannotFail !== undefined)
|
|
737
733
|
result.unverifiable = { reason: cannotFail };
|
|
734
|
+
// One check of the session that ran it, so its end does not say "nothing was checked".
|
|
735
|
+
noteReplayCheck(session, name, status, cannotFail !== undefined);
|
|
738
736
|
if (status !== ReplayStatus.OK)
|
|
739
737
|
result.decision = buildDecision(result, loaded.value, intentSaid, invokedFlows);
|
|
740
738
|
applyStartPathHint(result, startPathHint);
|
|
@@ -12,7 +12,7 @@ import type { EvalResult } from '@reticlehq/engine/question/predicate/predicate.
|
|
|
12
12
|
* (via the injected waitForPredicate). Mirrors PredicateSession so the same fake drives both.
|
|
13
13
|
*/
|
|
14
14
|
export interface FlowReplaySession {
|
|
15
|
-
command(name: string, args?: Record<string, unknown
|
|
15
|
+
command(name: string, args?: Record<string, unknown>, timeoutMs?: number): Promise<CommandResult>;
|
|
16
16
|
/**
|
|
17
17
|
* Attribution window around each replayed step. Optional so a minimal test double still satisfies the
|
|
18
18
|
* interface, but a real session MUST supply it: without a window the step's own effects carry no
|
|
@@ -43,6 +43,15 @@ export declare function runTestidStep(session: FlowReplaySession, step: FlowStep
|
|
|
43
43
|
* state it was never meant to run in.
|
|
44
44
|
*/
|
|
45
45
|
export declare function assertStepExpect(session: FlowReplaySession, expect: NonNullable<FlowStep['expect']>, waitForSignal: WaitForSignal, timeoutMs: number, since: number): Promise<Drift | undefined>;
|
|
46
|
+
/**
|
|
47
|
+
* A text check that missed only on case says so, with what would hold. Text checks match case
|
|
48
|
+
* exactly now, so a flow saved when they did not goes red on capitalisation alone; the person
|
|
49
|
+
* reading its replay needs the fix (`ignoreCase: true`, or re-record), not a bare "did not hold".
|
|
50
|
+
*/
|
|
51
|
+
export declare function withCaseOnly(reason: string, verdict: {
|
|
52
|
+
caseOnlyMiss?: boolean;
|
|
53
|
+
wouldHold?: string;
|
|
54
|
+
}): string;
|
|
46
55
|
/**
|
|
47
56
|
* Replay a loaded flow by RE-RESOLVING every step's semantic anchor against the live DOM — never
|
|
48
57
|
* a stale ref. A testid anchor is re-found by reticle_query; a signal anchor waits on a predicate.
|
|
@@ -58,6 +67,11 @@ export interface ReplayFromOptions {
|
|
|
58
67
|
* The HUD's replay chip draws its progress from this; it must never throw into the replay.
|
|
59
68
|
*/
|
|
60
69
|
onStep?: (done: number, total: number, held: boolean) => void;
|
|
70
|
+
/**
|
|
71
|
+
* Told each reported step the moment its outcome is decided, before it is kept, so a caller can
|
|
72
|
+
* add to it (the step's screenshot). Never allowed to fail the replay.
|
|
73
|
+
*/
|
|
74
|
+
onStepResult?: (result: FlowStepResult, flow: string) => Promise<void>;
|
|
61
75
|
/**
|
|
62
76
|
* Resume at this step: an index, or a step's `id` (which survives edits that shift indices).
|
|
63
77
|
*
|
|
@@ -114,7 +128,10 @@ export interface ReplayFromOptions {
|
|
|
114
128
|
* is not setup, it is a second charge, a second email, a second record.
|
|
115
129
|
*/
|
|
116
130
|
export declare function resumeIndex(from: number | string | undefined, steps: readonly FlowStep[]): number | undefined;
|
|
117
|
-
/**
|
|
131
|
+
/**
|
|
132
|
+
* How far a replay drives: `to` stops before a step (positive), `at` picks up at one on the page as
|
|
133
|
+
* it is. `at: 0` is the whole flow continuing the page the flow before it left, with no reload.
|
|
134
|
+
*/
|
|
118
135
|
export declare function replayWindow(args: Record<string, unknown>): {
|
|
119
136
|
to?: number;
|
|
120
137
|
at?: number;
|
|
@@ -7,7 +7,7 @@ import { routeOfEvent, routeOfUrl } from '@reticlehq/engine/question/predicate/p
|
|
|
7
7
|
import { evalConsole } from '@reticlehq/engine/question/predicate/predicate-console.js';
|
|
8
8
|
import { stepEffect } from '@reticlehq/engine/evidence/step-effect.js';
|
|
9
9
|
import { AnchorKind, DriftReason, EventType, FlowStepTool, StepEffect, PredicateKind, ReplayStatus, } from '@reticlehq/core';
|
|
10
|
-
import { asString, isConsequenceDrift } from '@reticlehq/core';
|
|
10
|
+
import { asString, invokedFlowMissing, isConsequenceDrift } from '@reticlehq/core';
|
|
11
11
|
import { anchorFieldName } from './fields/flow-secret-field.js';
|
|
12
12
|
import { degradedStepResult, isDegradedAnchor, runComponentStep, runRoleStep, runSequenceStep, } from './flow-step-runners.js';
|
|
13
13
|
import { inFlightRequestLabels } from '../../surface/tools/act/settle-in-flight.js';
|
|
@@ -282,11 +282,22 @@ export async function assertStepExpect(session, expect, waitForSignal, timeoutMs
|
|
|
282
282
|
: DriftReason.SIGNAL_NOT_OBSERVED,
|
|
283
283
|
reason: namedInFlight
|
|
284
284
|
? `${IN_FLIGHT_AT_BUDGET_END} (${openRequests.join(', ')})`
|
|
285
|
-
: (verdict.failureReason ?? "the step's declared consequence did not hold"),
|
|
285
|
+
: withCaseOnly(verdict.failureReason ?? "the step's declared consequence did not hold", verdict),
|
|
286
286
|
anchor: expectLabel(expect),
|
|
287
287
|
nearest: null,
|
|
288
288
|
};
|
|
289
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* A text check that missed only on case says so, with what would hold. Text checks match case
|
|
292
|
+
* exactly now, so a flow saved when they did not goes red on capitalisation alone; the person
|
|
293
|
+
* reading its replay needs the fix (`ignoreCase: true`, or re-record), not a bare "did not hold".
|
|
294
|
+
*/
|
|
295
|
+
export function withCaseOnly(reason, verdict) {
|
|
296
|
+
if (true !== verdict.caseOnlyMiss)
|
|
297
|
+
return reason;
|
|
298
|
+
const shown = verdict.wouldHold === undefined ? '' : ` ("${verdict.wouldHold}")`;
|
|
299
|
+
return `${reason} — the page shows it in another case${shown}. Text checks match case exactly: if any case is meant, add ignoreCase: true to this check, or re-record the flow.`;
|
|
300
|
+
}
|
|
290
301
|
/** Run one signal-anchored step: wait for the signal predicate, else drift (no nearest for signals). */
|
|
291
302
|
async function runSignalStep(session, step, index, name, waitForSignal, signalTimeoutMs, since) {
|
|
292
303
|
// Scope to THIS replay's floor, not the whole buffer.
|
|
@@ -328,11 +339,14 @@ export function resumeIndex(from, steps) {
|
|
|
328
339
|
return undefined;
|
|
329
340
|
return steps.slice(0, at).some((step) => StepEffect.COMMITS === step.effect) ? 0 : at;
|
|
330
341
|
}
|
|
331
|
-
/**
|
|
342
|
+
/**
|
|
343
|
+
* How far a replay drives: `to` stops before a step (positive), `at` picks up at one on the page as
|
|
344
|
+
* it is. `at: 0` is the whole flow continuing the page the flow before it left, with no reload.
|
|
345
|
+
*/
|
|
332
346
|
export function replayWindow(args) {
|
|
333
|
-
const index = (raw) => 'number' === typeof raw && Number.isInteger(raw) &&
|
|
334
|
-
const to = index(args['to']);
|
|
335
|
-
const at = index(args['at']);
|
|
347
|
+
const index = (raw, least) => 'number' === typeof raw && Number.isInteger(raw) && least <= raw ? raw : undefined;
|
|
348
|
+
const to = index(args['to'], 1);
|
|
349
|
+
const at = index(args['at'], 0);
|
|
336
350
|
return { ...(to === undefined ? {} : { to }), ...(at === undefined ? {} : { at }) };
|
|
337
351
|
}
|
|
338
352
|
/** A part-way replay's status, from the steps it drove. */
|
|
@@ -381,7 +395,7 @@ async function runInvokeStep(session, flow, step, index, waitForSignal, signalTi
|
|
|
381
395
|
return {
|
|
382
396
|
...base,
|
|
383
397
|
ok: false,
|
|
384
|
-
error:
|
|
398
|
+
error: invokedFlowMissing(name),
|
|
385
399
|
};
|
|
386
400
|
}
|
|
387
401
|
// `from` is an offset into the CALLER's steps. A sub-journey invoked from the setup prefix runs
|
|
@@ -555,6 +569,7 @@ export async function replayFlow(session, flow, waitForSignal, signalTimeoutMs,
|
|
|
555
569
|
}
|
|
556
570
|
if (index < from)
|
|
557
571
|
result.note = `setup step for resuming at step ${String(from)} failed`;
|
|
572
|
+
await options.onStepResult?.(result, flow.name).catch(() => undefined);
|
|
558
573
|
results.push(result);
|
|
559
574
|
tell(result);
|
|
560
575
|
// Under `sweep`, a failure whose action still RAN does not stop the run — the page is where the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FlowErrorCode } from '@reticlehq/core';
|
|
1
|
+
import { FlowErrorCode, ReplayStatus, Verified } from '@reticlehq/core';
|
|
2
2
|
import { type ProjectId } from '@reticlehq/core';
|
|
3
3
|
/** Discriminated result so callers never branch on free strings. */
|
|
4
4
|
export type FlowResult<T> = {
|
|
@@ -35,3 +35,24 @@ export type FlowResult<T> = {
|
|
|
35
35
|
export declare const safeProjectId: (projectId?: ProjectId) => ProjectId | undefined;
|
|
36
36
|
/** Map a structured FlowErrorCode to a legible one-line message for the agent. */
|
|
37
37
|
export declare function flowErrorMessage(code: FlowErrorCode, detail?: string): string;
|
|
38
|
+
/**
|
|
39
|
+
* A replay as one check of the session that ran it: held when it replayed clean, failed when a step
|
|
40
|
+
* failed, undecided when it drifted or its flow asserts nothing. A session whose only work was a
|
|
41
|
+
* failing replay ended "nothing was checked" beside the replay's own failure.
|
|
42
|
+
*/
|
|
43
|
+
export declare function replayVerdictEffect(name: string, status: ReplayStatus, assertsNothing: boolean): {
|
|
44
|
+
claim: string;
|
|
45
|
+
verified: Verified;
|
|
46
|
+
declaredBeforeActing: true;
|
|
47
|
+
grade: string;
|
|
48
|
+
};
|
|
49
|
+
/** Record a replay as one check of the session that ran it. A session double without a journal is skipped. */
|
|
50
|
+
export declare function noteReplayCheck(session: {
|
|
51
|
+
recordAction?: (tool: string, args: Record<string, unknown>, effect?: unknown) => string;
|
|
52
|
+
}, name: string, status: ReplayStatus, assertsNothing: boolean): void;
|
|
53
|
+
/**
|
|
54
|
+
* The active recording a refused `reticle_flow_save` was most likely about: the one it named, or
|
|
55
|
+
* the only one running when it named none and nothing is stopped yet.
|
|
56
|
+
*/
|
|
57
|
+
export declare function stillRecording(active: readonly string[], name: string, explicitName: string | undefined, held: readonly string[]): string | undefined;
|
|
58
|
+
export declare function stillRecordingMessage(recording: string): string;
|