@reticlehq/server 3.7.0 → 3.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +59 -68
- package/bin/reticle.js +9 -2
- package/dist/command/cli/adhoc-suite.js +1 -1
- package/dist/command/cli/adhoc-verdict.d.ts +12 -0
- package/dist/command/cli/adhoc-verdict.js +62 -4
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +5 -1
- package/dist/command/cli/auth/cloud-session.d.ts +11 -19
- package/dist/command/cli/auth/cloud-session.js +23 -0
- package/dist/command/cli/auth/device-flow.d.ts +3 -37
- package/dist/command/cli/cli-doctor.js +66 -21
- package/dist/command/cli/cli-flow-commands.js +53 -11
- package/dist/command/cli/cli-kill.d.ts +8 -0
- package/dist/command/cli/cli-kill.js +43 -3
- package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
- package/dist/command/cli/cli-parse-feedback.js +13 -1
- package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
- package/dist/command/cli/cli-parse-grammar.js +1 -6
- package/dist/command/cli/cli-parse-serve.d.ts +24 -0
- package/dist/command/cli/cli-parse-serve.js +124 -0
- package/dist/command/cli/cli-parse.d.ts +12 -11
- package/dist/command/cli/cli-parse.js +100 -123
- package/dist/command/cli/cli-usage.d.ts +0 -11
- package/dist/command/cli/cli-usage.js +43 -16
- package/dist/command/cli/cli-verify.d.ts +1 -1
- package/dist/command/cli/cli-verify.js +29 -14
- package/dist/command/cli/cloud-cli.js +27 -9
- package/dist/command/cli/cloud-kit.js +3 -3
- package/dist/command/cli/cloud-link.d.ts +1 -20
- package/dist/command/cli/cloud-link.js +2 -0
- package/dist/command/cli/cloud-login.d.ts +6 -2
- package/dist/command/cli/cloud-login.js +13 -41
- package/dist/command/cli/config/checkout.d.ts +10 -0
- package/dist/command/cli/config/checkout.js +78 -0
- package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
- package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
- package/dist/command/cli/doctor/doctor-rows.js +4 -0
- package/dist/command/cli/drive/drive-attach.d.ts +5 -0
- package/dist/command/cli/drive/drive-attach.js +21 -1
- package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
- package/dist/command/cli/hook/codex-transcript.js +224 -0
- package/dist/command/cli/hook/episode-structure.d.ts +24 -0
- package/dist/command/cli/hook/episode-structure.js +138 -0
- package/dist/command/cli/hook/hook-command.d.ts +9 -0
- package/dist/command/cli/hook/hook-command.js +211 -0
- package/dist/command/cli/hook/hook-fast.d.ts +31 -0
- package/dist/command/cli/hook/hook-fast.js +136 -0
- package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
- package/dist/command/cli/hook/prompt-hook.js +199 -0
- package/dist/command/cli/hook/tool-hook.d.ts +21 -0
- package/dist/command/cli/hook/tool-hook.js +259 -0
- package/dist/command/cli/launch/cli-launch.d.ts +2 -0
- package/dist/command/cli/launch/cli-launch.js +22 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
- package/dist/command/cli/mcp-command.d.ts +9 -0
- package/dist/command/cli/mcp-command.js +127 -41
- package/dist/command/cli/open-navigate.d.ts +43 -0
- package/dist/command/cli/open-navigate.js +85 -0
- package/dist/command/cli/ports/port-holder.d.ts +16 -4
- package/dist/command/cli/ports/port-holder.js +58 -12
- package/dist/command/cli/ports/resolve/cli-port.js +18 -2
- package/dist/command/cli/project-name.d.ts +1 -7
- package/dist/command/cli/project-name.js +1 -0
- package/dist/command/cli/report-command.d.ts +8 -2
- package/dist/command/cli/report-command.js +95 -18
- package/dist/command/cli/status-fields.d.ts +9 -2
- package/dist/command/cli/status-fields.js +148 -4
- package/dist/command/cli/try-command.d.ts +3 -4
- package/dist/command/cli/try-command.js +6 -11
- package/dist/command/cli/verify-results.d.ts +4 -1
- package/dist/command/cli/verify-results.js +3 -1
- package/dist/command/cli.d.ts +1 -7
- package/dist/command/cli.js +79 -160
- package/dist/command/daemon/daemon-resilience.d.ts +6 -1
- package/dist/command/daemon/daemon-resilience.js +31 -18
- package/dist/command/daemon/daemon.d.ts +11 -0
- package/dist/command/daemon/daemon.js +70 -2
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
- package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
- package/dist/command/daemon/wake-decision.js +4 -2
- package/dist/command/daemon/win32-escape.d.ts +32 -0
- package/dist/command/daemon/win32-escape.js +119 -0
- package/dist/command/setup/agent-configs.d.ts +9 -0
- package/dist/command/setup/agent-configs.js +9 -0
- package/dist/command/setup/auto-approve.d.ts +10 -3
- package/dist/command/setup/auto-approve.js +51 -3
- package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
- package/dist/command/setup/bringup/dev-server-wait.js +5 -1
- package/dist/command/setup/bringup/ensure-daemon.js +4 -7
- package/dist/command/setup/init/init-host.js +6 -0
- package/dist/command/setup/init/init-port.js +5 -4
- package/dist/command/setup/init/init-runtime.js +7 -1
- package/dist/command/setup/node-effects.d.ts +8 -0
- package/dist/command/setup/node-effects.js +36 -4
- package/dist/command/setup/probe/dev-port.d.ts +26 -0
- package/dist/command/setup/probe/dev-port.js +117 -0
- package/dist/command/setup/probe/page-probe.d.ts +1 -1
- package/dist/command/setup/probe/page-probe.js +11 -3
- package/dist/command/setup/remaining-steps.d.ts +0 -7
- package/dist/command/setup/remaining-steps.js +3 -2
- package/dist/command/setup/run-setup.d.ts +11 -0
- package/dist/command/setup/run-setup.js +33 -5
- package/dist/command/setup/setup-command.d.ts +2 -0
- package/dist/command/setup/setup-command.js +22 -4
- package/dist/command/update/updater.d.ts +1 -6
- package/dist/command/update/updater.js +4 -5
- package/dist/command/update/version-seen.d.ts +24 -0
- package/dist/command/update/version-seen.js +65 -0
- package/dist/command/version/peer-announce.d.ts +9 -1
- package/dist/command/version/peer-announce.js +25 -2
- package/dist/command/version/sdk-fix.d.ts +5 -6
- package/dist/command/version/sdk-fix.js +17 -32
- package/dist/command/version/version-skew.d.ts +16 -1
- package/dist/command/version/version-skew.js +84 -10
- package/dist/features/crawl/crawl-tools.js +2 -2
- package/dist/features/crawl/crawl.js +2 -0
- package/dist/features/exhaust/ledger.d.ts +15 -96
- package/dist/features/exhaust/ledger.js +3 -3
- package/dist/features/harness/drive-runs.d.ts +28 -4
- package/dist/features/harness/drive-runs.js +99 -7
- package/dist/features/harness/drivers.d.ts +1 -1
- package/dist/features/harness/drivers.js +1 -1
- package/dist/features/harness/harness.d.ts +5 -0
- package/dist/features/harness/harness.js +24 -12
- package/dist/features/harness/platform/platform-drives.d.ts +7 -1
- package/dist/features/harness/platform/platform-drives.js +12 -7
- package/dist/features/harness/platform/refusal.d.ts +1 -1
- package/dist/features/harness/platform/refusal.js +4 -4
- package/dist/features/harness/platform/remote-drive.js +70 -28
- package/dist/features/harness/platform/server-driver.js +22 -1
- package/dist/features/harness/platform-config.d.ts +1 -10
- package/dist/features/harness/platform-config.js +0 -20
- package/dist/features/license/license.d.ts +2 -14
- package/dist/features/visual/step-shots.d.ts +33 -1
- package/dist/features/visual/step-shots.js +155 -1
- package/dist/features/visual/visual-tools.js +12 -4
- package/dist/hooks/coding-agents.d.ts +6 -0
- package/dist/hooks/coding-agents.js +24 -3
- package/dist/hooks/episode-stamp.d.ts +32 -0
- package/dist/hooks/episode-stamp.js +61 -0
- package/dist/hooks/hook-commands.js +19 -9
- package/dist/index.d.ts +5 -1
- package/dist/index.js +66 -24
- package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
- package/dist/judgement/app-graph/journal-steps.js +92 -0
- package/dist/judgement/capsule/capsule-store.d.ts +2 -39
- package/dist/judgement/domain/domain-model.js +1 -10
- package/dist/judgement/domain/domain-tools.js +4 -2
- package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
- package/dist/judgement/runs/artifact/run-store.js +153 -28
- package/dist/judgement/runs/default-run-id.d.ts +3 -1
- package/dist/judgement/runs/default-run-id.js +15 -3
- package/dist/judgement/runs/drive-run.d.ts +3 -3
- package/dist/judgement/runs/drive-run.js +11 -7
- package/dist/judgement/runs/run-ledger.d.ts +21 -0
- package/dist/judgement/runs/run-ledger.js +143 -0
- package/dist/judgement/runs/runner-port.d.ts +1 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +4 -3
- package/dist/judgement/runs/verification-sync.js +27 -5
- package/dist/language/flows/affected-tools.js +2 -1
- package/dist/language/flows/annotate-notes/annotate.js +8 -3
- package/dist/language/flows/annotate-tools.js +1 -1
- package/dist/language/flows/change/affected.d.ts +8 -0
- package/dist/language/flows/change/affected.js +20 -7
- package/dist/language/flows/decision.js +19 -4
- package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
- package/dist/language/flows/fields/flow-secret-field.js +67 -5
- package/dist/language/flows/flow-anchor.d.ts +5 -0
- package/dist/language/flows/flow-anchor.js +4 -0
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +9 -0
- package/dist/language/flows/flow-expect-grammar.js +15 -10
- package/dist/language/flows/flow-intent.js +6 -1
- package/dist/language/flows/flow-journey.d.ts +8 -0
- package/dist/language/flows/flow-journey.js +13 -0
- package/dist/language/flows/flow-lease.d.ts +27 -0
- package/dist/language/flows/flow-lease.js +59 -0
- package/dist/language/flows/flow-replay-run.d.ts +1 -87
- package/dist/language/flows/flow-replay-run.js +111 -310
- package/dist/language/flows/flow-replay.js +21 -19
- package/dist/language/flows/flow-replayable.d.ts +38 -0
- package/dist/language/flows/flow-replayable.js +179 -0
- package/dist/language/flows/flow-start-path.d.ts +108 -0
- package/dist/language/flows/flow-start-path.js +313 -0
- package/dist/language/flows/flow-step-runners.d.ts +23 -2
- package/dist/language/flows/flow-step-runners.js +191 -32
- package/dist/language/flows/flow-store-for-session.d.ts +8 -1
- package/dist/language/flows/flow-store-for-session.js +6 -0
- package/dist/language/flows/flow-tools.d.ts +2 -23
- package/dist/language/flows/flow-tools.js +63 -113
- package/dist/language/flows/flows.d.ts +4 -6
- package/dist/language/flows/flows.js +90 -15
- package/dist/language/flows/heal-run.d.ts +10 -4
- package/dist/language/flows/heal-run.js +26 -9
- package/dist/language/flows/recording/flake.d.ts +3 -27
- package/dist/language/flows/recording/flake.js +1 -1
- package/dist/language/flows/recording/recording-backtrack.js +1 -4
- package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
- package/dist/language/flows/recording/tape/recordings.js +9 -3
- package/dist/language/flows/replay.d.ts +25 -5
- package/dist/language/flows/replay.js +83 -16
- package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
- package/dist/language/flows/suite/coverage.d.ts +9 -0
- package/dist/language/flows/suite/coverage.js +12 -1
- package/dist/language/flows/suite-selection.d.ts +25 -0
- package/dist/language/flows/suite-selection.js +41 -9
- package/dist/machine/git-tracks.d.ts +6 -0
- package/dist/machine/git-tracks.js +36 -0
- package/dist/memory/cloud/background-sync.d.ts +25 -0
- package/dist/memory/cloud/background-sync.js +79 -0
- package/dist/memory/cloud/cloud-config.d.ts +12 -1
- package/dist/memory/cloud/cloud-config.js +39 -13
- package/dist/memory/cloud/cloud-sync.d.ts +3 -24
- package/dist/memory/cloud/cloud-sync.js +5 -2
- package/dist/memory/cloud/harness-config.d.ts +0 -7
- package/dist/memory/cloud/memory-scope.d.ts +19 -0
- package/dist/memory/cloud/memory-scope.js +48 -0
- package/dist/memory/cloud/sync-answer.d.ts +43 -0
- package/dist/memory/cloud/sync-answer.js +42 -0
- package/dist/memory/cloud/sync-cycle.d.ts +40 -10
- package/dist/memory/cloud/sync-cycle.js +97 -144
- package/dist/memory/cloud/sync-daemon.d.ts +50 -3
- package/dist/memory/cloud/sync-daemon.js +473 -83
- package/dist/memory/cloud/sync-describe.d.ts +28 -0
- package/dist/memory/cloud/sync-describe.js +92 -0
- package/dist/memory/cloud/sync-disk.d.ts +9 -1
- package/dist/memory/cloud/sync-disk.js +137 -33
- package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
- package/dist/memory/cloud/sync-flow-versions.js +42 -0
- package/dist/memory/impact/impact-store.js +32 -15
- package/dist/memory/intent/intent-shard.d.ts +41 -266
- package/dist/memory/intent/intent-tools.js +20 -61
- package/dist/memory/intent/record-request.d.ts +27 -0
- package/dist/memory/intent/record-request.js +88 -0
- package/dist/memory/intent/settled-words.js +9 -1
- package/dist/memory/journal/drive-flow.d.ts +3 -0
- package/dist/memory/journal/drive-flow.js +11 -41
- package/dist/memory/journal/envelope-store.js +1 -1
- package/dist/memory/journal/envelope.d.ts +6 -154
- package/dist/memory/journal/episode-log.d.ts +107 -0
- package/dist/memory/journal/episode-log.js +302 -0
- package/dist/memory/journal/journal-recorder.d.ts +7 -0
- package/dist/memory/journal/journal-recorder.js +22 -9
- package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
- package/dist/memory/journal/on-disk/ambient-file.js +1 -1
- package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
- package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
- package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
- package/dist/memory/journal/self-observation.js +3 -1
- package/dist/memory/journal/session-end.js +23 -9
- package/dist/memory/journal/session-journal.js +39 -20
- package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
- package/dist/memory/project/artifact-root-resolver.js +68 -23
- package/dist/memory/project/artifact-root.d.ts +17 -3
- package/dist/memory/project/artifact-root.js +47 -9
- package/dist/memory/project/fs/fs-port.d.ts +5 -0
- package/dist/memory/project/fs/fs-port.js +13 -0
- package/dist/memory/project/learned-routes.d.ts +3 -4
- package/dist/memory/project/learned-routes.js +3 -11
- package/dist/memory/project/link-directory.js +5 -2
- package/dist/memory/project/root-claims.d.ts +3 -1
- package/dist/memory/project/root-claims.js +41 -7
- package/dist/memory/project/session-root.d.ts +1 -1
- package/dist/memory/project/session-root.js +1 -15
- package/dist/memory/project/sync-status.js +5 -6
- package/dist/memory/recall/memory-tools.js +2 -2
- package/dist/memory/recall/platform-memory.d.ts +3 -1
- package/dist/memory/recall/platform-memory.js +9 -1
- package/dist/memory/recall/project-memory.js +15 -19
- package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
- package/dist/portal/bridge/auth-failure-reason.js +19 -0
- package/dist/portal/bridge/bridge.d.ts +19 -4
- package/dist/portal/bridge/bridge.js +150 -177
- package/dist/portal/bridge/harness-request.d.ts +15 -0
- package/dist/portal/bridge/harness-request.js +19 -0
- package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
- package/dist/portal/bridge/origin/origin-follow.js +110 -0
- package/dist/portal/bridge/pairing-token.d.ts +6 -0
- package/dist/portal/bridge/pairing-token.js +47 -16
- package/dist/portal/bridge/protocol-skew.d.ts +27 -2
- package/dist/portal/bridge/protocol-skew.js +66 -2
- package/dist/portal/bridge/session-nonces.d.ts +46 -0
- package/dist/portal/bridge/session-nonces.js +72 -0
- package/dist/portal/input/viewport-tools.d.ts +31 -0
- package/dist/portal/input/viewport-tools.js +106 -15
- package/dist/portal/pool/bounded-close.d.ts +23 -0
- package/dist/portal/pool/bounded-close.js +38 -0
- package/dist/portal/pool/browser-pool.d.ts +44 -39
- package/dist/portal/pool/browser-pool.js +247 -95
- package/dist/portal/pool/context-permissions.d.ts +9 -1
- package/dist/portal/pool/context-permissions.js +26 -0
- package/dist/portal/pool/lease-emulation.d.ts +37 -0
- package/dist/portal/pool/lease-emulation.js +29 -0
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +74 -7
- package/dist/portal/pool/pool-contract.d.ts +23 -1
- package/dist/portal/pool/pool-lease.d.ts +128 -0
- package/dist/portal/pool/pool-lease.js +49 -0
- package/dist/portal/pool/zero-install.d.ts +8 -1
- package/dist/portal/pool/zero-install.js +24 -2
- package/dist/portal/production/production-activation.d.ts +136 -0
- package/dist/portal/production/production-activation.js +173 -0
- package/dist/portal/production/production-drive.d.ts +52 -0
- package/dist/portal/production/production-drive.js +301 -0
- package/dist/portal/production/production-hello.d.ts +23 -0
- package/dist/portal/production/production-hello.js +23 -0
- package/dist/portal/realm/web-realm.js +42 -15
- package/dist/portal/session/control-envelope.d.ts +1 -1
- package/dist/portal/session/dev-server/served-document.d.ts +0 -5
- package/dist/portal/session/dev-server/served-document.js +6 -8
- package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
- package/dist/portal/session/first-run-wiring.d.ts +3 -36
- package/dist/portal/session/first-run-wiring.js +10 -103
- package/dist/portal/session/live-control-tools.js +61 -19
- package/dist/portal/session/no-session-next-action.d.ts +11 -0
- package/dist/portal/session/no-session-next-action.js +40 -15
- package/dist/portal/session/no-session-watch.d.ts +7 -0
- package/dist/portal/session/no-session-watch.js +67 -23
- package/dist/portal/session/output-budget.d.ts +10 -0
- package/dist/portal/session/output-budget.js +16 -0
- package/dist/portal/session/presence/session-lease.d.ts +2 -0
- package/dist/portal/session/presence/session-lease.js +8 -0
- package/dist/portal/session/recorded-gaps.d.ts +15 -11
- package/dist/portal/session/recorded-gaps.js +39 -18
- package/dist/portal/session/serving-directory.d.ts +24 -2
- package/dist/portal/session/serving-directory.js +93 -5
- package/dist/portal/session/session-info.d.ts +26 -0
- package/dist/portal/session/session-info.js +20 -0
- package/dist/portal/session/session-manager.d.ts +35 -3
- package/dist/portal/session/session-manager.js +69 -14
- package/dist/portal/session/session-successor.js +1 -9
- package/dist/portal/session/session-tools.js +22 -4
- package/dist/portal/session/session.d.ts +10 -10
- package/dist/portal/session/session.js +37 -29
- package/dist/portal/session/zero-install-first-call.d.ts +7 -2
- package/dist/portal/session/zero-install-first-call.js +43 -20
- package/dist/start-wiring.d.ts +2 -2
- package/dist/start-wiring.js +17 -3
- package/dist/status-payload.d.ts +11 -1
- package/dist/status-payload.js +7 -1
- package/dist/surface/agent-presence-grace.d.ts +11 -0
- package/dist/surface/agent-presence-grace.js +34 -0
- package/dist/surface/http-server.d.ts +12 -1
- package/dist/surface/http-server.js +64 -15
- package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
- package/dist/surface/mcp/faults/mcp-outage.js +19 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
- package/dist/surface/mcp/mcp-proxy.js +194 -267
- package/dist/surface/mcp/mcp.d.ts +20 -3
- package/dist/surface/mcp/mcp.js +88 -25
- package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
- package/dist/surface/mcp/proxy/drive-calls.js +114 -5
- package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
- package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
- package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
- package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
- package/dist/surface/mcp/server-instructions.js +35 -16
- package/dist/surface/mcp/shared-params.d.ts +8 -0
- package/dist/surface/mcp/shared-params.js +15 -1
- package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
- package/dist/surface/mcp/sse-frame-parser.js +18 -0
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +13 -0
- package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
- package/dist/surface/mcp/tool-catalog-cache.js +14 -4
- package/dist/surface/tools/account-tool.d.ts +4 -3
- package/dist/surface/tools/account-tool.js +20 -31
- package/dist/surface/tools/act/act-danger.d.ts +2 -0
- package/dist/surface/tools/act/act-danger.js +41 -14
- package/dist/surface/tools/act/act-observation.d.ts +11 -0
- package/dist/surface/tools/act/act-observation.js +33 -0
- package/dist/surface/tools/act/act-preflight.js +10 -3
- package/dist/surface/tools/act/act-sequence-retry.js +2 -1
- package/dist/surface/tools/act/act-target.js +19 -5
- package/dist/surface/tools/act/durable.js +1 -1
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
- package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
- package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
- package/dist/surface/tools/act/unsettled-find.js +71 -0
- package/dist/surface/tools/act-sequence-tool.js +53 -24
- package/dist/surface/tools/act-tools.d.ts +2 -3
- package/dist/surface/tools/act-tools.js +49 -47
- package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
- package/dist/surface/tools/agent/for-the-agent.js +41 -3
- package/dist/surface/tools/assert/assert-grade.js +8 -3
- package/dist/surface/tools/assert/assert-verdict.js +4 -2
- package/dist/surface/tools/browser-tools.js +7 -4
- package/dist/surface/tools/chat-drives.js +50 -25
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.d.ts +8 -0
- package/dist/surface/tools/dynamic-tools.js +89 -34
- package/dist/surface/tools/empty-session-list.d.ts +18 -25
- package/dist/surface/tools/empty-session-list.js +67 -38
- package/dist/surface/tools/error-recovery.d.ts +17 -7
- package/dist/surface/tools/error-recovery.js +53 -20
- package/dist/surface/tools/explore-tools.d.ts +10 -0
- package/dist/surface/tools/explore-tools.js +72 -19
- package/dist/surface/tools/feedback-tools.js +23 -2
- package/dist/surface/tools/gap-novelty.d.ts +6 -0
- package/dist/surface/tools/gap-novelty.js +9 -0
- package/dist/surface/tools/gaps/capability-absences.js +4 -3
- package/dist/surface/tools/harness-explore.d.ts +1 -1
- package/dist/surface/tools/harness-explore.js +6 -4
- package/dist/surface/tools/harness-gate.d.ts +43 -21
- package/dist/surface/tools/harness-gate.js +55 -81
- package/dist/surface/tools/harness-script.d.ts +2 -0
- package/dist/surface/tools/harness-script.js +11 -6
- package/dist/surface/tools/harness-toolset.js +3 -4
- package/dist/surface/tools/invoke-tool.d.ts +0 -8
- package/dist/surface/tools/invoke-tool.js +164 -178
- package/dist/surface/tools/lease-hint.d.ts +9 -0
- package/dist/surface/tools/lease-hint.js +22 -3
- package/dist/surface/tools/lease-permissions.d.ts +1 -1
- package/dist/surface/tools/lease-readiness.d.ts +55 -0
- package/dist/surface/tools/lease-readiness.js +150 -2
- package/dist/surface/tools/lease-tools.d.ts +3 -75
- package/dist/surface/tools/lease-tools.js +124 -188
- package/dist/surface/tools/map-tools.d.ts +20 -0
- package/dist/surface/tools/map-tools.js +145 -0
- package/dist/surface/tools/merge-tools.js +11 -7
- package/dist/surface/tools/next-step.js +6 -3
- package/dist/surface/tools/observe-tools.js +46 -35
- package/dist/surface/tools/platform-moment.d.ts +3 -12
- package/dist/surface/tools/platform-moment.js +12 -24
- package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
- package/dist/surface/tools/read/complete-snapshot.js +13 -2
- package/dist/surface/tools/read/query-paginate.js +6 -0
- package/dist/surface/tools/read/query-shape.d.ts +9 -0
- package/dist/surface/tools/read/query-shape.js +15 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
- package/dist/surface/tools/read-tools.js +5 -5
- package/dist/surface/tools/real-input-attempt.d.ts +11 -0
- package/dist/surface/tools/real-input-attempt.js +206 -38
- package/dist/surface/tools/reconcile-tools.js +21 -8
- package/dist/surface/tools/reticle-result.d.ts +3 -0
- package/dist/surface/tools/reticle-result.js +8 -1
- package/dist/surface/tools/run-report.d.ts +22 -0
- package/dist/surface/tools/run-report.js +141 -0
- package/dist/surface/tools/session-ports.d.ts +57 -0
- package/dist/surface/tools/session-ports.js +102 -0
- package/dist/surface/tools/tool-kit.d.ts +58 -4
- package/dist/surface/tools/tool-kit.js +140 -6
- package/dist/surface/tools/tool-surface.d.ts +2 -0
- package/dist/surface/tools/tool-surface.js +45 -0
- package/dist/surface/tools/tools.js +49 -87
- package/dist/telemetry/automation-hint.d.ts +5 -0
- package/dist/telemetry/automation-hint.js +7 -0
- package/dist/telemetry/cli-telemetry.d.ts +22 -0
- package/dist/telemetry/cli-telemetry.js +80 -11
- package/dist/telemetry/daemon-telemetry.d.ts +3 -1
- package/dist/telemetry/daemon-telemetry.js +9 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +8 -3
- package/dist/telemetry/feedback.d.ts +1 -1
- package/dist/telemetry/feedback.js +51 -4
- package/dist/telemetry/harness-run.d.ts +3 -3
- package/dist/telemetry/harness-run.js +18 -7
- package/dist/telemetry/hud-events.d.ts +1 -1
- package/dist/telemetry/hud-metrics.d.ts +6 -3
- package/dist/telemetry/hud-metrics.js +20 -8
- package/dist/telemetry/install-source.js +1 -1
- package/dist/telemetry/mcp-connection.d.ts +1 -1
- package/dist/telemetry/mcp-connection.js +21 -2
- package/dist/telemetry/onboarding-firsts.d.ts +6 -1
- package/dist/telemetry/onboarding-firsts.js +41 -1
- package/dist/telemetry/proxy-telemetry.d.ts +42 -0
- package/dist/telemetry/proxy-telemetry.js +70 -1
- package/dist/telemetry/session-metrics.d.ts +1 -3
- package/dist/telemetry/session-metrics.js +16 -12
- package/dist/telemetry/telemetry.d.ts +9 -1
- package/dist/telemetry/telemetry.js +16 -1
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +7 -1
- package/dist/wire-journal.js +12 -2
- package/docs/README.md +4 -2
- package/docs/actions.mdx +7 -6
- package/docs/adapters.md +2 -1
- package/docs/agent-cheatsheet.md +19 -5
- package/docs/architecture.md +13 -10
- package/docs/autodrive.md +6 -5
- package/docs/benchmarks.md +2 -2
- package/docs/capabilities.mdx +1 -1
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +6 -6
- package/docs/cli/doctor.mdx +3 -1
- package/docs/cli/feedback.mdx +11 -7
- package/docs/cli/gate.mdx +1 -1
- package/docs/cli/help.mdx +1 -1
- package/docs/cli/init.mdx +20 -16
- package/docs/cli/mcp.mdx +5 -2
- package/docs/cli/open.mdx +5 -2
- package/docs/cli/report.mdx +1 -1
- package/docs/cli/restart.mdx +1 -1
- package/docs/cli/rollback.mdx +4 -4
- package/docs/cli/serve.mdx +7 -5
- package/docs/cli/setup.mdx +1 -1
- package/docs/cli/status.mdx +6 -2
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/telemetry.mdx +5 -1
- package/docs/cli/try.mdx +8 -8
- package/docs/cli/update.mdx +8 -5
- package/docs/cli/verify.mdx +12 -5
- package/docs/cli/version.mdx +1 -1
- package/docs/cli.mdx +10 -6
- package/docs/debugging.md +1 -1
- package/docs/deploy-checks.md +8 -6
- package/docs/desktop.mdx +14 -18
- package/docs/enterprise.md +6 -6
- package/docs/environment.mdx +5 -3
- package/docs/faq.mdx +9 -6
- package/docs/first-drive.md +19 -9
- package/docs/flows.md +3 -4
- package/docs/for-agents.md +1 -1
- package/docs/frameworks.mdx +34 -11
- package/docs/getting-started.md +46 -29
- package/docs/http-transport.md +2 -2
- package/docs/human-control.md +8 -8
- package/docs/index.mdx +2 -2
- package/docs/install-agentic.mdx +18 -19
- package/docs/install-manual.mdx +8 -4
- package/docs/integration-patterns.md +5 -5
- package/docs/multi-agent-testing.md +7 -5
- package/docs/packages/browser.mdx +34 -2
- package/docs/packages/core.mdx +2 -1
- package/docs/packages/electron.mdx +15 -3
- package/docs/packages/eslint-plugin.mdx +1 -1
- package/docs/packages/next.mdx +17 -5
- package/docs/packages/react.mdx +8 -1
- package/docs/packages/server.mdx +3 -3
- package/docs/packages/tauri.mdx +3 -3
- package/docs/packages/vite-plugin.mdx +1 -1
- package/docs/packages.mdx +19 -6
- package/docs/platform-integration.md +12 -4
- package/docs/predicates.mdx +18 -7
- package/docs/production-mode.md +108 -0
- package/docs/prompt-capture.md +99 -0
- package/docs/quickstart.mdx +14 -12
- package/docs/recipes.mdx +9 -8
- package/docs/required-checks.md +3 -2
- package/docs/skill-file.mdx +4 -3
- package/docs/skill-setup.md +2 -2
- package/docs/skill.md +62 -70
- package/docs/state-files.md +1 -0
- package/docs/state-management.mdx +11 -9
- package/docs/system-map.md +14 -13
- package/docs/telemetry.md +32 -24
- package/docs/testing.md +9 -5
- package/docs/tools/act-and-wait.mdx +17 -13
- package/docs/tools/act-sequence.mdx +40 -66
- package/docs/tools/act.mdx +7 -5
- package/docs/tools/assert.mdx +1 -1
- package/docs/tools/look.mdx +1 -1
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/network.mdx +13 -11
- package/docs/tools/overview.mdx +3 -3
- package/docs/tools/query.mdx +3 -3
- package/docs/tools/session-and-feedback.mdx +9 -6
- package/docs/tools/sessions.mdx +7 -0
- package/docs/tools/snapshot.mdx +9 -7
- package/docs/tools/tools-and-run.mdx +11 -10
- package/docs/tools/verify.mdx +1 -1
- package/docs/troubleshooting.mdx +21 -9
- package/docs/usage.md +58 -43
- package/docs/use-cases.mdx +2 -2
- package/docs/vs-chrome-devtools-mcp.mdx +5 -5
- package/docs/vs-playwright-mcp.mdx +5 -4
- package/docs/what-is-recorded.md +12 -7
- package/docs/what-is-reticle.mdx +2 -2
- package/docs/why-reticle.mdx +1 -1
- package/package.json +9 -12
- package/dist/command/dev/stale-issue-guard.d.ts +0 -34
- package/dist/command/dev/stale-issue-guard.js +0 -69
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { z } from 'zod';
|
|
13
13
|
import { timeoutMsSchema } from './args/numeric-bounds.js';
|
|
14
|
-
import { compileSequenceStep, pathOf } from '../../language/flows/replay.js';
|
|
14
|
+
import { compileSequenceStep, pathOf, wroteSince } from '../../language/flows/replay.js';
|
|
15
15
|
import { DEFAULT_SEQUENCE_STEP_TIMEOUT_MS } from '../../language/flows/flow-step-runners.js';
|
|
16
16
|
import { sequenceStepArgs } from './act/act-preflight.js';
|
|
17
|
-
import { REPLAY_PROGRAM_VERSION, ReticleTool, Verified, VerifiedReason, } from '@reticlehq/core';
|
|
17
|
+
import { REPLAY_PROGRAM_VERSION, ReticleTool, Verified, VerifiedReason, checkIntent, } from '@reticlehq/core';
|
|
18
18
|
import { healthEnvelope } from '../../portal/session/session-health.js';
|
|
19
19
|
import { pausedShortCircuit, pausedOutputShape, withControl, } from '../../portal/session/control-envelope.js';
|
|
20
20
|
import { asRecord, isAbsenceDerived, isAdvisory } from '@reticlehq/core';
|
|
@@ -26,7 +26,7 @@ import { takeStepShot } from '../../features/visual/step-shots.js';
|
|
|
26
26
|
import { actCommand } from './act-tools.js';
|
|
27
27
|
import { PredicateSchema, waitForPredicate, } from '@reticlehq/engine/question/predicate/predicate.js';
|
|
28
28
|
import { DeviationMode, gradeSequence, JOURNEY_RECORDING, offerToKeep, } from './act/sequence-grade.js';
|
|
29
|
-
import { stepEffect } from '@reticlehq/engine/evidence/step-effect.js';
|
|
29
|
+
import { stepEffect, appScope } from '@reticlehq/engine/evidence/step-effect.js';
|
|
30
30
|
// resolveActTarget moved out of act-tools into its own module on this branch; #706 was written
|
|
31
31
|
// against the older layout where act-tools re-exported it.
|
|
32
32
|
import { resolveActTarget } from './act/act-target.js';
|
|
@@ -34,6 +34,7 @@ import { gradeOfPredicate } from './assert/assert-grade.js';
|
|
|
34
34
|
import { describeWaitTarget } from '@reticlehq/engine/evidence/unsettled.js';
|
|
35
35
|
import { sourceOf } from './tools-helpers.js';
|
|
36
36
|
import { confirmedByDeclaration } from './act/act-danger.js';
|
|
37
|
+
import { unreachableTargetNote } from './act/act-observation.js';
|
|
37
38
|
/**
|
|
38
39
|
* The step's effect record, best-effort.
|
|
39
40
|
*
|
|
@@ -43,9 +44,11 @@ import { confirmedByDeclaration } from './act/act-danger.js';
|
|
|
43
44
|
* INSIDE the step loop, be caught as a step failure, and abort the rest of a journey that was
|
|
44
45
|
* running perfectly. The drive is the product; the description of it is not.
|
|
45
46
|
*/
|
|
46
|
-
function effectOf(session, since) {
|
|
47
|
+
function effectOf(session, since, expect) {
|
|
47
48
|
try {
|
|
48
|
-
|
|
49
|
+
// A failure the step declared is its expected result, as it is for `act_and_wait`'s `until`.
|
|
50
|
+
const declared = PredicateSchema.safeParse(expect);
|
|
51
|
+
return stepEffect(session.eventsSince(since), { since, until: session.elapsed() }, { ...appScope(session), ...(declared.success ? { declared: [declared.data] } : {}) });
|
|
49
52
|
}
|
|
50
53
|
catch {
|
|
51
54
|
return {};
|
|
@@ -58,12 +61,19 @@ function stepVerdictEffect(check) {
|
|
|
58
61
|
? { verified: Verified.NO, reason: VerifiedReason.CONTRADICTED }
|
|
59
62
|
: { verified: Verified.YES, reason: undefined }
|
|
60
63
|
: check.undecided
|
|
61
|
-
? {
|
|
64
|
+
? {
|
|
65
|
+
verified: Verified.UNKNOWN,
|
|
66
|
+
reason: true === check.unreachable
|
|
67
|
+
? VerifiedReason.INCONCLUSIVE
|
|
68
|
+
: VerifiedReason.OBSERVATION_LOST,
|
|
69
|
+
}
|
|
62
70
|
: { verified: Verified.NO, reason: VerifiedReason.ASSERTION_FAILED };
|
|
63
71
|
const source = sourceOf(check.source);
|
|
64
72
|
return {
|
|
65
73
|
claim: describeWaitTarget(check.expect),
|
|
66
74
|
verified,
|
|
75
|
+
// A step's sentence: the step names no intent of its own, so it is built from its expect.
|
|
76
|
+
...checkIntent(check.expect, check),
|
|
67
77
|
...(source === undefined ? {} : { source: `${source.file}:${String(source.line)}` }),
|
|
68
78
|
...(check.expected === undefined ? {} : { expected: check.expected }),
|
|
69
79
|
...(check.observed === undefined ? {} : { observed: check.observed }),
|
|
@@ -112,7 +122,7 @@ export const ACT_SEQUENCE_TOOL = {
|
|
|
112
122
|
description: "Drive a WHOLE journey in ONE round-trip, with NO snapshot first. Name each step's element by {testid} | {label} | {role,name} | {text} in `target` and Reticle resolves it AT THE MOMENT THAT STEP RUNS — so a control that does not exist yet (a modal an earlier step opens, a row it creates) is still addressable, and waits up to timeout_ms to appear. This is the fast path: snapshot -> act -> snapshot -> act costs a model turn per step and is the slowest thing an agent can do. Give each step an `expect` and the sequence stops at the first one that does not hold, returning the un-run `tail` verbatim so you re-plan only the failure. Returns per-step effects[] (see reticle_act).",
|
|
113
123
|
inputSchema: {
|
|
114
124
|
steps: z
|
|
115
|
-
.array(z.record(z.unknown()))
|
|
125
|
+
.array(z.record(z.string(), z.unknown()))
|
|
116
126
|
.describe('Ordered list of { ref | target, action, args?, expect? } objects. Each step is equivalent to one reticle_act call, and takes its arguments either way: `{ ref, action: "fill", value: "…" }` flat, as reticle_act does, or nested as `args: { value }`. Give `ref` from a snapshot/query, or `target` ({ testid } | { label } | { role, name } | { text }) to resolve in this call. Put confirmDangerous:true in a destructive step args object. `expect` is the same predicate shape as reticle_act_and_wait `until`, and it is what makes a step PROVE something: a step without one is driven, not verified, and the result says so. Naming the consequence is also FASTER — a named consequence is detected the instant it fires, where waiting for the page to settle can only conclude by waiting for silence.'),
|
|
117
127
|
// A plain number, not boolean|number: a zod union serialises to a JSON-Schema `anyOf` that
|
|
118
128
|
// cost 174 B on a surface re-sent every turn, against 81 B of headroom. One spelling is also
|
|
@@ -153,14 +163,14 @@ export const ACT_SEQUENCE_TOOL = {
|
|
|
153
163
|
/** How many steps declared a consequence, of how many were driven. Never averaged away. */
|
|
154
164
|
coverage: z.object({ declared: z.number(), total: z.number() }).optional(),
|
|
155
165
|
/** Steps never run, verbatim, so a caller re-plans the failure rather than the whole journey. */
|
|
156
|
-
tail: z.array(z.record(z.unknown())).optional(),
|
|
166
|
+
tail: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
157
167
|
/**
|
|
158
168
|
* Each step carries the same effect record a REPLAYED step carries: `window` (the
|
|
159
169
|
* `reticle_observe { since, until }` drill address), `digest` (what the app did, as counts) and
|
|
160
170
|
* `contradictions` (channels that disagree, present even when the step passed). Declared here
|
|
161
171
|
* because an undeclared field is stripped from structuredContent and would be silently lost.
|
|
162
172
|
*/
|
|
163
|
-
steps: z.array(z.record(z.unknown())).optional(),
|
|
173
|
+
steps: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
164
174
|
result: z.unknown().optional(),
|
|
165
175
|
session: z
|
|
166
176
|
.object({ lastSeenMs: z.number(), throttled: z.boolean(), focused: z.boolean() })
|
|
@@ -274,7 +284,7 @@ export const ACT_SEQUENCE_TOOL = {
|
|
|
274
284
|
*/
|
|
275
285
|
const describe = () => ({
|
|
276
286
|
...describeStepResult(step, asRecord(outcome.result)),
|
|
277
|
-
...effectOf(session, stepSince),
|
|
287
|
+
...effectOf(session, stepSince, step['expect']),
|
|
278
288
|
});
|
|
279
289
|
const deciding = (step) => (step.contradictions ?? [])
|
|
280
290
|
.map((c) => c.kind)
|
|
@@ -287,12 +297,15 @@ export const ACT_SEQUENCE_TOOL = {
|
|
|
287
297
|
* satisfy step four's assertion, which is a false green built out of correct parts.
|
|
288
298
|
*/
|
|
289
299
|
const parsed = PredicateSchema.safeParse(step['expect']);
|
|
300
|
+
// A click no person could have made decides nothing, whatever followed it.
|
|
301
|
+
const unreachable = unreachableTargetNote(outcome.result);
|
|
290
302
|
if (!parsed.success) {
|
|
291
303
|
const described = describe();
|
|
292
304
|
const contradicted = deciding(described);
|
|
293
305
|
expectations.push({
|
|
294
306
|
declared: false,
|
|
295
307
|
...(0 === contradicted.length ? {} : { contradicted }),
|
|
308
|
+
...(unreachable === undefined ? {} : { undecided: unreachable }),
|
|
296
309
|
});
|
|
297
310
|
await pushStep(described);
|
|
298
311
|
}
|
|
@@ -304,29 +317,35 @@ export const ACT_SEQUENCE_TOOL = {
|
|
|
304
317
|
const described = describe();
|
|
305
318
|
const contradicted = deciding(described);
|
|
306
319
|
const disagreement = 0 === contradicted.length ? {} : { contradicted };
|
|
307
|
-
const held = true === verdict.pass;
|
|
320
|
+
const held = true === verdict.pass && unreachable === undefined;
|
|
308
321
|
// A tab that went away (an external checkout page) or a predicate that could not be
|
|
309
322
|
// read decided nothing: unknown, never a miss blamed on the app.
|
|
310
|
-
const undecided =
|
|
323
|
+
const undecided = unreachable !== undefined ||
|
|
324
|
+
(!held && (true === verdict.observationLost || verdict.inconclusive !== undefined));
|
|
311
325
|
// One check per declared step, journaled as act_and_wait journals its own, so the
|
|
312
326
|
// session's result, its run file and the dashboard all count it. See sequence-journal.ts.
|
|
313
327
|
journalStep(session, { step: i, expect: step['expect'] }, stepVerdictEffect({
|
|
314
328
|
expect: parsed.data,
|
|
315
329
|
held,
|
|
316
330
|
undecided,
|
|
331
|
+
...(unreachable === undefined ? {} : { unreachable: true }),
|
|
317
332
|
contradicted,
|
|
318
333
|
expected: verdict.expected,
|
|
319
334
|
observed: held ? undefined : (verdict.observed ?? verdict.failureReason),
|
|
320
335
|
source: asRecord(outcome.result)['source'],
|
|
336
|
+
evidence: verdict.evidence,
|
|
337
|
+
assertion: verdict.assertion,
|
|
321
338
|
}));
|
|
322
339
|
expectations.push({
|
|
323
340
|
declared: true,
|
|
324
341
|
held,
|
|
325
342
|
...(undecided
|
|
326
343
|
? {
|
|
327
|
-
undecided:
|
|
328
|
-
?
|
|
329
|
-
:
|
|
344
|
+
undecided: unreachable !== undefined
|
|
345
|
+
? unreachable
|
|
346
|
+
: true === verdict.observationLost
|
|
347
|
+
? `${verdict.failureReason ?? 'the observation was lost'} (the page left)`
|
|
348
|
+
: (verdict.failureReason ?? 'the predicate could not be read'),
|
|
330
349
|
}
|
|
331
350
|
: {}),
|
|
332
351
|
...disagreement,
|
|
@@ -386,19 +405,29 @@ export const ACT_SEQUENCE_TOOL = {
|
|
|
386
405
|
// in the ambient tape. A stalled plan keeps only the prefix whose steps actually ran.
|
|
387
406
|
let journey;
|
|
388
407
|
if (completed > 0) {
|
|
389
|
-
//
|
|
390
|
-
// never replays
|
|
391
|
-
|
|
392
|
-
|
|
408
|
+
// On the ambient tape a sub-step keeps its `expect` only if it held — same rule as
|
|
409
|
+
// act_and_wait, so an auto-saved flow never replays a claim that was never once observed to
|
|
410
|
+
// hold. A recording somebody opened keeps every claim they declared: dropping a refuted one
|
|
411
|
+
// there saved a flow that replayed green on the very defect it had caught.
|
|
412
|
+
const ran = inputSteps.slice(0, completed).map(asRecord);
|
|
413
|
+
const proved = ran.map((step, i) => {
|
|
393
414
|
const { expect: _expect, ...rest } = step;
|
|
394
415
|
return true === expectations[i]?.held ? step : rest;
|
|
395
416
|
});
|
|
396
|
-
const
|
|
397
|
-
count: completed,
|
|
398
|
-
|
|
399
|
-
|
|
417
|
+
const compiled = (steps) => {
|
|
418
|
+
const step = compileSequenceStep({ ...args, steps }, { count: completed, steps: stepResults.slice(0, completed) });
|
|
419
|
+
// The journey sent a write request: saved `writes`, so a replay does not repeat it unasked.
|
|
420
|
+
if (wroteSince(session, since))
|
|
421
|
+
step.writes = true;
|
|
422
|
+
return step;
|
|
423
|
+
};
|
|
424
|
+
const recorded = compiled(proved);
|
|
400
425
|
journey = recorded;
|
|
401
|
-
|
|
426
|
+
const onPage = (step) => pageBefore === undefined ? step : { ...step, page: pageBefore };
|
|
427
|
+
// Every step was on Reticle's own panel: nothing of the app's journey to record.
|
|
428
|
+
const onApp = asRecord(recorded.args)['steps'];
|
|
429
|
+
if (Array.isArray(onApp) && 0 < onApp.length)
|
|
430
|
+
deps.recordings.capture(onPage(compiled(ran)), undefined, session.id, onPage(recorded));
|
|
402
431
|
deps.recordings.markEnded(pathOf(session.url), session.id);
|
|
403
432
|
}
|
|
404
433
|
/*
|
|
@@ -3,9 +3,8 @@ import { type ToolDef, type ToolDeps } from './tool-kit.js';
|
|
|
3
3
|
/**
|
|
4
4
|
* Single dispatch point for every ACT and ACT_SEQUENCE command.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* which also covers flow-replay, crawl, and any future dispatch site that goes through this helper.
|
|
6
|
+
* reticle_act, act_and_wait and act_sequence rewrite uploads here, once. The path resolves against
|
|
7
|
+
* the session's project, not the daemon's folder, so a worktree uploads its own fixture (#1769).
|
|
9
8
|
*
|
|
10
9
|
* captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
|
|
11
10
|
* the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
|
|
@@ -13,9 +13,9 @@ import { aliasParam } from './args/alias-args.js';
|
|
|
13
13
|
import { resolveSessionWithin } from '../../portal/session/timing/resolve-within.js';
|
|
14
14
|
import { WALL_CLOCK } from '../../portal/session/timing/wall-clock.js';
|
|
15
15
|
import { timeoutMsSchema } from './args/numeric-bounds.js';
|
|
16
|
-
import { captureAct, captureVerdictedAct, pathOf } from '../../language/flows/replay.js';
|
|
16
|
+
import { captureAct, captureVerdictedAct, pathOf, wroteSince } from '../../language/flows/replay.js';
|
|
17
17
|
import { durableArg, durableOutput, reloadAndRecheck, withDurability } from './act/durable.js';
|
|
18
|
-
import { ActionType, ActionWarning, ReticleCommand, CaptureLoss, DEFAULT_ASSERT_TIMEOUT_MS, InputMode, Verified, VerifiedReason, PredicateKind, } from '@reticlehq/core';
|
|
18
|
+
import { ActionType, ActionWarning, ReticleCommand, CaptureLoss, DEFAULT_ASSERT_TIMEOUT_MS, InputMode, Verified, VerifiedReason, PredicateKind, checkIntent, } from '@reticlehq/core';
|
|
19
19
|
import { leanActResult, mutatedWithin } from './act/act-view.js';
|
|
20
20
|
import { ReticleTool } from '@reticlehq/core';
|
|
21
21
|
import { buildReactionReport, summarizeReaction } from '@reticlehq/engine/question/reaction.js';
|
|
@@ -25,7 +25,7 @@ import { causalSummary } from '../../judgement/capsule/causal-summary.js';
|
|
|
25
25
|
import { findContradictions } from '@reticlehq/engine/disagreement/contradictions.js';
|
|
26
26
|
import { crashedRuleNotes } from '@reticlehq/engine/disagreement/contradiction-folds.js';
|
|
27
27
|
import { gapsForAction } from '@reticlehq/engine/evidence/instrumentation-gaps.js';
|
|
28
|
-
import { withGapNovelty } from './gap-novelty.js';
|
|
28
|
+
import { engineBlindSpotsOutput, withGapNovelty } from './gap-novelty.js';
|
|
29
29
|
import { noteSessionGaps } from '@reticlehq/engine/evidence/gap-ledger.js';
|
|
30
30
|
import { isChangeUndeclared } from '@reticlehq/engine/evidence/undeclared-change.js';
|
|
31
31
|
import { intentDebt, ledgerFor } from '../../memory/intent/open-intents.js';
|
|
@@ -37,16 +37,15 @@ import { inFlightRequestLabels, repeatedRequestLabels } from './act/settle-in-fl
|
|
|
37
37
|
import { finishAfterMatch } from './act/after-match.js';
|
|
38
38
|
import { noteProved } from './act/proved-controls.js';
|
|
39
39
|
import { decideVerified } from '@reticlehq/engine/evidence/verified.js';
|
|
40
|
-
import { honestyForVerdict } from '@reticlehq/engine/evidence/honesty.js';
|
|
40
|
+
import { buildHonestyBlock, honestyForVerdict } from '@reticlehq/engine/evidence/honesty.js';
|
|
41
41
|
import { declaredExpectations, declaresBodyIndependentChannel, } from '@reticlehq/engine/question/declared.js';
|
|
42
42
|
import { describeWaitTarget, namedNetIsInFlight } from '@reticlehq/engine/evidence/unsettled.js';
|
|
43
43
|
import { saveFailedAssertCapsule } from './act-capsule.js';
|
|
44
44
|
import { blastRadius, buildDivergenceCapsule, wireCapsule } from '../../judgement/capsule/capsule.js';
|
|
45
45
|
import { predicateToExpectedLinks } from '@reticlehq/engine/question/predicate/predicate-to-links.js';
|
|
46
|
-
import { buildHonestyBlock } from '@reticlehq/engine/evidence/honesty.js';
|
|
47
46
|
import { absenceBlindSpotNote, buildCoverageStatement, blindSpotsFromState, transportGapNote, Coverage, impeachesCapture, } from '@reticlehq/engine/evidence/blind-spots.js';
|
|
48
47
|
import { acceptedWriteLabels } from '@reticlehq/engine/evidence/accepted-write.js';
|
|
49
|
-
import { unreadWriteLabels } from '@reticlehq/engine/evidence/unread-outcome.js';
|
|
48
|
+
import { unreadWriteLabels, unreadWriteReason } from '@reticlehq/engine/evidence/unread-outcome.js';
|
|
50
49
|
import { evaluatePredicate, waitForPredicate, provenExpectedLinks, PredicateSchema, } from '@reticlehq/engine/question/predicate/predicate.js';
|
|
51
50
|
import { sessionVerdictFacts } from '../../portal/session/session-verdict-facts.js';
|
|
52
51
|
import { currentOf, healthEnvelope, refuseIfThrottled } from '../../portal/session/session-health.js';
|
|
@@ -55,16 +54,17 @@ import { asNumber, asRecord, asString } from '@reticlehq/core';
|
|
|
55
54
|
import { sourceOf } from './tools-helpers.js';
|
|
56
55
|
import { confirmedByDeclaration } from './act/act-danger.js';
|
|
57
56
|
import { dispatchAct, preflightAct } from './act/act-preflight.js';
|
|
58
|
-
import {
|
|
57
|
+
import { actTargetNote, checkNet, followLostObservation } from './act/act-observation.js';
|
|
59
58
|
import { intentArg, sessionIdShape } from './tool-kit.js';
|
|
60
59
|
import { verdictIntentGap } from '@reticlehq/engine/evidence/verdict-intent-gap.js';
|
|
61
60
|
import { asActionType, gradeOf } from './act/act-helpers.js';
|
|
62
61
|
import { resolveActTarget } from './act/act-target.js';
|
|
63
62
|
import { screenRequestFindings, withAdvisories } from './act/screen-request.js';
|
|
64
63
|
import { tryRealInput, rewriteUploadArgs, HOVER_NEEDS_POINTER_MSG } from './real-input-attempt.js';
|
|
64
|
+
import { sessionRoot } from '../../memory/project/session-root.js';
|
|
65
65
|
import { gradeOfPredicate } from './assert/assert-grade.js';
|
|
66
66
|
import { readAlreadyTrue } from './act/already-true.js';
|
|
67
|
-
import { noteSourceSeen } from '../../portal/session/recorded-gaps.js';
|
|
67
|
+
import { engineBlindSpotsField, noteSourceSeen } from '../../portal/session/recorded-gaps.js';
|
|
68
68
|
/**
|
|
69
69
|
* The action vocabulary, derived from ActionType — never retyped: a hand-copied list once omitted
|
|
70
70
|
* blur, upload and drag. The schema refuses an unknown action before any session is resolved.
|
|
@@ -74,32 +74,32 @@ const actionTypeEnum = z.enum(ACTION_TYPE_VALUES);
|
|
|
74
74
|
/**
|
|
75
75
|
* Single dispatch point for every ACT and ACT_SEQUENCE command.
|
|
76
76
|
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* which also covers flow-replay, crawl, and any future dispatch site that goes through this helper.
|
|
77
|
+
* reticle_act, act_and_wait and act_sequence rewrite uploads here, once. The path resolves against
|
|
78
|
+
* the session's project, not the daemon's folder, so a worktree uploads its own fixture (#1769).
|
|
80
79
|
*
|
|
81
80
|
* captureAct is called AFTER this, so the flow-recording captures the pre-rewrite args (the path
|
|
82
81
|
* the agent actually wrote) rather than the base64 blob — replay would otherwise send 750 KiB of
|
|
83
82
|
* base64 to the browser as if it were an inline content call.
|
|
84
83
|
*/
|
|
85
84
|
export async function actCommand(deps, session, actArgs, timeoutMs) {
|
|
86
|
-
const rewritten = await rewriteUploadArgs(deps, 'string' === typeof actArgs['action'] ? actArgs['action'] : '', asRecord(actArgs['args']));
|
|
85
|
+
const rewritten = await rewriteUploadArgs({ fs: deps.fs, reticleRoot: sessionRoot(deps, session.id) }, 'string' === typeof actArgs['action'] ? actArgs['action'] : '', asRecord(actArgs['args']));
|
|
87
86
|
// Sequence and act_and_wait dispatch through here without the ACT handler's tryRealInput.
|
|
88
87
|
// A synthetic hover reports dispatched/settled while CSS :hover never applies — drive a real
|
|
89
|
-
// pointer when one is available, otherwise refuse rather than lie.
|
|
90
|
-
|
|
88
|
+
// pointer when one is available, otherwise refuse rather than lie. A press on a lease takes its
|
|
89
|
+
// real keyboard, as reticle_act does: a synthetic Tab moves no focus.
|
|
90
|
+
const hover = ActionType.HOVER === actArgs['action'];
|
|
91
|
+
if (hover || (ActionType.PRESS === actArgs['action'] && deps.realInput === undefined)) {
|
|
91
92
|
const ref = asString(actArgs['ref']);
|
|
92
|
-
if (ref === undefined)
|
|
93
|
+
if (hover && ref === undefined)
|
|
93
94
|
throw new Error(HOVER_NEEDS_POINTER_MSG);
|
|
94
|
-
const
|
|
95
|
-
|
|
95
|
+
const action = hover ? ActionType.HOVER : ActionType.PRESS;
|
|
96
|
+
const real = await tryRealInput(deps, session, ref ?? '', action, actArgs);
|
|
97
|
+
if (hover && real.result === undefined)
|
|
96
98
|
throw new Error(HOVER_NEEDS_POINTER_MSG);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
result: { dispatched: true, settled: real.settled, ...asRecord(real.result) },
|
|
102
|
-
};
|
|
99
|
+
if (real.result !== undefined) {
|
|
100
|
+
const result = { dispatched: true, settled: real.settled, ...asRecord(real.result) };
|
|
101
|
+
return { kind: 'command_result', id: action, ok: true, result };
|
|
102
|
+
}
|
|
103
103
|
}
|
|
104
104
|
const bridgeArgs = { ...actArgs, args: rewritten };
|
|
105
105
|
// What the acted element shows (test id, source) is noted in `Session.command`, Harness acts too.
|
|
@@ -109,19 +109,19 @@ export const ACT_TOOLS = [
|
|
|
109
109
|
{
|
|
110
110
|
name: ReticleTool.ACT,
|
|
111
111
|
example: { ref: 'e42', action: 'fill', args: { value: 'hello' } },
|
|
112
|
-
description: 'Act WITHOUT checking the result — if the action is supposed to cause something, use reticle_act_and_wait { until } instead and get the verdict in the same call. This tool returns immediately with a `since` cursor; observe the reaction yourself with reticle_observe. Use it for actions with no observable consequence to assert (focus, hover, scrollIntoView, a fill you are about to submit). One action against a ref: click|dblclick|hover|focus|fill|type|clear|select|check|uncheck|submit|press|scrollIntoView. Carries effect:{dispatched,targetMatched,visible,enabled,focusMoved,valueChanged,domMutatedWithin,occluded,occludedBy,scrolledIntoView} to tell "action missed" from "app didn\'t react"; dispatched=landed, settled=a real frame flushed, and a settle timeout never fails the tool. Fields at their uninformative default are OMITTED so a clean action collapses to its consequence: an absent dispatched/targetMatched/visible/enabled means true, an absent occluded/scrolledIntoView/valueChanged/defaultPrevented means false, an absent focusMoved/occludedBy means null. occluded=true means the click point is covered by another element (a real user could not click it) — synthetic dispatch still delivered the event; scrolledIntoView=true means an off-viewport target was scrolled in first. effect.alreadyAtValue=true (check/uncheck only) means the box already read as the requested state, so NOTHING was dispatched and the app was never told — the DOM property is not evidence the application holds that value, so assert the app\'s own state (a signal, a request, a derived control), not the box. inputMode is "real" (native CDP, no synthetic effect block) or "synthetic"; clicks default to the occlusion-honest synthetic path even when CDP is configured — pass args.native:true to force a trusted native click (file pickers, clipboard). args.holdMs keeps the pointer DOWN for that long between mousedown and mouseup — the only way to drive a hold-to-confirm control (hold-to-delete, hold-to-record, long-press); effect.heldMs reports the hold actually achieved, which a throttled background tab can stretch. args.confirmDangerous is a permission gate and NOT a duration: it allows a destructive control, it does not hold one. inputModeReason explains any real→synthetic choice so it is never silent. Full model (real-input, throttled tabs, `reticle drive`): node_modules/@reticlehq/server/docs/usage.md §18.',
|
|
112
|
+
description: 'Act WITHOUT checking the result — if the action is supposed to cause something, use reticle_act_and_wait { until } instead and get the verdict in the same call. This tool returns immediately with a `since` cursor; observe the reaction yourself with reticle_observe. Use it for actions with no observable consequence to assert (focus, hover, scrollIntoView, a fill you are about to submit). One action against a ref: click|dblclick|hover|focus|fill|type|clear|select|check|uncheck|submit|press|scrollIntoView. Carries effect:{dispatched,targetMatched,visible,enabled,focusMoved,valueChanged,domMutatedWithin,occluded,occludedBy,scrolledIntoView} to tell "action missed" from "app didn\'t react"; dispatched=landed, settled=a real frame flushed, and a settle timeout never fails the tool. Fields at their uninformative default are OMITTED so a clean action collapses to its consequence: an absent dispatched/targetMatched/visible/enabled means true, an absent occluded/scrolledIntoView/valueChanged/defaultPrevented means false, an absent focusMoved/occludedBy means null. occluded=true means the click point is covered by another element (a real user could not click it) — synthetic dispatch still delivered the event; scrolledIntoView=true means an off-viewport target was scrolled in first. effect.alreadyAtValue=true (check/uncheck only) means the box already read as the requested state, so NOTHING was dispatched and the app was never told — the DOM property is not evidence the application holds that value, so assert the app\'s own state (a signal, a request, a derived control), not the box. inputMode is "real" (native CDP, no synthetic effect block) or "synthetic"; clicks default to the occlusion-honest synthetic path even when CDP is configured — pass args.native:true to force a trusted native click (file pickers, clipboard). args.holdMs keeps the pointer DOWN for that long between mousedown and mouseup — the only way to drive a hold-to-confirm control (hold-to-delete, hold-to-record, long-press); effect.heldMs reports the hold actually achieved, which a throttled background tab can stretch. args.confirmDangerous is a permission gate and NOT a duration: it allows a destructive control, it does not hold one. inputModeReason explains any real→synthetic choice so it is never silent. On a leased tab a press uses the real keyboard: Tab moves focus, and a press with a ref focuses that element first, so Enter or Space presses it as a person would. Full model (real-input, throttled tabs, `reticle drive`): node_modules/@reticlehq/server/docs/usage.md §18.',
|
|
113
113
|
inputSchema: {
|
|
114
114
|
ref: z
|
|
115
115
|
.string()
|
|
116
116
|
.optional()
|
|
117
117
|
.describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`. A press of Escape, Tab, or a modifier shortcut (Cmd+K) is a document key and needs neither.`),
|
|
118
118
|
target: z
|
|
119
|
-
.record(z.unknown())
|
|
119
|
+
.record(z.string(), z.unknown())
|
|
120
120
|
.optional()
|
|
121
121
|
.describe('Find the element and act on it in ONE call, instead of a reticle_query round trip first: { testid } | { text } | { role, name } | { label }. Refuses if it matches more than one, rather than guessing.'),
|
|
122
122
|
action: actionTypeEnum.describe('Action to perform.'),
|
|
123
123
|
args: z
|
|
124
|
-
.record(z.unknown())
|
|
124
|
+
.record(z.string(), z.unknown())
|
|
125
125
|
.optional()
|
|
126
126
|
.describe('Action-specific arguments: { value } for fill/select, { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt — a Cmd+K), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { native: true } to force a trusted native click, { holdMs: N } to keep the pointer or the key DOWN for N ms (hold-to-confirm controls; effect.heldMs reports what was achieved), { confirmDangerous: true } to allow a potentially destructive control — a permission gate, NOT a duration. For press: { keys: ["Control","k"] } holds several keys down TOGETHER (pressed in order, released in reverse) and { code } names the physical key — both stay on the in-page dispatcher, the only path that can express them. For upload: { path } is a path on disk (absolute or relative to the project root; the daemon reads the file and delivers real bytes to the file picker — this is the way to verify document-ingestion flows); or { name, content?, type? } to supply inline bytes directly.'),
|
|
127
127
|
refuseWhenThrottled: z
|
|
@@ -224,7 +224,7 @@ export const ACT_TOOLS = [
|
|
|
224
224
|
// Keep what only this call measured, so the observe that judges this window can ask whether
|
|
225
225
|
// anything happened INSIDE the target — the one fact that separates a dead control from a
|
|
226
226
|
// page that was merely busy with something else.
|
|
227
|
-
session.lastAct.markActed(since, action, mutatedWithin(r),
|
|
227
|
+
session.lastAct.markActed(since, action, mutatedWithin(r), targetRef.ref);
|
|
228
228
|
return withControl(session, {
|
|
229
229
|
since,
|
|
230
230
|
inputMode: InputMode.SYNTHETIC,
|
|
@@ -264,12 +264,12 @@ export const ACT_TOOLS = [
|
|
|
264
264
|
.optional()
|
|
265
265
|
.describe(`Element ref (e.g. 'e42') from reticle_snapshot/reticle_query — stable until the element leaves the DOM, so no re-snapshot between actions. Give this OR \`target\`. A press of Escape, Tab, or a modifier shortcut (Cmd+K) is a document key and needs neither.`),
|
|
266
266
|
target: z
|
|
267
|
-
.record(z.unknown())
|
|
267
|
+
.record(z.string(), z.unknown())
|
|
268
268
|
.optional()
|
|
269
269
|
.describe('Find the element and act on it in ONE call, instead of a reticle_query round trip first: { testid } | { text } | { role, name } | { label }. Refuses if it matches more than one, rather than guessing.'),
|
|
270
270
|
action: actionTypeEnum.describe('Action to perform.'),
|
|
271
271
|
args: z
|
|
272
|
-
.record(z.unknown())
|
|
272
|
+
.record(z.string(), z.unknown())
|
|
273
273
|
.optional()
|
|
274
274
|
.describe('Action-specific arguments: { value } for fill/select, { text } for type/press (the key NAME, e.g. Escape or Tab), { modifiers: ["Meta","Shift"] } for a press shortcut (Meta/Control/Shift/Alt), { toRef } for drag (the ref to drop ON — without it the drag lands nowhere), { confirmDangerous: true } for a potentially destructive control. For upload: { path } is a path on disk (absolute or relative to project root; daemon reads real bytes) or { name, content?, type? } for inline bytes.'),
|
|
275
275
|
predicate: PredicateSchema.optional().describe('Alias for `until`.'),
|
|
@@ -289,6 +289,7 @@ export const ACT_TOOLS = [
|
|
|
289
289
|
durable: durableOutput,
|
|
290
290
|
effect: z
|
|
291
291
|
.unknown()
|
|
292
|
+
.optional()
|
|
292
293
|
.describe('The reticle_act result (dispatched, settled, inputMode, etc.).'),
|
|
293
294
|
verdict: z.object({
|
|
294
295
|
pass: z.boolean(),
|
|
@@ -316,9 +317,11 @@ export const ACT_TOOLS = [
|
|
|
316
317
|
}),
|
|
317
318
|
trace: z
|
|
318
319
|
.unknown()
|
|
320
|
+
.optional()
|
|
319
321
|
.describe('Reaction digest: { window_ms, summary } of what the app did (DOM/network/route/console/signal counts). The full per-event timeline is one reticle_observe { since } away.'),
|
|
320
322
|
summary: z
|
|
321
323
|
.unknown()
|
|
324
|
+
.optional()
|
|
322
325
|
.describe('Bounded causal summary: net {total,errors,headline}, consoleErrors, statePathsChanged, storageKeysChanged, stateDiffs [{path,from,to}], storageDiffs [{key,from,to}], route, signals, layoutShift, longTasks — real before→after diffs (capped), not just readings. THIS IS THE ANSWER TO "what did that click do": console, network, storage and state for this action are all here, so do NOT follow an act with reticle_console + reticle_network + reticle_state to find out — call them only to go deeper into something this block already pointed at. Every list is length-capped so the verdict can never be the field a client truncates; `elided` says which lists lost entries and how many. `stateUnwatched: true` means NO subscribable store is registered, so an empty stateDiffs means unwatched, NOT unchanged — no state conclusion is available until one is registered.'),
|
|
323
326
|
// Promoted out of `effect` on RED only — the file:line the failure came from, the first thing a
|
|
324
327
|
// repair wants. Undeclared, it was stripped on the validating profile exactly like the structured
|
|
@@ -351,8 +354,10 @@ export const ACT_TOOLS = [
|
|
|
351
354
|
.array(z.unknown())
|
|
352
355
|
.optional()
|
|
353
356
|
.describe('What the APP did not tell Reticle, and the one change that would fix it — each entry is { kind, missing, cost, fix, source?, ref? }. Reported ONLY where an absence made THIS verdict weaker (a red that cannot name a file:line, a state assertion with no registered store, a DOM change no signal announced, a route change nothing signalled); never a survey of the page, so an entry is always work worth doing now. OMITTED when the app told Reticle everything it needed. Applying `fix` makes every later verdict on this app stronger, not just this one.'),
|
|
357
|
+
engineBlindSpots: engineBlindSpotsOutput,
|
|
354
358
|
honesty: z
|
|
355
359
|
.unknown()
|
|
360
|
+
.optional()
|
|
356
361
|
.describe('The verdict trust block { grade, attribution, coverage, integrity, envelope? } — a green never looks stronger than this. Gate on grade ≥ net AND integrity.clean. Fields that were not measured are OMITTED rather than reported as zero, so treat an absent `envelope` as "not sampled", never as a failure.'),
|
|
357
362
|
since: z
|
|
358
363
|
.number()
|
|
@@ -451,7 +456,7 @@ export const ACT_TOOLS = [
|
|
|
451
456
|
// Dispatched — now this act owns the cursor and the effect. Marking its OWN measurement
|
|
452
457
|
// also stops the spread below from inheriting an earlier reticle_act's action and
|
|
453
458
|
// mutation count.
|
|
454
|
-
session.lastAct.markActed(since, asString(args['action']), mutatedWithin(asRecord(actResult.result)),
|
|
459
|
+
session.lastAct.markActed(since, asString(args['action']), mutatedWithin(asRecord(actResult.result)), resolved.ref);
|
|
455
460
|
}
|
|
456
461
|
// Honesty: floor the predicate at this act's cursor so a stale buffered event can't satisfy it.
|
|
457
462
|
const predicateStarted = session.elapsed();
|
|
@@ -504,17 +509,12 @@ export const ACT_TOOLS = [
|
|
|
504
509
|
? undefined
|
|
505
510
|
: buildDivergenceCapsule(links, windowEvents, bufferLost);
|
|
506
511
|
/*
|
|
507
|
-
* The blast radius
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
* somewhere I never mentioned" is exactly the finding a passing verdict buries. A click that
|
|
512
|
-
* works and also fires a DELETE is a green that did extra damage.
|
|
512
|
+
* The blast radius goes on a GREEN too. On a red the capsule carries it. On a green, a click
|
|
513
|
+
* that works and also sends a DELETE did extra damage, and no other field shows that.
|
|
514
|
+
* It is attached only when it is not empty, because its presence is the signal. The full
|
|
515
|
+
* capsule stays red-only: its divergence walk and causal summary answer a red's question.
|
|
513
516
|
*
|
|
514
|
-
* One pass over a window already in hand
|
|
515
|
-
* that is always present teaches a reader to skim it, and the whole value here is that its
|
|
516
|
-
* presence is the signal. The full capsule stays red-only — the divergence walk and the
|
|
517
|
-
* causal summary are the expensive halves and answer a question a green does not have.
|
|
517
|
+
* One pass over a window that is already in hand.
|
|
518
518
|
*/
|
|
519
519
|
const greenRadius = verdict.pass ? blastRadius(links, windowEvents) : [];
|
|
520
520
|
// Grade from what the verdict PROVED, not what it declared. A green anyOf holds on one branch, so
|
|
@@ -644,8 +644,8 @@ export const ACT_TOOLS = [
|
|
|
644
644
|
});
|
|
645
645
|
const outcomeUnread = unreadWriteLabels(windowEvents);
|
|
646
646
|
const stillInFlight = inFlightRequestLabels(windowEvents, session.url, session.background);
|
|
647
|
-
// A click on a disabled control cannot cause anything
|
|
648
|
-
const inconclusive = verdict.inconclusive ??
|
|
647
|
+
// A click on a disabled control cannot cause anything, nor one no person could make.
|
|
648
|
+
const inconclusive = verdict.inconclusive ?? actTargetNote(verdict.pass, actResult?.result);
|
|
649
649
|
const { decision, durable } = await withDurability(args['durable'], until, decideVerified({
|
|
650
650
|
pass: verdict.pass,
|
|
651
651
|
// Threaded rather than looked up: decideVerified is pure and has no session.
|
|
@@ -673,7 +673,9 @@ export const ACT_TOOLS = [
|
|
|
673
673
|
honesty,
|
|
674
674
|
contradictions,
|
|
675
675
|
...(0 === outcomePending.length ? {} : { outcomePending }),
|
|
676
|
-
...(outcomeUnread.length > 0
|
|
676
|
+
...(outcomeUnread.length > 0
|
|
677
|
+
? { outcomeUnread, outcomeUnreadReason: unreadWriteReason(windowEvents) }
|
|
678
|
+
: {}),
|
|
677
679
|
// `settled` is genuinely optional: a wait that declared no predicate never measured it, and
|
|
678
680
|
// passing `false` there would report "never settled" about something never asked to settle.
|
|
679
681
|
...(settledOutcome === undefined ? {} : { settled: settledOutcome }),
|
|
@@ -752,6 +754,7 @@ export const ACT_TOOLS = [
|
|
|
752
754
|
verdictEffect = {
|
|
753
755
|
claim: describeWaitTarget(until),
|
|
754
756
|
verified: decision.verified,
|
|
757
|
+
...checkIntent(until, verdict, asString(args['intent'])),
|
|
755
758
|
...(actedSourceLabel === undefined ? {} : { source: actedSourceLabel }),
|
|
756
759
|
...checkWords(verdict),
|
|
757
760
|
// TRUE here, and false on the `assert` path, and the difference is the point. This tool
|
|
@@ -796,19 +799,18 @@ export const ACT_TOOLS = [
|
|
|
796
799
|
// where an absence made this very verdict weaker — never as a survey of the page.
|
|
797
800
|
/*
|
|
798
801
|
* …and, on a pass, whether anybody said what this verdict was FOR.
|
|
799
|
-
*
|
|
800
802
|
* Intent capture was reachable and unasked-for: the argument sits on this very tool, and
|
|
801
803
|
* the only nudge lived on `flow_save` — which a build-mode agent may never reach. An
|
|
802
804
|
* optional capability nobody is told about is one nobody uses, measured on `bodies` this
|
|
803
805
|
* same week.
|
|
804
806
|
*/
|
|
805
|
-
// Remedy once per session, facts every time
|
|
806
|
-
// shipped 11 identical copies of its fix text in one measured drive.
|
|
807
|
+
// Remedy once per session, facts every time: see gap-novelty.ts for the measurement.
|
|
807
808
|
...(gaps.length > 0 || intentGap !== undefined
|
|
808
809
|
? {
|
|
809
810
|
instrumentationGaps: withGapNovelty(session.id, intentGap === undefined ? gaps : [...gaps, intentGap]),
|
|
810
811
|
}
|
|
811
812
|
: {}),
|
|
813
|
+
...engineBlindSpotsField(session.id, until, args['intent'], openIntents),
|
|
812
814
|
// Cross-channel disagreement, reported WITH the action that caused it.
|
|
813
815
|
//
|
|
814
816
|
// This is the one finding here a human structurally cannot make — they watch one channel,
|
|
@@ -832,7 +834,7 @@ export const ACT_TOOLS = [
|
|
|
832
834
|
}
|
|
833
835
|
finally {
|
|
834
836
|
if (dispatched !== undefined)
|
|
835
|
-
captureVerdictedAct(deps.recordings, args, dispatched.result, routeBeforeWait, recordedVerdict, session.id);
|
|
837
|
+
captureVerdictedAct(deps.recordings, args, dispatched.result, routeBeforeWait, recordedVerdict, session.id, wroteSince(acted, actedSince));
|
|
836
838
|
deps.recordings.markEnded(pathOf(currentOf(deps.sessions, session).url), session.id);
|
|
837
839
|
acted.finishAction(verdictEffect, settledOutcome, true === settledOutcome ? acted.elapsed() - actedSince : undefined);
|
|
838
840
|
}
|
|
@@ -75,6 +75,6 @@ export declare function shapeForAgent(tool: string, args: Record<string, unknown
|
|
|
75
75
|
*/
|
|
76
76
|
export declare function withCompactEnvelope<T extends {
|
|
77
77
|
name: string;
|
|
78
|
-
inputSchema: z.
|
|
79
|
-
outputSchema?: z.
|
|
78
|
+
inputSchema: Record<string, z.ZodType>;
|
|
79
|
+
outputSchema?: Record<string, z.ZodType>;
|
|
80
80
|
}>(tools: T[]): T[];
|
|
@@ -7,15 +7,53 @@
|
|
|
7
7
|
* which was already shaped. Everything here runs AFTER the verdict was decided and after telemetry
|
|
8
8
|
* read the full result; none of it can change a verdict.
|
|
9
9
|
*/
|
|
10
|
-
import {
|
|
10
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { AgentRules, ReticleTool } from '@reticlehq/core';
|
|
11
12
|
import { addAppNote, readAppNotes } from './app-notes.js';
|
|
12
13
|
import { shapeForAgent, wantsFull } from './compact-envelope.js';
|
|
13
14
|
import { learnFromVerdict } from './app-notes-learning.js';
|
|
14
15
|
import { reteachFor } from './reteach.js';
|
|
15
16
|
import { staleBuildNotice } from './build-staleness.js';
|
|
16
17
|
import { PRIMER_POINTER, foldNotices } from './notices.js';
|
|
17
|
-
import { dirname } from 'node:path';
|
|
18
|
+
import { dirname, join } from 'node:path';
|
|
18
19
|
import { keychainNoticeOnce, projectReader } from '../../../command/cli/doctor/doctor-signing-line.js';
|
|
20
|
+
const GIT_DIR = '.git';
|
|
21
|
+
/** A file's text, or empty when it cannot be read: a pointer is never worth a failed answer. */
|
|
22
|
+
function textOf(path) {
|
|
23
|
+
try {
|
|
24
|
+
return readFileSync(path, 'utf8');
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return '';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Whether `dir`, or a folder above it up to the repository root, has a rules file with the section. */
|
|
31
|
+
function rulesSectionAbove(dir) {
|
|
32
|
+
for (let at = dir;; at = dirname(at)) {
|
|
33
|
+
for (const file of AgentRules.FILES) {
|
|
34
|
+
if (textOf(join(at, file)).includes(AgentRules.BEGIN)) {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (existsSync(join(at, GIT_DIR)) || dirname(at) === at) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/** Read once per agent session: the pointer is said once, on the first answer. */
|
|
44
|
+
const sectionByAttach = new Map();
|
|
45
|
+
/**
|
|
46
|
+
* Only where `init` wrote the section. In an unwired project the pointer named a file that did not
|
|
47
|
+
* exist, so the agent was sent to read nothing.
|
|
48
|
+
*/
|
|
49
|
+
function primerPointerFor(attach, project) {
|
|
50
|
+
let has = sectionByAttach.get(attach);
|
|
51
|
+
if (has === undefined) {
|
|
52
|
+
has = project !== undefined && rulesSectionAbove(project);
|
|
53
|
+
sectionByAttach.set(attach, has);
|
|
54
|
+
}
|
|
55
|
+
return has ? [PRIMER_POINTER] : [];
|
|
56
|
+
}
|
|
19
57
|
const isRecord = (value) => 'object' === typeof value && null !== value && !Array.isArray(value);
|
|
20
58
|
export function forTheAgent(answer) {
|
|
21
59
|
const { name, args, attach, root } = answer;
|
|
@@ -37,7 +75,7 @@ export function forTheAgent(answer) {
|
|
|
37
75
|
return foldNotices(shaped, attach, answer.fold, [
|
|
38
76
|
...(stale === undefined ? [] : [stale]),
|
|
39
77
|
...(keychain === undefined ? [] : [keychain]),
|
|
40
|
-
|
|
78
|
+
...primerPointerFor(attach, project),
|
|
41
79
|
...notes,
|
|
42
80
|
...reteachFor(attach, name, args, shaped),
|
|
43
81
|
]);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*
|
|
11
11
|
* Pure: no IO, no clock.
|
|
12
12
|
*/
|
|
13
|
-
import { compareSourceClauses, isConsequenceKind, isPresenceKind, PredicateKind, } from '@reticlehq/core';
|
|
13
|
+
import { compareSourceClauses, ElementState, isConsequenceKind, isPresenceKind, PredicateKind, } from '@reticlehq/core';
|
|
14
14
|
import { HonestyGrade, strongerGrade, weakerGrade } from '@reticlehq/engine/evidence/honesty.js';
|
|
15
15
|
export const PRESENCE_ONLY_ADVICE = 'This predicate only checks element/text presence, not an observable consequence. A locator healed to the wrong element (or a stale render) can satisfy it while the feature is broken. Prefer a { signal } or { net } assertion (or allOf it with one) so green means the feature actually worked.';
|
|
16
16
|
function walk(predicate, negated = false) {
|
|
@@ -43,7 +43,7 @@ function walk(predicate, negated = false) {
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* An element predicate that checks
|
|
46
|
+
* An element predicate that checks its content or state, not merely that it is there.
|
|
47
47
|
*
|
|
48
48
|
* The presence nudge exists because "a locator healed to the wrong element, or a stale render, can
|
|
49
49
|
* satisfy this while the feature is broken". That is exactly true of `{ element, role, name }` and
|
|
@@ -58,7 +58,12 @@ function walk(predicate, negated = false) {
|
|
|
58
58
|
function assertsElementContent(predicate) {
|
|
59
59
|
if (predicate.kind !== PredicateKind.ELEMENT)
|
|
60
60
|
return false;
|
|
61
|
-
return predicate.query?.value !== undefined ||
|
|
61
|
+
return (predicate.query?.value !== undefined ||
|
|
62
|
+
predicate.query?.text !== undefined ||
|
|
63
|
+
(predicate.state !== undefined &&
|
|
64
|
+
predicate.state !== ElementState.PRESENT &&
|
|
65
|
+
predicate.state !== ElementState.VISIBLE &&
|
|
66
|
+
predicate.state !== ElementState.HIDDEN));
|
|
62
67
|
}
|
|
63
68
|
/**
|
|
64
69
|
* True when the predicate asserts ONLY element/text presence with no signal/net consequence anywhere
|