@reticlehq/server 2.0.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 +105 -0
- package/README.md +17 -0
- package/dist/bridge-security.d.ts +23 -0
- package/dist/bridge-security.d.ts.map +1 -0
- package/dist/bridge-security.js +44 -0
- package/dist/bridge-security.js.map +1 -0
- package/dist/bridge.d.ts +42 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +281 -0
- package/dist/bridge.js.map +1 -0
- package/dist/bridge.test-harness.d.ts +42 -0
- package/dist/bridge.test-harness.d.ts.map +1 -0
- package/dist/bridge.test-harness.js +192 -0
- package/dist/bridge.test-harness.js.map +1 -0
- package/dist/cli-launch.d.ts +53 -0
- package/dist/cli-launch.d.ts.map +1 -0
- package/dist/cli-launch.js +109 -0
- package/dist/cli-launch.js.map +1 -0
- package/dist/cli-parse.d.ts +74 -0
- package/dist/cli-parse.d.ts.map +1 -0
- package/dist/cli-parse.js +321 -0
- package/dist/cli-parse.js.map +1 -0
- package/dist/cli-port.d.ts +26 -0
- package/dist/cli-port.d.ts.map +1 -0
- package/dist/cli-port.js +57 -0
- package/dist/cli-port.js.map +1 -0
- package/dist/cli-verify.d.ts +46 -0
- package/dist/cli-verify.d.ts.map +1 -0
- package/dist/cli-verify.js +181 -0
- package/dist/cli-verify.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +337 -0
- package/dist/cli.js.map +1 -0
- package/dist/cloud/cloud-sync.d.ts +50 -0
- package/dist/cloud/cloud-sync.d.ts.map +1 -0
- package/dist/cloud/cloud-sync.js +47 -0
- package/dist/cloud/cloud-sync.js.map +1 -0
- package/dist/crawl/crawl-tools.d.ts +8 -0
- package/dist/crawl/crawl-tools.d.ts.map +1 -0
- package/dist/crawl/crawl-tools.js +61 -0
- package/dist/crawl/crawl-tools.js.map +1 -0
- package/dist/crawl/crawl.d.ts +45 -0
- package/dist/crawl/crawl.d.ts.map +1 -0
- package/dist/crawl/crawl.js +106 -0
- package/dist/crawl/crawl.js.map +1 -0
- package/dist/daemon-resilience.d.ts +17 -0
- package/dist/daemon-resilience.d.ts.map +1 -0
- package/dist/daemon-resilience.js +23 -0
- package/dist/daemon-resilience.js.map +1 -0
- package/dist/daemon.d.ts +26 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +122 -0
- package/dist/daemon.js.map +1 -0
- package/dist/domain/domain-model.d.ts +64 -0
- package/dist/domain/domain-model.d.ts.map +1 -0
- package/dist/domain/domain-model.js +127 -0
- package/dist/domain/domain-model.js.map +1 -0
- package/dist/domain/domain-tools.d.ts +9 -0
- package/dist/domain/domain-tools.d.ts.map +1 -0
- package/dist/domain/domain-tools.js +66 -0
- package/dist/domain/domain-tools.js.map +1 -0
- package/dist/domain/flow-risk.d.ts +34 -0
- package/dist/domain/flow-risk.d.ts.map +1 -0
- package/dist/domain/flow-risk.js +81 -0
- package/dist/domain/flow-risk.js.map +1 -0
- package/dist/ee/audit-log.d.ts +15 -0
- package/dist/ee/audit-log.d.ts.map +1 -0
- package/dist/ee/audit-log.js +12 -0
- package/dist/ee/audit-log.js.map +1 -0
- package/dist/events/event-filters.d.ts +65 -0
- package/dist/events/event-filters.d.ts.map +1 -0
- package/dist/events/event-filters.js +98 -0
- package/dist/events/event-filters.js.map +1 -0
- package/dist/events/predicate-eval.d.ts +91 -0
- package/dist/events/predicate-eval.d.ts.map +1 -0
- package/dist/events/predicate-eval.js +299 -0
- package/dist/events/predicate-eval.js.map +1 -0
- package/dist/events/predicate.d.ts +19 -0
- package/dist/events/predicate.d.ts.map +1 -0
- package/dist/events/predicate.js +188 -0
- package/dist/events/predicate.js.map +1 -0
- package/dist/events/reaction.d.ts +34 -0
- package/dist/events/reaction.d.ts.map +1 -0
- package/dist/events/reaction.js +60 -0
- package/dist/events/reaction.js.map +1 -0
- package/dist/events/ring-buffer.d.ts +32 -0
- package/dist/events/ring-buffer.d.ts.map +1 -0
- package/dist/events/ring-buffer.js +75 -0
- package/dist/events/ring-buffer.js.map +1 -0
- package/dist/flows/annotate-tools.d.ts +16 -0
- package/dist/flows/annotate-tools.d.ts.map +1 -0
- package/dist/flows/annotate-tools.js +136 -0
- package/dist/flows/annotate-tools.js.map +1 -0
- package/dist/flows/annotate.d.ts +22 -0
- package/dist/flows/annotate.d.ts.map +1 -0
- package/dist/flows/annotate.js +134 -0
- package/dist/flows/annotate.js.map +1 -0
- package/dist/flows/annotation-store.d.ts +23 -0
- package/dist/flows/annotation-store.d.ts.map +1 -0
- package/dist/flows/annotation-store.js +51 -0
- package/dist/flows/annotation-store.js.map +1 -0
- package/dist/flows/decision.d.ts +13 -0
- package/dist/flows/decision.d.ts.map +1 -0
- package/dist/flows/decision.js +111 -0
- package/dist/flows/decision.js.map +1 -0
- package/dist/flows/flow-classify.d.ts +52 -0
- package/dist/flows/flow-classify.d.ts.map +1 -0
- package/dist/flows/flow-classify.js +99 -0
- package/dist/flows/flow-classify.js.map +1 -0
- package/dist/flows/flow-replay-run.d.ts +15 -0
- package/dist/flows/flow-replay-run.d.ts.map +1 -0
- package/dist/flows/flow-replay-run.js +120 -0
- package/dist/flows/flow-replay-run.js.map +1 -0
- package/dist/flows/flow-replay.d.ts +49 -0
- package/dist/flows/flow-replay.d.ts.map +1 -0
- package/dist/flows/flow-replay.js +391 -0
- package/dist/flows/flow-replay.js.map +1 -0
- package/dist/flows/flow-report.d.ts +23 -0
- package/dist/flows/flow-report.d.ts.map +1 -0
- package/dist/flows/flow-report.js +106 -0
- package/dist/flows/flow-report.js.map +1 -0
- package/dist/flows/flow-scope.d.ts +25 -0
- package/dist/flows/flow-scope.d.ts.map +1 -0
- package/dist/flows/flow-scope.js +32 -0
- package/dist/flows/flow-scope.js.map +1 -0
- package/dist/flows/flow-success.d.ts +33 -0
- package/dist/flows/flow-success.d.ts.map +1 -0
- package/dist/flows/flow-success.js +131 -0
- package/dist/flows/flow-success.js.map +1 -0
- package/dist/flows/flow-tools.d.ts +4 -0
- package/dist/flows/flow-tools.d.ts.map +1 -0
- package/dist/flows/flow-tools.js +460 -0
- package/dist/flows/flow-tools.js.map +1 -0
- package/dist/flows/flows.d.ts +86 -0
- package/dist/flows/flows.d.ts.map +1 -0
- package/dist/flows/flows.js +319 -0
- package/dist/flows/flows.js.map +1 -0
- package/dist/flows/heal.d.ts +43 -0
- package/dist/flows/heal.d.ts.map +1 -0
- package/dist/flows/heal.js +98 -0
- package/dist/flows/heal.js.map +1 -0
- package/dist/flows/recordings.d.ts +46 -0
- package/dist/flows/recordings.d.ts.map +1 -0
- package/dist/flows/recordings.js +43 -0
- package/dist/flows/recordings.js.map +1 -0
- package/dist/flows/replay.d.ts +23 -0
- package/dist/flows/replay.d.ts.map +1 -0
- package/dist/flows/replay.js +160 -0
- package/dist/flows/replay.js.map +1 -0
- package/dist/http-server.d.ts +39 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +145 -0
- package/dist/http-server.js.map +1 -0
- package/dist/idle-shutdown.d.ts +34 -0
- package/dist/idle-shutdown.d.ts.map +1 -0
- package/dist/idle-shutdown.js +68 -0
- package/dist/idle-shutdown.js.map +1 -0
- package/dist/index.d.ts +135 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +371 -0
- package/dist/index.js.map +1 -0
- package/dist/init/cursor.d.ts +25 -0
- package/dist/init/cursor.d.ts.map +1 -0
- package/dist/init/cursor.js +49 -0
- package/dist/init/cursor.js.map +1 -0
- package/dist/init/detect.d.ts +49 -0
- package/dist/init/detect.d.ts.map +1 -0
- package/dist/init/detect.js +84 -0
- package/dist/init/detect.js.map +1 -0
- package/dist/init/mcp.d.ts +40 -0
- package/dist/init/mcp.d.ts.map +1 -0
- package/dist/init/mcp.js +55 -0
- package/dist/init/mcp.js.map +1 -0
- package/dist/init/node-io.d.ts +8 -0
- package/dist/init/node-io.d.ts.map +1 -0
- package/dist/init/node-io.js +57 -0
- package/dist/init/node-io.js.map +1 -0
- package/dist/init/plan.d.ts +72 -0
- package/dist/init/plan.d.ts.map +1 -0
- package/dist/init/plan.js +280 -0
- package/dist/init/plan.js.map +1 -0
- package/dist/init/project-id.d.ts +17 -0
- package/dist/init/project-id.d.ts.map +1 -0
- package/dist/init/project-id.js +38 -0
- package/dist/init/project-id.js.map +1 -0
- package/dist/init/run.d.ts +42 -0
- package/dist/init/run.d.ts.map +1 -0
- package/dist/init/run.js +171 -0
- package/dist/init/run.js.map +1 -0
- package/dist/init/snippets.d.ts +33 -0
- package/dist/init/snippets.d.ts.map +1 -0
- package/dist/init/snippets.js +117 -0
- package/dist/init/snippets.js.map +1 -0
- package/dist/init/vite-config.d.ts +25 -0
- package/dist/init/vite-config.d.ts.map +1 -0
- package/dist/init/vite-config.js +45 -0
- package/dist/init/vite-config.js.map +1 -0
- package/dist/input/network-mock-tools.d.ts +3 -0
- package/dist/input/network-mock-tools.d.ts.map +1 -0
- package/dist/input/network-mock-tools.js +94 -0
- package/dist/input/network-mock-tools.js.map +1 -0
- package/dist/input/network-mock.d.ts +55 -0
- package/dist/input/network-mock.d.ts.map +1 -0
- package/dist/input/network-mock.js +62 -0
- package/dist/input/network-mock.js.map +1 -0
- package/dist/input/real-input.d.ts +174 -0
- package/dist/input/real-input.d.ts.map +1 -0
- package/dist/input/real-input.js +289 -0
- package/dist/input/real-input.js.map +1 -0
- package/dist/input/scroll-find.d.ts +41 -0
- package/dist/input/scroll-find.d.ts.map +1 -0
- package/dist/input/scroll-find.js +59 -0
- package/dist/input/scroll-find.js.map +1 -0
- package/dist/input/scroll-tools.d.ts +8 -0
- package/dist/input/scroll-tools.d.ts.map +1 -0
- package/dist/input/scroll-tools.js +68 -0
- package/dist/input/scroll-tools.js.map +1 -0
- package/dist/input/viewport-tools.d.ts +3 -0
- package/dist/input/viewport-tools.d.ts.map +1 -0
- package/dist/input/viewport-tools.js +65 -0
- package/dist/input/viewport-tools.js.map +1 -0
- package/dist/license/license.d.ts +108 -0
- package/dist/license/license.d.ts.map +1 -0
- package/dist/license/license.js +203 -0
- package/dist/license/license.js.map +1 -0
- package/dist/log.d.ts +6 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +9 -0
- package/dist/log.js.map +1 -0
- package/dist/mcp-proxy.d.ts +16 -0
- package/dist/mcp-proxy.d.ts.map +1 -0
- package/dist/mcp-proxy.js +168 -0
- package/dist/mcp-proxy.js.map +1 -0
- package/dist/mcp.d.ts +14 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +101 -0
- package/dist/mcp.js.map +1 -0
- package/dist/pairing-token.d.ts +28 -0
- package/dist/pairing-token.d.ts.map +1 -0
- package/dist/pairing-token.js +62 -0
- package/dist/pairing-token.js.map +1 -0
- package/dist/pool/browser-pool.d.ts +90 -0
- package/dist/pool/browser-pool.d.ts.map +1 -0
- package/dist/pool/browser-pool.js +221 -0
- package/dist/pool/browser-pool.js.map +1 -0
- package/dist/pool/lease-reaper.d.ts +16 -0
- package/dist/pool/lease-reaper.d.ts.map +1 -0
- package/dist/pool/lease-reaper.js +41 -0
- package/dist/pool/lease-reaper.js.map +1 -0
- package/dist/pool/playwright-launcher.d.ts +19 -0
- package/dist/pool/playwright-launcher.d.ts.map +1 -0
- package/dist/pool/playwright-launcher.js +51 -0
- package/dist/pool/playwright-launcher.js.map +1 -0
- package/dist/project/baselines.d.ts +22 -0
- package/dist/project/baselines.d.ts.map +1 -0
- package/dist/project/baselines.js +45 -0
- package/dist/project/baselines.js.map +1 -0
- package/dist/project/fs-port.d.ts +27 -0
- package/dist/project/fs-port.d.ts.map +1 -0
- package/dist/project/fs-port.js +32 -0
- package/dist/project/fs-port.js.map +1 -0
- package/dist/project/project-store.d.ts +32 -0
- package/dist/project/project-store.d.ts.map +1 -0
- package/dist/project/project-store.js +127 -0
- package/dist/project/project-store.js.map +1 -0
- package/dist/project/project-tools.d.ts +9 -0
- package/dist/project/project-tools.d.ts.map +1 -0
- package/dist/project/project-tools.js +118 -0
- package/dist/project/project-tools.js.map +1 -0
- package/dist/project/reticle-dir.d.ts +61 -0
- package/dist/project/reticle-dir.d.ts.map +1 -0
- package/dist/project/reticle-dir.js +144 -0
- package/dist/project/reticle-dir.js.map +1 -0
- package/dist/runs/build-verification-run.d.ts +30 -0
- package/dist/runs/build-verification-run.d.ts.map +1 -0
- package/dist/runs/build-verification-run.js +71 -0
- package/dist/runs/build-verification-run.js.map +1 -0
- package/dist/runs/profile-redact.d.ts +16 -0
- package/dist/runs/profile-redact.d.ts.map +1 -0
- package/dist/runs/profile-redact.js +32 -0
- package/dist/runs/profile-redact.js.map +1 -0
- package/dist/runs/render-report.d.ts +9 -0
- package/dist/runs/render-report.d.ts.map +1 -0
- package/dist/runs/render-report.js +70 -0
- package/dist/runs/render-report.js.map +1 -0
- package/dist/runs/repair-prompt.d.ts +15 -0
- package/dist/runs/repair-prompt.d.ts.map +1 -0
- package/dist/runs/repair-prompt.js +59 -0
- package/dist/runs/repair-prompt.js.map +1 -0
- package/dist/runs/replay-mapping.d.ts +12 -0
- package/dist/runs/replay-mapping.d.ts.map +1 -0
- package/dist/runs/replay-mapping.js +35 -0
- package/dist/runs/replay-mapping.js.map +1 -0
- package/dist/runs/reticle-runner.d.ts +48 -0
- package/dist/runs/reticle-runner.d.ts.map +1 -0
- package/dist/runs/reticle-runner.js +56 -0
- package/dist/runs/reticle-runner.js.map +1 -0
- package/dist/runs/risk-classify.d.ts +27 -0
- package/dist/runs/risk-classify.d.ts.map +1 -0
- package/dist/runs/risk-classify.js +76 -0
- package/dist/runs/risk-classify.js.map +1 -0
- package/dist/runs/run-store.d.ts +40 -0
- package/dist/runs/run-store.d.ts.map +1 -0
- package/dist/runs/run-store.js +118 -0
- package/dist/runs/run-store.js.map +1 -0
- package/dist/runs/run-tools.d.ts +10 -0
- package/dist/runs/run-tools.d.ts.map +1 -0
- package/dist/runs/run-tools.js +69 -0
- package/dist/runs/run-tools.js.map +1 -0
- package/dist/runs/runner-port.d.ts +14 -0
- package/dist/runs/runner-port.d.ts.map +1 -0
- package/dist/runs/runner-port.js +23 -0
- package/dist/runs/runner-port.js.map +1 -0
- package/dist/runs/verify-http.d.ts +34 -0
- package/dist/runs/verify-http.d.ts.map +1 -0
- package/dist/runs/verify-http.js +102 -0
- package/dist/runs/verify-http.js.map +1 -0
- package/dist/runs/verify-server.d.ts +26 -0
- package/dist/runs/verify-server.d.ts.map +1 -0
- package/dist/runs/verify-server.js +99 -0
- package/dist/runs/verify-server.js.map +1 -0
- package/dist/server-version.d.ts +3 -0
- package/dist/server-version.d.ts.map +1 -0
- package/dist/server-version.js +5 -0
- package/dist/server-version.js.map +1 -0
- package/dist/session/control-envelope.d.ts +49 -0
- package/dist/session/control-envelope.d.ts.map +1 -0
- package/dist/session/control-envelope.js +44 -0
- package/dist/session/control-envelope.js.map +1 -0
- package/dist/session/live-control-tools.d.ts +16 -0
- package/dist/session/live-control-tools.d.ts.map +1 -0
- package/dist/session/live-control-tools.js +204 -0
- package/dist/session/live-control-tools.js.map +1 -0
- package/dist/session/output-budget.d.ts +41 -0
- package/dist/session/output-budget.d.ts.map +1 -0
- package/dist/session/output-budget.js +54 -0
- package/dist/session/output-budget.js.map +1 -0
- package/dist/session/presenter-args.d.ts +8 -0
- package/dist/session/presenter-args.d.ts.map +1 -0
- package/dist/session/presenter-args.js +15 -0
- package/dist/session/presenter-args.js.map +1 -0
- package/dist/session/review-store.d.ts +40 -0
- package/dist/session/review-store.d.ts.map +1 -0
- package/dist/session/review-store.js +61 -0
- package/dist/session/review-store.js.map +1 -0
- package/dist/session/session-health.d.ts +22 -0
- package/dist/session/session-health.d.ts.map +1 -0
- package/dist/session/session-health.js +26 -0
- package/dist/session/session-health.js.map +1 -0
- package/dist/session/session-manager.d.ts +43 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +155 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/session-readiness.d.ts +35 -0
- package/dist/session/session-readiness.d.ts.map +1 -0
- package/dist/session/session-readiness.js +32 -0
- package/dist/session/session-readiness.js.map +1 -0
- package/dist/session/session-reaper.d.ts +37 -0
- package/dist/session/session-reaper.d.ts.map +1 -0
- package/dist/session/session-reaper.js +94 -0
- package/dist/session/session-reaper.js.map +1 -0
- package/dist/session/session-recommendation.d.ts +18 -0
- package/dist/session/session-recommendation.d.ts.map +1 -0
- package/dist/session/session-recommendation.js +14 -0
- package/dist/session/session-recommendation.js.map +1 -0
- package/dist/session/session-tools.d.ts +9 -0
- package/dist/session/session-tools.d.ts.map +1 -0
- package/dist/session/session-tools.js +43 -0
- package/dist/session/session-tools.js.map +1 -0
- package/dist/session/session.d.ts +166 -0
- package/dist/session/session.d.ts.map +1 -0
- package/dist/session/session.js +408 -0
- package/dist/session/session.js.map +1 -0
- package/dist/session/state-select.d.ts +8 -0
- package/dist/session/state-select.d.ts.map +1 -0
- package/dist/session/state-select.js +8 -0
- package/dist/session/state-select.js.map +1 -0
- package/dist/token-auth.d.ts +24 -0
- package/dist/token-auth.d.ts.map +1 -0
- package/dist/token-auth.js +71 -0
- package/dist/token-auth.js.map +1 -0
- package/dist/tools/act-tools.d.ts +3 -0
- package/dist/tools/act-tools.d.ts.map +1 -0
- package/dist/tools/act-tools.js +327 -0
- package/dist/tools/act-tools.js.map +1 -0
- package/dist/tools/act-view.d.ts +19 -0
- package/dist/tools/act-view.d.ts.map +1 -0
- package/dist/tools/act-view.js +46 -0
- package/dist/tools/act-view.js.map +1 -0
- package/dist/tools/assert-grade.d.ts +21 -0
- package/dist/tools/assert-grade.d.ts.map +1 -0
- package/dist/tools/assert-grade.js +52 -0
- package/dist/tools/assert-grade.js.map +1 -0
- package/dist/tools/browser-tools.d.ts +3 -0
- package/dist/tools/browser-tools.d.ts.map +1 -0
- package/dist/tools/browser-tools.js +52 -0
- package/dist/tools/browser-tools.js.map +1 -0
- package/dist/tools/contract-tools.d.ts +8 -0
- package/dist/tools/contract-tools.d.ts.map +1 -0
- package/dist/tools/contract-tools.js +62 -0
- package/dist/tools/contract-tools.js.map +1 -0
- package/dist/tools/dynamic-tools.d.ts +7 -0
- package/dist/tools/dynamic-tools.d.ts.map +1 -0
- package/dist/tools/dynamic-tools.js +103 -0
- package/dist/tools/dynamic-tools.js.map +1 -0
- package/dist/tools/error-recovery.d.ts +31 -0
- package/dist/tools/error-recovery.d.ts.map +1 -0
- package/dist/tools/error-recovery.js +52 -0
- package/dist/tools/error-recovery.js.map +1 -0
- package/dist/tools/invoke-tool.d.ts +23 -0
- package/dist/tools/invoke-tool.d.ts.map +1 -0
- package/dist/tools/invoke-tool.js +99 -0
- package/dist/tools/invoke-tool.js.map +1 -0
- package/dist/tools/lease-tools.d.ts +31 -0
- package/dist/tools/lease-tools.d.ts.map +1 -0
- package/dist/tools/lease-tools.js +164 -0
- package/dist/tools/lease-tools.js.map +1 -0
- package/dist/tools/observe-tools.d.ts +3 -0
- package/dist/tools/observe-tools.d.ts.map +1 -0
- package/dist/tools/observe-tools.js +259 -0
- package/dist/tools/observe-tools.js.map +1 -0
- package/dist/tools/profiles.d.ts +33 -0
- package/dist/tools/profiles.d.ts.map +1 -0
- package/dist/tools/profiles.js +105 -0
- package/dist/tools/profiles.js.map +1 -0
- package/dist/tools/query-paginate.d.ts +15 -0
- package/dist/tools/query-paginate.d.ts.map +1 -0
- package/dist/tools/query-paginate.js +31 -0
- package/dist/tools/query-paginate.js.map +1 -0
- package/dist/tools/read-tools.d.ts +3 -0
- package/dist/tools/read-tools.d.ts.map +1 -0
- package/dist/tools/read-tools.js +329 -0
- package/dist/tools/read-tools.js.map +1 -0
- package/dist/tools/snapshot-delta.d.ts +59 -0
- package/dist/tools/snapshot-delta.d.ts.map +1 -0
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/snapshot-delta.js.map +1 -0
- package/dist/tools/tool-invoker.d.ts +15 -0
- package/dist/tools/tool-invoker.d.ts.map +1 -0
- package/dist/tools/tool-invoker.js +20 -0
- package/dist/tools/tool-invoker.js.map +1 -0
- package/dist/tools/tool-kit.d.ts +60 -0
- package/dist/tools/tool-kit.d.ts.map +1 -0
- package/dist/tools/tool-kit.js +33 -0
- package/dist/tools/tool-kit.js.map +1 -0
- package/dist/tools/tool-names.d.ts +89 -0
- package/dist/tools/tool-names.d.ts.map +1 -0
- package/dist/tools/tool-names.js +88 -0
- package/dist/tools/tool-names.js.map +1 -0
- package/dist/tools/tools-helpers.d.ts +12 -0
- package/dist/tools/tools-helpers.d.ts.map +1 -0
- package/dist/tools/tools-helpers.js +22 -0
- package/dist/tools/tools-helpers.js.map +1 -0
- package/dist/tools/tools.d.ts +4 -0
- package/dist/tools/tools.d.ts.map +1 -0
- package/dist/tools/tools.js +268 -0
- package/dist/tools/tools.js.map +1 -0
- package/dist/update/update-checker.d.ts +20 -0
- package/dist/update/update-checker.d.ts.map +1 -0
- package/dist/update/update-checker.js +94 -0
- package/dist/update/update-checker.js.map +1 -0
- package/dist/update/update-tools.d.ts +3 -0
- package/dist/update/update-tools.d.ts.map +1 -0
- package/dist/update/update-tools.js +94 -0
- package/dist/update/update-tools.js.map +1 -0
- package/dist/update/updater.d.ts +31 -0
- package/dist/update/updater.d.ts.map +1 -0
- package/dist/update/updater.js +120 -0
- package/dist/update/updater.js.map +1 -0
- package/dist/visual/visual-diff.d.ts +46 -0
- package/dist/visual/visual-diff.d.ts.map +1 -0
- package/dist/visual/visual-diff.js +100 -0
- package/dist/visual/visual-diff.js.map +1 -0
- package/dist/visual/visual-store.d.ts +22 -0
- package/dist/visual/visual-store.d.ts.map +1 -0
- package/dist/visual/visual-store.js +60 -0
- package/dist/visual/visual-store.js.map +1 -0
- package/dist/visual/visual-tools.d.ts +9 -0
- package/dist/visual/visual-tools.d.ts.map +1 -0
- package/dist/visual/visual-tools.js +182 -0
- package/dist/visual/visual-tools.js.map +1 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-ALv2
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 Reticle Labs
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
91
|
+
the date we make the Software available. On or after that date, you may use the
|
|
92
|
+
Software under the Apache License, Version 2.0, in which case the following
|
|
93
|
+
will apply:
|
|
94
|
+
|
|
95
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
96
|
+
this file except in compliance with the License.
|
|
97
|
+
|
|
98
|
+
You may obtain a copy of the License at
|
|
99
|
+
|
|
100
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
101
|
+
|
|
102
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
103
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
|
+
specific language governing permissions and limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @reticlehq/server
|
|
2
|
+
|
|
3
|
+
The [Reticle](https://github.com/reticlehq/reticle) bridge + MCP server. It hosts a localhost WebSocket endpoint your app's `@reticlehq/browser` SDK connects to, and exposes MCP tools your coding agent uses to look at, act on, observe, and assert against the live app.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx @reticlehq/server # bridge on ws://localhost:4400, MCP over stdio
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Point your agent at it (e.g. Claude Code `.mcp.json`):
|
|
10
|
+
|
|
11
|
+
```jsonc
|
|
12
|
+
{ "mcpServers": { "reticle": { "command": "npx", "args": ["@reticlehq/server", "mcp"] } } }
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Tools: `reticle_snapshot`, `reticle_query`, `reticle_inspect`, `reticle_act`, `reticle_act_sequence`, `reticle_observe`, `reticle_wait_for`, `reticle_assert`, `reticle_network`, `reticle_console`, `reticle_animations`, `reticle_baseline_save`/`_list`, `reticle_diff`, `reticle_record_start`/`_stop`, `reticle_explore`, `reticle_sessions`.
|
|
16
|
+
|
|
17
|
+
See the [main README](https://github.com/reticlehq/reticle). MIT.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { StartOptions } from './index.js';
|
|
2
|
+
/** The security contract the bridge/daemon enforce: bind host, pairing token, and WS origin allow-list. */
|
|
3
|
+
interface BridgeSecurity {
|
|
4
|
+
host?: string;
|
|
5
|
+
token?: string;
|
|
6
|
+
allowedOrigins?: string[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the bridge's security options from explicit options first, then the environment. Shared by
|
|
10
|
+
* both `start()` and `startDaemon()` so the token/host/origin contract is enforced identically on
|
|
11
|
+
* every entrypoint — a past divergence let daemon mode silently run with auth disabled.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveBridgeSecurity(options: StartOptions): BridgeSecurity;
|
|
14
|
+
/**
|
|
15
|
+
* Same as `resolveBridgeSecurity`, but when no explicit/env token is set it auto-provisions one from
|
|
16
|
+
* ~/.reticle/pairing-token so the bridge always requires a secret by default — this is what closes the
|
|
17
|
+
* "any loopback origin is trusted" gap (a rogue localhost app can't read the file to present it). The
|
|
18
|
+
* build plugins read the same file and inject it, so plugin-served apps stay zero-config. Best-effort:
|
|
19
|
+
* if provisioning fails, the daemon degrades to the prior tokenless behavior rather than failing to start.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveBridgeSecurityWithAutoToken(options: StartOptions): Promise<BridgeSecurity>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=bridge-security.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-security.d.ts","sourceRoot":"","sources":["../src/bridge-security.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ/C,2GAA2G;AAC3G,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,GAAG,cAAc,CAiB3E;AAED;;;;;;GAMG;AACH,wBAAsB,kCAAkC,CACtD,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,cAAc,CAAC,CAUzB"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { ReticleEnv } from '@reticlehq/core';
|
|
2
|
+
import { defaultPairingTokenDir, nodePairingTokenDeps, readOrCreatePairingToken, } from './pairing-token.js';
|
|
3
|
+
import { log } from './log.js';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the bridge's security options from explicit options first, then the environment. Shared by
|
|
6
|
+
* both `start()` and `startDaemon()` so the token/host/origin contract is enforced identically on
|
|
7
|
+
* every entrypoint — a past divergence let daemon mode silently run with auth disabled.
|
|
8
|
+
*/
|
|
9
|
+
export function resolveBridgeSecurity(options) {
|
|
10
|
+
const envToken = process.env[ReticleEnv.TOKEN];
|
|
11
|
+
const envOrigins = process.env[ReticleEnv.ALLOWED_ORIGINS];
|
|
12
|
+
const host = options.host ?? process.env[ReticleEnv.HOST];
|
|
13
|
+
const token = options.token ?? (envToken !== undefined && envToken.length > 0 ? envToken : undefined);
|
|
14
|
+
const allowedOrigins = options.allowedOrigins ??
|
|
15
|
+
envOrigins
|
|
16
|
+
?.split(',')
|
|
17
|
+
.map((origin) => origin.trim())
|
|
18
|
+
.filter((origin) => origin.length > 0);
|
|
19
|
+
return {
|
|
20
|
+
...(host === undefined ? {} : { host }),
|
|
21
|
+
...(token === undefined ? {} : { token }),
|
|
22
|
+
...(allowedOrigins === undefined ? {} : { allowedOrigins }),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Same as `resolveBridgeSecurity`, but when no explicit/env token is set it auto-provisions one from
|
|
27
|
+
* ~/.reticle/pairing-token so the bridge always requires a secret by default — this is what closes the
|
|
28
|
+
* "any loopback origin is trusted" gap (a rogue localhost app can't read the file to present it). The
|
|
29
|
+
* build plugins read the same file and inject it, so plugin-served apps stay zero-config. Best-effort:
|
|
30
|
+
* if provisioning fails, the daemon degrades to the prior tokenless behavior rather than failing to start.
|
|
31
|
+
*/
|
|
32
|
+
export async function resolveBridgeSecurityWithAutoToken(options) {
|
|
33
|
+
const security = resolveBridgeSecurity(options);
|
|
34
|
+
if (security.token !== undefined)
|
|
35
|
+
return security;
|
|
36
|
+
const dir = options.pairingTokenDir ?? defaultPairingTokenDir();
|
|
37
|
+
const token = await readOrCreatePairingToken(dir, nodePairingTokenDeps());
|
|
38
|
+
if (token === undefined) {
|
|
39
|
+
log('pairing_token_provision_failed', { dir });
|
|
40
|
+
return security;
|
|
41
|
+
}
|
|
42
|
+
return { ...security, token };
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=bridge-security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge-security.js","sourceRoot":"","sources":["../src/bridge-security.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAS/B;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAqB;IACzD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAC/C,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;IAC3D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;IAC1D,MAAM,KAAK,GACT,OAAO,CAAC,KAAK,IAAI,CAAC,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC1F,MAAM,cAAc,GAClB,OAAO,CAAC,cAAc;QACtB,UAAU;YACR,EAAE,KAAK,CAAC,GAAG,CAAC;aACX,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;aAC9B,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3C,OAAO;QACL,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;QACvC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACzC,GAAG,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,kCAAkC,CACtD,OAAqB;IAErB,MAAM,QAAQ,GAAG,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAChD,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAClD,MAAM,GAAG,GAAG,OAAO,CAAC,eAAe,IAAI,sBAAsB,EAAE,CAAC;IAChE,MAAM,KAAK,GAAG,MAAM,wBAAwB,CAAC,GAAG,EAAE,oBAAoB,EAAE,CAAC,CAAC;IAC1E,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,GAAG,CAAC,gCAAgC,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/C,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,OAAO,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,CAAC;AAChC,CAAC"}
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import * as http from 'node:http';
|
|
2
|
+
import { Session, SessionManager } from './session/session.js';
|
|
3
|
+
/** A human clicked ▶ on a saved flow in the panel — replay it with no agent. Wired by the daemon. */
|
|
4
|
+
type ReplayRequestHandler = (sessionId: string, flowName: string) => void;
|
|
5
|
+
/** Called once a browser session connects, so the daemon can push it the replayable-flow list. */
|
|
6
|
+
type SessionReadyHandler = (session: Session) => void;
|
|
7
|
+
interface BridgeOptions {
|
|
8
|
+
port: number;
|
|
9
|
+
host?: string;
|
|
10
|
+
token?: string;
|
|
11
|
+
allowedOrigins?: string[];
|
|
12
|
+
maxMessagesPerSecond?: number;
|
|
13
|
+
maxSessions?: number;
|
|
14
|
+
maxPendingConnections?: number;
|
|
15
|
+
helloTimeoutMs?: number;
|
|
16
|
+
clock?: () => number;
|
|
17
|
+
/**
|
|
18
|
+
* When set, the WebSocket server attaches to this HTTP server instead of binding standalone.
|
|
19
|
+
* Used in daemon mode where a single HTTP server handles both WS and SSE MCP traffic.
|
|
20
|
+
* `port` and `host` are ignored for binding when this is provided.
|
|
21
|
+
*/
|
|
22
|
+
server?: http.Server;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The browser-facing half of the relay: a localhost WebSocket server. Each connection
|
|
26
|
+
* announces itself with HELLO (registering a Session), then streams EVENTs and replies to
|
|
27
|
+
* COMMANDs.
|
|
28
|
+
*/
|
|
29
|
+
export declare class Bridge {
|
|
30
|
+
#private;
|
|
31
|
+
readonly sessions: SessionManager;
|
|
32
|
+
/** Resolves with the actually-bound port once the server is listening. */
|
|
33
|
+
readonly ready: Promise<number>;
|
|
34
|
+
constructor(options: BridgeOptions);
|
|
35
|
+
/** Register the daemon's handler for a panel ▶ replay (it owns the flow store). */
|
|
36
|
+
attachReplay(handler: ReplayRequestHandler): void;
|
|
37
|
+
/** Register a callback fired when a browser session connects (to push it the replayable flows). */
|
|
38
|
+
attachSessionReady(handler: SessionReadyHandler): void;
|
|
39
|
+
close(): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
export {};
|
|
42
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAalC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAI/D,qGAAqG;AACrG,KAAK,oBAAoB,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;AAC1E,kGAAkG;AAClG,KAAK,mBAAmB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;AAqBtD,UAAU,aAAa;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC;CACtB;AAkBD;;;;GAIG;AACH,qBAAa,MAAM;;IACjB,QAAQ,CAAC,QAAQ,iBAAwB;IACzC,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;gBAapB,OAAO,EAAE,aAAa;IAyMlC,mFAAmF;IACnF,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI;IAIjD,mGAAmG;IACnG,kBAAkB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAItD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAQvB"}
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import * as http from 'node:http';
|
|
2
|
+
import { WebSocketServer } from 'ws';
|
|
3
|
+
import { EventType, HumanControlKind, RETICLE_WS_PATH, ReticleMessageSchema, LOOPBACK_HOST, MessageKind, TRANSPORT_LIMITS, isLoopbackHostname, } from '@reticlehq/core';
|
|
4
|
+
import { Session, SessionManager } from './session/session.js';
|
|
5
|
+
import { tokensMatch } from './token-auth.js';
|
|
6
|
+
import { log } from './log.js';
|
|
7
|
+
/** WS close codes + reasons the bridge sends to the SDK (1008 = policy violation, 1013 = try again later). */
|
|
8
|
+
const WS_CLOSE = {
|
|
9
|
+
TOO_MANY_HANDSHAKES: [1013, 'too many pending handshakes'],
|
|
10
|
+
HELLO_TIMEOUT: [1008, 'hello timeout'],
|
|
11
|
+
RATE_EXCEEDED: [1008, 'message rate exceeded'],
|
|
12
|
+
INVALID_MESSAGE: [1008, 'invalid message'],
|
|
13
|
+
HELLO_DUPLICATE: [1008, 'hello already received'],
|
|
14
|
+
AUTH_FAILED: [1008, 'authentication failed'],
|
|
15
|
+
SESSION_LIMIT: [1013, 'session limit reached'],
|
|
16
|
+
};
|
|
17
|
+
/** The flow name if this event is a panel ▶ replay request, else undefined. Pure boundary narrowing. */
|
|
18
|
+
function replayRequest(event) {
|
|
19
|
+
if (event.type !== EventType.HUMAN_CONTROL)
|
|
20
|
+
return undefined;
|
|
21
|
+
if (event.data['kind'] !== HumanControlKind.REPLAY)
|
|
22
|
+
return undefined;
|
|
23
|
+
const name = event.data['text'];
|
|
24
|
+
return typeof name === 'string' && name.length > 0 ? name : undefined;
|
|
25
|
+
}
|
|
26
|
+
function normalizeOrigin(origin) {
|
|
27
|
+
try {
|
|
28
|
+
return new URL(origin).origin;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
/** Normalize ws RawData (string | Buffer | Buffer[] | ArrayBuffer) into a UTF-8 string. */
|
|
35
|
+
function rawToString(raw) {
|
|
36
|
+
if (typeof raw === 'string')
|
|
37
|
+
return raw;
|
|
38
|
+
if (Array.isArray(raw))
|
|
39
|
+
return Buffer.concat(raw).toString('utf8');
|
|
40
|
+
if (raw instanceof ArrayBuffer)
|
|
41
|
+
return Buffer.from(raw).toString('utf8');
|
|
42
|
+
return raw.toString('utf8');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The browser-facing half of the relay: a localhost WebSocket server. Each connection
|
|
46
|
+
* announces itself with HELLO (registering a Session), then streams EVENTs and replies to
|
|
47
|
+
* COMMANDs.
|
|
48
|
+
*/
|
|
49
|
+
export class Bridge {
|
|
50
|
+
sessions = new SessionManager();
|
|
51
|
+
/** Resolves with the actually-bound port once the server is listening. */
|
|
52
|
+
ready;
|
|
53
|
+
#wss;
|
|
54
|
+
#clock;
|
|
55
|
+
#token;
|
|
56
|
+
#allowedOrigins;
|
|
57
|
+
#maxMessagesPerSecond;
|
|
58
|
+
#maxSessions;
|
|
59
|
+
#maxPendingConnections;
|
|
60
|
+
#helloTimeoutMs;
|
|
61
|
+
#pendingConnections = 0;
|
|
62
|
+
#onReplay;
|
|
63
|
+
#onSessionReady;
|
|
64
|
+
constructor(options) {
|
|
65
|
+
const host = options.host ?? LOOPBACK_HOST;
|
|
66
|
+
if ((options.token?.length ?? 0) > TRANSPORT_LIMITS.MAX_TOKEN_LENGTH) {
|
|
67
|
+
throw new Error(`Reticle pairing token exceeds ${String(TRANSPORT_LIMITS.MAX_TOKEN_LENGTH)} characters`);
|
|
68
|
+
}
|
|
69
|
+
if (!isLoopbackHostname(host) && (options.token === undefined || options.token.length === 0)) {
|
|
70
|
+
throw new Error('a pairing token is required when the Reticle bridge binds beyond localhost');
|
|
71
|
+
}
|
|
72
|
+
this.#clock = options.clock ?? (() => Date.now());
|
|
73
|
+
this.#token =
|
|
74
|
+
options.token !== undefined && options.token.length > 0 ? options.token : undefined;
|
|
75
|
+
this.#allowedOrigins = new Set((options.allowedOrigins ?? [])
|
|
76
|
+
.map(normalizeOrigin)
|
|
77
|
+
.filter((origin) => origin !== null));
|
|
78
|
+
this.#maxMessagesPerSecond =
|
|
79
|
+
options.maxMessagesPerSecond ?? TRANSPORT_LIMITS.MAX_MESSAGES_PER_SECOND;
|
|
80
|
+
this.#maxSessions = options.maxSessions ?? TRANSPORT_LIMITS.MAX_SESSIONS;
|
|
81
|
+
this.#maxPendingConnections =
|
|
82
|
+
options.maxPendingConnections ?? TRANSPORT_LIMITS.MAX_PENDING_CONNECTIONS;
|
|
83
|
+
this.#helloTimeoutMs = options.helloTimeoutMs ?? TRANSPORT_LIMITS.HELLO_TIMEOUT_MS;
|
|
84
|
+
if (options.server !== undefined) {
|
|
85
|
+
const srv = options.server;
|
|
86
|
+
this.#wss = new WebSocketServer({
|
|
87
|
+
server: srv,
|
|
88
|
+
path: RETICLE_WS_PATH,
|
|
89
|
+
maxPayload: TRANSPORT_LIMITS.MAX_MESSAGE_BYTES,
|
|
90
|
+
verifyClient: ({ origin }, done) => {
|
|
91
|
+
const allowed = this.#originAllowed(origin);
|
|
92
|
+
if (!allowed)
|
|
93
|
+
log('origin_rejected', { origin: origin ?? 'missing' });
|
|
94
|
+
done(allowed, 403, 'Forbidden');
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
// In shared-server mode the daemon owns listen(); but a WebSocketServer bound to a server that
|
|
98
|
+
// fails to listen (EADDRINUSE) surfaces the error on the WS instance too. Without a listener
|
|
99
|
+
// that is an unhandled 'error' that can crash/hang the process — so absorb it here and reject
|
|
100
|
+
// `ready`, mirroring the standalone branch. The daemon's own listen handler reports the failure.
|
|
101
|
+
this.ready = new Promise((resolve, reject) => {
|
|
102
|
+
this.#wss.once('error', reject);
|
|
103
|
+
if (srv.listening) {
|
|
104
|
+
this.#wss.removeListener('error', reject);
|
|
105
|
+
resolve(srv.address().port);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
srv.once('listening', () => {
|
|
109
|
+
this.#wss.removeListener('error', reject);
|
|
110
|
+
resolve(srv.address().port);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
this.#wss = new WebSocketServer({
|
|
117
|
+
port: options.port,
|
|
118
|
+
host,
|
|
119
|
+
path: RETICLE_WS_PATH,
|
|
120
|
+
maxPayload: TRANSPORT_LIMITS.MAX_MESSAGE_BYTES,
|
|
121
|
+
verifyClient: ({ origin }, done) => {
|
|
122
|
+
const allowed = this.#originAllowed(origin);
|
|
123
|
+
if (!allowed)
|
|
124
|
+
log('origin_rejected', { origin: origin ?? 'missing' });
|
|
125
|
+
done(allowed, 403, 'Forbidden');
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
// Reject on 'error' as well as resolve on 'listening'. A port collision (EADDRINUSE) emits
|
|
129
|
+
// 'error'; with no listener that becomes an unhandled 'error' (process crash) AND leaves
|
|
130
|
+
// `ready` pending forever. Surfacing it lets the CLI print "port already in use" cleanly.
|
|
131
|
+
this.ready = new Promise((resolve, reject) => {
|
|
132
|
+
this.#wss.once('error', reject);
|
|
133
|
+
this.#wss.on('listening', () => {
|
|
134
|
+
this.#wss.removeListener('error', reject);
|
|
135
|
+
resolve(this.#wss.address().port);
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
this.#wss.on('connection', (socket) => {
|
|
140
|
+
this.#onConnection(socket);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
#onConnection(socket) {
|
|
144
|
+
if (this.#pendingConnections >= this.#maxPendingConnections) {
|
|
145
|
+
socket.close(...WS_CLOSE.TOO_MANY_HANDSHAKES);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
this.#pendingConnections += 1;
|
|
149
|
+
let awaitingHello = true;
|
|
150
|
+
let session;
|
|
151
|
+
let messageWindowStartedAt = this.#clock();
|
|
152
|
+
let messagesInWindow = 0;
|
|
153
|
+
const releasePending = () => {
|
|
154
|
+
if (!awaitingHello)
|
|
155
|
+
return;
|
|
156
|
+
awaitingHello = false;
|
|
157
|
+
this.#pendingConnections -= 1;
|
|
158
|
+
};
|
|
159
|
+
const helloTimer = setTimeout(() => {
|
|
160
|
+
if (!awaitingHello)
|
|
161
|
+
return;
|
|
162
|
+
releasePending();
|
|
163
|
+
socket.close(...WS_CLOSE.HELLO_TIMEOUT);
|
|
164
|
+
}, this.#helloTimeoutMs);
|
|
165
|
+
socket.on('message', (raw) => {
|
|
166
|
+
const now = this.#clock();
|
|
167
|
+
if (now - messageWindowStartedAt >= 1000) {
|
|
168
|
+
messageWindowStartedAt = now;
|
|
169
|
+
messagesInWindow = 0;
|
|
170
|
+
}
|
|
171
|
+
messagesInWindow += 1;
|
|
172
|
+
if (messagesInWindow > this.#maxMessagesPerSecond) {
|
|
173
|
+
log('message_rate_exceeded', {});
|
|
174
|
+
socket.close(...WS_CLOSE.RATE_EXCEEDED);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
const parsed = this.#parse(rawToString(raw));
|
|
178
|
+
if (parsed === null) {
|
|
179
|
+
socket.close(...WS_CLOSE.INVALID_MESSAGE);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (parsed.kind === MessageKind.HELLO) {
|
|
183
|
+
if (session !== undefined) {
|
|
184
|
+
socket.close(...WS_CLOSE.HELLO_DUPLICATE);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
if (this.#token !== undefined && !tokensMatch(this.#token, parsed.token)) {
|
|
188
|
+
log('authentication_failed', {});
|
|
189
|
+
socket.close(...WS_CLOSE.AUTH_FAILED);
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const existing = this.sessions.get(parsed.sessionId);
|
|
193
|
+
if (existing === undefined && this.sessions.count() >= this.#maxSessions) {
|
|
194
|
+
socket.close(...WS_CLOSE.SESSION_LIMIT);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
clearTimeout(helloTimer);
|
|
198
|
+
releasePending();
|
|
199
|
+
session = new Session(parsed, socket, this.#clock);
|
|
200
|
+
const replaced = this.sessions.add(session);
|
|
201
|
+
replaced?.disconnect('session replaced by a newer connection');
|
|
202
|
+
log('session_connected', { sessionId: session.id, url: session.url });
|
|
203
|
+
this.#onSessionReady?.(session); // daemon pushes the replayable-flow list to the panel
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (session === undefined)
|
|
207
|
+
return;
|
|
208
|
+
session.touch();
|
|
209
|
+
if (parsed.kind === MessageKind.EVENT) {
|
|
210
|
+
// A panel ▶ replay needs the daemon's flow store, which the Session can't reach — route it to
|
|
211
|
+
// the daemon-wired handler instead of the in-session control path. Everything else is normal.
|
|
212
|
+
const replay = replayRequest(parsed.event);
|
|
213
|
+
if (replay !== undefined)
|
|
214
|
+
this.#onReplay?.(session.id, replay);
|
|
215
|
+
else
|
|
216
|
+
session.pushEvent(parsed.event);
|
|
217
|
+
}
|
|
218
|
+
else if (parsed.kind === MessageKind.COMMAND_RESULT) {
|
|
219
|
+
session.handleResult(parsed);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
socket.on('close', () => {
|
|
223
|
+
clearTimeout(helloTimer);
|
|
224
|
+
releasePending();
|
|
225
|
+
if (session !== undefined) {
|
|
226
|
+
if (this.sessions.remove(session)) {
|
|
227
|
+
log('session_disconnected', { sessionId: session.id });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
socket.on('error', (err) => {
|
|
232
|
+
log('socket_error', { error: err.message });
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
#originAllowed(origin) {
|
|
236
|
+
// A real browser SDK connection always carries an Origin. A missing Origin means a non-browser
|
|
237
|
+
// local process (another app, a malicious npm postinstall, an extension's native host) — untrusted
|
|
238
|
+
// unless a pairing token is required, in which case the HELLO token check is the real gate.
|
|
239
|
+
if (origin === undefined)
|
|
240
|
+
return this.#token !== undefined;
|
|
241
|
+
const normalized = normalizeOrigin(origin);
|
|
242
|
+
if (normalized === null)
|
|
243
|
+
return false;
|
|
244
|
+
if (this.#allowedOrigins.has(normalized))
|
|
245
|
+
return true;
|
|
246
|
+
return isLoopbackHostname(new URL(normalized).hostname);
|
|
247
|
+
}
|
|
248
|
+
#parse(text) {
|
|
249
|
+
let json;
|
|
250
|
+
try {
|
|
251
|
+
json = JSON.parse(text);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
const result = ReticleMessageSchema.safeParse(json);
|
|
257
|
+
if (!result.success) {
|
|
258
|
+
log('bad_message', { issues: result.error.issues.length });
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
return result.data;
|
|
262
|
+
}
|
|
263
|
+
/** Register the daemon's handler for a panel ▶ replay (it owns the flow store). */
|
|
264
|
+
attachReplay(handler) {
|
|
265
|
+
this.#onReplay = handler;
|
|
266
|
+
}
|
|
267
|
+
/** Register a callback fired when a browser session connects (to push it the replayable flows). */
|
|
268
|
+
attachSessionReady(handler) {
|
|
269
|
+
this.#onSessionReady = handler;
|
|
270
|
+
}
|
|
271
|
+
close() {
|
|
272
|
+
return new Promise((resolve) => {
|
|
273
|
+
for (const client of this.#wss.clients)
|
|
274
|
+
client.terminate();
|
|
275
|
+
this.#wss.close(() => {
|
|
276
|
+
resolve();
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ElementQuery } from '@reticlehq/core';
|
|
2
|
+
import type { Bridge } from './bridge.js';
|
|
3
|
+
import { type ToolDeps } from './tools/tools.js';
|
|
4
|
+
/** The app-advertised testable surface a FakeBrowser reports for an reticle_capabilities round-trip. */
|
|
5
|
+
export declare const FAKE_CAPABILITIES: {
|
|
6
|
+
testids: string[];
|
|
7
|
+
signals: string[];
|
|
8
|
+
stores: string[];
|
|
9
|
+
flows: {
|
|
10
|
+
name: string;
|
|
11
|
+
steps: string[];
|
|
12
|
+
}[];
|
|
13
|
+
};
|
|
14
|
+
/** A stand-in for the real @reticlehq/browser SDK: replies to commands and emits events. */
|
|
15
|
+
export declare class FakeBrowser {
|
|
16
|
+
#private;
|
|
17
|
+
private readonly sessionId;
|
|
18
|
+
private readonly hasCapabilities;
|
|
19
|
+
matcher: (query: ElementQuery) => boolean;
|
|
20
|
+
/** When false, the browser pretends it has no CAPABILITIES handler (older build). */
|
|
21
|
+
handlesCapabilities: boolean;
|
|
22
|
+
/** When false, ACT results omit a testid (element has no data-testid → unstable step). */
|
|
23
|
+
actHasTestid: boolean;
|
|
24
|
+
/** when false, ACT reports settled:false + settleReason:'timeout' (throttled-tab path). */
|
|
25
|
+
actSettled: boolean;
|
|
26
|
+
/** When false, QUERY by testid returns no match (testid not in current DOM at replay). */
|
|
27
|
+
queryResolves: boolean;
|
|
28
|
+
/** Records every command the bridge sent (for replay assertions). */
|
|
29
|
+
readonly received: {
|
|
30
|
+
name: string;
|
|
31
|
+
args: Record<string, unknown>;
|
|
32
|
+
}[];
|
|
33
|
+
constructor(port: number, sessionId: string, hasCapabilities?: boolean);
|
|
34
|
+
open(): Promise<void>;
|
|
35
|
+
emit(type: string, data: Record<string, unknown>, ref?: string): void;
|
|
36
|
+
close(): void;
|
|
37
|
+
}
|
|
38
|
+
export declare function waitUntil(cond: () => boolean, timeoutMs?: number): Promise<void>;
|
|
39
|
+
export declare const callTool: (deps: ToolDeps, name: string, args?: Record<string, unknown>) => Promise<unknown>;
|
|
40
|
+
/** Builds the ToolDeps wired to a running bridge, with a frozen clock for deterministic tests. */
|
|
41
|
+
export declare function makeDeps(bridge: Bridge): ToolDeps;
|
|
42
|
+
//# sourceMappingURL=bridge.test-harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.test-harness.d.ts","sourceRoot":"","sources":["../src/bridge.test-harness.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,YAAY,EAClB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAO1C,OAAO,EAAS,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAExD,wGAAwG;AACxG,eAAO,MAAM,iBAAiB;;;;;;;;CAK7B,CAAC;AAEF,4FAA4F;AAC5F,qBAAa,WAAW;;IAgBpB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAflC,OAAO,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAe;IACxD,qFAAqF;IACrF,mBAAmB,UAAQ;IAC3B,0FAA0F;IAC1F,YAAY,UAAQ;IACpB,2FAA2F;IAC3F,UAAU,UAAQ;IAClB,0FAA0F;IAC1F,aAAa,UAAQ;IACrB,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,CAAM;gBAGxE,IAAI,EAAE,MAAM,EACK,SAAS,EAAE,MAAM,EACjB,eAAe,UAAQ;IAQ1C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBrB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAOrE,KAAK,IAAI,IAAI;CAwFd;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,OAAO,EAAE,SAAS,SAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9E;AAED,eAAO,MAAM,QAAQ,GACnB,MAAM,QAAQ,EACd,MAAM,MAAM,EACZ,OAAM,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,KACjC,OAAO,CAAC,OAAO,CAIjB,CAAC;AAEF,kGAAkG;AAClG,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAcjD"}
|