@reticlehq/server 3.2.0 → 3.4.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/LICENSE-ENTERPRISE +1 -1
- package/README.md +3 -3
- package/SKILL.md +23 -22
- package/dist/chromium-launch-options.d.ts +4 -3
- package/dist/chromium-launch-options.js +6 -2
- package/dist/command/cli/adhoc-suite.d.ts +41 -0
- package/dist/command/cli/adhoc-suite.js +159 -0
- package/dist/command/cli/adhoc-verdict.d.ts +58 -2
- package/dist/command/cli/adhoc-verdict.js +108 -13
- package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
- package/dist/command/cli/answers/gate-hook-message.js +6 -0
- package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
- package/dist/command/cli/auth/cloud-keystore.js +0 -3
- package/dist/command/cli/auth/cloud-session.d.ts +4 -0
- package/dist/command/cli/auth/cloud-session.js +2 -0
- package/dist/command/cli/cli-doctor.js +30 -8
- package/dist/command/cli/cli-flow-commands.d.ts +3 -6
- package/dist/command/cli/cli-flow-commands.js +67 -4
- package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
- package/dist/command/cli/cli-parse-grammar.js +7 -0
- package/dist/command/cli/cli-parse-verify.d.ts +2 -5
- package/dist/command/cli/cli-parse-verify.js +86 -13
- package/dist/command/cli/cli-parse.d.ts +14 -1
- package/dist/command/cli/cli-parse.js +54 -8
- package/dist/command/cli/cli-update-commands.js +8 -1
- package/dist/command/cli/cli-verify.d.ts +80 -0
- package/dist/command/cli/cli-verify.js +181 -26
- package/dist/command/cli/cloud-cli.js +5 -2
- package/dist/command/cli/cloud-kit.d.ts +0 -2
- package/dist/command/cli/cloud-kit.js +3 -5
- package/dist/command/cli/cloud-login.js +21 -3
- package/dist/command/cli/demo/demo-page.js +6 -3
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
- package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
- package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
- package/dist/command/cli/launch/cli-launch.d.ts +9 -29
- package/dist/command/cli/launch/cli-launch.js +27 -49
- package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
- package/dist/command/cli/launch/sdk-version-match.js +206 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
- package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
- package/dist/command/cli/ports/resolve/cli-port.js +169 -15
- package/dist/command/cli/report-command.d.ts +16 -0
- package/dist/command/cli/report-command.js +97 -0
- package/dist/command/cli/setup-mcp-cli.js +13 -13
- package/dist/command/cli/tutorial.d.ts +2 -2
- package/dist/command/cli/tutorial.js +21 -7
- package/dist/command/cli.js +67 -10
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
- package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
- package/dist/command/daemon/binding/port-presence.d.ts +1 -1
- package/dist/command/daemon/daemon-resolve.d.ts +9 -0
- package/dist/command/daemon/daemon-resolve.js +1 -1
- package/dist/command/daemon/idle-shutdown.d.ts +2 -1
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
- package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
- package/dist/command/dev/stale-issue-guard.d.ts +3 -4
- package/dist/command/dev/stale-issue-guard.js +8 -8
- package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
- package/dist/command/setup/bringup/connect-lease.js +38 -0
- package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
- package/dist/command/setup/bringup/dev-server-files.js +131 -0
- package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
- package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
- package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
- package/dist/command/setup/bringup/ensure-daemon.js +135 -16
- package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
- package/dist/command/setup/bringup/static-page-server.js +151 -0
- package/dist/command/setup/desktop-shape.d.ts +4 -0
- package/dist/command/setup/desktop-shape.js +18 -2
- package/dist/command/setup/init/init-host.js +8 -0
- package/dist/command/setup/init/init-port.d.ts +15 -0
- package/dist/command/setup/init/init-port.js +44 -0
- package/dist/command/setup/init/init-runtime.d.ts +1 -1
- package/dist/command/setup/init/init-runtime.js +39 -2
- package/dist/command/setup/node-effects.d.ts +27 -14
- package/dist/command/setup/node-effects.js +80 -44
- package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
- package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
- package/dist/command/setup/probe/page-probe.d.ts +13 -2
- package/dist/command/setup/probe/page-probe.js +18 -3
- package/dist/command/setup/run-setup.d.ts +26 -1
- package/dist/command/setup/run-setup.js +96 -13
- package/dist/command/setup/session-pick.d.ts +13 -0
- package/dist/command/setup/session-pick.js +20 -0
- package/dist/command/setup/setup-command.d.ts +2 -14
- package/dist/command/setup/setup-command.js +105 -31
- package/dist/command/setup/setup-mcp.js +3 -3
- package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
- package/dist/command/setup/terminal/wait-progress.js +17 -0
- package/dist/features/crawl/crawl-empty.js +1 -1
- package/dist/features/crawl/crawl-tools.d.ts +6 -0
- package/dist/features/crawl/crawl-tools.js +57 -0
- package/dist/features/crawl/crawl.d.ts +2 -0
- package/dist/features/crawl/crawl.js +171 -156
- package/dist/features/exhaust/app-coverage.d.ts +33 -0
- package/dist/features/exhaust/app-coverage.js +31 -0
- package/dist/features/exhaust/code-coverage.d.ts +47 -0
- package/dist/features/exhaust/code-coverage.js +77 -0
- package/dist/features/exhaust/exhaust-run.d.ts +33 -0
- package/dist/features/exhaust/exhaust-run.js +82 -0
- package/dist/features/exhaust/explorer.d.ts +103 -0
- package/dist/features/exhaust/explorer.js +195 -0
- package/dist/features/exhaust/failure-branches.d.ts +33 -0
- package/dist/features/exhaust/failure-branches.js +92 -0
- package/dist/features/exhaust/ledger.d.ts +202 -0
- package/dist/features/exhaust/ledger.js +252 -0
- package/dist/features/exhaust/session-fold.d.ts +31 -0
- package/dist/features/exhaust/session-fold.js +79 -0
- package/dist/features/exhaust/session-port.d.ts +36 -0
- package/dist/features/exhaust/session-port.js +102 -0
- package/dist/features/harness/drive-report.d.ts +0 -9
- package/dist/features/harness/drive-report.js +18 -0
- package/dist/features/harness/driver.js +4 -7
- package/dist/features/harness/fill-values.d.ts +6 -0
- package/dist/features/harness/fill-values.js +3 -0
- package/dist/features/harness/jev-driver.js +36 -22
- package/dist/features/harness/openai-driver.js +4 -7
- package/dist/features/harness/platform-config.d.ts +10 -0
- package/dist/features/harness/platform-config.js +13 -6
- package/dist/index.d.ts +10 -1
- package/dist/index.js +78 -104
- package/dist/judgement/capsule/capsule-store.d.ts +31 -2
- package/dist/judgement/capsule/capsule-store.js +58 -6
- package/dist/judgement/capsule/capsule.js +5 -0
- package/dist/judgement/capsule/causal-summary.d.ts +13 -1
- package/dist/judgement/capsule/causal-summary.js +7 -0
- package/dist/judgement/domain/domain-model.js +40 -9
- package/dist/judgement/oracles/self-instrument.js +4 -2
- package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
- package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
- package/dist/judgement/runs/artifact/gap-report.js +46 -0
- package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
- package/dist/judgement/runs/artifact/gap-summary.js +85 -0
- package/dist/judgement/runs/artifact/render-report.js +4 -1
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
- package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
- package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
- package/dist/judgement/runs/artifact/to-artifact.js +1 -1
- package/dist/judgement/runs/context-tools.js +21 -3
- package/dist/judgement/runs/drive-run.js +7 -2
- package/dist/judgement/runs/verification-sync.d.ts +3 -1
- package/dist/judgement/runs/verification-sync.js +1 -1
- package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
- package/dist/language/flows/annotate-notes/annotate.js +66 -18
- package/dist/language/flows/change/affected.d.ts +9 -0
- package/dist/language/flows/change/affected.js +35 -0
- package/dist/language/flows/change/gate.d.ts +20 -0
- package/dist/language/flows/change/gate.js +12 -1
- package/dist/language/flows/flow-anchor.d.ts +12 -0
- package/dist/language/flows/flow-anchor.js +20 -0
- package/dist/language/flows/flow-author.d.ts +7 -0
- package/dist/language/flows/flow-author.js +19 -0
- package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
- package/dist/language/flows/flow-expect-grammar.js +92 -11
- package/dist/language/flows/flow-intent.js +1 -1
- package/dist/language/flows/flow-journey.d.ts +54 -0
- package/dist/language/flows/flow-journey.js +119 -0
- package/dist/language/flows/flow-learning.d.ts +3 -0
- package/dist/language/flows/flow-learning.js +39 -8
- package/dist/language/flows/flow-replay-run.d.ts +33 -12
- package/dist/language/flows/flow-replay-run.js +131 -52
- package/dist/language/flows/flow-replay-types.d.ts +9 -0
- package/dist/language/flows/flow-replay.d.ts +27 -12
- package/dist/language/flows/flow-replay.js +127 -111
- package/dist/language/flows/flow-result.d.ts +2 -0
- package/dist/language/flows/flow-result.js +25 -0
- package/dist/language/flows/flow-step-runners.d.ts +26 -10
- package/dist/language/flows/flow-step-runners.js +20 -4
- package/dist/language/flows/flow-success.d.ts +21 -6
- package/dist/language/flows/flow-success.js +50 -138
- package/dist/language/flows/flow-tools.js +17 -5
- package/dist/language/flows/flows.d.ts +18 -5
- package/dist/language/flows/flows.js +101 -16
- package/dist/language/flows/heal.d.ts +9 -1
- package/dist/language/flows/heal.js +24 -2
- package/dist/language/flows/learned-sources.d.ts +21 -0
- package/dist/language/flows/learned-sources.js +84 -0
- package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
- package/dist/language/flows/recording/recording-backtrack.js +1 -1
- package/dist/language/flows/recording/replay-halt.d.ts +2 -1
- package/dist/language/flows/recording/replay-halt.js +3 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
- package/dist/language/flows/recording/tape/recordings.js +55 -1
- package/dist/language/flows/replay.d.ts +19 -0
- package/dist/language/flows/replay.js +53 -13
- package/dist/language/flows/stores/annotation-store.d.ts +5 -5
- package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
- package/dist/language/flows/stores/flake-store.js +2 -3
- package/dist/language/flows/suite/coverage.d.ts +1 -1
- package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
- package/dist/language/flows/verify-change-tools.js +19 -2
- package/dist/launch-chromium.d.ts +80 -0
- package/dist/launch-chromium.js +218 -0
- package/dist/memory/cloud/cloud-config.d.ts +11 -2
- package/dist/memory/cloud/cloud-config.js +47 -7
- package/dist/memory/cloud/cloud-sync.d.ts +4 -3
- package/dist/memory/cloud/cloud-sync.js +7 -10
- package/dist/memory/cloud/harness-config.d.ts +2 -0
- package/dist/memory/cloud/harness-offer.js +5 -6
- package/dist/memory/cloud/harness-switch.js +5 -6
- package/dist/memory/cloud/sync-cycle.d.ts +78 -1
- package/dist/memory/cloud/sync-cycle.js +321 -53
- package/dist/memory/cloud/sync-daemon.d.ts +13 -0
- package/dist/memory/cloud/sync-daemon.js +45 -20
- package/dist/memory/cloud/sync-disk.js +27 -8
- package/dist/memory/impact/impact-store.js +6 -0
- package/dist/memory/intent/inline-intent.js +8 -3
- package/dist/memory/intent/intent-shard-store.d.ts +33 -47
- package/dist/memory/intent/intent-shard-store.js +252 -140
- package/dist/memory/intent/intent-shard.d.ts +0 -23
- package/dist/memory/intent/intent-shard.js +1 -11
- package/dist/memory/intent/intent-store.d.ts +13 -8
- package/dist/memory/intent/intent-store.js +46 -90
- package/dist/memory/intent/intent-tools.js +34 -23
- package/dist/memory/journal/ambient-store.js +2 -3
- package/dist/memory/journal/deviation-report.js +4 -1
- package/dist/memory/journal/deviation-service.js +10 -2
- package/dist/memory/journal/drive-flow.d.ts +19 -14
- package/dist/memory/journal/drive-flow.js +65 -48
- package/dist/memory/journal/envelope-store.js +2 -3
- package/dist/memory/journal/journal-recorder.d.ts +21 -0
- package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
- package/dist/memory/journal/on-disk/retain-policy.js +44 -0
- package/dist/memory/journal/on-disk/retention.d.ts +14 -10
- package/dist/memory/journal/on-disk/retention.js +13 -12
- package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
- package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
- package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
- package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
- package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
- package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
- package/dist/memory/journal/route-template.d.ts +22 -0
- package/dist/memory/journal/route-template.js +44 -0
- package/dist/memory/journal/session-end.d.ts +13 -2
- package/dist/memory/journal/session-end.js +88 -18
- package/dist/memory/journal/session-journal.d.ts +8 -1
- package/dist/memory/journal/session-journal.js +10 -0
- package/dist/memory/project/baselines.d.ts +1 -1
- package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
- package/dist/memory/project/dir/reticle-dir.js +1 -0
- package/dist/memory/project/fs/fs-port.js +44 -5
- package/dist/memory/project/fs/write-atomic.d.ts +26 -0
- package/dist/memory/project/fs/write-atomic.js +48 -0
- package/dist/memory/project/project-tools.js +3 -1
- package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
- package/dist/memory/recall/prior/connection-memory.js +8 -0
- package/dist/memory/recall/registered-projects.d.ts +2 -1
- package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
- package/dist/portal/bridge/auth-failure-reason.js +9 -4
- package/dist/portal/bridge/bridge.d.ts +8 -0
- package/dist/portal/bridge/bridge.js +43 -2
- package/dist/portal/input/js-coverage.d.ts +25 -0
- package/dist/portal/input/js-coverage.js +30 -0
- package/dist/portal/input/real-input.d.ts +11 -0
- package/dist/portal/input/real-input.js +31 -5
- package/dist/portal/pool/browser-pool.d.ts +10 -0
- package/dist/portal/pool/browser-pool.js +10 -0
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +21 -13
- package/dist/portal/pool/pool-contract.d.ts +2 -0
- package/dist/portal/pool/storage-seed.d.ts +2 -1
- package/dist/portal/pool/zero-install.d.ts +27 -0
- package/dist/portal/pool/zero-install.js +54 -0
- package/dist/portal/realm/web-realm.js +6 -0
- package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
- package/dist/portal/session/dev-server/dev-command.js +30 -12
- package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
- package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
- package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
- package/dist/portal/session/dev-server/route-status-probe.js +57 -0
- package/dist/portal/session/dev-server/served-document.d.ts +21 -0
- package/dist/portal/session/dev-server/served-document.js +57 -0
- package/dist/portal/session/facts/background-traffic.d.ts +9 -0
- package/dist/portal/session/facts/background-traffic.js +25 -0
- package/dist/portal/session/facts/observed-state.d.ts +11 -0
- package/dist/portal/session/facts/observed-state.js +34 -0
- package/dist/portal/session/live-control-tools.js +48 -3
- package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
- package/dist/portal/session/no-session-diagnosis.js +62 -5
- package/dist/portal/session/no-session-next-action.d.ts +13 -0
- package/dist/portal/session/no-session-next-action.js +48 -9
- package/dist/portal/session/no-session-watch.d.ts +18 -0
- package/dist/portal/session/no-session-watch.js +88 -2
- package/dist/portal/session/presence/attachment-history.d.ts +13 -2
- package/dist/portal/session/session-health.d.ts +61 -0
- package/dist/portal/session/session-health.js +43 -3
- package/dist/portal/session/session-info.d.ts +6 -0
- package/dist/portal/session/session-manager.d.ts +29 -6
- package/dist/portal/session/session-manager.js +42 -5
- package/dist/portal/session/session-reaper.d.ts +28 -0
- package/dist/portal/session/session-reaper.js +49 -1
- package/dist/portal/session/session-successor.d.ts +11 -0
- package/dist/portal/session/session-successor.js +14 -1
- package/dist/portal/session/session-verdict-facts.d.ts +28 -0
- package/dist/portal/session/session-verdict-facts.js +15 -0
- package/dist/portal/session/session.d.ts +10 -0
- package/dist/portal/session/session.js +34 -26
- package/dist/surface/http-server.d.ts +2 -1
- package/dist/surface/http-server.js +4 -2
- package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
- package/dist/surface/mcp/mcp-proxy.js +5 -5
- package/dist/surface/mcp/mcp.js +4 -2
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
- package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
- package/dist/surface/mcp/server-instructions.js +21 -8
- package/dist/surface/tools/act/after-match.d.ts +17 -0
- package/dist/surface/tools/act/after-match.js +30 -0
- package/dist/surface/tools/act/already-true.d.ts +40 -0
- package/dist/surface/tools/act/already-true.js +36 -0
- package/dist/surface/tools/act/durable.d.ts +69 -0
- package/dist/surface/tools/act/durable.js +139 -0
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
- package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
- package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
- package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
- package/dist/surface/tools/act/proved-controls.d.ts +9 -0
- package/dist/surface/tools/act/proved-controls.js +11 -0
- package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
- package/dist/surface/tools/act/sequence-grade.js +32 -1
- package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
- package/dist/surface/tools/act/settle-in-flight.js +29 -6
- package/dist/surface/tools/act-capsule.d.ts +7 -0
- package/dist/surface/tools/act-capsule.js +68 -8
- package/dist/surface/tools/act-sequence-tool.js +25 -8
- package/dist/surface/tools/act-tools.js +51 -74
- package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
- package/dist/surface/tools/args/numeric-bounds.js +30 -3
- package/dist/surface/tools/assert/assert-grade.js +26 -3
- package/dist/surface/tools/assert/assert-verdict.js +32 -6
- package/dist/surface/tools/browser-tools.js +17 -4
- package/dist/surface/tools/coverage-tools.js +27 -1
- package/dist/surface/tools/dynamic-tools.js +6 -0
- package/dist/surface/tools/error-recovery.js +4 -4
- package/dist/surface/tools/feedback-invite.js +6 -4
- package/dist/surface/tools/feedback-tools.d.ts +2 -1
- package/dist/surface/tools/feedback-tools.js +1 -1
- package/dist/surface/tools/harness-explore.d.ts +3 -2
- package/dist/surface/tools/harness-explore.js +7 -6
- package/dist/surface/tools/invoke-tool.js +17 -4
- package/dist/surface/tools/lease-hint.d.ts +8 -0
- package/dist/surface/tools/lease-hint.js +10 -0
- package/dist/surface/tools/lease-tools.d.ts +16 -28
- package/dist/surface/tools/lease-tools.js +68 -11
- package/dist/surface/tools/lineage-tools.js +1 -1
- package/dist/surface/tools/live-call-text.js +4 -1
- package/dist/surface/tools/observe-tools.js +23 -7
- package/dist/surface/tools/real-input-attempt.d.ts +0 -5
- package/dist/surface/tools/real-input-attempt.js +1 -1
- package/dist/surface/tools/tool-kit.d.ts +5 -0
- package/dist/surface/tools/tool-kit.js +6 -1
- package/dist/surface/tools/tool-surface.js +17 -5
- package/dist/surface/tools/tools.js +68 -29
- package/dist/telemetry/argument-shape.d.ts +0 -2
- package/dist/telemetry/argument-shape.js +0 -4
- package/dist/telemetry/error-class.d.ts +2 -3
- package/dist/telemetry/error-class.js +2 -3
- package/dist/telemetry/feedback-local.d.ts +1 -0
- package/dist/telemetry/feedback-local.js +1 -3
- package/dist/telemetry/feedback.d.ts +1 -1
- package/dist/telemetry/harness-drive.d.ts +0 -2
- package/dist/telemetry/harness-drive.js +0 -4
- package/dist/telemetry/hud-metrics.d.ts +32 -0
- package/dist/telemetry/hud-metrics.js +95 -0
- package/dist/telemetry/session-metrics.d.ts +5 -0
- package/dist/telemetry/session-metrics.js +15 -1
- package/dist/wire-journal.d.ts +34 -0
- package/dist/wire-journal.js +104 -0
- package/dist/workspace-packages.d.ts +0 -2
- package/dist/workspace-packages.js +1 -9
- package/docs/README.md +5 -2
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +4 -4
- package/docs/architecture.md +6 -6
- package/docs/best-practices.mdx +1 -1
- package/docs/capabilities.mdx +32 -1
- package/docs/cli/cloud.mdx +21 -9
- package/docs/cli/doctor.mdx +4 -0
- package/docs/cli/feedback.mdx +2 -2
- package/docs/cli/gate.mdx +9 -4
- package/docs/cli/init.mdx +1 -0
- package/docs/cli/report.mdx +44 -0
- package/docs/cli/update.mdx +10 -0
- package/docs/cli.mdx +9 -0
- package/docs/desktop.mdx +14 -10
- package/docs/environment.mdx +87 -0
- package/docs/faq.mdx +18 -16
- package/docs/first-drive.md +5 -13
- package/docs/flows.md +32 -2
- package/docs/frameworks.mdx +140 -9
- package/docs/getting-started.md +3 -3
- package/docs/http-transport.md +6 -3
- package/docs/human-control.md +2 -2
- package/docs/index.mdx +16 -6
- package/docs/install-agentic.mdx +37 -1
- package/docs/install-manual.mdx +1 -1
- package/docs/integration-patterns.md +3 -3
- package/docs/multi-agent-testing.md +1 -1
- package/docs/packages/babel-plugin.mdx +1 -1
- package/docs/packages/browser.mdx +2 -2
- package/docs/packages/react.mdx +2 -2
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages/vite-plugin.mdx +2 -2
- package/docs/packages.mdx +9 -9
- package/docs/predicates.mdx +176 -7
- package/docs/quickstart.mdx +2 -2
- package/docs/recipes.mdx +2 -2
- package/docs/state-management.mdx +2 -2
- package/docs/system-map.md +1 -1
- package/docs/telemetry.md +1 -1
- package/docs/token-efficiency.md +3 -3
- package/docs/tools/act-and-wait.mdx +1 -0
- package/docs/tools/act-sequence.mdx +1 -1
- package/docs/tools/console.mdx +1 -1
- package/docs/tools/inspect.mdx +1 -1
- package/docs/tools/network.mdx +1 -1
- package/docs/tools/query.mdx +11 -11
- package/docs/tools/sessions.mdx +1 -1
- package/docs/tools/snapshot.mdx +1 -1
- package/docs/tools/state.mdx +1 -1
- package/docs/tools/wait-for.mdx +1 -1
- package/docs/usage.md +8 -7
- package/docs/use-cases.mdx +157 -0
- package/docs/vs-screenshots.mdx +3 -3
- package/docs/what-is-recorded.md +62 -0
- package/docs/what-is-reticle.mdx +17 -20
- package/docs/why-reticle.mdx +14 -21
- package/package.json +11 -10
- package/dist/judgement/capsule/minimize.d.ts +0 -12
- package/dist/judgement/capsule/minimize.js +0 -22
- package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
- package/dist/judgement/outcome/predicate-to-expect.js +0 -148
- package/dist/judgement/phenomena/phenomena.d.ts +0 -26
- package/dist/judgement/phenomena/phenomena.js +0 -101
- package/dist/language/flows/flow-report.d.ts +0 -22
- package/dist/language/flows/flow-report.js +0 -106
|
@@ -9,22 +9,25 @@ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
9
9
|
import { homedir } from 'node:os';
|
|
10
10
|
import { join } from 'node:path';
|
|
11
11
|
import { planAgentConfigs } from './agent-configs.js';
|
|
12
|
-
import { AppShape, readShape } from './desktop-shape.js';
|
|
12
|
+
import { AppShape, describeShape, readShape } from './desktop-shape.js';
|
|
13
13
|
import { stopOnInterrupt } from './terminal/interrupt.js';
|
|
14
14
|
import { stopOnCrash, crashSentence } from './terminal/crash.js';
|
|
15
15
|
import { applyAgentPlan, applyAgentSkills } from './agent-writer.js';
|
|
16
16
|
import { ApprovalOutcome, grantAutoApproval } from './auto-approve.js';
|
|
17
17
|
import { agentIo } from './agent-io.js';
|
|
18
|
-
import { EnsureDaemon, ensureDaemon, nodeEnsureDaemonDeps } from './bringup/ensure-daemon.js';
|
|
18
|
+
import { EnsureDaemon, ensureDaemon, holdDaemon, nodeEnsureDaemonDeps, nodeRetireDeps, retireMovedDaemons, } from './bringup/ensure-daemon.js';
|
|
19
19
|
import { openInBrowser } from '../cli/launch/cli-launch.js';
|
|
20
|
+
import { openLeaseFor } from './bringup/connect-lease.js';
|
|
20
21
|
import { readProjectId } from '../cli/ports/resolve/cli-port.js';
|
|
21
|
-
import {
|
|
22
|
+
import { spawnSync } from 'node:child_process';
|
|
23
|
+
import { isAlive, reticleStateHome } from '../daemon/daemon.js';
|
|
22
24
|
import { readDevServers } from '../daemon/dev-servers.js';
|
|
23
25
|
import { urlOfExistingApp } from './probe/existing-app.js';
|
|
26
|
+
import { handedOverUrl, stopHandedOver } from './bringup/dev-server-files.js';
|
|
24
27
|
import { listSessions, OwnedDevServer, probePage } from './node-effects.js';
|
|
25
28
|
import { fetchStatus } from '../daemon/binding/daemon-status-probe.js';
|
|
26
|
-
import { summarizeStatus } from '../cli/launch/cli-launch.js';
|
|
27
|
-
import { runSetupPhases, } from './run-setup.js';
|
|
29
|
+
import { daemonSkew, summarizeStatus } from '../cli/launch/cli-launch.js';
|
|
30
|
+
import { runSetupPhases, SetupPhase, } from './run-setup.js';
|
|
28
31
|
import { noticeKey, readSaid, rememberSaid, unsaidNotices } from './agent-notice-memory.js';
|
|
29
32
|
/**
|
|
30
33
|
* The dev server a crash should take with it, if one is running right now.
|
|
@@ -84,13 +87,15 @@ function hasElectronDependency(dir) {
|
|
|
84
87
|
* scope unwritten — it exists on machines today, and init only ever writes the project-scope file,
|
|
85
88
|
* so a VS Code user has no tools outside the directory they ran init in.
|
|
86
89
|
*/
|
|
90
|
+
/** `agent`, `agents`. */
|
|
91
|
+
const agentWord = (n) => (1 === n ? 'agent' : 'agents');
|
|
87
92
|
export function registerOtherAgents(print) {
|
|
88
93
|
const platform = process.platform;
|
|
89
94
|
const home = homedir();
|
|
90
95
|
const results = applyAgentPlan(planAgentConfigs({ home, platform, exists: agentIo.exists, readFile: agentIo.readFile }), agentIo);
|
|
91
96
|
const wrote = results.filter((r) => 'created' === r.action || 'merged' === r.action);
|
|
92
97
|
if (0 < wrote.length) {
|
|
93
|
-
print(`
|
|
98
|
+
print(` ✓ ${String(wrote.length)} more ${agentWord(wrote.length)}: ${wrote.map((r) => r.name).join(', ')}`);
|
|
94
99
|
}
|
|
95
100
|
// A format we will not rewrite is somebody's to edit, so it has to be said rather than skipped --
|
|
96
101
|
// but said ONCE. Two commands call this function by design, so a `curl | sh` followed by
|
|
@@ -103,21 +108,21 @@ export function registerOtherAgents(print) {
|
|
|
103
108
|
.map((r) => ({ name: r.name, file: r.file, why: r.why }));
|
|
104
109
|
const fresh = unsaidNotices(readSaid(stateHome), manual);
|
|
105
110
|
for (const notice of fresh) {
|
|
106
|
-
print(
|
|
111
|
+
print(` ⚠ ${notice.name}: ${notice.why} — add the reticle entry to ${notice.file} by hand.`);
|
|
107
112
|
}
|
|
108
113
|
rememberSaid(stateHome, fresh.map((n) => noticeKey(n)));
|
|
109
114
|
const skills = applyAgentSkills(agentIo, { home, platform });
|
|
110
115
|
if (0 < skills.length)
|
|
111
|
-
print(`
|
|
116
|
+
print(` ✓ the /reticle skill, for ${String(skills.length)} ${agentWord(skills.length)}`);
|
|
112
117
|
// Registration alone still leaves an Accept dialog in front of every call, and a verification run
|
|
113
118
|
// makes dozens of them: the loop is only autonomous once the tools are pre-approved.
|
|
114
119
|
const approvals = grantAutoApproval(agentIo, { home, platform });
|
|
115
120
|
const granted = approvals.filter((a) => ApprovalOutcome.GRANTED === a.outcome);
|
|
116
121
|
if (0 < granted.length) {
|
|
117
|
-
print(`pre-approved
|
|
122
|
+
print(` ✓ tools pre-approved in ${granted.map((a) => a.name).join(', ')}, so no Accept prompt per call`);
|
|
118
123
|
}
|
|
119
124
|
for (const noted of approvals.filter((a) => undefined !== a.warn)) {
|
|
120
|
-
print(
|
|
125
|
+
print(` ⚠ ${noted.name}: ${String(noted.warn)}`);
|
|
121
126
|
}
|
|
122
127
|
}
|
|
123
128
|
/**
|
|
@@ -127,13 +132,70 @@ export function registerOtherAgents(print) {
|
|
|
127
132
|
* instrumented app they can watch is the deliverable, and killing it would leave them with config
|
|
128
133
|
* files and a dead tab.
|
|
129
134
|
*/
|
|
135
|
+
/** How long a stopped dev server gets to let go of its port before the new one is started. */
|
|
136
|
+
const HANDED_OVER_EXIT_MS = 10_000;
|
|
137
|
+
const HANDED_OVER_EXIT_POLL_MS = 100;
|
|
138
|
+
/** Stop the server a previous init handed over for `appDir`, and wait (bounded) for it to exit. */
|
|
139
|
+
async function restartHandedOverServer(appDir) {
|
|
140
|
+
let stoppedPid;
|
|
141
|
+
const stopped = stopHandedOver(reticleStateHome(), appDir, {
|
|
142
|
+
alive: isAlive,
|
|
143
|
+
kill: (pid) => {
|
|
144
|
+
stoppedPid = pid;
|
|
145
|
+
try {
|
|
146
|
+
// Its own process group (it was spawned detached), so what it started goes with it.
|
|
147
|
+
if ('win32' === process.platform) {
|
|
148
|
+
spawnSync('taskkill', ['/PID', String(pid), '/T', '/F']);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
process.kill(-pid, 'SIGTERM');
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
/* already gone */
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
const deadline = Date.now() + HANDED_OVER_EXIT_MS;
|
|
160
|
+
while (undefined !== stoppedPid && isAlive(stoppedPid) && Date.now() < deadline) {
|
|
161
|
+
await new Promise((done) => setTimeout(done, HANDED_OVER_EXIT_POLL_MS));
|
|
162
|
+
}
|
|
163
|
+
return stopped;
|
|
164
|
+
}
|
|
130
165
|
export async function runSetupCommand(input, print) {
|
|
131
166
|
if (input.registerAgents)
|
|
132
167
|
registerOtherAgents(print);
|
|
168
|
+
// A moved port first: this project's daemon on the OLD port would otherwise be the one the page
|
|
169
|
+
// finds and dials, while everything below waits on the new one.
|
|
170
|
+
const retired = await retireMovedDaemons(readProjectId(input.appDir), input.bridgePort, nodeRetireDeps());
|
|
171
|
+
for (const port of retired) {
|
|
172
|
+
print(`stopped this project's Reticle daemon on port ${String(port)}: the project now uses ` +
|
|
173
|
+
`${String(input.bridgePort)}, and the page would have kept dialling the old one.`);
|
|
174
|
+
}
|
|
175
|
+
// And the dev server a previous init left running, which may have read the old port once at
|
|
176
|
+
// startup (Next does) — so the attach below would keep a page dialling the daemon just stopped.
|
|
177
|
+
if (0 < retired.length && (await restartHandedOverServer(input.appDir))) {
|
|
178
|
+
print(`stopped the dev server a previous init started, so it restarts on port ${String(input.bridgePort)}.`);
|
|
179
|
+
}
|
|
133
180
|
// Before the app is booted, because the app's whole job from here is to dial this port. Without
|
|
134
181
|
// it the phases wait out their budget and then report the SDK as the thing that failed.
|
|
135
|
-
const daemon = await ensureDaemon(input.bridgePort, nodeEnsureDaemonDeps());
|
|
136
|
-
if (
|
|
182
|
+
const daemon = await ensureDaemon(input.bridgePort, nodeEnsureDaemonDeps((status) => undefined !== daemonSkew(status)));
|
|
183
|
+
if (undefined !== daemon.message)
|
|
184
|
+
print(daemon.message);
|
|
185
|
+
if (EnsureDaemon.SKEWED_IN_USE === daemon.state) {
|
|
186
|
+
// Stop here: every hello from the page would be refused, and waiting out the connect budget
|
|
187
|
+
// only to blame the page is the run this exists to prevent.
|
|
188
|
+
return {
|
|
189
|
+
ok: false,
|
|
190
|
+
reachedPhase: SetupPhase.DEV_SERVER,
|
|
191
|
+
flowSaved: false,
|
|
192
|
+
notes: undefined === daemon.message ? [] : [daemon.message],
|
|
193
|
+
fallback: [
|
|
194
|
+
`Once those sessions are done, free the port with \`npx @reticlehq/server kill --port ${String(input.bridgePort)}\` and re-run init.`,
|
|
195
|
+
],
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
if (EnsureDaemon.UNAVAILABLE === daemon.state) {
|
|
137
199
|
print(`could not start the Reticle daemon on port ${String(input.bridgePort)}, so nothing is listening for the app to connect to. Run \`npx @reticlehq/server serve --port ${String(input.bridgePort)}\` and try again.`);
|
|
138
200
|
}
|
|
139
201
|
// Which shell this is decides three things the phases would otherwise get wrong: opening a
|
|
@@ -145,7 +207,7 @@ export async function runSetupCommand(input, print) {
|
|
|
145
207
|
hasElectronDep: hasElectronDependency(input.appDir),
|
|
146
208
|
});
|
|
147
209
|
if (AppShape.WEB !== shape)
|
|
148
|
-
print(`detected
|
|
210
|
+
print(`detected ${describeShape(shape)}`);
|
|
149
211
|
const server = new OwnedDevServer();
|
|
150
212
|
const effects = {
|
|
151
213
|
startDevServer: (command, cwd) => {
|
|
@@ -153,10 +215,16 @@ export async function runSetupCommand(input, print) {
|
|
|
153
215
|
server.start(command, cwd, input.env);
|
|
154
216
|
return Promise.resolve();
|
|
155
217
|
},
|
|
156
|
-
|
|
218
|
+
// The server the plugin announced (Vite), or failing that the one a previous init handed over
|
|
219
|
+
// and recorded — the only way to know a Next or Angular server on the port is this project's own.
|
|
220
|
+
existingAppUrl: async () => urlOfExistingApp(readDevServers(reticleStateHome()), {
|
|
157
221
|
projectId: readProjectId(input.appDir),
|
|
158
222
|
root: input.appDir,
|
|
159
|
-
})
|
|
223
|
+
}) ??
|
|
224
|
+
(await handedOverUrl(reticleStateHome(), input.appDir, {
|
|
225
|
+
alive: isAlive,
|
|
226
|
+
answers: async (url) => (await probePage(url)).served,
|
|
227
|
+
})),
|
|
160
228
|
devServerOutput: () => server.output(),
|
|
161
229
|
devServerExited: () => server.exited(),
|
|
162
230
|
devServerQuietForMs: () => server.quietForMs(),
|
|
@@ -164,20 +232,16 @@ export async function runSetupCommand(input, print) {
|
|
|
164
232
|
probePage,
|
|
165
233
|
openBrowser: async (url) => {
|
|
166
234
|
const failure = await openInBrowser(url);
|
|
167
|
-
if (null
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
// says which url needs one rather than inventing a Reticle that can conjure it.
|
|
176
|
-
`open one: this asks the OS for your default browser, and it is a machine with none — ` +
|
|
177
|
-
`CI, a container, an SSH session, WSL with no host browser. Point any browser that can ` +
|
|
178
|
-
`reach it at ${url}; the session appears within a second of the page loading.`);
|
|
179
|
-
}
|
|
235
|
+
if (null === failure)
|
|
236
|
+
return undefined;
|
|
237
|
+
// It used to end "nothing else here will open one", which stopped being true once a
|
|
238
|
+
// Reticle-owned browser could always launch: run-setup opens a lease on this failure, so the
|
|
239
|
+
// reader is told what happens next rather than sent to find a browser by hand.
|
|
240
|
+
print(`could not open a browser (${failure}), so the connect proof will come from a ` +
|
|
241
|
+
`Reticle-owned headless browser instead. To use the app yourself, point any browser at ${url}.`);
|
|
242
|
+
return failure;
|
|
180
243
|
},
|
|
244
|
+
openLease: (url) => openLeaseFor(input.bridgePort, url, input.pairingToken),
|
|
181
245
|
listSessions: () => listSessions(input.bridgePort),
|
|
182
246
|
// `summarizeStatus` already narrows this payload for `reticle status`; reusing it here keeps one
|
|
183
247
|
// reader of the wire shape rather than two that can disagree about which key carries the reason.
|
|
@@ -207,16 +271,26 @@ export async function runSetupCommand(input, print) {
|
|
|
207
271
|
activeDevServerStop = () => {
|
|
208
272
|
server.stop();
|
|
209
273
|
};
|
|
274
|
+
// Hold the daemon for as long as this run waits on it. Its idle rule counted none of this as
|
|
275
|
+
// activity, and on a slow desktop build the daemon init had just started idled out mid-wait.
|
|
276
|
+
const releaseDaemon = holdDaemon(input.bridgePort);
|
|
210
277
|
try {
|
|
211
|
-
const outcome = await runSetupPhases({ ...input, shape }, effects);
|
|
278
|
+
const outcome = await runSetupPhases({ ...input, shape, projectId: readProjectId(input.appDir) }, effects);
|
|
212
279
|
// The app stays up only when there is something worth watching.
|
|
213
|
-
if (outcome.ok)
|
|
214
|
-
server.handOver();
|
|
280
|
+
if (outcome.ok) {
|
|
281
|
+
server.handOver(outcome.url);
|
|
282
|
+
// Its output is on a file now, not this terminal, so say where: a compile error that used to
|
|
283
|
+
// scroll past here is the first thing somebody will look for.
|
|
284
|
+
const log = server.logPath();
|
|
285
|
+
if (undefined !== log)
|
|
286
|
+
print(`The dev server keeps running; its output goes to ${log}`);
|
|
287
|
+
}
|
|
215
288
|
return {
|
|
216
289
|
...outcome,
|
|
217
290
|
};
|
|
218
291
|
}
|
|
219
292
|
finally {
|
|
293
|
+
releaseDaemon();
|
|
220
294
|
releaseSignals();
|
|
221
295
|
activeDevServerStop = null;
|
|
222
296
|
server.stop();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { McpClient, MCP_CLIENTS, claudeAddCommand, claudeAvailableProbe,
|
|
1
|
+
import { McpClient, MCP_CLIENTS, claudeAddCommand, claudeAvailableProbe, claudeHasReticle, detectMcpClients, mergeClientConfig, clientSpec, ClientMergeStatus, } from '@reticlehq/init';
|
|
2
2
|
import { OnboardingPhase, OnboardingStepStatus, } from '@reticlehq/core/telemetry';
|
|
3
3
|
export function setupMcp(io) {
|
|
4
4
|
const detected = [];
|
|
@@ -22,8 +22,8 @@ export function setupMcp(io) {
|
|
|
22
22
|
const available = claudeAvailableProbe();
|
|
23
23
|
if (io.runCli(available.command, available.args)) {
|
|
24
24
|
detected.push(McpClient.CLAUDE_CODE);
|
|
25
|
-
|
|
26
|
-
if (io
|
|
25
|
+
// Read from Claude's config: `claude mcp get` health-checks by launching the server.
|
|
26
|
+
if (claudeHasReticle(io, undefined)) {
|
|
27
27
|
alreadyThere.push(McpClient.CLAUDE_CODE);
|
|
28
28
|
}
|
|
29
29
|
else {
|
|
@@ -26,3 +26,11 @@ export declare const WAIT_PROGRESS_EVERY_MS = 15000;
|
|
|
26
26
|
* without a line per poll burying the output it exists to explain.
|
|
27
27
|
*/
|
|
28
28
|
export declare function waitProgressLine(elapsedMs: number, watching: string | undefined, lastSpokeAtMs: number | undefined): string | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* The same, for the wait on a session after the app is up.
|
|
31
|
+
*
|
|
32
|
+
* That wait was silent as well: a desktop init printed "Waiting for the app to launch and dial in."
|
|
33
|
+
* and then nothing for the whole of its budget. Naming what is awaited and how long remains is what
|
|
34
|
+
* lets somebody tell a slow start from a wedged one — and when to stop waiting themselves.
|
|
35
|
+
*/
|
|
36
|
+
export declare function connectProgressLine(elapsedMs: number, lastSpokeAtMs: number | undefined, budgetMs: number, awaiting: string): string | undefined;
|
|
@@ -41,3 +41,20 @@ export function waitProgressLine(elapsedMs, watching, lastSpokeAtMs) {
|
|
|
41
41
|
return (`Waiting ${seconds} for the dev server — watching ${watching}. If the app is already up ` +
|
|
42
42
|
`somewhere else, that url is the thing to check first.`);
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* The same, for the wait on a session after the app is up.
|
|
46
|
+
*
|
|
47
|
+
* That wait was silent as well: a desktop init printed "Waiting for the app to launch and dial in."
|
|
48
|
+
* and then nothing for the whole of its budget. Naming what is awaited and how long remains is what
|
|
49
|
+
* lets somebody tell a slow start from a wedged one — and when to stop waiting themselves.
|
|
50
|
+
*/
|
|
51
|
+
export function connectProgressLine(elapsedMs, lastSpokeAtMs, budgetMs, awaiting) {
|
|
52
|
+
if (elapsedMs < WAIT_PROGRESS_EVERY_MS)
|
|
53
|
+
return undefined;
|
|
54
|
+
if (lastSpokeAtMs !== undefined && elapsedMs - lastSpokeAtMs < WAIT_PROGRESS_EVERY_MS) {
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
const seconds = (ms) => `${String(Math.max(0, Math.floor(ms / 1000)))}s`;
|
|
58
|
+
return (`Still waiting for ${awaiting} to connect: ${seconds(elapsedMs)} so far, giving up in ` +
|
|
59
|
+
`${seconds(budgetMs - elapsedMs)}.`);
|
|
60
|
+
}
|
|
@@ -19,6 +19,6 @@ export function crawlEmptyNote(outcome) {
|
|
|
19
19
|
return `no interactive controls were found on this page, so nothing was clicked — the crawl ran and found none, which is a result rather than a failure.${capped}`;
|
|
20
20
|
}
|
|
21
21
|
return (`${String(outcome.interactiveFound)} interactive controls were found and none of them were clicked. ` +
|
|
22
|
-
`That is not an empty page, so something stopped the loop — report it with
|
|
22
|
+
`That is not an empty page, so something stopped the loop — report it with reticle_session { action: "feedback" }, ` +
|
|
23
23
|
`including this page's URL and one control's ref.`);
|
|
24
24
|
}
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import type { ToolDef } from '../../surface/tools/tool-kit.js';
|
|
2
|
+
/**
|
|
3
|
+
* The configured secret for a field, only on the origin the crawl started on. The field name comes
|
|
4
|
+
* from whatever page is on screen, so without the check a page on another origin could name an
|
|
5
|
+
* empty textbox after a secret and have the crawl type it in.
|
|
6
|
+
*/
|
|
7
|
+
export declare function crawlSecret(startUrl: string, env: Readonly<Record<string, string | undefined>>): (name: string, pageUrl: string) => string | undefined;
|
|
2
8
|
/**
|
|
3
9
|
* The autonomous "smart monkey" tool. Builds on reticle_explore (which only LISTS) by
|
|
4
10
|
* actually clicking each reachable control and classifying the reaction. DESTRUCTIVE by nature —
|
|
@@ -5,8 +5,29 @@ import { ReticleTool } from '@reticlehq/core';
|
|
|
5
5
|
import { asNumber, asString } from '@reticlehq/core';
|
|
6
6
|
import { stepCountSchema, timeoutMsSchema } from '../../surface/tools/args/numeric-bounds.js';
|
|
7
7
|
import { crawl } from './crawl.js';
|
|
8
|
+
import { EXHAUST_DEFAULT_ACTIONS, runExhaustive } from '../exhaust/exhaust-run.js';
|
|
9
|
+
import { heuristicFillValue } from '../harness/fill-values.js';
|
|
10
|
+
import { secretEnvKey } from '../../language/flows/flows.js';
|
|
11
|
+
import { CRAWL_DEFAULTS } from '@reticlehq/core';
|
|
8
12
|
import { routeFromUrl, routesFromEvents } from '../../memory/project/learned-routes.js';
|
|
9
13
|
const nodeSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
|
+
/**
|
|
15
|
+
* The configured secret for a field, only on the origin the crawl started on. The field name comes
|
|
16
|
+
* from whatever page is on screen, so without the check a page on another origin could name an
|
|
17
|
+
* empty textbox after a secret and have the crawl type it in.
|
|
18
|
+
*/
|
|
19
|
+
export function crawlSecret(startUrl, env) {
|
|
20
|
+
const originOf = (url) => {
|
|
21
|
+
try {
|
|
22
|
+
return new URL(url).origin;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const home = originOf(startUrl);
|
|
29
|
+
return (name, pageUrl) => home !== undefined && home === originOf(pageUrl) ? env[secretEnvKey(name)] : undefined;
|
|
30
|
+
}
|
|
10
31
|
/**
|
|
11
32
|
* The autonomous "smart monkey" tool. Builds on reticle_explore (which only LISTS) by
|
|
12
33
|
* actually clicking each reachable control and classifying the reaction. DESTRUCTIVE by nature —
|
|
@@ -27,6 +48,10 @@ export const CRAWL_TOOLS = [
|
|
|
27
48
|
.string()
|
|
28
49
|
.optional()
|
|
29
50
|
.describe('CSS selector or element ref to restrict crawling to a subtree.'),
|
|
51
|
+
exhaustive: z
|
|
52
|
+
.boolean()
|
|
53
|
+
.optional()
|
|
54
|
+
.describe("Walk every state it can tell apart, drive each write's failure path, fold into the coverage ledger."),
|
|
30
55
|
confirmDangerous: z
|
|
31
56
|
.boolean()
|
|
32
57
|
.optional()
|
|
@@ -62,6 +87,8 @@ export const CRAWL_TOOLS = [
|
|
|
62
87
|
.optional()
|
|
63
88
|
.describe('Present only when the page exceeded one snapshot, so controls past the cap were never listed. When present, a zero-anomaly result does NOT mean the app is clean.'),
|
|
64
89
|
truncated: z.boolean(),
|
|
90
|
+
// Only on `exhaustive` — see features/exhaust/exhaust-run.ts. Loose: it carries the levels.
|
|
91
|
+
exhaustive: z.record(z.unknown()).optional(),
|
|
65
92
|
},
|
|
66
93
|
handler: async (deps, args) => {
|
|
67
94
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
@@ -76,6 +103,36 @@ export const CRAWL_TOOLS = [
|
|
|
76
103
|
...(scope !== undefined ? { scope } : {}),
|
|
77
104
|
...(true === args['confirmDangerous'] ? { confirmDangerous: true } : {}),
|
|
78
105
|
};
|
|
106
|
+
if (true === args['exhaustive']) {
|
|
107
|
+
// Starts code-coverage collection, so the drive below is measured. See takeCodeCoverage.
|
|
108
|
+
await deps.realInput?.takeCodeCoverage?.(session.url);
|
|
109
|
+
const secret = crawlSecret(session.url, process.env);
|
|
110
|
+
return runExhaustive({
|
|
111
|
+
sessions: deps.sessions,
|
|
112
|
+
session,
|
|
113
|
+
startUrl: session.url,
|
|
114
|
+
maxActions: maxSteps ?? EXHAUST_DEFAULT_ACTIONS,
|
|
115
|
+
settleMs: settleMs ?? CRAWL_DEFAULTS.SETTLE_MS,
|
|
116
|
+
fillValue: (label, pageUrl) => {
|
|
117
|
+
const name = /"([^"]*)"/.exec(label)?.[1] ?? label;
|
|
118
|
+
return secret(name, pageUrl) ?? heuristicFillValue(name);
|
|
119
|
+
},
|
|
120
|
+
now: deps.now,
|
|
121
|
+
sleep: nodeSleep,
|
|
122
|
+
...(deps.realInput?.setMocks === undefined
|
|
123
|
+
? {}
|
|
124
|
+
: {
|
|
125
|
+
setMocks: (url, rules) => deps.realInput?.setMocks?.(url, rules) ?? Promise.resolve(false),
|
|
126
|
+
}),
|
|
127
|
+
...(deps.realInput?.takeCodeCoverage === undefined
|
|
128
|
+
? {}
|
|
129
|
+
: {
|
|
130
|
+
takeCode: (url) => deps.realInput?.takeCodeCoverage?.(url) ?? Promise.resolve(undefined),
|
|
131
|
+
}),
|
|
132
|
+
fs: deps.fs,
|
|
133
|
+
reticleRoot: sessionRoot(deps, session.id),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
79
136
|
const report = await crawl(session, opts, nodeSleep);
|
|
80
137
|
const routes = [
|
|
81
138
|
...(initialRoute === undefined ? [] : [initialRoute]),
|
|
@@ -16,6 +16,8 @@ export interface CrawlSession {
|
|
|
16
16
|
/** The page under test, so a third-party beacon cannot be reported against a control. Optional
|
|
17
17
|
* for the same reason `currentDocumentId` is. */
|
|
18
18
|
readonly url?: string | undefined;
|
|
19
|
+
/** Same-origin endpoints the project declared as background. Optional like `url`. */
|
|
20
|
+
readonly background?: readonly string[] | undefined;
|
|
19
21
|
/**
|
|
20
22
|
* Is the page BACKGROUNDED? A hidden tab has its rAF clamped and the DOM observer flushes on rAF,
|
|
21
23
|
* so real renders emit nothing and every absence-derived contradiction reads that silence as a
|