@reticlehq/server 2.4.0 → 2.6.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 +719 -0
- package/dist/bridge/auth-failure-reason.d.ts +19 -0
- package/dist/bridge/auth-failure-reason.js +29 -0
- package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
- package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
- package/dist/{bridge.d.ts → bridge/bridge.d.ts} +13 -1
- package/dist/{bridge.js → bridge/bridge.js} +95 -15
- package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +9 -11
- package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +18 -10
- package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
- package/dist/capsule/capsule-store.d.ts +8 -3
- package/dist/capsule/capsule-store.js +7 -2
- package/dist/capsule/capsule.js +3 -3
- package/dist/capsule/causal-summary.d.ts +8 -0
- package/dist/capsule/causal-summary.js +22 -12
- package/dist/capsule/divergence.d.ts +9 -4
- package/dist/capsule/divergence.js +8 -8
- package/dist/capsule/predicate-to-links.js +11 -8
- package/dist/cli/cli-doctor.d.ts +1 -0
- package/dist/cli/cli-doctor.js +135 -0
- package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
- package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
- package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
- package/dist/cli/cli-launch.js +171 -0
- package/dist/cli/cli-parse-feedback.d.ts +31 -0
- package/dist/cli/cli-parse-feedback.js +56 -0
- package/dist/{cli-parse.d.ts → cli/cli-parse.d.ts} +6 -19
- package/dist/{cli-parse.js → cli/cli-parse.js} +118 -81
- package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +12 -0
- package/dist/{cli-port.js → cli/cli-port.js} +9 -9
- package/dist/cli/cli-update-commands.d.ts +4 -0
- package/dist/cli/cli-update-commands.js +93 -0
- package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
- package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
- package/dist/cli/doctor-daemon-line.d.ts +37 -0
- package/dist/cli/doctor-daemon-line.js +35 -0
- package/dist/cli/port-holder.d.ts +43 -0
- package/dist/cli/port-holder.js +99 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +302 -100
- package/dist/cloud/cloud-config.d.ts +0 -1
- package/dist/cloud/cloud-config.js +9 -9
- package/dist/cloud/cloud-sync.d.ts +1 -7
- package/dist/cloud/cloud-sync.js +12 -12
- package/dist/crawl/crawl-empty.d.ts +16 -0
- package/dist/crawl/crawl-empty.js +24 -0
- package/dist/crawl/crawl-tools.js +4 -1
- package/dist/crawl/crawl.js +26 -7
- package/dist/daemon/daemon-resilience.d.ts +73 -0
- package/dist/daemon/daemon-resilience.js +279 -0
- package/dist/daemon/daemon-usefulness.d.ts +61 -0
- package/dist/daemon/daemon-usefulness.js +62 -0
- package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
- package/dist/{daemon.js → daemon/daemon.js} +105 -48
- package/dist/daemon/heartbeat.d.ts +115 -0
- package/dist/daemon/heartbeat.js +141 -0
- package/dist/daemon/idle-grace.d.ts +32 -0
- package/dist/daemon/idle-grace.js +41 -0
- package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +23 -2
- package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +37 -6
- package/dist/daemon/port-presence.d.ts +76 -0
- package/dist/daemon/port-presence.js +93 -0
- package/dist/daemon/state-dir.d.ts +7 -0
- package/dist/daemon/state-dir.js +59 -0
- package/dist/daemon/unclean-predecessor.d.ts +23 -0
- package/dist/daemon/unclean-predecessor.js +27 -0
- package/dist/domain/domain-model.js +2 -2
- package/dist/events/body-failures.js +8 -8
- package/dist/events/contradictions.d.ts +1 -1
- package/dist/events/contradictions.js +60 -10
- package/dist/events/echo-mismatch.js +10 -10
- package/dist/events/event-filters.js +6 -6
- package/dist/events/json-salvage.d.ts +2 -1
- package/dist/events/json-salvage.js +6 -6
- package/dist/events/observed-in-window.d.ts +12 -0
- package/dist/events/observed-in-window.js +21 -0
- package/dist/events/predicate-eval.d.ts +53 -20
- package/dist/events/predicate-eval.js +179 -55
- package/dist/events/predicate-parse.d.ts +23 -0
- package/dist/events/predicate-parse.js +54 -0
- package/dist/events/predicate.d.ts +7 -2
- package/dist/events/predicate.js +126 -35
- package/dist/events/reconcile.js +5 -5
- package/dist/events/ring-buffer.js +2 -17
- package/dist/events/stale-response.js +6 -6
- package/dist/events/testid-near-miss.d.ts +22 -0
- package/dist/events/testid-near-miss.js +33 -0
- package/dist/events/unit-mismatch.js +8 -8
- package/dist/flows/affected-tools.js +19 -4
- package/dist/flows/affected.js +1 -1
- package/dist/flows/annotate-target.d.ts +1 -0
- package/dist/flows/annotate-target.js +20 -0
- package/dist/flows/annotate-tools.js +25 -3
- package/dist/flows/annotate.js +17 -4
- package/dist/flows/assertion-integrity.d.ts +2 -1
- package/dist/flows/assertion-tiers-store.d.ts +3 -66
- package/dist/flows/assertion-tiers-store.js +2 -2
- package/dist/flows/attributed-failure.d.ts +17 -0
- package/dist/flows/attributed-failure.js +20 -0
- package/dist/flows/buddy-status.d.ts +2 -1
- package/dist/flows/buddy-status.js +2 -2
- package/dist/flows/coverage.d.ts +3 -2
- package/dist/flows/coverage.js +2 -2
- package/dist/flows/decision.js +24 -9
- package/dist/flows/empty-flow.d.ts +6 -0
- package/dist/flows/empty-flow.js +24 -0
- package/dist/flows/flake-store.d.ts +0 -1
- package/dist/flows/flake-store.js +1 -1
- package/dist/flows/flake.d.ts +2 -1
- package/dist/flows/flake.js +2 -2
- package/dist/flows/flow-classify.js +12 -0
- package/dist/flows/flow-replay-run.js +4 -4
- package/dist/flows/flow-replay.d.ts +6 -8
- package/dist/flows/flow-replay.js +132 -48
- package/dist/flows/flow-report.js +1 -1
- package/dist/flows/flow-scope.d.ts +1 -6
- package/dist/flows/flow-step-runners.d.ts +26 -6
- package/dist/flows/flow-step-runners.js +156 -6
- package/dist/flows/flow-success.js +20 -15
- package/dist/flows/flow-tools.js +63 -21
- package/dist/flows/flows.js +15 -11
- package/dist/flows/gate.d.ts +4 -3
- package/dist/flows/gate.js +1 -1
- package/dist/flows/heal-run.d.ts +0 -8
- package/dist/flows/heal-run.js +5 -5
- package/dist/flows/heal.js +3 -3
- package/dist/flows/predicate-to-expect.d.ts +38 -0
- package/dist/flows/predicate-to-expect.js +95 -0
- package/dist/flows/replay.d.ts +16 -1
- package/dist/flows/replay.js +58 -22
- package/dist/flows/role-anchor-nearest.d.ts +6 -0
- package/dist/flows/role-anchor-nearest.js +45 -0
- package/dist/flows/role-drift-reason.d.ts +20 -0
- package/dist/flows/role-drift-reason.js +39 -0
- package/dist/flows/server-verify.d.ts +1 -1
- package/dist/flows/server-verify.js +5 -5
- package/dist/flows/suite-flakes.d.ts +33 -0
- package/dist/flows/suite-flakes.js +32 -0
- package/dist/flows/verify-change-tools.js +32 -10
- package/dist/flows/verify-change-verdict.d.ts +15 -0
- package/dist/flows/verify-change-verdict.js +25 -0
- package/dist/flows/watch-batcher.d.ts +3 -2
- package/dist/honesty/already-true.d.ts +2 -0
- package/dist/honesty/already-true.js +31 -0
- package/dist/honesty/blind-spots.d.ts +35 -3
- package/dist/honesty/blind-spots.js +57 -12
- package/dist/honesty/honesty.d.ts +3 -2
- package/dist/honesty/honesty.js +4 -4
- package/dist/honesty/uncaptured-bodies.js +1 -1
- package/dist/honesty/unread-outcome.js +2 -2
- package/dist/honesty/verified.d.ts +31 -3
- package/dist/honesty/verified.js +64 -8
- package/dist/http-server.js +23 -7
- package/dist/hunt/hunt-report.d.ts +2 -1
- package/dist/hunt/hunt-report.js +2 -2
- package/dist/index.d.ts +9 -6
- package/dist/index.js +41 -25
- package/dist/init/agent-rules.d.ts +20 -1
- package/dist/init/agent-rules.js +64 -8
- package/dist/init/app-choice.d.ts +20 -0
- package/dist/init/app-choice.js +25 -0
- package/dist/init/astro-host.d.ts +21 -0
- package/dist/init/astro-host.js +27 -0
- package/dist/init/astro-patch.d.ts +16 -0
- package/dist/init/astro-patch.js +240 -0
- package/dist/init/capabilities.js +4 -1
- package/dist/init/cra.d.ts +50 -0
- package/dist/init/cra.js +106 -0
- package/dist/init/cursor.js +39 -4
- package/dist/init/desktop-doctor.d.ts +3 -2
- package/dist/init/desktop-doctor.js +4 -4
- package/dist/init/detect.d.ts +9 -2
- package/dist/init/detect.js +24 -5
- package/dist/init/mcp-clients.d.ts +81 -0
- package/dist/init/mcp-clients.js +248 -0
- package/dist/init/mcp-registered.d.ts +12 -0
- package/dist/init/mcp-registered.js +14 -0
- package/dist/init/mcp.d.ts +27 -2
- package/dist/init/mcp.js +40 -4
- package/dist/init/next-patch.d.ts +2 -4
- package/dist/init/next-patch.js +109 -19
- package/dist/init/node-io.js +29 -6
- package/dist/init/plan-framework.d.ts +16 -1
- package/dist/init/plan-framework.js +166 -8
- package/dist/init/plan.d.ts +85 -6
- package/dist/init/plan.js +196 -33
- package/dist/init/project-id.d.ts +5 -9
- package/dist/init/project-id.js +10 -22
- package/dist/init/run.d.ts +23 -1
- package/dist/init/run.js +338 -47
- package/dist/init/slash-command.d.ts +9 -0
- package/dist/init/slash-command.js +10 -1
- package/dist/init/snippets.d.ts +7 -10
- package/dist/init/snippets.js +44 -15
- package/dist/init/vite-config.js +1 -1
- package/dist/init/windows-quote.d.ts +38 -0
- package/dist/init/windows-quote.js +70 -0
- package/dist/init/workspace-apps.d.ts +23 -0
- package/dist/init/workspace-apps.js +68 -0
- package/dist/input/driven-redaction.js +1 -1
- package/dist/input/network-detail.js +8 -8
- package/dist/input/network-mock-tools.js +2 -2
- package/dist/input/network-mock.js +4 -4
- package/dist/input/real-input.js +8 -3
- package/dist/input/scroll-find.js +2 -2
- package/dist/input/scroll-tools.d.ts +0 -5
- package/dist/input/scroll-tools.js +11 -4
- package/dist/input/viewport-tools.js +2 -2
- package/dist/journal/ambient-store.d.ts +0 -2
- package/dist/journal/ambient-store.js +1 -1
- package/dist/journal/ambient.js +1 -1
- package/dist/journal/attach-journal.d.ts +2 -1
- package/dist/journal/deviation-report.js +6 -6
- package/dist/journal/deviation-service.js +1 -1
- package/dist/journal/envelope-store.d.ts +0 -2
- package/dist/journal/envelope-store.js +1 -1
- package/dist/journal/envelope.d.ts +2 -3
- package/dist/journal/envelope.js +3 -3
- package/dist/journal/journal-query.js +1 -1
- package/dist/journal/journal-recorder.d.ts +2 -1
- package/dist/journal/journal-recorder.js +2 -2
- package/dist/journal/rollups.js +9 -9
- package/dist/journal/session-end.d.ts +2 -1
- package/dist/journal/session-journal.js +4 -4
- package/dist/license/license.d.ts +0 -14
- package/dist/license/license.js +8 -8
- package/dist/log.d.ts +10 -0
- package/dist/log.js +11 -1
- package/dist/mcp/mcp-is-error.d.ts +13 -0
- package/dist/mcp/mcp-is-error.js +18 -0
- package/dist/mcp/mcp-outage.d.ts +32 -0
- package/dist/mcp/mcp-outage.js +55 -0
- package/dist/mcp/mcp-proxy.d.ts +134 -0
- package/dist/mcp/mcp-proxy.js +720 -0
- package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
- package/dist/{mcp.js → mcp/mcp.js} +139 -37
- package/dist/mcp/proxy-handshake.d.ts +3 -0
- package/dist/mcp/proxy-handshake.js +54 -0
- package/dist/mcp/proxy-lifecycle.d.ts +64 -0
- package/dist/mcp/proxy-lifecycle.js +70 -0
- package/dist/mcp/tool-catalog-cache.d.ts +29 -0
- package/dist/mcp/tool-catalog-cache.js +55 -0
- package/dist/oracles/propose-consequences.d.ts +2 -1
- package/dist/oracles/propose-consequences.js +16 -11
- package/dist/oracles/self-instrument.d.ts +2 -1
- package/dist/oracles/self-instrument.js +1 -1
- package/dist/phenomena/phenomena.js +3 -3
- package/dist/platform.d.ts +16 -0
- package/dist/platform.js +16 -0
- package/dist/pool/browser-pool.d.ts +9 -0
- package/dist/pool/browser-pool.js +38 -9
- package/dist/pool/playwright-launcher.d.ts +15 -2
- package/dist/pool/playwright-launcher.js +21 -2
- package/dist/project/fs-port.js +1 -1
- package/dist/project/project-tools.js +2 -2
- package/dist/runs/build-verification-run.js +1 -1
- package/dist/runs/repair-prompt.d.ts +0 -6
- package/dist/runs/repair-prompt.js +3 -3
- package/dist/runs/risk-classify.js +1 -1
- package/dist/runs/run-diff.d.ts +0 -2
- package/dist/runs/run-diff.js +3 -3
- package/dist/runs/run-tools.js +2 -2
- package/dist/runs/verification-sync.js +2 -2
- package/dist/runs/verify-http.js +1 -1
- package/dist/runs/verify-server.js +1 -1
- package/dist/session/attachment-history.d.ts +46 -0
- package/dist/session/attachment-history.js +65 -0
- package/dist/session/command-timeout.d.ts +11 -3
- package/dist/session/command-timeout.js +2 -2
- package/dist/session/control-envelope.d.ts +6 -0
- package/dist/session/control-envelope.js +7 -1
- package/dist/session/dev-server-probe.d.ts +13 -0
- package/dist/session/dev-server-probe.js +52 -0
- package/dist/session/last-act.d.ts +17 -3
- package/dist/session/last-act.js +16 -4
- package/dist/session/live-control-tools.js +7 -2
- package/dist/session/live-control.js +1 -1
- package/dist/session/looks-like-dev-server.d.ts +14 -0
- package/dist/session/looks-like-dev-server.js +25 -0
- package/dist/session/no-session-diagnosis.d.ts +45 -0
- package/dist/session/no-session-diagnosis.js +120 -0
- package/dist/session/no-session-watch.d.ts +21 -0
- package/dist/session/no-session-watch.js +69 -0
- package/dist/session/observed-state.d.ts +4 -0
- package/dist/session/observed-state.js +19 -1
- package/dist/session/output-budget.js +1 -1
- package/dist/session/pending-commands.js +1 -0
- package/dist/session/session-health.d.ts +8 -1
- package/dist/session/session-health.js +8 -7
- package/dist/session/session-info.d.ts +43 -8
- package/dist/session/session-info.js +46 -1
- package/dist/session/session-lease.d.ts +0 -11
- package/dist/session/session-lease.js +1 -1
- package/dist/session/session-manager.d.ts +6 -0
- package/dist/session/session-manager.js +124 -12
- package/dist/session/session-readiness.d.ts +1 -1
- package/dist/session/session-readiness.js +6 -1
- package/dist/session/session-reaper.js +1 -1
- package/dist/session/session-reconnect.d.ts +32 -0
- package/dist/session/session-reconnect.js +42 -0
- package/dist/session/session.d.ts +15 -2
- package/dist/session/session.js +77 -26
- package/dist/session/state-select.d.ts +1 -1
- package/dist/session/state-select.js +1 -1
- package/dist/status-payload.d.ts +19 -0
- package/dist/status-payload.js +11 -0
- package/dist/telemetry/argument-shape.js +10 -1
- package/dist/telemetry/browser-mode.d.ts +27 -0
- package/dist/telemetry/browser-mode.js +33 -0
- package/dist/telemetry/bug-found.d.ts +17 -21
- package/dist/telemetry/bug-found.js +120 -8
- package/dist/telemetry/cli-telemetry.d.ts +2 -12
- package/dist/telemetry/cli-telemetry.js +27 -4
- package/dist/telemetry/crash-cause.d.ts +47 -0
- package/dist/telemetry/crash-cause.js +104 -0
- package/dist/telemetry/daemon-telemetry.d.ts +38 -1
- package/dist/telemetry/daemon-telemetry.js +37 -12
- package/dist/telemetry/dev-repo.js +4 -4
- package/dist/telemetry/error-class.d.ts +26 -0
- package/dist/telemetry/error-class.js +52 -0
- package/dist/telemetry/error-fingerprint.js +21 -2
- package/dist/telemetry/feedback-cli.d.ts +8 -3
- package/dist/telemetry/feedback-cli.js +52 -8
- package/dist/telemetry/feedback-context.d.ts +23 -6
- package/dist/telemetry/feedback-context.js +105 -5
- package/dist/telemetry/feedback-delivery.d.ts +20 -0
- package/dist/telemetry/feedback-delivery.js +30 -0
- package/dist/telemetry/feedback-outbox.d.ts +22 -0
- package/dist/telemetry/feedback-outbox.js +87 -0
- package/dist/telemetry/feedback.d.ts +22 -1
- package/dist/telemetry/feedback.js +67 -8
- package/dist/telemetry/git-facts.d.ts +7 -0
- package/dist/telemetry/git-facts.js +5 -5
- package/dist/telemetry/project-profile.js +2 -1
- package/dist/telemetry/session-metrics.d.ts +47 -3
- package/dist/telemetry/session-metrics.js +315 -15
- package/dist/telemetry/telemetry.d.ts +45 -2
- package/dist/telemetry/telemetry.js +150 -37
- package/dist/telemetry/verification-of.d.ts +22 -0
- package/dist/telemetry/verification-of.js +84 -0
- package/dist/tools/act-capsule.js +2 -2
- package/dist/tools/act-danger.d.ts +12 -0
- package/dist/tools/act-danger.js +20 -3
- package/dist/tools/act-helpers.js +4 -4
- package/dist/tools/act-tools.d.ts +0 -8
- package/dist/tools/act-tools.js +114 -118
- package/dist/tools/act-view.js +7 -7
- package/dist/tools/alias-args.d.ts +17 -0
- package/dist/tools/alias-args.js +25 -0
- package/dist/tools/assert-grade.js +9 -9
- package/dist/tools/assert-verdict.d.ts +9 -1
- package/dist/tools/assert-verdict.js +21 -6
- package/dist/tools/browser-tools.js +36 -11
- package/dist/tools/contract-tools.d.ts +0 -5
- package/dist/tools/contract-tools.js +27 -1
- package/dist/tools/coverage-identity.d.ts +34 -0
- package/dist/tools/coverage-identity.js +46 -0
- package/dist/tools/coverage-tools.js +10 -14
- package/dist/tools/dynamic-tools.d.ts +2 -1
- package/dist/tools/dynamic-tools.js +96 -19
- package/dist/tools/error-recovery.d.ts +34 -2
- package/dist/tools/error-recovery.js +255 -4
- package/dist/tools/feedback-invite.d.ts +48 -0
- package/dist/tools/feedback-invite.js +71 -0
- package/dist/tools/feedback-tools.d.ts +12 -1
- package/dist/tools/feedback-tools.js +28 -5
- package/dist/tools/invoke-tool.d.ts +0 -12
- package/dist/tools/invoke-tool.js +126 -33
- package/dist/tools/lease-hint.d.ts +17 -0
- package/dist/tools/lease-hint.js +24 -0
- package/dist/tools/lease-tools.js +6 -5
- package/dist/tools/merge-tools.d.ts +10 -1
- package/dist/tools/merge-tools.js +9 -3
- package/dist/tools/merged-name-redirect.d.ts +13 -0
- package/dist/tools/merged-name-redirect.js +55 -0
- package/dist/tools/navigate-arrival.d.ts +26 -0
- package/dist/tools/navigate-arrival.js +60 -0
- package/dist/tools/navigate-result.d.ts +31 -0
- package/dist/tools/navigate-result.js +38 -0
- package/dist/tools/observe-tools.js +72 -20
- package/dist/tools/observed-nothing.d.ts +25 -0
- package/dist/tools/observed-nothing.js +33 -0
- package/dist/tools/query-paginate.js +2 -2
- package/dist/tools/query-shape.d.ts +18 -0
- package/dist/tools/query-shape.js +39 -0
- package/dist/tools/read-tools.js +81 -20
- package/dist/tools/real-input-attempt.d.ts +28 -0
- package/dist/tools/real-input-attempt.js +93 -0
- package/dist/tools/reconcile-tools.js +7 -7
- package/dist/tools/reload-result.d.ts +14 -0
- package/dist/tools/reload-result.js +29 -0
- package/dist/tools/snapshot-delta.d.ts +4 -5
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/tool-kit.d.ts +16 -0
- package/dist/tools/tool-surface.d.ts +83 -0
- package/dist/tools/tool-surface.js +217 -0
- package/dist/tools/tools-helpers.js +6 -6
- package/dist/tools/tools.d.ts +15 -0
- package/dist/tools/tools.js +53 -17
- package/dist/tools/unadvertised-help.d.ts +5 -0
- package/dist/tools/unadvertised-help.js +39 -0
- package/dist/trace.d.ts +69 -0
- package/dist/trace.js +150 -0
- package/dist/update/nudge-credit.d.ts +4 -0
- package/dist/update/nudge-credit.js +53 -0
- package/dist/update/sdk-sync.d.ts +21 -0
- package/dist/update/sdk-sync.js +42 -0
- package/dist/update/update-checker.js +3 -3
- package/dist/update/update-nudge.d.ts +63 -6
- package/dist/update/update-nudge.js +128 -15
- package/dist/update/updater.d.ts +1 -9
- package/dist/update/updater.js +13 -8
- package/dist/version/peer-announce.d.ts +4 -0
- package/dist/version/peer-announce.js +30 -0
- package/dist/{server-version.js → version/server-version.js} +5 -1
- package/dist/version/version-nudge.d.ts +28 -0
- package/dist/version/version-nudge.js +40 -0
- package/dist/version/version-skew.d.ts +66 -0
- package/dist/version/version-skew.js +71 -0
- package/dist/visual/visual-diff.js +2 -2
- package/dist/visual/visual-tools.js +4 -4
- package/docs/README.md +55 -0
- package/docs/agent-cheatsheet.md +85 -0
- package/docs/architecture.md +113 -0
- package/docs/benchmarks.md +255 -0
- package/docs/debugging.md +102 -0
- package/docs/deploy-checks.md +69 -0
- package/docs/desktop-apps.md +256 -0
- package/docs/enterprise.md +62 -0
- package/docs/fixtures-dispatch-receiver.yml +76 -0
- package/docs/fixtures.md +45 -0
- package/docs/flows.md +166 -0
- package/docs/gate-plan.md +98 -0
- package/docs/gates.md +117 -0
- package/docs/getting-started.md +469 -0
- package/docs/human-control.md +63 -0
- package/docs/integration-patterns.md +171 -0
- package/docs/local-registry.md +126 -0
- package/docs/matrix/2.5.0/claude-code-machine.json +19 -0
- package/docs/matrix/2.5.0/codex-machine.json +20 -0
- package/docs/matrix/2.5.0/cursor-machine.json +22 -0
- package/docs/matrix/2.5.0/gemini-machine.json +22 -0
- package/docs/matrix/2.5.0/opencode-machine.json +22 -0
- package/docs/matrix/2.5.0/vscode-machine.json +22 -0
- package/docs/matrix/2.5.0/windsurf-machine.json +22 -0
- package/docs/matrix/MATRIX.md +26 -0
- package/docs/matrix/README.md +59 -0
- package/docs/mint.json +61 -0
- package/docs/multi-agent-testing.md +55 -0
- package/docs/platform-integration.md +122 -0
- package/docs/system-map.md +152 -0
- package/docs/telemetry-contract.md +214 -0
- package/docs/telemetry.md +191 -0
- package/docs/testing.md +82 -0
- package/docs/token-efficiency.md +80 -0
- package/docs/usage.md +1046 -0
- package/package.json +8 -5
- package/dist/cli-doctor.d.ts +0 -6
- package/dist/cli-doctor.js +0 -60
- package/dist/cli-launch.js +0 -112
- package/dist/daemon-resilience.d.ts +0 -22
- package/dist/daemon-resilience.js +0 -85
- package/dist/mcp-proxy.d.ts +0 -67
- package/dist/mcp-proxy.js +0 -337
- package/dist/tools/profiles.d.ts +0 -37
- package/dist/tools/profiles.js +0 -139
- /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
- /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
- /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
- /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
- /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
- /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
package/dist/init/snippets.d.ts
CHANGED
|
@@ -15,19 +15,16 @@ export declare function nextConfigManual(configFile: string): string;
|
|
|
15
15
|
* setup ended at `bridge refused the connection: authentication failed` and no session ever appeared.
|
|
16
16
|
*/
|
|
17
17
|
export declare function nextReticleDevFile(port: number | undefined, projectId?: string, testids?: readonly string[], stores?: readonly string[]): string;
|
|
18
|
+
export declare function astroManual(port: number | undefined, projectId?: string,
|
|
18
19
|
/**
|
|
19
|
-
*
|
|
20
|
+
* A layout file that actually exists, when one does.
|
|
20
21
|
*
|
|
21
|
-
*
|
|
22
|
-
* `
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* Astro bundles a page `<script>`, so the bare import resolves there. The token has to be inlined by
|
|
27
|
-
* the config because there is no plugin in the page's path to inject it, and `build.target` has to be
|
|
28
|
-
* raised or Astro down-levels the modern SDK bundle and dies on a destructuring transform.
|
|
22
|
+
* Reported from the field: on `examples/framework-react` — which has no layout at all, only
|
|
23
|
+
* `src/pages/index.astro` — init printed thirty lines telling the user to paste into "your
|
|
24
|
+
* layout". Instructions that name a file the project does not have read as a mistake by the
|
|
25
|
+
* reader, and cost them the time it takes to go and confirm it is missing.
|
|
29
26
|
*/
|
|
30
|
-
|
|
27
|
+
layoutPath?: string): string;
|
|
31
28
|
/**
|
|
32
29
|
* The app-side dev module the Vite plugin imports by convention.
|
|
33
30
|
*
|
package/dist/init/snippets.js
CHANGED
|
@@ -47,9 +47,9 @@ export function nextConfigManual(configFile) {
|
|
|
47
47
|
*/
|
|
48
48
|
export function nextReticleDevFile(port, projectId, testids = [], stores = []) {
|
|
49
49
|
const base = connectArg(port, projectId);
|
|
50
|
-
const fields =
|
|
50
|
+
const fields = '' === base ? '' : `${base.slice(1, -1).trim()}, `;
|
|
51
51
|
const ids = testids.map((t) => `'${t}'`).join(', ');
|
|
52
|
-
const storeBlock = stores.length
|
|
52
|
+
const storeBlock = 0 === stores.length
|
|
53
53
|
? ' // No state library detected. If you add one, register it here — see docs/usage.md.'
|
|
54
54
|
: stores.map((h) => ` // import your store, then: ${h}`).join('\n');
|
|
55
55
|
return `'use client';
|
|
@@ -73,7 +73,7 @@ export function ReticleDev() {
|
|
|
73
73
|
// form wires \`subscribe\` too, so every mutation emits a diff; the getter form is read-only.
|
|
74
74
|
${storeBlock}
|
|
75
75
|
registerCapabilities({
|
|
76
|
-
testids: [${ids}],${testids.length
|
|
76
|
+
testids: [${ids}],${0 === testids.length ? ' // none found — add data-testid to your key elements' : ''}
|
|
77
77
|
signals: [], // names you pass to reticle.signal()
|
|
78
78
|
stores: [], // the keys you registered above
|
|
79
79
|
});
|
|
@@ -95,8 +95,28 @@ ${storeBlock}
|
|
|
95
95
|
* the config because there is no plugin in the page's path to inject it, and `build.target` has to be
|
|
96
96
|
* raised or Astro down-levels the modern SDK bundle and dies on a destructuring transform.
|
|
97
97
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
/**
|
|
99
|
+
* Name the file the connect <script> should go in — the layout when one exists, otherwise the page,
|
|
100
|
+
* because a project with no layout has nowhere else to put it and should not be told otherwise.
|
|
101
|
+
*/
|
|
102
|
+
function layoutHost(layoutPath) {
|
|
103
|
+
return layoutPath === undefined
|
|
104
|
+
? '2. This project has no layout, so put it in the page you want instrumented (e.g.\n src/pages/index.astro) — every page you want a session from needs it — inside <body>:'
|
|
105
|
+
: `2. In ${layoutPath} (or any other page you want instrumented), inside <body>:`;
|
|
106
|
+
}
|
|
107
|
+
export function astroManual(port, projectId,
|
|
108
|
+
/**
|
|
109
|
+
* A layout file that actually exists, when one does.
|
|
110
|
+
*
|
|
111
|
+
* Reported from the field: on `examples/framework-react` — which has no layout at all, only
|
|
112
|
+
* `src/pages/index.astro` — init printed thirty lines telling the user to paste into "your
|
|
113
|
+
* layout". Instructions that name a file the project does not have read as a mistake by the
|
|
114
|
+
* reader, and cost them the time it takes to go and confirm it is missing.
|
|
115
|
+
*/
|
|
116
|
+
layoutPath) {
|
|
117
|
+
const extra = port !== undefined && port !== RETICLE_DEFAULT_PORT
|
|
118
|
+
? `\n url: '${bridgeWsUrl(port)}',`
|
|
119
|
+
: '';
|
|
100
120
|
const id = projectId !== undefined && projectId.length > 0 ? `\n projectId: '${projectId}',` : '';
|
|
101
121
|
return `Astro renders its own HTML, so the connect goes in a page <script> and the pairing token is inlined by the config.
|
|
102
122
|
|
|
@@ -125,7 +145,7 @@ export function astroManual(port, projectId) {
|
|
|
125
145
|
},
|
|
126
146
|
});
|
|
127
147
|
|
|
128
|
-
|
|
148
|
+
${layoutHost(layoutPath)}
|
|
129
149
|
|
|
130
150
|
<script>
|
|
131
151
|
if (import.meta.env.DEV) {
|
|
@@ -153,7 +173,7 @@ Start the daemon BEFORE \`astro dev\`, so the token file exists when the config
|
|
|
153
173
|
*/
|
|
154
174
|
export function viteDevModuleFile(testids, stores) {
|
|
155
175
|
const ids = testids.map((t) => `'${t}'`).join(', ');
|
|
156
|
-
const storeBlock = stores.length
|
|
176
|
+
const storeBlock = 0 === stores.length
|
|
157
177
|
? ' // No state library detected. If you add one, register it here — see docs/usage.md.'
|
|
158
178
|
: stores.map((h) => ` // import your store, then: ${h}`).join('\n');
|
|
159
179
|
return `// Dev-only. Imported automatically by @reticlehq/vite-plugin — you do not need to import it.
|
|
@@ -173,7 +193,7 @@ if (import.meta.env.DEV) {
|
|
|
173
193
|
${storeBlock}
|
|
174
194
|
|
|
175
195
|
registerCapabilities({
|
|
176
|
-
testids: [${ids}],${testids.length
|
|
196
|
+
testids: [${ids}],${0 === testids.length ? ' // none found — add data-testid to your key elements' : ''}
|
|
177
197
|
signals: [], // names you pass to reticle.signal()
|
|
178
198
|
stores: [], // the keys you registered above
|
|
179
199
|
});
|
|
@@ -203,10 +223,11 @@ export function htmlManual(port, projectId) {
|
|
|
203
223
|
• Bundled app (Create React App, webpack, Parcel, Vue/Svelte CLI, etc.) — add to your ENTRY module
|
|
204
224
|
(e.g. src/index.js or src/main.js), where '@reticlehq/react' resolves through your bundler:
|
|
205
225
|
|
|
206
|
-
if (location.hostname === 'localhost') {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
226
|
+
if (window.location.hostname === 'localhost') {
|
|
227
|
+
void import('@reticlehq/react').then(({ reticle, install }) => {
|
|
228
|
+
install();
|
|
229
|
+
reticle.connect(${arg});
|
|
230
|
+
});
|
|
210
231
|
}
|
|
211
232
|
|
|
212
233
|
• Plain static HTML with no build step — the browser can't resolve the bare '@reticlehq/react' import, so
|
|
@@ -226,7 +247,7 @@ export const SVELTEKIT_HOOKS_PATH = 'src/hooks.client.ts';
|
|
|
226
247
|
* here is the one thing this project exists not to do.
|
|
227
248
|
*/
|
|
228
249
|
export function unverifiedUiLibraryNote(library) {
|
|
229
|
-
return `Detected a ${library} app. Reticle's DOM, network, console and state tools work here,
|
|
250
|
+
return `Detected a ${library} app. Reticle's DOM, network, console and state tools work here, and source file:line does too — the build plugin stamps data-reticle-source regardless of UI library (measured on preact and svelte). What @reticlehq/react adds and you will NOT get is React component identity: component names and component stacks. No CI gate covers ${library}. Gated today: Vite + React, Next.js, Remix, Astro. If something doesn't work, please open an issue.`;
|
|
230
251
|
}
|
|
231
252
|
export const UNVERIFIED_FRAMEWORK_NOTE = 'Reticle has no SvelteKit app and no CI gate for one, so this wiring is untested — it may work, but nothing proves it and nothing will tell us if it breaks. Supported and gated today: Vite + React, Next.js, Remix and Astro. If the hook does not register a session, please open an issue.';
|
|
232
253
|
/**
|
|
@@ -236,7 +257,7 @@ export const UNVERIFIED_FRAMEWORK_NOTE = 'Reticle has no SvelteKit app and no CI
|
|
|
236
257
|
*/
|
|
237
258
|
export function svelteKitHooksFile(port, projectId) {
|
|
238
259
|
const base = connectArg(port, projectId);
|
|
239
|
-
const fields =
|
|
260
|
+
const fields = '' === base ? '' : `${base.slice(1, -1).trim()}, `;
|
|
240
261
|
return `// Dev-only: connect Reticle on the client. SvelteKit renders via app.html, so the Vite-plugin
|
|
241
262
|
// index.html injection doesn't fire — connect from this client hook instead.
|
|
242
263
|
if (import.meta.env.DEV) {
|
|
@@ -246,11 +267,19 @@ if (import.meta.env.DEV) {
|
|
|
246
267
|
// file it lives in, so @reticlehq/vite-plugin inlines it here at build time. Without it the
|
|
247
268
|
// console reads "bridge refused the connection: authentication failed" and no session appears.
|
|
248
269
|
const token = typeof __RETICLE_TOKEN__ !== 'undefined' ? __RETICLE_TOKEN__ : '';
|
|
249
|
-
|
|
270
|
+
const root = typeof __RETICLE_ROOT__ !== 'undefined' ? __RETICLE_ROOT__ : '';
|
|
271
|
+
const sdkVersion = typeof __RETICLE_SDK_VERSION__ !== 'undefined' ? __RETICLE_SDK_VERSION__ : '';
|
|
272
|
+
reticle.connect({
|
|
273
|
+
${fields}...(token.length > 0 ? { token } : {}),
|
|
274
|
+
...(root.length > 0 ? { root } : {}),
|
|
275
|
+
...(sdkVersion.length > 0 ? { sdkVersion } : {}),
|
|
276
|
+
});
|
|
250
277
|
});
|
|
251
278
|
}
|
|
252
279
|
|
|
253
280
|
declare const __RETICLE_TOKEN__: string | undefined;
|
|
281
|
+
declare const __RETICLE_ROOT__: string | undefined;
|
|
282
|
+
declare const __RETICLE_SDK_VERSION__: string | undefined;
|
|
254
283
|
`;
|
|
255
284
|
}
|
|
256
285
|
/**
|
package/dist/init/vite-config.js
CHANGED
|
@@ -37,7 +37,7 @@ function insertImport(source) {
|
|
|
37
37
|
function insertPlugin(source, port) {
|
|
38
38
|
return source.replace(PLUGINS_ARRAY, (match, _g, offset) => {
|
|
39
39
|
const next = source[offset + match.length] ?? '';
|
|
40
|
-
const separator =
|
|
40
|
+
const separator = '' === next || /\s/.test(next) ? '' : ' ';
|
|
41
41
|
return `${match}${reticlePluginCall(port)},${separator}`;
|
|
42
42
|
});
|
|
43
43
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quote one argument for a Windows command line. Pure, and deliberately NOT platform-gated.
|
|
3
|
+
*
|
|
4
|
+
* The rule used to live inside a `process.platform === WINDOWS` branch in node-io.ts, which meant
|
|
5
|
+
* the Windows path could not be exercised on a mac or in CI's Linux job — so it stayed wrong. A
|
|
6
|
+
* pure function is most of the fix: it can be asserted anywhere, and it is.
|
|
7
|
+
*
|
|
8
|
+
* ## What was wrong
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* /[\s"]/.test(arg) ? `"${arg.replace(/"/g, '\\"')}"` : arg
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Two independent holes, both reachable from an ordinary directory path:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Backslashes were not escaped.** `C:\Users\ada\My Projects\` became
|
|
17
|
+
* `"C:\Users\ada\My Projects\"`, whose trailing `\"` reads as an ESCAPED quote — the quoted
|
|
18
|
+
* region never closes and the rest of the line is re-parsed by cmd.exe. CodeQL flagged this one
|
|
19
|
+
* (`js/incomplete-sanitization`, high).
|
|
20
|
+
* 2. **The predicate only looked for whitespace and quotes.** An argument like `foo&whoami` has
|
|
21
|
+
* neither, so it was handed to cmd.exe completely unquoted. Correct backslash escaping does
|
|
22
|
+
* nothing for that; it needs the metacharacters in the trigger.
|
|
23
|
+
*
|
|
24
|
+
* ## The rule implemented here
|
|
25
|
+
*
|
|
26
|
+
* `CommandLineToArgvW`: a run of backslashes is literal unless it precedes a `"`, in which case the
|
|
27
|
+
* run is doubled and the quote escaped; a run at the very end sits before the closing quote we add,
|
|
28
|
+
* so it is doubled too. Correctly-terminated quotes also neutralise cmd.exe's metacharacters, which
|
|
29
|
+
* it does not interpret inside a quoted region.
|
|
30
|
+
*
|
|
31
|
+
* ## Known limit, stated rather than papered over
|
|
32
|
+
*
|
|
33
|
+
* `%VAR%` is expanded by cmd.exe even inside quotes, and no quoting prevents it — only avoiding
|
|
34
|
+
* `shell: true` does, which Windows needs so `pnpm.cmd`/`npx.cmd` resolve (see `shellOpt`). That is
|
|
35
|
+
* variable substitution, not command execution, and every caller here passes paths and package
|
|
36
|
+
* names rather than user prose.
|
|
37
|
+
*/
|
|
38
|
+
export declare function windowsShellArg(arg: string): string;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quote one argument for a Windows command line. Pure, and deliberately NOT platform-gated.
|
|
3
|
+
*
|
|
4
|
+
* The rule used to live inside a `process.platform === WINDOWS` branch in node-io.ts, which meant
|
|
5
|
+
* the Windows path could not be exercised on a mac or in CI's Linux job — so it stayed wrong. A
|
|
6
|
+
* pure function is most of the fix: it can be asserted anywhere, and it is.
|
|
7
|
+
*
|
|
8
|
+
* ## What was wrong
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* /[\s"]/.test(arg) ? `"${arg.replace(/"/g, '\\"')}"` : arg
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Two independent holes, both reachable from an ordinary directory path:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Backslashes were not escaped.** `C:\Users\ada\My Projects\` became
|
|
17
|
+
* `"C:\Users\ada\My Projects\"`, whose trailing `\"` reads as an ESCAPED quote — the quoted
|
|
18
|
+
* region never closes and the rest of the line is re-parsed by cmd.exe. CodeQL flagged this one
|
|
19
|
+
* (`js/incomplete-sanitization`, high).
|
|
20
|
+
* 2. **The predicate only looked for whitespace and quotes.** An argument like `foo&whoami` has
|
|
21
|
+
* neither, so it was handed to cmd.exe completely unquoted. Correct backslash escaping does
|
|
22
|
+
* nothing for that; it needs the metacharacters in the trigger.
|
|
23
|
+
*
|
|
24
|
+
* ## The rule implemented here
|
|
25
|
+
*
|
|
26
|
+
* `CommandLineToArgvW`: a run of backslashes is literal unless it precedes a `"`, in which case the
|
|
27
|
+
* run is doubled and the quote escaped; a run at the very end sits before the closing quote we add,
|
|
28
|
+
* so it is doubled too. Correctly-terminated quotes also neutralise cmd.exe's metacharacters, which
|
|
29
|
+
* it does not interpret inside a quoted region.
|
|
30
|
+
*
|
|
31
|
+
* ## Known limit, stated rather than papered over
|
|
32
|
+
*
|
|
33
|
+
* `%VAR%` is expanded by cmd.exe even inside quotes, and no quoting prevents it — only avoiding
|
|
34
|
+
* `shell: true` does, which Windows needs so `pnpm.cmd`/`npx.cmd` resolve (see `shellOpt`). That is
|
|
35
|
+
* variable substitution, not command execution, and every caller here passes paths and package
|
|
36
|
+
* names rather than user prose.
|
|
37
|
+
*/
|
|
38
|
+
/**
|
|
39
|
+
* Characters that make cmd.exe do something other than pass the text along.
|
|
40
|
+
*
|
|
41
|
+
* Whitespace and `"` split or delimit; the rest are the shell's control operators. An argument
|
|
42
|
+
* containing any of them must be quoted, not just one containing a space.
|
|
43
|
+
*/
|
|
44
|
+
const NEEDS_QUOTING = /[\s"&|<>^()!%,;=]/;
|
|
45
|
+
export function windowsShellArg(arg) {
|
|
46
|
+
// An empty argument must still occupy a slot in argv. Unquoted it disappears entirely, silently
|
|
47
|
+
// shifting every argument after it by one.
|
|
48
|
+
if (0 === arg.length)
|
|
49
|
+
return '""';
|
|
50
|
+
if (!NEEDS_QUOTING.test(arg))
|
|
51
|
+
return arg;
|
|
52
|
+
let out = '"';
|
|
53
|
+
let backslashes = 0;
|
|
54
|
+
for (const ch of arg) {
|
|
55
|
+
if ('\\' === ch) {
|
|
56
|
+
backslashes += 1;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if ('"' === ch) {
|
|
60
|
+
// 2n+1 backslashes → n literal backslashes and an escaped quote.
|
|
61
|
+
out += '\\'.repeat(2 * backslashes + 1) + '"';
|
|
62
|
+
backslashes = 0;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
out += '\\'.repeat(backslashes) + ch;
|
|
66
|
+
backslashes = 0;
|
|
67
|
+
}
|
|
68
|
+
// A trailing run sits immediately before the closing quote, so it must be doubled or it escapes it.
|
|
69
|
+
return `${out}${'\\'.repeat(2 * backslashes)}"`;
|
|
70
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which directories to look in for the app, when `reticle init` runs at a monorepo root.
|
|
3
|
+
*
|
|
4
|
+
* This used to be the literal list `['apps', 'packages']`. Measured on a real repo with three Next
|
|
5
|
+
* apps at `web/`, `admin/` and `space/`, it found none — so the redirect never fired, init ran
|
|
6
|
+
* against the root, and it reported ✓ for writing `app/reticle-dev.tsx` into a directory Next never
|
|
7
|
+
* compiles. A ⚠ tells a human to act; a ✓ tells them it is handled.
|
|
8
|
+
*
|
|
9
|
+
* A workspace DECLARES its packages, so that declaration is used first and directory names are not
|
|
10
|
+
* guessed at all. Where nothing is declared, every top-level directory is a better candidate than two
|
|
11
|
+
* hardcoded ones — filtered by the usual non-source suspects, and still subject to the `looksLikeApp`
|
|
12
|
+
* check that follows, so a wrong guess here costs a `package.json` read.
|
|
13
|
+
*/
|
|
14
|
+
interface WorkspaceSources {
|
|
15
|
+
/** Raw contents of pnpm-workspace.yaml, when present. */
|
|
16
|
+
pnpmWorkspace?: string;
|
|
17
|
+
/** The `workspaces` field of package.json — array form or the yarn/npm object form. */
|
|
18
|
+
pkgWorkspaces?: unknown;
|
|
19
|
+
/** Directory names at the repo root, used when nothing is declared. */
|
|
20
|
+
topLevelDirs?: readonly string[];
|
|
21
|
+
}
|
|
22
|
+
export declare function workspaceParents(sources: WorkspaceSources): string[];
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which directories to look in for the app, when `reticle init` runs at a monorepo root.
|
|
3
|
+
*
|
|
4
|
+
* This used to be the literal list `['apps', 'packages']`. Measured on a real repo with three Next
|
|
5
|
+
* apps at `web/`, `admin/` and `space/`, it found none — so the redirect never fired, init ran
|
|
6
|
+
* against the root, and it reported ✓ for writing `app/reticle-dev.tsx` into a directory Next never
|
|
7
|
+
* compiles. A ⚠ tells a human to act; a ✓ tells them it is handled.
|
|
8
|
+
*
|
|
9
|
+
* A workspace DECLARES its packages, so that declaration is used first and directory names are not
|
|
10
|
+
* guessed at all. Where nothing is declared, every top-level directory is a better candidate than two
|
|
11
|
+
* hardcoded ones — filtered by the usual non-source suspects, and still subject to the `looksLikeApp`
|
|
12
|
+
* check that follows, so a wrong guess here costs a `package.json` read.
|
|
13
|
+
*/
|
|
14
|
+
/** Directories that are never a workspace package, whatever the layout. */
|
|
15
|
+
const NEVER_A_PACKAGE = new Set(['node_modules', 'dist', 'build', 'out', 'coverage', 'target']);
|
|
16
|
+
/** `packages/*` -> `packages`; `web` -> `web`. The base directory a glob searches. */
|
|
17
|
+
function globBase(pattern) {
|
|
18
|
+
const base = pattern
|
|
19
|
+
.split('/')[0]
|
|
20
|
+
?.trim()
|
|
21
|
+
.replace(/^['"]|['"]$/g, '');
|
|
22
|
+
return base === undefined || '' === base || '.' === base || base.includes('*') ? undefined : base;
|
|
23
|
+
}
|
|
24
|
+
function fromPnpm(yaml) {
|
|
25
|
+
// A deliberately small reader rather than a YAML dependency: this file is a list of globs, and the
|
|
26
|
+
// only shape that matters is `- 'pattern'` under `packages:`. A malformed file yields nothing,
|
|
27
|
+
// which falls through to the top-level scan rather than failing the install.
|
|
28
|
+
const out = [];
|
|
29
|
+
let inPackages = false;
|
|
30
|
+
for (const line of yaml.split('\n')) {
|
|
31
|
+
if (/^packages\s*:/.test(line)) {
|
|
32
|
+
inPackages = true;
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
if (inPackages && /^\S/.test(line))
|
|
36
|
+
break;
|
|
37
|
+
const item = /^\s*-\s*(.+)$/.exec(line);
|
|
38
|
+
if (inPackages && item?.[1] !== undefined) {
|
|
39
|
+
const base = globBase(item[1]);
|
|
40
|
+
if (base !== undefined)
|
|
41
|
+
out.push(base);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
function fromPkg(workspaces) {
|
|
47
|
+
const list = Array.isArray(workspaces)
|
|
48
|
+
? workspaces
|
|
49
|
+
: 'object' === typeof workspaces && workspaces !== null
|
|
50
|
+
? workspaces.packages
|
|
51
|
+
: undefined;
|
|
52
|
+
if (!Array.isArray(list))
|
|
53
|
+
return [];
|
|
54
|
+
return list
|
|
55
|
+
.filter((p) => 'string' === typeof p)
|
|
56
|
+
.map(globBase)
|
|
57
|
+
.filter((p) => p !== undefined);
|
|
58
|
+
}
|
|
59
|
+
export function workspaceParents(sources) {
|
|
60
|
+
const declared = [
|
|
61
|
+
...(sources.pnpmWorkspace === undefined ? [] : fromPnpm(sources.pnpmWorkspace)),
|
|
62
|
+
...fromPkg(sources.pkgWorkspaces),
|
|
63
|
+
];
|
|
64
|
+
const candidates = declared.length > 0
|
|
65
|
+
? declared
|
|
66
|
+
: (sources.topLevelDirs ?? []).filter((d) => !d.startsWith('.') && !NEVER_A_PACKAGE.has(d));
|
|
67
|
+
return [...new Set(candidates)];
|
|
68
|
+
}
|
|
@@ -35,7 +35,7 @@ function invalidate() {
|
|
|
35
35
|
}
|
|
36
36
|
/** Record what a session declared sensitive. Called when its hello lands. */
|
|
37
37
|
export function declareDrivenRedactionKeys(sessionId, keys) {
|
|
38
|
-
if (keys.length
|
|
38
|
+
if (0 === keys.length) {
|
|
39
39
|
if (declaredBySession.delete(sessionId))
|
|
40
40
|
invalidate();
|
|
41
41
|
return;
|
|
@@ -21,7 +21,7 @@ const DEFAULT_POLICY = { isSensitiveKey: defaultIsSensitiveKey };
|
|
|
21
21
|
function redactByKey(value, policy) {
|
|
22
22
|
if (Array.isArray(value))
|
|
23
23
|
return value.map((v) => redactByKey(v, policy));
|
|
24
|
-
if (value !== null && typeof value
|
|
24
|
+
if (value !== null && 'object' === typeof value) {
|
|
25
25
|
const out = {};
|
|
26
26
|
for (const [k, v] of Object.entries(value)) {
|
|
27
27
|
out[k] = policy.isSensitiveKey(k) ? REDACTED_VALUE : redactByKey(v, policy);
|
|
@@ -82,15 +82,15 @@ export function buildNetworkDetail(raw, policy = DEFAULT_POLICY) {
|
|
|
82
82
|
status: raw.status,
|
|
83
83
|
headers: projectHeaders(raw.headers, policy),
|
|
84
84
|
...(raw.resourceType === undefined ? {} : { resourceType: raw.resourceType }),
|
|
85
|
-
...(raw.requestBody === undefined || raw.requestBody.length
|
|
85
|
+
...(raw.requestBody === undefined || 0 === raw.requestBody.length
|
|
86
86
|
? {}
|
|
87
87
|
: { requestBody: projectWireBody(raw.requestBody, policy) }),
|
|
88
|
-
...(raw.pageUrl === undefined || raw.pageUrl.length
|
|
88
|
+
...(raw.pageUrl === undefined || 0 === raw.pageUrl.length ? {} : { pageUrl: raw.pageUrl }),
|
|
89
89
|
};
|
|
90
90
|
}
|
|
91
91
|
function keyOf(url, method) {
|
|
92
|
-
const m = typeof method
|
|
93
|
-
const u = typeof url
|
|
92
|
+
const m = 'string' === typeof method ? method.toUpperCase() : '';
|
|
93
|
+
const u = 'string' === typeof url ? url : '';
|
|
94
94
|
return `${m} ${u}`;
|
|
95
95
|
}
|
|
96
96
|
/**
|
|
@@ -127,9 +127,9 @@ export function mergeNetworkDetail(events) {
|
|
|
127
127
|
// finding — that is the whole reason for capturing it — so the authoritative one wins and the
|
|
128
128
|
// divergence is flagged rather than silently resolved.
|
|
129
129
|
const wireBody = e.data['requestBody'];
|
|
130
|
-
if (typeof wireBody
|
|
130
|
+
if ('string' === typeof wireBody) {
|
|
131
131
|
const pageBody = data['requestBody'];
|
|
132
|
-
if (typeof pageBody
|
|
132
|
+
if ('string' === typeof pageBody && pageBody !== wireBody) {
|
|
133
133
|
data['requestBodyDivergedFromPage'] = true;
|
|
134
134
|
}
|
|
135
135
|
data['requestBody'] = wireBody;
|
|
@@ -162,7 +162,7 @@ export function attachNetworkDetail(page, emit) {
|
|
|
162
162
|
status: response.status(),
|
|
163
163
|
headers,
|
|
164
164
|
...(resourceType === undefined ? {} : { resourceType }),
|
|
165
|
-
...(
|
|
165
|
+
...(null === postData ? {} : { requestBody: postData }),
|
|
166
166
|
pageUrl: page.url(),
|
|
167
167
|
},
|
|
168
168
|
// Resolved per response, not per attachment: a session declaring extra keys can connect
|
|
@@ -5,7 +5,7 @@ import { sessionIdShape } from '../tools/tool-kit.js';
|
|
|
5
5
|
import { asString } from '../tools/tools-helpers.js';
|
|
6
6
|
function mockProvider(deps) {
|
|
7
7
|
const p = deps.realInput;
|
|
8
|
-
return p !== undefined && typeof p.setMocks
|
|
8
|
+
return p !== undefined && 'function' === typeof p.setMocks ? p : undefined;
|
|
9
9
|
}
|
|
10
10
|
const ruleShape = z.object({
|
|
11
11
|
urlContains: z
|
|
@@ -80,7 +80,7 @@ export const NETWORK_MOCK_TOOLS = [
|
|
|
80
80
|
};
|
|
81
81
|
}
|
|
82
82
|
const session = deps.sessions.resolve(asString(args['sessionId']));
|
|
83
|
-
const rules = args['clear']
|
|
83
|
+
const rules = true === args['clear'] ? [] : toRules(args['mocks']);
|
|
84
84
|
const applied = await provider.setMocks(session.url, rules);
|
|
85
85
|
return { applied, count: applied ? rules.length : 0 };
|
|
86
86
|
},
|
|
@@ -10,7 +10,7 @@ export function matchMock(rules, req) {
|
|
|
10
10
|
continue;
|
|
11
11
|
if (rule.method !== undefined && rule.method.toUpperCase() !== req.method.toUpperCase())
|
|
12
12
|
continue;
|
|
13
|
-
if (rule.abort
|
|
13
|
+
if (true === rule.abort)
|
|
14
14
|
return { kind: 'abort' };
|
|
15
15
|
const outcome = {
|
|
16
16
|
kind: 'fulfill',
|
|
@@ -27,11 +27,11 @@ export function matchMock(rules, req) {
|
|
|
27
27
|
}
|
|
28
28
|
/** Apply a matched outcome to a Playwright Route. Exported so the route handler is testable in isolation. */
|
|
29
29
|
export async function applyOutcome(route, outcome, sleep) {
|
|
30
|
-
if (outcome.kind
|
|
30
|
+
if ('continue' === outcome.kind) {
|
|
31
31
|
await route.continue();
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
|
-
if (outcome.kind
|
|
34
|
+
if ('abort' === outcome.kind) {
|
|
35
35
|
await route.abort('failed');
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
@@ -51,7 +51,7 @@ const realSleep = (ms) => new Promise((res) => setTimeout(res, ms));
|
|
|
51
51
|
*/
|
|
52
52
|
export async function installNetworkMocks(page, rules, sleep = realSleep) {
|
|
53
53
|
await page.unroute('**/*').catch(() => undefined);
|
|
54
|
-
if (rules.length
|
|
54
|
+
if (0 === rules.length)
|
|
55
55
|
return;
|
|
56
56
|
await page.route('**/*', (route) => {
|
|
57
57
|
const req = route.request();
|
package/dist/input/real-input.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { gotoOptions } from '../pool/playwright-launcher.js';
|
|
1
2
|
import { BrowserLaunchKind } from '@reticlehq/core';
|
|
2
3
|
import { getSessionMetrics } from '../telemetry/session-metrics.js';
|
|
3
4
|
import { classifyConnectFailure } from '../telemetry/connect-failure.js';
|
|
@@ -93,7 +94,7 @@ const SCREENSHOT_DETERMINISM = { style: HIDE_RETICLE_CHROME_CSS, animations: 'di
|
|
|
93
94
|
export async function capturePage(page, opts) {
|
|
94
95
|
const buf = await page.screenshot(opts.clip !== undefined
|
|
95
96
|
? { ...SCREENSHOT_DETERMINISM, clip: opts.clip }
|
|
96
|
-
: opts.fullPage
|
|
97
|
+
: true === opts.fullPage
|
|
97
98
|
? { ...SCREENSHOT_DETERMINISM, fullPage: true }
|
|
98
99
|
: { ...SCREENSHOT_DETERMINISM });
|
|
99
100
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
@@ -269,7 +270,11 @@ export class LaunchedRealInputProvider {
|
|
|
269
270
|
if (this.#onNetworkDetail !== undefined)
|
|
270
271
|
attachNetworkDetail(page, this.#onNetworkDetail);
|
|
271
272
|
try {
|
|
272
|
-
|
|
273
|
+
// Same navigation rule as the pool, and for the same measured reason: Playwright's default
|
|
274
|
+
// waits for `load`, which an app with one never-finishing subresource never fires — 30s of
|
|
275
|
+
// nothing and then a failure that blames the app. The SDK connect is a module script, so it
|
|
276
|
+
// has already run by DOMContentLoaded. See gotoOptions.
|
|
277
|
+
await page.goto(this.#driveUrl, gotoOptions(undefined));
|
|
273
278
|
}
|
|
274
279
|
catch (e) {
|
|
275
280
|
throw new DriveError(DriveErrorCode.NAVIGATE_FAILED, e instanceof Error ? e.message : String(e));
|
|
@@ -369,7 +374,7 @@ export function selectPage(pages, sessionUrl) {
|
|
|
369
374
|
return exact;
|
|
370
375
|
const target = stripVolatile(sessionUrl);
|
|
371
376
|
const loose = pages.filter((p) => stripVolatile(p.url()) === target);
|
|
372
|
-
return loose.length
|
|
377
|
+
return 1 === loose.length ? loose[0] : undefined;
|
|
373
378
|
}
|
|
374
379
|
function stripVolatile(url) {
|
|
375
380
|
const hash = url.indexOf('#');
|
|
@@ -38,7 +38,7 @@ export async function scrollToFind(session, q, opts = {}) {
|
|
|
38
38
|
return { found: true, element: hit, scrolls, exhausted: false };
|
|
39
39
|
// Fall through to linear refinement from current position (already near the target).
|
|
40
40
|
const data = asRecord(sr.result);
|
|
41
|
-
if (data['atEnd']
|
|
41
|
+
if (true === data['atEnd'] || false === data['scrolled']) {
|
|
42
42
|
return { found: false, scrolls, exhausted: true };
|
|
43
43
|
}
|
|
44
44
|
}
|
|
@@ -50,7 +50,7 @@ export async function scrollToFind(session, q, opts = {}) {
|
|
|
50
50
|
if (hit !== undefined)
|
|
51
51
|
return { found: true, element: hit, scrolls, exhausted: false };
|
|
52
52
|
// Reached the bottom or the container would not move — no more rows to reveal.
|
|
53
|
-
if (data['atEnd']
|
|
53
|
+
if (true === data['atEnd'] || false === data['scrolled']) {
|
|
54
54
|
return { found: false, scrolls, exhausted: true };
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -1,7 +1,2 @@
|
|
|
1
1
|
import type { ToolDef } from '../tools/tools.js';
|
|
2
|
-
/**
|
|
3
|
-
* reticle_scroll_to — the windowed/virtualized-list escape hatch. A plain reticle_query
|
|
4
|
-
* only sees rendered nodes, so an off-screen row in a react-window/react-virtualized list returns
|
|
5
|
-
* nothing. This scrolls the container until the row mounts, then returns its ref.
|
|
6
|
-
*/
|
|
7
2
|
export declare const SCROLL_TOOLS: ToolDef[];
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { QueryBy } from '@reticlehq/core';
|
|
2
3
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
3
4
|
import { asNumber, asString } from '../tools/tools-helpers.js';
|
|
4
5
|
import { scrollToFind } from './scroll-find.js';
|
|
@@ -7,14 +8,20 @@ import { scrollToFind } from './scroll-find.js';
|
|
|
7
8
|
* only sees rendered nodes, so an off-screen row in a react-window/react-virtualized list returns
|
|
8
9
|
* nothing. This scrolls the container until the row mounts, then returns its ref.
|
|
9
10
|
*/
|
|
11
|
+
/**
|
|
12
|
+
* The query strategies, derived from QueryBy — the same vocabulary reticle_query uses, and for the
|
|
13
|
+
* same reason. A free string here produced the identical false negative: `by:'css'` scrolled the
|
|
14
|
+
* whole list and reported `{ found: false, exhausted: true }`, which reads as "the row is not in
|
|
15
|
+
* this list" rather than "that strategy does not exist".
|
|
16
|
+
*/
|
|
17
|
+
const QUERY_BY_LIST = Object.values(QueryBy).join(' | ');
|
|
18
|
+
const queryByEnum = z.enum(Object.values(QueryBy));
|
|
10
19
|
export const SCROLL_TOOLS = [
|
|
11
20
|
{
|
|
12
21
|
name: ReticleTool.SCROLL_TO,
|
|
13
|
-
description: 'Find an element in a VIRTUALIZED list that has not rendered yet. Pass `by` (
|
|
22
|
+
description: 'Find an element in a VIRTUALIZED list that has not rendered yet. Pass `by` (see the parameter for the exact strategies) and `value` (query string) to identify the target row. Scrolls the container until the row mounts, the list ends, or maxScrolls (default 20) is spent. Pass targetIndex + totalCount for bisection — jumps directly to the estimated offset in one scroll (e.g. targetIndex:800 totalCount:1000 jumps to 80% of scrollHeight). Returns { found, element?, scrolls, exhausted }.',
|
|
14
23
|
inputSchema: {
|
|
15
|
-
by:
|
|
16
|
-
.string()
|
|
17
|
-
.describe('Query strategy for finding the target: role | text | testid | label | placeholder | alt'),
|
|
24
|
+
by: queryByEnum.describe(`Query strategy for finding the target: ${QUERY_BY_LIST}`),
|
|
18
25
|
value: z
|
|
19
26
|
.string()
|
|
20
27
|
.describe('Query value for the selected strategy (the element to scroll into view).'),
|
|
@@ -8,7 +8,7 @@ const MIN_DIM = 64;
|
|
|
8
8
|
const MAX_DIM = 10000;
|
|
9
9
|
function viewportProvider(deps) {
|
|
10
10
|
const p = deps.realInput;
|
|
11
|
-
return p !== undefined && typeof p.setViewport
|
|
11
|
+
return p !== undefined && 'function' === typeof p.setViewport
|
|
12
12
|
? p
|
|
13
13
|
: undefined;
|
|
14
14
|
}
|
|
@@ -54,6 +54,6 @@ export const VIEWPORT_TOOLS = [
|
|
|
54
54
|
];
|
|
55
55
|
/** Clamp a requested dimension into [MIN_DIM, MAX_DIM]; a missing/NaN value falls back to MIN_DIM. */
|
|
56
56
|
function clampDim(value) {
|
|
57
|
-
const n = typeof value
|
|
57
|
+
const n = 'number' === typeof value && Number.isFinite(value) ? Math.round(value) : MIN_DIM;
|
|
58
58
|
return Math.max(MIN_DIM, Math.min(n, MAX_DIM));
|
|
59
59
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { FileSystemPort } from '../project/fs-port.js';
|
|
2
2
|
import { type AmbientCounts } from './ambient.js';
|
|
3
|
-
/** Bumped on any breaking change to the persisted ambient-map shape. */
|
|
4
|
-
export declare const AMBIENT_FILE_VERSION = 1;
|
|
5
3
|
/**
|
|
6
4
|
* Persists the learned ambient-churn region map at `.reticle/ambient.json`. Local, single-project
|
|
7
5
|
* memory (stays OSS — OSS-VS-SERVER). Loads never throw: missing/malformed/wrong-version degrades to
|
|
@@ -2,7 +2,7 @@ import { dirname } from 'node:path';
|
|
|
2
2
|
import { reticleDirPaths } from '../project/reticle-dir.js';
|
|
3
3
|
import { AmbientFileSchema } from './ambient.js';
|
|
4
4
|
/** Bumped on any breaking change to the persisted ambient-map shape. */
|
|
5
|
-
|
|
5
|
+
const AMBIENT_FILE_VERSION = 1;
|
|
6
6
|
/**
|
|
7
7
|
* Persists the learned ambient-churn region map at `.reticle/ambient.json`. Local, single-project
|
|
8
8
|
* memory (stays OSS — OSS-VS-SERVER). Loads never throw: missing/malformed/wrong-version degrades to
|
package/dist/journal/ambient.js
CHANGED
|
@@ -8,7 +8,7 @@ import { z } from 'zod';
|
|
|
8
8
|
*/
|
|
9
9
|
export function ambientKeyOf(event) {
|
|
10
10
|
const region = event.data?.['region'];
|
|
11
|
-
if (typeof region
|
|
11
|
+
if ('string' === typeof region && region.length > 0)
|
|
12
12
|
return region;
|
|
13
13
|
return event.ref;
|
|
14
14
|
}
|