@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
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type { ToolDeps } from './tool-kit.js';
|
|
2
|
+
import { type ConfigFetch } from '../../features/harness/platform-config.js';
|
|
3
|
+
/** What the platform half of the gate reads off a drive's options; `ExploreOptions` satisfies it. */
|
|
4
|
+
export interface HarnessAsk {
|
|
5
|
+
skipPlatformConfig?: boolean;
|
|
6
|
+
configFetch?: ConfigFetch;
|
|
7
|
+
planId?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Why the harness is unavailable, phrased as the way to make it available.
|
|
11
|
+
*
|
|
12
|
+
* A missing key is a configuration fact, not a fault, and the sentence a user reads has to tell them
|
|
13
|
+
* the one thing to do about it. Named here because both the CLI and the honest no-flows refusal
|
|
14
|
+
* print it, and two copies of this sentence would drift.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MSG_NO_HARNESS_KEY: string;
|
|
17
|
+
/**
|
|
18
|
+
* The environment, plus the credential this machine already has.
|
|
19
|
+
*
|
|
20
|
+
* `reticle link` mints a project-scoped key and files it in `~/.reticle/credentials.json`; the CLI
|
|
21
|
+
* has read it from there for as long as it has existed. The harness did not, and read only
|
|
22
|
+
* `process.env` — so somebody who had signed in, linked their project and been told they were
|
|
23
|
+
* connected still got "no model configured to drive the app", and the only way out was to find the
|
|
24
|
+
* key in the console and export it by hand. Five manual steps to reach a feature they had already
|
|
25
|
+
* finished setting up.
|
|
26
|
+
*
|
|
27
|
+
* Resolved into the env rather than threaded through four call sites: the drivers and the
|
|
28
|
+
* preference lookup all read an env record, and giving them a completed one leaves each of them
|
|
29
|
+
* exactly as simple as it was. The key precedence is the resolver's, the same as sync's and the
|
|
30
|
+
* CLI's: the stored key for the link's host, else the exported one (which is how CI, with no
|
|
31
|
+
* keystore, gets here). An explicitly exported HOST still wins, so a proxy is not overridden.
|
|
32
|
+
*
|
|
33
|
+
* The credential arrives through `deps.linkedCloud`, a port, because resolving it here would make
|
|
34
|
+
* the tool surface reach into `memory/cloud` — a reach the directory guard refused, correctly.
|
|
35
|
+
*/
|
|
36
|
+
export declare function withLinkedCredential(deps: ToolDeps, env: Record<string, string | undefined>,
|
|
37
|
+
/**
|
|
38
|
+
* The tab a drive is for: its own project's link, not the daemon's. A plan saved with the
|
|
39
|
+
* daemon's key while its runs synced under the tab's project left every run link of the plan
|
|
40
|
+
* "Run unavailable". Absent: the daemon's own link.
|
|
41
|
+
*/
|
|
42
|
+
tab?: {
|
|
43
|
+
sessionId: string | undefined;
|
|
44
|
+
}): Promise<Record<string, string | undefined>>;
|
|
45
|
+
/** Introduces the prompt under a coverage refusal, so the agent knows it is for itself. */
|
|
46
|
+
export declare const MSG_GATE_PROMPT_LEAD = "To unlock it, do this (or hand it to your coding agent):";
|
|
47
|
+
/**
|
|
48
|
+
* Why the Harness must not drive this tab's app yet, or undefined when it may: below the coverage
|
|
49
|
+
* gate (core's `instrumentation-coverage.ts`), one reason sentence and the prompt that closes it. Every Harness
|
|
50
|
+
* start passes here (an agent's explore, Run Harness, `reticle try`, the platform's chat), so the
|
|
51
|
+
* gate holds wherever a drive starts; every other tool works at any coverage. A tab that cannot be
|
|
52
|
+
* resolved is not refused here: the drive itself answers for a missing tab. Counted once per refusal.
|
|
53
|
+
*/
|
|
54
|
+
export declare function coverageRefusal(deps: ToolDeps, sessionId: string | undefined): string | undefined;
|
|
55
|
+
/**
|
|
56
|
+
* The gate a Harness start obeys. When the project is linked, the platform's verdict is the one
|
|
57
|
+
* source of truth: it locks a run mid-drive on the same report, so a daemon that refused what the
|
|
58
|
+
* platform unlocked showed two scores for one project. The daemon's own reading only refuses when
|
|
59
|
+
* the platform said nothing (not linked, unreachable, an older API) or said locked too, in which
|
|
60
|
+
* case the daemon's sentence names what this tab can fix.
|
|
61
|
+
*/
|
|
62
|
+
export declare function harnessLockRefusal(deps: ToolDeps, sessionId: string | undefined, env: Record<string, string | undefined>, fetchConfig?: ConfigFetch): Promise<string | undefined>;
|
|
63
|
+
/**
|
|
64
|
+
* Can this machine reach the Harness? Only through the platform: a linked project or a platform
|
|
65
|
+
* key. Whether the workspace is entitled is the platform's answer, asked when the drive starts.
|
|
66
|
+
*/
|
|
67
|
+
export declare function harnessAvailable(env: Record<string, string | undefined>): boolean;
|
|
68
|
+
/**
|
|
69
|
+
* The reason this drive must not start, or `undefined` to go ahead.
|
|
70
|
+
*
|
|
71
|
+
* A drive on somebody's OWN model key never waits on the platform beyond the off switch: their key,
|
|
72
|
+
* their spend. A drive through the platform proxy bills Reticle, and that one needs a confirmed yes
|
|
73
|
+
* — enabled, entitled, and a model ready. It used to fail open: `fetchPlatformConfig` answers
|
|
74
|
+
* `undefined` on a network error, a non-2xx, a body that does not parse, or a two-second timeout,
|
|
75
|
+
* and all four read as "carry on", so a slow second on a settings endpoint let an unentitled
|
|
76
|
+
* workspace drive on Reticle's budget. Now the same silence refuses with a message that says to
|
|
77
|
+
* retry or bring a key. Fields an older platform omits still default to yes inside
|
|
78
|
+
* `fetchPlatformConfig`; only an answer that never arrived is a no.
|
|
79
|
+
*/
|
|
80
|
+
export declare function refusedByPlatform(env: Record<string, string | undefined>, options: HarnessAsk): Promise<string | undefined>;
|
|
81
|
+
/**
|
|
82
|
+
* `refusedByPlatform`, for a run that may be a saved plan. A plan that only replays saved flows
|
|
83
|
+
* spends no model turn, so a model drive's gates do not stop it; a refused plan is still reported to
|
|
84
|
+
* the plan, every journey blocked with the reason, so its history records the attempt.
|
|
85
|
+
*/
|
|
86
|
+
export declare function refusedForPlan(env: Record<string, string | undefined>, options: HarnessAsk): Promise<string | undefined>;
|
|
87
|
+
/** The sentence a refusal leads with, without the prompt that follows it. */
|
|
88
|
+
export declare const firstLine: (text: string) => string;
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the Harness may drive at all, and with which credential — answered before a drive starts.
|
|
3
|
+
*
|
|
4
|
+
* Split from `harness-explore.ts`, which runs the drive. This is the gate every Harness start passes
|
|
5
|
+
* through (an agent's explore, Run Harness, `reticle try`, the platform's chat): the linked
|
|
6
|
+
* credential, the instrumentation-coverage lock, and the platform's own yes or no.
|
|
7
|
+
*/
|
|
8
|
+
import { reportAppsNow } from '../../features/harness/platform/local-apps.js';
|
|
9
|
+
import { serverOptionsFromEnv } from '../../features/harness/platform/server-driver.js';
|
|
10
|
+
import { ReticleEnv, cloudUrlFrom } from '@reticlehq/core';
|
|
11
|
+
import { creditsSpent, creditsUsedLine } from '@reticlehq/core/hud';
|
|
12
|
+
import { planUrl } from '../../features/harness/platform/platform-drives.js';
|
|
13
|
+
import { isUnmatchedRoot } from '../../memory/project/dir/reticle-dir.js';
|
|
14
|
+
import { sessionRoot } from '../../memory/project/session-root.js';
|
|
15
|
+
import { fetchPlatformConfig } from '../../features/harness/platform-config.js';
|
|
16
|
+
import { reportPlanBlocked, savedPlanDrivesNothing } from '../../features/harness/platform/script.js';
|
|
17
|
+
import { instrumentationOf, probeMarkers } from '../../portal/session/recorded-gaps.js';
|
|
18
|
+
import { getSessionMetrics } from '../../telemetry/session-metrics.js';
|
|
19
|
+
import { MSG_HARNESS_DISABLED, MSG_HARNESS_UNCLAIMED, MSG_HARNESS_UNCONFIRMED, } from '../../features/harness/platform/refusal.js';
|
|
20
|
+
/**
|
|
21
|
+
* Why the harness is unavailable, phrased as the way to make it available.
|
|
22
|
+
*
|
|
23
|
+
* A missing key is a configuration fact, not a fault, and the sentence a user reads has to tell them
|
|
24
|
+
* the one thing to do about it. Named here because both the CLI and the honest no-flows refusal
|
|
25
|
+
* print it, and two copies of this sentence would drift.
|
|
26
|
+
*/
|
|
27
|
+
export const MSG_NO_HARNESS_KEY = `The Reticle Harness runs on the Reticle platform, and a new account gets 10 free credits ` +
|
|
28
|
+
`to try it: run \`reticle connect\` to link this project and sign in. ` +
|
|
29
|
+
`Without it, drive the journey yourself with reticle_act_and_wait and an \`until\` on its last step: ` +
|
|
30
|
+
`what you drive is saved as a flow just the same.`;
|
|
31
|
+
/**
|
|
32
|
+
* The environment, plus the credential this machine already has.
|
|
33
|
+
*
|
|
34
|
+
* `reticle link` mints a project-scoped key and files it in `~/.reticle/credentials.json`; the CLI
|
|
35
|
+
* has read it from there for as long as it has existed. The harness did not, and read only
|
|
36
|
+
* `process.env` — so somebody who had signed in, linked their project and been told they were
|
|
37
|
+
* connected still got "no model configured to drive the app", and the only way out was to find the
|
|
38
|
+
* key in the console and export it by hand. Five manual steps to reach a feature they had already
|
|
39
|
+
* finished setting up.
|
|
40
|
+
*
|
|
41
|
+
* Resolved into the env rather than threaded through four call sites: the drivers and the
|
|
42
|
+
* preference lookup all read an env record, and giving them a completed one leaves each of them
|
|
43
|
+
* exactly as simple as it was. The key precedence is the resolver's, the same as sync's and the
|
|
44
|
+
* CLI's: the stored key for the link's host, else the exported one (which is how CI, with no
|
|
45
|
+
* keystore, gets here). An explicitly exported HOST still wins, so a proxy is not overridden.
|
|
46
|
+
*
|
|
47
|
+
* The credential arrives through `deps.linkedCloud`, a port, because resolving it here would make
|
|
48
|
+
* the tool surface reach into `memory/cloud` — a reach the directory guard refused, correctly.
|
|
49
|
+
*/
|
|
50
|
+
export async function withLinkedCredential(deps, env,
|
|
51
|
+
/**
|
|
52
|
+
* The tab a drive is for: its own project's link, not the daemon's. A plan saved with the
|
|
53
|
+
* daemon's key while its runs synced under the tab's project left every run link of the plan
|
|
54
|
+
* "Run unavailable". Absent: the daemon's own link.
|
|
55
|
+
*/
|
|
56
|
+
tab) {
|
|
57
|
+
try {
|
|
58
|
+
const root = tab === undefined ? undefined : tabRoot(deps, tab);
|
|
59
|
+
// A tab whose page reported no project (its root is `unmatched/`) is nobody else's: it drives on
|
|
60
|
+
// the daemon's own link, never "run reticle connect" to a project that is linked.
|
|
61
|
+
const own = root !== undefined && isUnmatchedRoot(root) ? undefined : root;
|
|
62
|
+
const linked = await deps.linkedCloud?.(own);
|
|
63
|
+
if (linked === undefined || null === linked)
|
|
64
|
+
return env;
|
|
65
|
+
return {
|
|
66
|
+
...env,
|
|
67
|
+
[ReticleEnv.API_KEY]: linked.apiKey,
|
|
68
|
+
[ReticleEnv.CLOUD_URL]: cloudUrlFrom(env) ?? linked.url,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// A credential store that cannot be read is "not linked", not an error. The harness is optional
|
|
73
|
+
// and its absence is a routine answer; a drive must never fail because a JSON file was odd.
|
|
74
|
+
return env;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/** A tab's `.reticle`, or undefined (the daemon's) when the tab cannot be resolved to one. */
|
|
78
|
+
function tabRoot(deps, tab) {
|
|
79
|
+
try {
|
|
80
|
+
return sessionRoot(deps, tab.sessionId);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Introduces the prompt under a coverage refusal, so the agent knows it is for itself. */
|
|
87
|
+
export const MSG_GATE_PROMPT_LEAD = 'To unlock it, do this (or hand it to your coding agent):';
|
|
88
|
+
/**
|
|
89
|
+
* Why the Harness must not drive this tab's app yet, or undefined when it may: below the coverage
|
|
90
|
+
* gate (core's `instrumentation-coverage.ts`), one reason sentence and the prompt that closes it. Every Harness
|
|
91
|
+
* start passes here (an agent's explore, Run Harness, `reticle try`, the platform's chat), so the
|
|
92
|
+
* gate holds wherever a drive starts; every other tool works at any coverage. A tab that cannot be
|
|
93
|
+
* resolved is not refused here: the drive itself answers for a missing tab. Counted once per refusal.
|
|
94
|
+
*/
|
|
95
|
+
export function coverageRefusal(deps, sessionId) {
|
|
96
|
+
const refused = localGateRefusal(deps, sessionId);
|
|
97
|
+
if (refused !== undefined)
|
|
98
|
+
getSessionMetrics().recordHarnessRefused(refused.percent);
|
|
99
|
+
return refused?.text;
|
|
100
|
+
}
|
|
101
|
+
/** This tab and every other live tab of its app, or undefined when the tab cannot be resolved. */
|
|
102
|
+
function appTabsOf(deps, sessionId) {
|
|
103
|
+
let tab;
|
|
104
|
+
try {
|
|
105
|
+
tab = deps.sessions.resolve(sessionId);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
// Every tab of the app, the way the platform's merged report reads it, so the two name the same
|
|
111
|
+
// missing items.
|
|
112
|
+
const siblings = (deps.sessions.list?.() ?? [])
|
|
113
|
+
.filter((info) => info.sessionId !== tab.id && sameApp(info.projectId, tab.projectId))
|
|
114
|
+
.flatMap((info) => {
|
|
115
|
+
const live = deps.sessions.get?.(info.sessionId);
|
|
116
|
+
return live === undefined ? [] : [live];
|
|
117
|
+
});
|
|
118
|
+
return { tab, siblings };
|
|
119
|
+
}
|
|
120
|
+
/** The daemon's own reading of the gate for this tab's app, uncounted. */
|
|
121
|
+
function localGateRefusal(deps, sessionId) {
|
|
122
|
+
const app = appTabsOf(deps, sessionId);
|
|
123
|
+
if (app === undefined)
|
|
124
|
+
return undefined;
|
|
125
|
+
const { tab } = app;
|
|
126
|
+
const siblings = app.siblings.map((live) => ({
|
|
127
|
+
id: live.id,
|
|
128
|
+
url: live.url,
|
|
129
|
+
projectId: live.projectId,
|
|
130
|
+
channels: live.channels,
|
|
131
|
+
sourceMapping: live.sourceMapping,
|
|
132
|
+
}));
|
|
133
|
+
const coverage = instrumentationOf(tab, siblings);
|
|
134
|
+
const gate = coverage.harnessGate;
|
|
135
|
+
if (gate.unlocked || gate.reason === undefined)
|
|
136
|
+
return undefined;
|
|
137
|
+
const text = coverage.prompt === undefined
|
|
138
|
+
? gate.reason
|
|
139
|
+
: `${gate.reason}\n\n${MSG_GATE_PROMPT_LEAD}\n${coverage.prompt}`;
|
|
140
|
+
return { text, percent: gate.percent };
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The gate a Harness start obeys. When the project is linked, the platform's verdict is the one
|
|
144
|
+
* source of truth: it locks a run mid-drive on the same report, so a daemon that refused what the
|
|
145
|
+
* platform unlocked showed two scores for one project. The daemon's own reading only refuses when
|
|
146
|
+
* the platform said nothing (not linked, unreachable, an older API) or said locked too, in which
|
|
147
|
+
* case the daemon's sentence names what this tab can fix.
|
|
148
|
+
*/
|
|
149
|
+
export async function harnessLockRefusal(deps, sessionId, env, fetchConfig) {
|
|
150
|
+
// What the app's pages carry decides, not what an act happened to reach: ask them first.
|
|
151
|
+
const app = appTabsOf(deps, sessionId);
|
|
152
|
+
// Learned something: the platform hears it before it is asked, or it refuses on its old score.
|
|
153
|
+
if (app !== undefined && (await probeMarkers([app.tab, ...app.siblings])))
|
|
154
|
+
await reportAppsNow().catch(() => undefined);
|
|
155
|
+
if (undefined === localGateRefusal(deps, sessionId))
|
|
156
|
+
return undefined;
|
|
157
|
+
const platform = await fetchPlatformConfig(env, fetchConfig);
|
|
158
|
+
if (true === platform?.gate?.unlocked)
|
|
159
|
+
return undefined;
|
|
160
|
+
return coverageRefusal(deps, sessionId);
|
|
161
|
+
}
|
|
162
|
+
/** Two tabs are one app when both name the same project. A tab that names none stands alone. */
|
|
163
|
+
const sameApp = (a, b) => a !== undefined && a === b;
|
|
164
|
+
/**
|
|
165
|
+
* Can this machine reach the Harness? Only through the platform: a linked project or a platform
|
|
166
|
+
* key. Whether the workspace is entitled is the platform's answer, asked when the drive starts.
|
|
167
|
+
*/
|
|
168
|
+
export function harnessAvailable(env) {
|
|
169
|
+
return serverOptionsFromEnv(env) !== undefined;
|
|
170
|
+
}
|
|
171
|
+
/** One read, however many questions are asked of the answer. */
|
|
172
|
+
function platformConfig(env, options) {
|
|
173
|
+
return options.configFetch === undefined
|
|
174
|
+
? fetchPlatformConfig(env)
|
|
175
|
+
: fetchPlatformConfig(env, options.configFetch);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The reason this drive must not start, or `undefined` to go ahead.
|
|
179
|
+
*
|
|
180
|
+
* A drive on somebody's OWN model key never waits on the platform beyond the off switch: their key,
|
|
181
|
+
* their spend. A drive through the platform proxy bills Reticle, and that one needs a confirmed yes
|
|
182
|
+
* — enabled, entitled, and a model ready. It used to fail open: `fetchPlatformConfig` answers
|
|
183
|
+
* `undefined` on a network error, a non-2xx, a body that does not parse, or a two-second timeout,
|
|
184
|
+
* and all four read as "carry on", so a slow second on a settings endpoint let an unentitled
|
|
185
|
+
* workspace drive on Reticle's budget. Now the same silence refuses with a message that says to
|
|
186
|
+
* retry or bring a key. Fields an older platform omits still default to yes inside
|
|
187
|
+
* `fetchPlatformConfig`; only an answer that never arrived is a no.
|
|
188
|
+
*/
|
|
189
|
+
export async function refusedByPlatform(env, options) {
|
|
190
|
+
if (true === options.skipPlatformConfig)
|
|
191
|
+
return undefined;
|
|
192
|
+
// No platform, no Harness: it runs there, on the workspace's credits.
|
|
193
|
+
if (serverOptionsFromEnv(env) === undefined)
|
|
194
|
+
return MSG_NO_HARNESS_KEY;
|
|
195
|
+
const config = await platformConfig(env, options);
|
|
196
|
+
// It needs a confirmed yes, not the absence of a no. The platform also checks on every turn.
|
|
197
|
+
if (config === undefined)
|
|
198
|
+
return MSG_HARNESS_UNCONFIRMED;
|
|
199
|
+
// The project-wide lock before the switch: a fresh tab passes the per-tab gate with no gaps
|
|
200
|
+
// recorded, and "off" hid the one refusal that names its fix.
|
|
201
|
+
const gate = config.gate;
|
|
202
|
+
if (false === gate?.unlocked && gate.reason !== undefined)
|
|
203
|
+
return gate.prompt === undefined
|
|
204
|
+
? gate.reason
|
|
205
|
+
: `${gate.reason}\n\n${MSG_GATE_PROMPT_LEAD}\n${gate.prompt}`;
|
|
206
|
+
if (!config.harnessEnabled)
|
|
207
|
+
return MSG_HARNESS_DISABLED;
|
|
208
|
+
// Before entitlement: no credits left is why most workspaces are not entitled, said as the HUD says it.
|
|
209
|
+
if (config.credits !== undefined && creditsSpent(config.credits))
|
|
210
|
+
return creditsUsedLine(config.credits,
|
|
211
|
+
// The platform's own page; built from the API origin only for a platform that names none.
|
|
212
|
+
config.planUrl ?? planUrl(config.platformUrl ?? cloudUrlFrom(env) ?? ''));
|
|
213
|
+
if (!config.harnessEntitled)
|
|
214
|
+
return MSG_HARNESS_UNCLAIMED;
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* `refusedByPlatform`, for a run that may be a saved plan. A plan that only replays saved flows
|
|
219
|
+
* spends no model turn, so a model drive's gates do not stop it; a refused plan is still reported to
|
|
220
|
+
* the plan, every journey blocked with the reason, so its history records the attempt.
|
|
221
|
+
*/
|
|
222
|
+
export async function refusedForPlan(env, options) {
|
|
223
|
+
const planId = options.planId;
|
|
224
|
+
const platform = serverOptionsFromEnv(env);
|
|
225
|
+
if (planId === undefined || platform === undefined)
|
|
226
|
+
return refusedByPlatform(env, options);
|
|
227
|
+
if (await savedPlanDrivesNothing(platform, planId))
|
|
228
|
+
return undefined;
|
|
229
|
+
const refusal = await refusedByPlatform(env, options);
|
|
230
|
+
if (refusal !== undefined)
|
|
231
|
+
await reportPlanBlocked(platform, planId, firstLine(refusal));
|
|
232
|
+
return refusal;
|
|
233
|
+
}
|
|
234
|
+
/** The sentence a refusal leads with, without the prompt that follows it. */
|
|
235
|
+
export const firstLine = (text) => text.split('\n')[0] ?? text;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { RunDisparity } from '@reticlehq/core';
|
|
2
|
+
import type { HarnessMap } from '@reticlehq/core/artifacts';
|
|
3
|
+
import { type Goal, type GoalCheck } from '../../features/harness/goals.js';
|
|
4
|
+
import type { ToolOutcome } from '../../features/harness/harness.js';
|
|
5
|
+
import type { Invoke } from '../../features/harness/explore/page-tree.js';
|
|
6
|
+
import type { ToolDeps } from './tool-kit.js';
|
|
7
|
+
/** The pages a map knows, by route: what a drive is pointed at before it guesses. */
|
|
8
|
+
export declare const knownRoutes: (map: HarnessMap | undefined) => string[];
|
|
9
|
+
/** The app's map: the kept one while it is fresh, else a new survey merged over it. */
|
|
10
|
+
export declare function siteMapFor(deps: ToolDeps, sessionId: string | undefined, invoke: Invoke): Promise<HarnessMap | undefined>;
|
|
11
|
+
/** What a drive read, folded into the kept map, so the map grows from use. */
|
|
12
|
+
export declare function refreshMap(deps: ToolDeps, sessionId: string | undefined, map: HarnessMap | undefined, calls: readonly ToolOutcome[]): Promise<void>;
|
|
13
|
+
/** A drive's goals as graded, and how each compared with the agent's verdict. */
|
|
14
|
+
export interface Graded {
|
|
15
|
+
goals: GoalCheck[];
|
|
16
|
+
disparity: RunDisparity[];
|
|
17
|
+
/** The navigations and clicks the hunt made: the Harness driving the app, said as such. */
|
|
18
|
+
moved: ToolOutcome[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* One grade from each lane's: per goal, the lane that proved it, else one that disproved it on its
|
|
22
|
+
* own page, else the first. A plan's lane that reached the end text proved it, whatever the others
|
|
23
|
+
* (a known-defects lane, a lane on another page) saw.
|
|
24
|
+
*/
|
|
25
|
+
export declare function bestOfLanes(lanes: readonly Graded[]): Graded;
|
|
26
|
+
/**
|
|
27
|
+
* The goals graded after a hunt for the journey's end. The end is the last goal the page did not
|
|
28
|
+
* already show; when the hunt does not find it the check is undecided and says where it looked.
|
|
29
|
+
*/
|
|
30
|
+
export declare function huntAndGrade(deps: ToolDeps, driving: Invoke, ask: {
|
|
31
|
+
sessionId?: string | undefined;
|
|
32
|
+
goals: readonly (string | Goal)[];
|
|
33
|
+
expect?: Record<string, unknown> | undefined;
|
|
34
|
+
opening?: string | undefined;
|
|
35
|
+
journey?: string | undefined;
|
|
36
|
+
map?: HarnessMap | undefined;
|
|
37
|
+
/** Text the Harness wrote besides the journey: its plan's journeys, its flows' names. */
|
|
38
|
+
own?: readonly string[] | undefined;
|
|
39
|
+
/** The pages the drive reached (`pagesReached`), searched when the end is not where it stopped. */
|
|
40
|
+
reached?: readonly string[] | undefined;
|
|
41
|
+
/** The values the drive typed (`typedValues`): inputs, graded only when one is the end. */
|
|
42
|
+
typed?: readonly string[] | undefined;
|
|
43
|
+
}): Promise<Graded>;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The exploratory Harness around a drive: map the app first, hunt for the goal before grading it,
|
|
3
|
+
* and compare the verdict with the coding agent's. The drive itself is the platform's; these are the
|
|
4
|
+
* daemon's deterministic halves, shared by the planned and the unplanned path.
|
|
5
|
+
*/
|
|
6
|
+
import { dirname, join } from 'node:path';
|
|
7
|
+
import { checkExpect, checkGoals, endGoalsOf, } from '../../features/harness/goals.js';
|
|
8
|
+
import { ReticleTool } from '@reticlehq/core';
|
|
9
|
+
import { searchForGoal } from '../../features/harness/explore/goal-search.js';
|
|
10
|
+
import { MAP_FRESH_MS, mergePages, pagesReadIn, parseMap, surveyApp, } from '../../features/harness/explore/site-map.js';
|
|
11
|
+
import { agentVerdictsIn, disparityFor } from '../../features/harness/explore/disparity.js';
|
|
12
|
+
import { reticleDirPaths } from '../../memory/project/dir/reticle-dir.js';
|
|
13
|
+
import { sessionRoot } from '../../memory/project/session-root.js';
|
|
14
|
+
import { JournalActionSchema, ReticleDir, Verified, VerifiedReason, } from '@reticlehq/core';
|
|
15
|
+
import { isValidSessionId } from '../../memory/project/dir/reticle-dir.js';
|
|
16
|
+
/**
|
|
17
|
+
* Kept beside the plans: what this machine's drives learned about the app, local like them.
|
|
18
|
+
* ponytail: a file in `plans/`, not a new `.reticle/` name, which would need the workspace tiers
|
|
19
|
+
* and the ignore file to learn it; give it its own name if it ever needs to be shared.
|
|
20
|
+
*/
|
|
21
|
+
const HARNESS_MAP_FILE = 'harness-map.json';
|
|
22
|
+
/** Fewer pages than this and the kept map is not a map of the app. */
|
|
23
|
+
const MIN_MAPPED_PAGES = 2;
|
|
24
|
+
/** Sessions read from disk for the agent's verdicts: the recent past of one project, not its history. */
|
|
25
|
+
const MAX_JOURNALS_READ = 40;
|
|
26
|
+
function mapPath(deps, sessionId) {
|
|
27
|
+
try {
|
|
28
|
+
return join(reticleDirPaths(sessionRoot(deps, sessionId)).plans, HARNESS_MAP_FILE);
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function readMap(deps, path) {
|
|
35
|
+
try {
|
|
36
|
+
return parseMap(await deps.fs.readFile(path));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function writeMap(deps, path, map) {
|
|
43
|
+
try {
|
|
44
|
+
await deps.fs.mkdir(dirname(path));
|
|
45
|
+
await deps.fs.writeFile(path, `${JSON.stringify(map, null, 2)}\n`);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
/* a map that cannot be kept is surveyed again next time */
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/** The pages a map knows, by route: what a drive is pointed at before it guesses. */
|
|
52
|
+
export const knownRoutes = (map) => map === undefined ? [] : [...new Set(map.pages.map((page) => page.route))];
|
|
53
|
+
/** The app's map: the kept one while it is fresh, else a new survey merged over it. */
|
|
54
|
+
export async function siteMapFor(deps, sessionId, invoke) {
|
|
55
|
+
const path = mapPath(deps, sessionId);
|
|
56
|
+
const kept = path === undefined ? undefined : await readMap(deps, path);
|
|
57
|
+
// A map of one page is a survey that saw nothing (a menu was open): it is surveyed again.
|
|
58
|
+
if (kept !== undefined &&
|
|
59
|
+
MIN_MAPPED_PAGES <= kept.pages.length &&
|
|
60
|
+
deps.now() - kept.surveyedAt < MAP_FRESH_MS)
|
|
61
|
+
return kept;
|
|
62
|
+
const surveyed = await surveyApp(invoke, deps.now);
|
|
63
|
+
if (surveyed === undefined)
|
|
64
|
+
return kept;
|
|
65
|
+
const map = kept === undefined ? surveyed : mergePages(kept, surveyed.pages, surveyed.surveyedAt);
|
|
66
|
+
if (path !== undefined)
|
|
67
|
+
await writeMap(deps, path, map);
|
|
68
|
+
return map;
|
|
69
|
+
}
|
|
70
|
+
/** What a drive read, folded into the kept map, so the map grows from use. */
|
|
71
|
+
export async function refreshMap(deps, sessionId, map, calls) {
|
|
72
|
+
const path = mapPath(deps, sessionId);
|
|
73
|
+
if (path === undefined || map === undefined)
|
|
74
|
+
return;
|
|
75
|
+
const read = pagesReadIn(calls, deps.now());
|
|
76
|
+
if (0 < read.length)
|
|
77
|
+
await writeMap(deps, path, mergePages(map, read));
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The decided verdicts the connected agent made on this app: in its live tabs, and in the journals
|
|
81
|
+
* on disk of tabs that have closed. Persona 21's agent proved both goals on a tab that had closed by
|
|
82
|
+
* the time the Harness graded, and the comparison was never made.
|
|
83
|
+
*/
|
|
84
|
+
async function agentVerdicts(deps, sessionId) {
|
|
85
|
+
let projectId;
|
|
86
|
+
let own;
|
|
87
|
+
try {
|
|
88
|
+
const tab = deps.sessions.resolve(sessionId);
|
|
89
|
+
projectId = tab.projectId;
|
|
90
|
+
own = tab.id;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
const tabs = deps.sessions
|
|
96
|
+
.all()
|
|
97
|
+
.filter((s) => s.id === own || (projectId !== undefined && s.projectId === projectId));
|
|
98
|
+
const live = await Promise.all(tabs.map((s) => s.readJournalActions().catch(() => [])));
|
|
99
|
+
const onDisk = await journalsOnDisk(deps, sessionId, new Set(tabs.map((s) => s.id)));
|
|
100
|
+
return agentVerdictsIn([...live.flat(), ...onDisk]);
|
|
101
|
+
}
|
|
102
|
+
/** A journal's lines as actions; a line that does not parse is left out, as the journal reader does. */
|
|
103
|
+
function actionsIn(text) {
|
|
104
|
+
return text.split('\n').flatMap((line) => {
|
|
105
|
+
if (0 === line.trim().length)
|
|
106
|
+
return [];
|
|
107
|
+
try {
|
|
108
|
+
const parsed = JournalActionSchema.safeParse(JSON.parse(line));
|
|
109
|
+
return parsed.success ? [parsed.data] : [];
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/** The actions of this project's sessions that are no longer live, from their journals. */
|
|
117
|
+
async function journalsOnDisk(deps, sessionId, live) {
|
|
118
|
+
try {
|
|
119
|
+
const root = sessionRoot(deps, sessionId);
|
|
120
|
+
const ids = (await deps.fs.readdir(reticleDirPaths(root).sessions))
|
|
121
|
+
.filter((id) => !live.has(id) && isValidSessionId(id))
|
|
122
|
+
.slice(-MAX_JOURNALS_READ);
|
|
123
|
+
const read = await Promise.all(ids.map((id) => deps.fs
|
|
124
|
+
.readFile(join(reticleDirPaths(root).sessions, id, ReticleDir.JOURNAL_ACTIONS_FILE))
|
|
125
|
+
.then(actionsIn)
|
|
126
|
+
.catch(() => [])));
|
|
127
|
+
return read.flat();
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** What the hunt does to the app. Its asserts are not kept here: they would count as checks. */
|
|
134
|
+
const HUNT_MOVES = new Set([ReticleTool.NAVIGATE, ReticleTool.ACT]);
|
|
135
|
+
/** The invoke, keeping each move it makes. */
|
|
136
|
+
function keepingMoves(invoke, moved) {
|
|
137
|
+
return async (name, args) => {
|
|
138
|
+
const result = await invoke(name, args);
|
|
139
|
+
if (HUNT_MOVES.has(name))
|
|
140
|
+
moved.push({ id: `hunt-${String(moved.length + 1)}`, name, args, result, isError: false });
|
|
141
|
+
return result;
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
const RANK = { [Verified.YES]: 0, [Verified.NO]: 1 };
|
|
145
|
+
/**
|
|
146
|
+
* One grade from each lane's: per goal, the lane that proved it, else one that disproved it on its
|
|
147
|
+
* own page, else the first. A plan's lane that reached the end text proved it, whatever the others
|
|
148
|
+
* (a known-defects lane, a lane on another page) saw.
|
|
149
|
+
*/
|
|
150
|
+
export function bestOfLanes(lanes) {
|
|
151
|
+
const first = lanes[0] ?? { goals: [], disparity: [], moved: [] };
|
|
152
|
+
const goals = first.goals
|
|
153
|
+
.map((_, i) => {
|
|
154
|
+
const all = lanes.flatMap((l) => (l.goals[i] === undefined ? [] : [l.goals[i]]));
|
|
155
|
+
return ([...all].sort((a, b) => (RANK[a.verified] ?? 2) - (RANK[b.verified] ?? 2))[0] ??
|
|
156
|
+
first.goals[i]);
|
|
157
|
+
})
|
|
158
|
+
.filter((g) => g !== undefined);
|
|
159
|
+
const disparity = goals.flatMap((g) => {
|
|
160
|
+
const lane = lanes.find((l) => l.goals.includes(g));
|
|
161
|
+
return lane?.disparity.filter((d) => d.goal === g.text) ?? [];
|
|
162
|
+
});
|
|
163
|
+
return { goals, disparity, moved: lanes.flatMap((l) => l.moved) };
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* The goals graded after a hunt for the journey's end. The end is the last goal the page did not
|
|
167
|
+
* already show; when the hunt does not find it the check is undecided and says where it looked.
|
|
168
|
+
*/
|
|
169
|
+
export async function huntAndGrade(deps, driving, ask) {
|
|
170
|
+
const moved = [];
|
|
171
|
+
const invoke = keepingMoves(driving, moved);
|
|
172
|
+
// The journey names the plan and the flows this run saves: shown back on a page, it proves nothing.
|
|
173
|
+
const own = [...(ask.own ?? []), ...(ask.journey === undefined ? [] : [ask.journey])];
|
|
174
|
+
const goals = endGoalsOf(ask.goals.map((g) => ('string' === typeof g ? { text: g } : g)), ask.typed ?? []);
|
|
175
|
+
const end = goals
|
|
176
|
+
.filter((g) => true !== g.absent && true !== ask.opening?.includes(g.text))
|
|
177
|
+
.at(-1);
|
|
178
|
+
const hunt = (goal) => searchForGoal(invoke, {
|
|
179
|
+
goal,
|
|
180
|
+
...(ask.journey === undefined ? {} : { journey: ask.journey }),
|
|
181
|
+
...(ask.map === undefined ? {} : { map: ask.map }),
|
|
182
|
+
...(ask.reached === undefined ? {} : { reached: ask.reached }),
|
|
183
|
+
own,
|
|
184
|
+
});
|
|
185
|
+
const search = end === undefined ? undefined : await hunt(end.text);
|
|
186
|
+
// The end not found anywhere: the tab is left where an earlier goal is, so that one is graded
|
|
187
|
+
// where it shows rather than where the hunt gave up.
|
|
188
|
+
if (search !== undefined && !search.found)
|
|
189
|
+
for (const earlier of goals.filter((g) => g !== end && true !== g.absent).reverse())
|
|
190
|
+
if ((await hunt(earlier.text)).found)
|
|
191
|
+
break;
|
|
192
|
+
const checks = (await checkGoals(invoke, goals, ask.opening, own)).map((c) => end !== undefined &&
|
|
193
|
+
c.text === end.text &&
|
|
194
|
+
Verified.YES !== c.verified &&
|
|
195
|
+
search !== undefined &&
|
|
196
|
+
!search.found
|
|
197
|
+
? {
|
|
198
|
+
...c,
|
|
199
|
+
reason: `${VerifiedReason.INCONCLUSIVE}: not found after searching ${search.searched.join(' → ')}`,
|
|
200
|
+
}
|
|
201
|
+
: c);
|
|
202
|
+
const agent = await agentVerdicts(deps, ask.sessionId);
|
|
203
|
+
const disparity = checks.flatMap((c) => {
|
|
204
|
+
const d = disparityFor(c, agent, c.text === end?.text ? search : undefined);
|
|
205
|
+
return d === undefined ? [] : [d];
|
|
206
|
+
});
|
|
207
|
+
return {
|
|
208
|
+
goals: [
|
|
209
|
+
...checks,
|
|
210
|
+
...(ask.expect === undefined ? [] : [await checkExpect(invoke, ask.expect)]),
|
|
211
|
+
],
|
|
212
|
+
disparity,
|
|
213
|
+
moved,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
@@ -80,6 +80,11 @@ export declare function planAsText(plan: HarnessPlan): string;
|
|
|
80
80
|
* the journey it was asked for, and spent most of its drive there.
|
|
81
81
|
*/
|
|
82
82
|
export declare function withoutReplays(plan: HarnessPlan): HarnessPlan;
|
|
83
|
+
/**
|
|
84
|
+
* The plan a drive is handed: the gaps, or nothing beside a journey a person named. A named run was
|
|
85
|
+
* handed every other session's open intents too, and named its flow after one of them.
|
|
86
|
+
*/
|
|
87
|
+
export declare function drivingPlan(plan: HarnessPlan, focus: string | undefined): HarnessPlan;
|
|
83
88
|
/**
|
|
84
89
|
* What the planner is told about the product: the plan from `.reticle`, then the app's own controls
|
|
85
90
|
* as they are on screen now. With only the plan, an empty project read "PLAN: none" and the planner
|
|
@@ -163,6 +163,13 @@ export function planAsText(plan) {
|
|
|
163
163
|
export function withoutReplays(plan) {
|
|
164
164
|
return { ...plan, steps: plan.steps.filter((step) => PlanStepKind.DRIVE === step.kind) };
|
|
165
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* The plan a drive is handed: the gaps, or nothing beside a journey a person named. A named run was
|
|
168
|
+
* handed every other session's open intents too, and named its flow after one of them.
|
|
169
|
+
*/
|
|
170
|
+
export function drivingPlan(plan, focus) {
|
|
171
|
+
return focus === undefined ? withoutReplays(plan) : { ...plan, steps: [] };
|
|
172
|
+
}
|
|
166
173
|
/** How much of the live page the planner reads. Enough for a dashboard's nav and main controls. */
|
|
167
174
|
const MAX_ABOUT_SNAPSHOT = 6_000;
|
|
168
175
|
/**
|
|
@@ -1,8 +1,30 @@
|
|
|
1
|
+
import { type SeedStorage } from '@reticlehq/core';
|
|
2
|
+
import { type JourneyStatus } from '../../features/harness/drive-report.js';
|
|
3
|
+
import { type HarnessResult } from '../../features/harness/harness.js';
|
|
1
4
|
import type { ToolDeps } from './tool-kit.js';
|
|
2
5
|
import { type ExploreOptions, type ExploreResult } from './harness-explore.js';
|
|
6
|
+
/** A saved plan this run was asked for and could not read: said, never swapped for another drive. */
|
|
7
|
+
export declare const msgSavedPlanUnreadable: (planId: string) => string;
|
|
8
|
+
/** The platform could not plan the run: the drive that follows is the journey alone, unplanned. */
|
|
9
|
+
export declare const msgNoPlan: (why: string) => string;
|
|
10
|
+
/** Said when a plan's lanes cannot carry this tab's sign-in into new browsers, so they take turns here. */
|
|
11
|
+
export declare const MSG_LANES_IN_THIS_TAB: string;
|
|
12
|
+
/**
|
|
13
|
+
* The sign-in a plan's lanes start from: what this tab's browser holds, or undefined when it cannot
|
|
14
|
+
* be copied (no browser this daemon drives, nothing to copy), in which case the lanes take turns here.
|
|
15
|
+
*/
|
|
16
|
+
export declare function laneSeed(deps: ToolDeps, sessionId: string | undefined, appUrl: string | undefined): Promise<SeedStorage | undefined>;
|
|
3
17
|
/**
|
|
4
18
|
* The platform plans the drive; this machine runs the plan: saved flows replayed in lanes side by side, shared starts
|
|
5
19
|
* driven once and branched from, open journeys handed to the model. `undefined` when there is
|
|
6
20
|
* nothing to plan from, so the caller drives the app with no plan, as before.
|
|
7
21
|
*/
|
|
8
22
|
export declare function exploreScript(deps: ToolDeps, env: Record<string, string | undefined>, options: ExploreOptions, before: ReadonlySet<string>): Promise<ExploreResult | undefined>;
|
|
23
|
+
/**
|
|
24
|
+
* The run's goal verdict: false if any drive missed its goal, true if all judged ones reached it.
|
|
25
|
+
* Every journey passed is the page's answer, already graded at each journey's end: a driver's own
|
|
26
|
+
* "not done" (a lane whose model call failed) read "but the goal was not reached" beside it.
|
|
27
|
+
*/
|
|
28
|
+
export declare function goalOfRun(drives: readonly HarnessResult[], journeys: readonly JourneyStatus[]): {
|
|
29
|
+
goalMet?: boolean;
|
|
30
|
+
};
|