@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
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { FlowErrorCode } from '@reticlehq/core';
|
|
1
|
+
import { FlowErrorCode, NO_SUCH_FLOW, ReplayStatus, ReticleTool, Verified } from '@reticlehq/core';
|
|
2
2
|
import { SAFE_SEGMENT_PATTERN } from '@reticlehq/core';
|
|
3
3
|
import { FlowParseNote } from './flow-expect-grammar.js';
|
|
4
|
+
import { isAmbient } from './recording/tape/recordings.js';
|
|
4
5
|
/**
|
|
5
6
|
* A project id that is safe to put in a path, or nothing.
|
|
6
7
|
*
|
|
@@ -36,7 +37,7 @@ export function flowErrorMessage(code, detail) {
|
|
|
36
37
|
case FlowErrorCode.INVALID_NAME:
|
|
37
38
|
return 'invalid flow name — use a single safe segment (letters/digits/-/_), no path separators';
|
|
38
39
|
case FlowErrorCode.NOT_FOUND:
|
|
39
|
-
return
|
|
40
|
+
return `${NO_SUCH_FLOW} — run reticle_flow{action:"list"} to see saved flows`;
|
|
40
41
|
case FlowErrorCode.PARSE_FAILED:
|
|
41
42
|
return FlowParseNote.MALFORMED;
|
|
42
43
|
case FlowErrorCode.NO_RECORDING:
|
|
@@ -49,3 +50,47 @@ export function flowErrorMessage(code, detail) {
|
|
|
49
50
|
return (detail ?? 'the step to resume at is not in this flow — pass a 0-based index or a step id');
|
|
50
51
|
}
|
|
51
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* A replay as one check of the session that ran it: held when it replayed clean, failed when a step
|
|
55
|
+
* failed, undecided when it drifted or its flow asserts nothing. A session whose only work was a
|
|
56
|
+
* failing replay ended "nothing was checked" beside the replay's own failure.
|
|
57
|
+
*/
|
|
58
|
+
export function replayVerdictEffect(name, status, assertsNothing) {
|
|
59
|
+
const verified = ReplayStatus.OK === status && !assertsNothing
|
|
60
|
+
? Verified.YES
|
|
61
|
+
: ReplayStatus.ERROR === status
|
|
62
|
+
? Verified.NO
|
|
63
|
+
: Verified.UNKNOWN;
|
|
64
|
+
return {
|
|
65
|
+
claim: `the flow "${name}" replays and its checks hold`,
|
|
66
|
+
verified,
|
|
67
|
+
declaredBeforeActing: true,
|
|
68
|
+
grade: REPLAY_GRADE,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** The grade a replay's check is recorded with. */
|
|
72
|
+
const REPLAY_GRADE = 'flow';
|
|
73
|
+
/** Record a replay as one check of the session that ran it. A session double without a journal is skipped. */
|
|
74
|
+
export function noteReplayCheck(session, name, status, assertsNothing) {
|
|
75
|
+
session.recordAction?.(ReticleTool.FLOW_REPLAY, { flowName: name }, replayVerdictEffect(name, status, assertsNothing));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The active recording a refused `reticle_flow_save` was most likely about: the one it named, or
|
|
79
|
+
* the only one running when it named none and nothing is stopped yet.
|
|
80
|
+
*/
|
|
81
|
+
// A running recording has no compiled program yet, so a save refusal names it (#1551).
|
|
82
|
+
export function stillRecording(active, name, explicitName, held) {
|
|
83
|
+
if (active.includes(name) && !isAmbient(name))
|
|
84
|
+
return name;
|
|
85
|
+
// The ambient tape is the daemon's own, never one the agent started, so it is neither named nor
|
|
86
|
+
// counted: with a named recording beside it, that one is still the only candidate.
|
|
87
|
+
const opened = active.filter((recording) => !isAmbient(recording));
|
|
88
|
+
if ((explicitName === undefined || 0 === explicitName.length) && 0 === held.length) {
|
|
89
|
+
return 1 === opened.length ? opened[0] : undefined;
|
|
90
|
+
}
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
export function stillRecordingMessage(recording) {
|
|
94
|
+
return (`'${recording}' is still recording, and flow_save only saves a stopped recording. ` +
|
|
95
|
+
`Stop it first with reticle_record{action:"stop", recordingName:"${recording}"}, then save again.`);
|
|
96
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { AnchorKind, type FlowAnchor, type FlowReplayResult, type FlowStep, type FlowStepResult, type Predicate } from '@reticlehq/core';
|
|
2
2
|
import type { FlowReplaySession, Sleep } from './flow-replay-types.js';
|
|
3
3
|
import { type Reresolved } from './flow-anchor.js';
|
|
4
|
+
/** The live act_sequence tool gives each step this transport budget when none was supplied. */
|
|
5
|
+
export declare const DEFAULT_SEQUENCE_STEP_TIMEOUT_MS = 8000;
|
|
4
6
|
export declare function runRoleStep(session: FlowReplaySession, step: FlowStep, index: number, anchor: Extract<FlowAnchor, {
|
|
5
7
|
kind: typeof AnchorKind.ROLE;
|
|
6
8
|
}>, confirmDangerous: boolean, sleep: Sleep): Promise<FlowStepResult>;
|
|
@@ -16,6 +16,8 @@ import { anchorFieldName } from './flows.js';
|
|
|
16
16
|
import { ambiguityDrift, refFor, anchorLabel, componentLabel, componentQueryArgs, expectElementDrift, reresolved, resolveQuery, testidDrift, } from './flow-anchor.js';
|
|
17
17
|
import { nearestRoleName } from './role-anchor-nearest.js';
|
|
18
18
|
import { roleDriftReason } from '../../judgement/outcome/role-drift-reason.js';
|
|
19
|
+
/** The live act_sequence tool gives each step this transport budget when none was supplied. */
|
|
20
|
+
export const DEFAULT_SEQUENCE_STEP_TIMEOUT_MS = 8_000;
|
|
19
21
|
/** Query args for a NAMED role anchor — the handle that identifies an instance, not a JSX site. */
|
|
20
22
|
function roleQueryArgs(anchor) {
|
|
21
23
|
return {
|
|
@@ -134,11 +136,8 @@ function replayDestructiveActionHint(rawError) {
|
|
|
134
136
|
return (`${rawError} — this is a flow REPLAY: a step's own args.confirmDangerous is stripped before ` +
|
|
135
137
|
'dispatch and never persists, so editing the flow file does nothing. Pass it at the call level ' +
|
|
136
138
|
`instead: ${ReticleTool.FLOW_REPLAY} { confirmDangerous: true } acknowledges every flagged step ` +
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
// that a flow with a flagged step currently has to be replayed on its own to pass it.
|
|
140
|
-
'for this run. The batch reticle_verify{action:"flows"} has no equivalent option yet, so a flow ' +
|
|
141
|
-
'with a flagged step has to be replayed on its own to acknowledge it.');
|
|
139
|
+
'for this run, as do reticle_verify{action:"flows", confirmDangerous: true} for a suite and ' +
|
|
140
|
+
'`reticle verify <url> --confirm-dangerous` from the command line.');
|
|
142
141
|
}
|
|
143
142
|
/**
|
|
144
143
|
* Dispatch one already-resolved step. Shared so every anchor kind runs the action the same way —
|
|
@@ -467,7 +466,14 @@ dynamic = new Set()) {
|
|
|
467
466
|
const send = async (steps) => {
|
|
468
467
|
session.beginAction?.(ReticleTool.FLOW_REPLAY, { steps: steps.length });
|
|
469
468
|
try {
|
|
470
|
-
|
|
469
|
+
// A recorded zero means "do not wait for the element", not "abort the whole batch now".
|
|
470
|
+
// Keep the transport alive long enough for the sequence's default per-step budget, and give
|
|
471
|
+
// an omitted timeout the same aggregate budget as the live tool's independent step waits.
|
|
472
|
+
const perStepTimeout = undefined === step.timeoutMs || 0 === step.timeoutMs
|
|
473
|
+
? DEFAULT_SEQUENCE_STEP_TIMEOUT_MS
|
|
474
|
+
: step.timeoutMs;
|
|
475
|
+
const timeoutMs = perStepTimeout * steps.length;
|
|
476
|
+
return await session.command(ReticleCommand.ACT_SEQUENCE, { steps }, timeoutMs);
|
|
471
477
|
}
|
|
472
478
|
finally {
|
|
473
479
|
session.finishAction?.();
|
|
@@ -29,5 +29,9 @@ export function flowsForSession(deps, target) {
|
|
|
29
29
|
if (resolved === undefined || resolved.root === deps.reticleRoot) {
|
|
30
30
|
return { flows: deps.flows, root: deps.reticleRoot };
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
const onWrote = deps.onRunPersisted;
|
|
33
|
+
return {
|
|
34
|
+
flows: new FlowStore(deps.fs, resolved.root, { now: deps.now }, onWrote === undefined ? {} : { onWrote }),
|
|
35
|
+
root: resolved.root,
|
|
36
|
+
};
|
|
33
37
|
}
|
|
@@ -10,6 +10,16 @@ export { replayNamedFlow } from './flow-replay-run.js';
|
|
|
10
10
|
* point; flows that need another page carry their own startPath.
|
|
11
11
|
*/
|
|
12
12
|
export declare function leasableAppUrl(deps: ToolDeps, sessionId: string | undefined): string | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* The live session's own URL — what the fixture port must be looked up by.
|
|
15
|
+
*
|
|
16
|
+
* NOT `leasableAppUrl`. That returns an ORIGIN, and the input provider finds a page by comparing
|
|
17
|
+
* full URLs, so an origin matched no page: `suiteFixtureSeed` answered `undefined` on every run and
|
|
18
|
+
* every leased flow booted cold while the code read as if it were seeded. Silent, because every
|
|
19
|
+
* refusal on that path is deliberately silent — a fixture is an optimisation, and a suite must not
|
|
20
|
+
* die when one is unavailable.
|
|
21
|
+
*/
|
|
22
|
+
export declare function sessionUrlOf(deps: ToolDeps, sessionId: string | undefined): string | undefined;
|
|
13
23
|
/** A flow whose leased context never came up is a suite ERROR, never a silent pass. */
|
|
14
24
|
export declare function leaseFailureReplay(name: string, error: string | undefined): FlowReplayResult;
|
|
15
25
|
export declare const FLOW_TOOLS: ToolDef[];
|
|
@@ -1,19 +1,24 @@
|
|
|
1
|
+
import { CALL_SECRETS_ARG, callSecretsArg } from './fields/flow-secret-field.js';
|
|
1
2
|
import { flowAuthor } from './flow-author.js';
|
|
2
3
|
import { FLOW_MUTATE_TOOL } from './flow-mutate-tools.js';
|
|
3
|
-
import { seedSchema } from '../../surface/tools/args/numeric-bounds.js';
|
|
4
|
+
import { seedSchema, workerCountSchema } from '../../surface/tools/args/numeric-bounds.js';
|
|
5
|
+
import { confirmDangerousArg } from '../../surface/tools/args/confirm-dangerous-arg.js';
|
|
4
6
|
import { z } from 'zod';
|
|
5
7
|
import { emptyFlowRefusal } from './empty-flow.js';
|
|
6
|
-
import { aliasParam } from '../../surface/tools/args/alias-args.js';
|
|
8
|
+
import { aliasParam, aliasUsed } from '../../surface/tools/args/alias-args.js';
|
|
9
|
+
import { stillRecording, stillRecordingMessage } from './flow-result.js';
|
|
10
|
+
import { resolveAnnotateTarget } from './annotate-notes/annotate-target.js';
|
|
7
11
|
import { FlowErrorCode, RecordedSaveError, ReplayStatus, SuiteIsolation, } from '@reticlehq/core';
|
|
8
12
|
import { recordSuiteFlakes } from './suite/suite-flakes.js';
|
|
9
13
|
import { AppRuntime, ReticleTool } from '@reticlehq/core';
|
|
10
|
-
import { asNumber, asString
|
|
11
|
-
import { workerCountSchema } from '../../surface/tools/args/numeric-bounds.js';
|
|
14
|
+
import { asNumber, asString } from '@reticlehq/core';
|
|
12
15
|
import { log } from '../../log.js';
|
|
13
16
|
import { cloudFetch, syncFlowToCloud, SyncOutcome } from '../../memory/cloud/cloud-sync.js';
|
|
14
17
|
import { mapWithConcurrency, resolveConcurrency } from './suite/parallel-suite.js';
|
|
15
|
-
import { acquireLeasedSession,
|
|
18
|
+
import { acquireLeasedSession, suiteFixtureSeed } from '../../surface/tools/lease-tools.js';
|
|
16
19
|
import { homedir } from 'node:os';
|
|
20
|
+
import { withShotRun } from '../../judgement/runs/default-run-id.js';
|
|
21
|
+
import { defaultRunId } from '../../judgement/runs/default-run-id.js';
|
|
17
22
|
import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
|
|
18
23
|
import { buildSuiteVerdict } from './decision.js';
|
|
19
24
|
import { classifyFlowAssertions, flattenSteps } from './flow-classify.js';
|
|
@@ -24,10 +29,12 @@ import { flowsForSession } from './flow-store-for-session.js';
|
|
|
24
29
|
import { rootForTarget, sessionTarget } from '../../memory/project/session-root.js';
|
|
25
30
|
import { originOf } from '../../portal/session/session-manager.js';
|
|
26
31
|
import { resolveSuiteSelection } from './suite-selection.js';
|
|
27
|
-
import {
|
|
32
|
+
import { flowErrorMessage, latestRecordedFlow, sessionProjectId } from './flow-replay-run.js';
|
|
28
33
|
import { persistAndSyncVerificationRun, } from '../../judgement/runs/verification-sync.js';
|
|
29
34
|
import { runServerVerify } from './suite/server-verify.js';
|
|
30
35
|
import { healFlow } from './heal-run.js';
|
|
36
|
+
import { RESULT_FIELD, resultField, suiteResult } from '../../surface/tools/reticle-result.js';
|
|
37
|
+
import { replayOneFlow } from './single-replay.js';
|
|
31
38
|
export { replayNamedFlow } from './flow-replay-run.js';
|
|
32
39
|
import { replayAndLearn } from './flow-learning.js';
|
|
33
40
|
/**
|
|
@@ -81,7 +88,7 @@ export function leasableAppUrl(deps, sessionId) {
|
|
|
81
88
|
* refusal on that path is deliberately silent — a fixture is an optimisation, and a suite must not
|
|
82
89
|
* die when one is unavailable.
|
|
83
90
|
*/
|
|
84
|
-
function sessionUrlOf(deps, sessionId) {
|
|
91
|
+
export function sessionUrlOf(deps, sessionId) {
|
|
85
92
|
try {
|
|
86
93
|
return deps.sessions.resolve(sessionId).url;
|
|
87
94
|
}
|
|
@@ -118,15 +125,17 @@ export const FLOW_TOOLS = [
|
|
|
118
125
|
FLOW_MUTATE_TOOL,
|
|
119
126
|
{
|
|
120
127
|
name: ReticleTool.FLOW_SAVE,
|
|
121
|
-
description: 'Persist
|
|
128
|
+
description: 'Persist a STOPPED recording (by name) as a git-checked, anchor-resolved flow at .reticle/flows/<name>.json. A recording that is still running is refused: stop it first with reticle_record{action:"stop"}, and the refusal names the exact call. Each step is bound to a SEMANTIC anchor (testid/role/signal), never a volatile ref; steps without a resolvable testid are kept with degraded:true (a "add a data-testid here" marker) rather than dropped. Returns { name, stepCount, degraded, empty, assertions, warning? } — `assertions.grade` is asserted | presence-only | assertion-free: a flow that only acts (or only checks element presence) will pass even if the feature breaks, so when grade is not "asserted" follow assertions.warning and add a consequence assertion via reticle_annotate (assert-signal / assert-net / success-state). `warning` is present when the recording left a page and returned to it: replay has no navigation steps, so the next click will look for a control on a page the tab is no longer on.',
|
|
122
129
|
inputSchema: {
|
|
123
130
|
flow: z
|
|
124
131
|
.string()
|
|
125
132
|
.optional()
|
|
126
133
|
.describe('Alias for `flowName` (the name reticle_annotate uses).'),
|
|
134
|
+
name: z.string().optional().describe('Alias for `flowName`.'),
|
|
127
135
|
flowName: z
|
|
128
136
|
.string()
|
|
129
|
-
.
|
|
137
|
+
.optional()
|
|
138
|
+
.describe('Which RECORDING to save — the name reticle_record{start} was called with ("last-journey" for the reticle_act {steps} just proved). Omit when only one is stopped. This is a lookup key, not the filename: pass `saveAs` to choose that.'),
|
|
130
139
|
saveAs: z
|
|
131
140
|
.string()
|
|
132
141
|
.optional()
|
|
@@ -162,6 +171,7 @@ export const FLOW_TOOLS = [
|
|
|
162
171
|
})
|
|
163
172
|
.optional(),
|
|
164
173
|
intentGap: INTENT_GAP_FIELD,
|
|
174
|
+
normalized: z.array(z.string()).optional(),
|
|
165
175
|
warning: z
|
|
166
176
|
.string()
|
|
167
177
|
.optional()
|
|
@@ -170,7 +180,12 @@ export const FLOW_TOOLS = [
|
|
|
170
180
|
code: z.string().optional(),
|
|
171
181
|
},
|
|
172
182
|
handler: (deps, args) => {
|
|
173
|
-
const
|
|
183
|
+
const aliases = ['flow', 'name', 'recordingName'];
|
|
184
|
+
const normalized = aliasUsed(args, 'flowName', aliases);
|
|
185
|
+
const explicitName = asString(aliasParam(args, 'flowName', aliases)['flowName']);
|
|
186
|
+
// The one stopped recording when the call names none — the same defaulting record{stop} and
|
|
187
|
+
// annotate use. With several, nothing is picked: the refusal below names them.
|
|
188
|
+
const name = resolveAnnotateTarget(explicitName, deps.recordings.compiled());
|
|
174
189
|
const program = deps.recordings.getCompiled(name);
|
|
175
190
|
if (program === undefined) {
|
|
176
191
|
/*
|
|
@@ -183,6 +198,13 @@ export const FLOW_TOOLS = [
|
|
|
183
198
|
* before the names were compared.
|
|
184
199
|
*/
|
|
185
200
|
const held = deps.recordings.compiled();
|
|
201
|
+
const running = stillRecording(deps.recordings.active(), name, explicitName, held);
|
|
202
|
+
if (running !== undefined) {
|
|
203
|
+
return Promise.resolve({
|
|
204
|
+
error: stillRecordingMessage(running),
|
|
205
|
+
code: FlowErrorCode.NO_RECORDING,
|
|
206
|
+
});
|
|
207
|
+
}
|
|
186
208
|
return Promise.resolve({
|
|
187
209
|
error: 0 === held.length
|
|
188
210
|
? flowErrorMessage(FlowErrorCode.NO_RECORDING)
|
|
@@ -251,6 +273,7 @@ export const FLOW_TOOLS = [
|
|
|
251
273
|
const invoked = loaded.ok ? await loadInvoked(flows, loaded.value, projectId) : new Map();
|
|
252
274
|
return loaded.ok
|
|
253
275
|
? {
|
|
276
|
+
...(0 === normalized.length ? {} : { normalized }),
|
|
254
277
|
...res.value,
|
|
255
278
|
...(path === undefined ? {} : { path }),
|
|
256
279
|
assertions: classifyFlowAssertions(loaded.value, invoked),
|
|
@@ -391,10 +414,8 @@ export const FLOW_TOOLS = [
|
|
|
391
414
|
flowName: z
|
|
392
415
|
.string()
|
|
393
416
|
.describe('Flow file name (without .json extension) from reticle_flow{action:"list"}.'),
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
.optional()
|
|
397
|
-
.describe('Set true to allow destructive controls during this replay only.'),
|
|
417
|
+
[CALL_SECRETS_ARG]: callSecretsArg,
|
|
418
|
+
confirmDangerous: confirmDangerousArg('this replay'),
|
|
398
419
|
from: z
|
|
399
420
|
.union([z.number().int().nonnegative(), z.string().min(1)])
|
|
400
421
|
.optional()
|
|
@@ -409,10 +430,10 @@ export const FLOW_TOOLS = [
|
|
|
409
430
|
at: z
|
|
410
431
|
.number()
|
|
411
432
|
.int()
|
|
412
|
-
.
|
|
433
|
+
.nonnegative()
|
|
413
434
|
.max(MAX_REPLAY_STEP)
|
|
414
435
|
.optional()
|
|
415
|
-
.describe('Continue at this step on the page as it is (after another flow ran `to` it).'),
|
|
436
|
+
.describe('Continue at this step on the page as it is (after another flow ran `to` it); 0 replays the whole flow on the page the flow before it left, with no reload.'),
|
|
416
437
|
sweep: z
|
|
417
438
|
.boolean()
|
|
418
439
|
.optional()
|
|
@@ -430,10 +451,12 @@ export const FLOW_TOOLS = [
|
|
|
430
451
|
.array(z.unknown())
|
|
431
452
|
.optional()
|
|
432
453
|
.describe('Present when `seed` was given: which endpoints were delayed, and by how long.'),
|
|
454
|
+
[RESULT_FIELD]: z.string().optional(),
|
|
433
455
|
// The flow's name — always present in FlowReplayResult (the description promises `{ name, … }`),
|
|
434
456
|
// but omitted here, so a validating profile stripped it and a replay result arrived anonymous.
|
|
435
457
|
name: z.string(),
|
|
436
458
|
status: z.string().describe('ok | drift | error | unverifiable'),
|
|
459
|
+
runId: z.string().optional().describe('The run this replay was written down as.'),
|
|
437
460
|
steps: z.array(z.unknown()),
|
|
438
461
|
proposals: z.array(z.unknown()).optional(),
|
|
439
462
|
deviation: z
|
|
@@ -487,42 +510,7 @@ export const FLOW_TOOLS = [
|
|
|
487
510
|
},
|
|
488
511
|
// The decision envelope is attached by replayNamedFlow only on drift/fail (clean pass stays
|
|
489
512
|
// token-flat). Single-flow replay and whole-suite verify share that one implementation.
|
|
490
|
-
handler:
|
|
491
|
-
const seed = asNumber(args['seed']);
|
|
492
|
-
if (seed === undefined)
|
|
493
|
-
return await replayAndLearn(deps, args);
|
|
494
|
-
/*
|
|
495
|
-
* Seeded chaos, and always put the page back.
|
|
496
|
-
*
|
|
497
|
-
* The targets are the endpoints the FLOW declared it depends on, so the perturbation lands on
|
|
498
|
-
* traffic the flow claims to care about rather than on something it never mentioned. No
|
|
499
|
-
* declared endpoints means nothing to slow, and the replay runs clean rather than pretending
|
|
500
|
-
* a seed did something.
|
|
501
|
-
*
|
|
502
|
-
* `finally` is not tidiness: a page left slowed is damage the NEXT run inherits, and it would
|
|
503
|
-
* inherit it as a mystery — the same rule the mutation loop had to earn.
|
|
504
|
-
*/
|
|
505
|
-
const sessionId = asString(args['sessionId']);
|
|
506
|
-
const target = sessionTarget(deps, sessionId);
|
|
507
|
-
const loaded = await flowsForSession(deps, target)
|
|
508
|
-
.flows.load(asString(args['flowName']) ?? asString(args['flow']) ?? '', target.projectId)
|
|
509
|
-
.catch(() => null);
|
|
510
|
-
const targets = loaded !== null && loaded.ok ? mutationTargetsFor(loaded.value) : [];
|
|
511
|
-
const rules = perturbationFor(seed, targets);
|
|
512
|
-
const port = 0 === rules.length
|
|
513
|
-
? undefined
|
|
514
|
-
: await sessionPerturbationPort(deps.realInput, leasableAppUrl(deps, sessionId));
|
|
515
|
-
if (port === undefined)
|
|
516
|
-
return replayAndLearn(deps, args);
|
|
517
|
-
try {
|
|
518
|
-
await port.slow(rules);
|
|
519
|
-
const replay = await replayNamedFlow(deps, args);
|
|
520
|
-
return { ...replay, perturbed: rules };
|
|
521
|
-
}
|
|
522
|
-
finally {
|
|
523
|
-
await port.clear().catch(() => undefined);
|
|
524
|
-
}
|
|
525
|
-
},
|
|
513
|
+
handler: (deps, args) => replayOneFlow(deps, args, leasableAppUrl(deps, asString(args['sessionId']))),
|
|
526
514
|
},
|
|
527
515
|
{
|
|
528
516
|
name: ReticleTool.FLOW_VERIFY,
|
|
@@ -532,6 +520,7 @@ export const FLOW_TOOLS = [
|
|
|
532
520
|
'whatChanged, whereInSource, nextAction }] } plus `flaky` (flows seen to pass AND fail on unchanged code) — passing flows are counted, only failures carry ' +
|
|
533
521
|
'detail (the actionable fix). One call replaces N hand-driven replays.',
|
|
534
522
|
inputSchema: {
|
|
523
|
+
[CALL_SECRETS_ARG]: callSecretsArg,
|
|
535
524
|
names: z
|
|
536
525
|
.array(z.string())
|
|
537
526
|
.optional()
|
|
@@ -543,6 +532,7 @@ export const FLOW_TOOLS = [
|
|
|
543
532
|
parallel: workerCountSchema
|
|
544
533
|
.optional()
|
|
545
534
|
.describe('Run this many flows at once, each in its own isolated leased browser context (needs the browser pool). Clamped to the pool capacity and the flow count. Omit for the sequential single-tab run.'),
|
|
535
|
+
confirmDangerous: confirmDangerousArg('this run of the suite'),
|
|
546
536
|
sessionId: z
|
|
547
537
|
.string()
|
|
548
538
|
.optional()
|
|
@@ -550,10 +540,12 @@ export const FLOW_TOOLS = [
|
|
|
550
540
|
},
|
|
551
541
|
outputSchema: {
|
|
552
542
|
status: z.string().describe('pass | fail'),
|
|
543
|
+
runId: z.string().optional().describe('The run this suite was written down as.'),
|
|
553
544
|
total: z.number(),
|
|
554
545
|
passed: z.number(),
|
|
555
546
|
failed: z.number(),
|
|
556
547
|
summary: z.string(),
|
|
548
|
+
[RESULT_FIELD]: z.string().optional(),
|
|
557
549
|
failures: z.array(z.unknown()),
|
|
558
550
|
isolation: z
|
|
559
551
|
.string()
|
|
@@ -595,8 +587,10 @@ export const FLOW_TOOLS = [
|
|
|
595
587
|
// feedback ask here or a validating profile strips it off the suite verdict.
|
|
596
588
|
feedback_prompt: z.unknown().optional(),
|
|
597
589
|
},
|
|
598
|
-
|
|
590
|
+
// The run id is minted first, so each replayed step's screenshot is filed under the run.
|
|
591
|
+
handler: (deps, args) => withShotRun(defaultRunId(), async () => {
|
|
599
592
|
const sessionId = asString(args['sessionId']);
|
|
593
|
+
const confirmed = true === args['confirmDangerous'] ? { confirmDangerous: true } : {};
|
|
600
594
|
// "Replay all" means all of THIS app's flows (+ legacy), not every project's on a shared daemon.
|
|
601
595
|
const target = sessionTarget(deps, sessionId);
|
|
602
596
|
const { projectId } = target;
|
|
@@ -652,7 +646,11 @@ export const FLOW_TOOLS = [
|
|
|
652
646
|
const start = deps.now();
|
|
653
647
|
const lease = await acquireLeasedSession(pool, deps.sessions, appUrl, projectId, seed);
|
|
654
648
|
try {
|
|
655
|
-
const replay = await replayAndLearn(deps, {
|
|
649
|
+
const replay = await replayAndLearn(deps, {
|
|
650
|
+
flowName,
|
|
651
|
+
sessionId: lease.sessionId,
|
|
652
|
+
...confirmed,
|
|
653
|
+
});
|
|
656
654
|
return { replay, durationMs: deps.now() - start };
|
|
657
655
|
}
|
|
658
656
|
finally {
|
|
@@ -673,12 +671,14 @@ export const FLOW_TOOLS = [
|
|
|
673
671
|
durationMs: o.ok && o.value !== undefined ? o.value.durationMs : 0,
|
|
674
672
|
}));
|
|
675
673
|
const flaky = await recordSuiteFlakes(deps.fs, rootForTarget(deps, target), parallelRuns);
|
|
676
|
-
await persistAndSyncVerificationRun(deps, timed, target);
|
|
674
|
+
const runId = await persistAndSyncVerificationRun(deps, timed, target);
|
|
677
675
|
const verdict = buildSuiteVerdict(parallelRuns, selected.knownRoutes, SuiteIsolation.PER_FLOW_LEASE);
|
|
678
676
|
return {
|
|
679
677
|
...verdict,
|
|
678
|
+
...(runId === undefined ? {} : { runId }),
|
|
680
679
|
...(flaky.length > 0 ? { flaky: [...flaky] } : {}),
|
|
681
680
|
...heldBack,
|
|
681
|
+
...resultField(() => suiteResult(rootForTarget(deps, target), verdict, timed, runId)),
|
|
682
682
|
};
|
|
683
683
|
}
|
|
684
684
|
// The flow FILE travels with each replay so the verdict can tell a green that verified
|
|
@@ -696,7 +696,7 @@ export const FLOW_TOOLS = [
|
|
|
696
696
|
// (1 of 2 flows). Restoring two thirds of a session is worse than restoring none.
|
|
697
697
|
for (const flowName of requested) {
|
|
698
698
|
const start = deps.now();
|
|
699
|
-
const replay = await replayAndLearn(deps, { flowName, sessionId });
|
|
699
|
+
const replay = await replayAndLearn(deps, { flowName, sessionId, ...confirmed });
|
|
700
700
|
const loaded = await flowsForSession(deps, target)
|
|
701
701
|
.flows.load(flowName, projectId)
|
|
702
702
|
.catch(() => null);
|
|
@@ -714,17 +714,19 @@ export const FLOW_TOOLS = [
|
|
|
714
714
|
// one an agent uses was the blind half.
|
|
715
715
|
const flaky = await recordSuiteFlakes(deps.fs, rootForTarget(deps, target), runs);
|
|
716
716
|
// Emit the consolidated run artifact (Runs tab) + best-effort cloud push. Never blocks the verdict.
|
|
717
|
-
await persistAndSyncVerificationRun(deps, timed, target);
|
|
717
|
+
const runId = await persistAndSyncVerificationRun(deps, timed, target);
|
|
718
718
|
const verdict = buildSuiteVerdict(runs, selected.knownRoutes, SuiteIsolation.SHARED_SESSION);
|
|
719
719
|
// A flow that has both passed and failed on UNCHANGED code is a different thing from a
|
|
720
720
|
// regression, and an agent that cannot tell them apart either chases a ghost or ignores a real
|
|
721
721
|
// break. Present only when the ledger has seen enough runs to say so.
|
|
722
722
|
return {
|
|
723
723
|
...verdict,
|
|
724
|
+
...(runId === undefined ? {} : { runId }),
|
|
724
725
|
...(flaky.length > 0 ? { flaky: [...flaky] } : {}),
|
|
725
726
|
...heldBack,
|
|
727
|
+
...resultField(() => suiteResult(rootForTarget(deps, target), verdict, timed, runId)),
|
|
726
728
|
};
|
|
727
|
-
},
|
|
729
|
+
}),
|
|
728
730
|
},
|
|
729
731
|
{
|
|
730
732
|
name: ReticleTool.FLOW_SAVE_RECORDED,
|
|
@@ -819,10 +821,7 @@ export const FLOW_TOOLS = [
|
|
|
819
821
|
.describe('Alias for `flowName` (the name reticle_annotate uses).'),
|
|
820
822
|
flowName: z.string().describe('Flow file name to heal (from reticle_flow{action:"list"}).'),
|
|
821
823
|
apply: z.boolean().optional(),
|
|
822
|
-
confirmDangerous:
|
|
823
|
-
.boolean()
|
|
824
|
-
.optional()
|
|
825
|
-
.describe('Set true to allow destructive controls during this heal replay only.'),
|
|
824
|
+
confirmDangerous: confirmDangerousArg('this heal replay'),
|
|
826
825
|
sessionId: z
|
|
827
826
|
.string()
|
|
828
827
|
.optional()
|
|
@@ -11,6 +11,14 @@ export declare function anchorForStep(args: Record<string, unknown>): {
|
|
|
11
11
|
anchor: FlowAnchor;
|
|
12
12
|
degraded: boolean;
|
|
13
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* The recorded steps as they may be SHOWN: every credential fill carries the placeholder.
|
|
16
|
+
*
|
|
17
|
+
* The same rule the saved flow is written by, applied to what a tool hands back. `record stop`
|
|
18
|
+
* returned the compiled program verbatim, so the password a saved flow never contained went into
|
|
19
|
+
* the agent's transcript instead. The store keeps the real value — an in-session replay types it.
|
|
20
|
+
*/
|
|
21
|
+
export declare function redactRecordedSteps(steps: readonly RecordedStep[]): RecordedStep[];
|
|
14
22
|
/**
|
|
15
23
|
* What the anchor CALLS the field it points at.
|
|
16
24
|
*
|
|
@@ -58,7 +66,14 @@ export interface FlowAnnotations {
|
|
|
58
66
|
/** Persists anchored flows to .reticle/flows/<name>.json. Filesystem + clock are injected. */
|
|
59
67
|
export declare class FlowStore {
|
|
60
68
|
#private;
|
|
61
|
-
|
|
69
|
+
/**
|
|
70
|
+
* `onWrote` is told after a save lands, so cloud sync cycles on a new flow the way it does on a
|
|
71
|
+
* new run (`RunStore` takes the same callback). Without it a flow saved with no run behind it
|
|
72
|
+
* waited for the timer, and a daemon that exited first never sent it.
|
|
73
|
+
*/
|
|
74
|
+
constructor(fs: FileSystemPort, root: string, clock: Clock, opts?: {
|
|
75
|
+
onWrote?: () => void;
|
|
76
|
+
});
|
|
62
77
|
/**
|
|
63
78
|
* Convert a CompiledProgram (testid-normalized) into an anchored, on-disk flow + write it.
|
|
64
79
|
* Optionally fold structured annotations (per-step expect, dynamic[], success) onto
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { asFlowName, asProjectId, } from '@reticlehq/core';
|
|
2
|
-
import { REDACTED_FILL } from './fields/flow-secret-field.js';
|
|
2
|
+
import { REDACTED_FILL, SECRET_NAME_ARG, secretEnvKey } from './fields/flow-secret-field.js';
|
|
3
3
|
export { REDACTED_FILL, secretEnvKey } from './fields/flow-secret-field.js';
|
|
4
4
|
import { safeProjectId } from './flow-result.js';
|
|
5
5
|
import { changeInPlace } from './narrow-write.js';
|
|
6
6
|
import { AnchorKind, DEGRADED_ANCHOR_ROLE, FLOW_FILE_VERSION, flowFileVersionFor, FlowErrorCode, FlowFileSchema, FlowStepTool, QueryBy, defaultIsSensitiveKey, } from '@reticlehq/core';
|
|
7
|
-
import { ReticleTool } from '@reticlehq/core';
|
|
7
|
+
import { ReticleTool, flowJsonReplacer } from '@reticlehq/core';
|
|
8
8
|
import { asRecord, asString } from '@reticlehq/core';
|
|
9
9
|
import { applyHealChanges } from './heal.js';
|
|
10
10
|
import { withLearnedSources } from './learned-sources.js';
|
|
11
11
|
import { flowIntentGap, linkFlowIntent } from './flow-intent.js';
|
|
12
|
-
import { journeyFingerprint, journeyName, mergeJourney, routeClaims } from './flow-journey.js';
|
|
12
|
+
import { journeyFingerprint, journeyName, mergeJourney, routeClaims, withinJourney, } from './flow-journey.js';
|
|
13
13
|
import { IntentStore } from '../../memory/intent/intent-store.js';
|
|
14
14
|
import { flowDir, flowParentDir, flowPath, reticleDirPaths, isValidFlowName, } from '../../memory/project/dir/reticle-dir.js';
|
|
15
15
|
import { describeFlowZodFailure, parseFlowFileText } from './flow-expect-grammar.js';
|
|
@@ -130,7 +130,32 @@ function redactSecretFill(anchor, args) {
|
|
|
130
130
|
const field = anchorFieldName(anchor);
|
|
131
131
|
if (field === undefined || !defaultIsSensitiveKey(field))
|
|
132
132
|
return args;
|
|
133
|
-
|
|
133
|
+
// The variable that supplies it, beside the placeholder: the file alone says what to set.
|
|
134
|
+
return { ...args, value: REDACTED_FILL, [SECRET_NAME_ARG]: secretEnvKey(field) };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The recorded steps as they may be SHOWN: every credential fill carries the placeholder.
|
|
138
|
+
*
|
|
139
|
+
* The same rule the saved flow is written by, applied to what a tool hands back. `record stop`
|
|
140
|
+
* returned the compiled program verbatim, so the password a saved flow never contained went into
|
|
141
|
+
* the agent's transcript instead. The store keeps the real value — an in-session replay types it.
|
|
142
|
+
*/
|
|
143
|
+
export function redactRecordedSteps(steps) {
|
|
144
|
+
return steps.map((step) => {
|
|
145
|
+
if (step.tool === ReticleTool.ACT_SEQUENCE && Array.isArray(step.args['steps'])) {
|
|
146
|
+
const subs = step.args['steps'].map((raw) => redactNormalizedArgs(asRecord(raw)));
|
|
147
|
+
return { ...step, args: { ...step.args, steps: subs } };
|
|
148
|
+
}
|
|
149
|
+
return { ...step, args: redactNormalizedArgs(step.args) };
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/** One normalized act's args with its inner fill `args` redacted by the anchor it would save as. */
|
|
153
|
+
function redactNormalizedArgs(normalized) {
|
|
154
|
+
const inner = normalized['args'];
|
|
155
|
+
if ('object' !== typeof inner || null === inner)
|
|
156
|
+
return normalized;
|
|
157
|
+
const redacted = redactSecretFill(anchorForStep(normalized).anchor, asRecord(inner));
|
|
158
|
+
return redacted === inner ? normalized : { ...normalized, args: redacted };
|
|
134
159
|
}
|
|
135
160
|
/**
|
|
136
161
|
* What the anchor CALLS the field it points at.
|
|
@@ -169,6 +194,8 @@ function buildStep(tool, anchor, action, args, degraded) {
|
|
|
169
194
|
*/
|
|
170
195
|
export function recordedStepToFlowStep(step) {
|
|
171
196
|
const out = anchoredStep(step);
|
|
197
|
+
if (step.timeoutMs !== undefined)
|
|
198
|
+
out.timeoutMs = step.timeoutMs;
|
|
172
199
|
if (step.page !== undefined)
|
|
173
200
|
out.page = step.page;
|
|
174
201
|
if (step.endPage !== undefined && step.endPage !== step.page)
|
|
@@ -238,10 +265,17 @@ export class FlowStore {
|
|
|
238
265
|
#fs;
|
|
239
266
|
#root;
|
|
240
267
|
#clock;
|
|
241
|
-
|
|
268
|
+
#onWrote;
|
|
269
|
+
/**
|
|
270
|
+
* `onWrote` is told after a save lands, so cloud sync cycles on a new flow the way it does on a
|
|
271
|
+
* new run (`RunStore` takes the same callback). Without it a flow saved with no run behind it
|
|
272
|
+
* waited for the timer, and a daemon that exited first never sent it.
|
|
273
|
+
*/
|
|
274
|
+
constructor(fs, root, clock, opts = {}) {
|
|
242
275
|
this.#fs = fs;
|
|
243
276
|
this.#root = root;
|
|
244
277
|
this.#clock = clock;
|
|
278
|
+
this.#onWrote = opts.onWrote;
|
|
245
279
|
}
|
|
246
280
|
/**
|
|
247
281
|
* The single byte-stable flow serializer: 2-space indent + one trailing newline. save,
|
|
@@ -250,7 +284,7 @@ export class FlowStore {
|
|
|
250
284
|
*/
|
|
251
285
|
#serialize(flow) {
|
|
252
286
|
const stamped = { ...flow, version: flowFileVersionFor(flow) };
|
|
253
|
-
return `${JSON.stringify(stamped,
|
|
287
|
+
return `${JSON.stringify(stamped, flowJsonReplacer, JSON_INDENT)}\n`;
|
|
254
288
|
}
|
|
255
289
|
/**
|
|
256
290
|
* Register the flow's business goal in the intent ledger and stamp the row's id onto the flow.
|
|
@@ -324,6 +358,7 @@ export class FlowStore {
|
|
|
324
358
|
const flow = await this.#linkIntent(base);
|
|
325
359
|
await this.#fs.mkdir(flowParentDir(this.#root, program.name, pid));
|
|
326
360
|
await this.#fs.writeFile(flowPath(this.#root, program.name, pid), this.#serialize(flow));
|
|
361
|
+
this.#onWrote?.();
|
|
327
362
|
return { ok: true, value: this.#summary(flow) };
|
|
328
363
|
}
|
|
329
364
|
/**
|
|
@@ -340,19 +375,40 @@ export class FlowStore {
|
|
|
340
375
|
const pid = safeProjectId(projectId);
|
|
341
376
|
const fresh = this.#build(program, undefined, pid);
|
|
342
377
|
const saved = [];
|
|
343
|
-
|
|
378
|
+
const freshPrint = journeyFingerprint(fresh);
|
|
379
|
+
for (const name of await this.list(pid)) {
|
|
344
380
|
const loaded = await this.load(name, pid);
|
|
345
|
-
if (loaded.ok)
|
|
381
|
+
if (!loaded.ok)
|
|
382
|
+
continue;
|
|
383
|
+
if (name.startsWith(prefix))
|
|
346
384
|
saved.push(loaded.value);
|
|
385
|
+
// The agent already saved this journey under its own name: one journey, one flow. A web drive
|
|
386
|
+
// saved its named flow and an automatic `drive-saved-<email>` beside it, every time.
|
|
387
|
+
else if (journeyFingerprint(loaded.value) === freshPrint) {
|
|
388
|
+
return { ok: true, value: this.#summary(loaded.value) };
|
|
389
|
+
}
|
|
347
390
|
}
|
|
348
391
|
const byPrint = new Map();
|
|
349
392
|
for (const flow of saved) {
|
|
350
393
|
const print = journeyFingerprint(flow);
|
|
351
394
|
byPrint.set(print, [...(byPrint.get(print) ?? []), flow]);
|
|
352
395
|
}
|
|
353
|
-
const print =
|
|
396
|
+
const print = freshPrint;
|
|
354
397
|
const taken = new Map(saved.map((flow) => [flow.name, journeyFingerprint(flow)]));
|
|
355
|
-
|
|
398
|
+
// The same name holding this journey driven with a step more or less: one file, the fuller drive.
|
|
399
|
+
const same = saved.find((flow) => flow.name === fresh.name && taken.get(flow.name) !== print);
|
|
400
|
+
if (same !== undefined && withinJourney(same, fresh))
|
|
401
|
+
return { ok: true, value: this.#summary(same) };
|
|
402
|
+
const extended = same !== undefined && withinJourney(fresh, same);
|
|
403
|
+
if (extended)
|
|
404
|
+
taken.delete(fresh.name);
|
|
405
|
+
const named = {
|
|
406
|
+
...fresh,
|
|
407
|
+
...(extended && fresh.intent === undefined && same.intent !== undefined
|
|
408
|
+
? { intent: same.intent }
|
|
409
|
+
: {}),
|
|
410
|
+
name: journeyName(fresh.name, print, taken),
|
|
411
|
+
};
|
|
356
412
|
byPrint.set(print, [...(byPrint.get(print) ?? []), named]);
|
|
357
413
|
let result = named;
|
|
358
414
|
for (const [groupPrint, group] of byPrint) {
|
|
@@ -370,6 +426,7 @@ export class FlowStore {
|
|
|
370
426
|
if (groupPrint === print)
|
|
371
427
|
result = merged;
|
|
372
428
|
}
|
|
429
|
+
this.#onWrote?.();
|
|
373
430
|
return { ok: true, value: this.#summary(result) };
|
|
374
431
|
}
|
|
375
432
|
/** Write a flow where it already lives, or into its project's directory when it is new. */
|
|
@@ -404,6 +461,7 @@ export class FlowStore {
|
|
|
404
461
|
const valid = await this.#linkIntent(parsed.data);
|
|
405
462
|
await this.#fs.mkdir(flowParentDir(this.#root, asFlowName(valid.name), pid));
|
|
406
463
|
await this.#fs.writeFile(flowPath(this.#root, asFlowName(valid.name), pid), this.#serialize(valid));
|
|
464
|
+
this.#onWrote?.();
|
|
407
465
|
return { ok: true, value: this.#summary(valid) };
|
|
408
466
|
}
|
|
409
467
|
/**
|
|
@@ -422,6 +480,7 @@ export class FlowStore {
|
|
|
422
480
|
resolvePath: (n, p) => this.#resolveReadPath(asFlowName(n), p),
|
|
423
481
|
write: (path, contents) => this.#fs.writeFile(path, contents),
|
|
424
482
|
serialize: (flow) => this.#serialize(flow),
|
|
483
|
+
readRaw: (path) => this.#fs.readFile(path),
|
|
425
484
|
}, name, projectId, change);
|
|
426
485
|
}
|
|
427
486
|
/** Write back only what a replay LEARNED. See `#changeInPlace` for why it is not `saveFlow`. */
|