@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/dist/mcp.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { isToonable, resultToToon } from '@reticlehq/core';
|
|
4
|
+
import { TOOLS } from './tools/tools.js';
|
|
5
|
+
import { filterTools, TOOL_PROFILE } from './tools/profiles.js';
|
|
6
|
+
import { buildDynamicTools } from './tools/dynamic-tools.js';
|
|
7
|
+
import { runTool } from './tools/invoke-tool.js';
|
|
8
|
+
import { buildErrorPayload } from './tools/error-recovery.js';
|
|
9
|
+
import { log } from './log.js';
|
|
10
|
+
import { SERVER_VERSION } from './server-version.js';
|
|
11
|
+
const SERVER_INFO = { name: 'reticle', version: SERVER_VERSION };
|
|
12
|
+
/** First sentence of a description (purpose only) for lean profiles — keeps per-turn def cost
|
|
13
|
+
* down. Cuts at the first sentence-ending period or newline; falls back to a 160-char cap. The
|
|
14
|
+
* first clause retains the essentials (enum hints like "role | text | label" live there). */
|
|
15
|
+
function firstSentence(description) {
|
|
16
|
+
const nl = description.indexOf('\n');
|
|
17
|
+
const base = nl >= 0 ? description.slice(0, nl) : description;
|
|
18
|
+
const dot = base.search(/\.\s/);
|
|
19
|
+
const sentence = dot >= 0 ? base.slice(0, dot + 1) : base;
|
|
20
|
+
return sentence.length > 160 ? `${sentence.slice(0, 159)}…` : sentence;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Lean copy of a tool's zod input shape for lean profiles: each parameter's description is
|
|
24
|
+
* truncated to its first sentence via zod's own `.describe()` (which returns a new schema, so the
|
|
25
|
+
* shared shape is never mutated). The per-parameter prose is the bulk of the re-sent-every-turn
|
|
26
|
+
* schema cost; the first clause keeps each param's purpose and any enum hints. Params without a
|
|
27
|
+
* description pass through unchanged.
|
|
28
|
+
*/
|
|
29
|
+
function leanZodShape(shape) {
|
|
30
|
+
const out = {};
|
|
31
|
+
for (const [key, schema] of Object.entries(shape)) {
|
|
32
|
+
const desc = schema.description;
|
|
33
|
+
out[key] = typeof desc === 'string' ? schema.describe(firstSentence(desc)) : schema;
|
|
34
|
+
}
|
|
35
|
+
return out;
|
|
36
|
+
}
|
|
37
|
+
const ENCODING_ENV = 'RETICLE_ENCODING';
|
|
38
|
+
const TOON_VALUE = 'toon';
|
|
39
|
+
const PRETTY_VALUE = 'pretty';
|
|
40
|
+
/**
|
|
41
|
+
* Serialize a tool result to the MCP `text` content block. The agent consumes this text — the
|
|
42
|
+
* typed contract travels separately as `structuredContent`, unchanged by encoding — so the text
|
|
43
|
+
* is compact JSON (no indentation) by default: pretty-printing spends a whitespace token on every
|
|
44
|
+
* field of every line, ~40% overhead on the structured payloads that dominate Reticle's cost, for
|
|
45
|
+
* readability only a human re-reading a raw transcript would notice. Opt into the older indented
|
|
46
|
+
* form with `RETICLE_ENCODING=pretty`; `RETICLE_ENCODING=toon` is the even-denser tabular encoding.
|
|
47
|
+
*/
|
|
48
|
+
export function encodeResult(result, encoding) {
|
|
49
|
+
if (encoding === TOON_VALUE && isToonable(result)) {
|
|
50
|
+
return resultToToon(result);
|
|
51
|
+
}
|
|
52
|
+
return encoding === PRETTY_VALUE ? JSON.stringify(result, null, 2) : JSON.stringify(result);
|
|
53
|
+
}
|
|
54
|
+
export function createMcpServer(deps, profile = TOOL_PROFILE.HYBRID) {
|
|
55
|
+
const encoding = (process.env[ENCODING_ENV] ?? '').toLowerCase();
|
|
56
|
+
const server = new McpServer(SERVER_INFO);
|
|
57
|
+
// Cast once to our bridge type so every per-tool call site is typed without `any`.
|
|
58
|
+
const registerTool = server.registerTool.bind(server);
|
|
59
|
+
// `dynamic` advertises only the 2 meta-tools (reticle_tools + reticle_run); real tools load on demand.
|
|
60
|
+
// core/standard advertise the filtered set with terse descriptions (first sentence + trimmed
|
|
61
|
+
// param prose) — the full prose is re-sent every turn, and the first clause carries the purpose.
|
|
62
|
+
const advertised = profile === TOOL_PROFILE.DYNAMIC
|
|
63
|
+
? buildDynamicTools(TOOLS)
|
|
64
|
+
: profile === TOOL_PROFILE.HYBRID
|
|
65
|
+
? [...filterTools(TOOLS, TOOL_PROFILE.CORE), ...buildDynamicTools(TOOLS)]
|
|
66
|
+
: filterTools(TOOLS, profile);
|
|
67
|
+
const terse = profile === TOOL_PROFILE.CORE ||
|
|
68
|
+
profile === TOOL_PROFILE.STANDARD ||
|
|
69
|
+
profile === TOOL_PROFILE.HYBRID;
|
|
70
|
+
for (const tool of advertised) {
|
|
71
|
+
const config = {
|
|
72
|
+
description: terse ? firstSentence(tool.description) : tool.description,
|
|
73
|
+
inputSchema: terse ? leanZodShape(tool.inputSchema) : tool.inputSchema,
|
|
74
|
+
...(tool.outputSchema !== undefined ? { outputSchema: tool.outputSchema } : {}),
|
|
75
|
+
};
|
|
76
|
+
registerTool(tool.name, config, async (args) => {
|
|
77
|
+
try {
|
|
78
|
+
const result = await runTool(tool, deps, args);
|
|
79
|
+
const text = encodeResult(result, encoding);
|
|
80
|
+
if (tool.outputSchema !== undefined) {
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: 'text', text }],
|
|
83
|
+
structuredContent: result,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
return { content: [{ type: 'text', text }] };
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
90
|
+
log('tool_error', { tool: tool.name, error: message });
|
|
91
|
+
// Every error the agent hits should answer "what next?", not just "what broke".
|
|
92
|
+
return {
|
|
93
|
+
isError: true,
|
|
94
|
+
content: [{ type: 'text', text: JSON.stringify(buildErrorPayload(message)) }],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return server;
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=mcp.js.map
|
package/dist/mcp.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../src/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,KAAK,EAAiB,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAoB,MAAM,qBAAqB,CAAC;AAClF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,MAAM,WAAW,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,CAAC;AAEjE;;6FAE6F;AAC7F,SAAS,aAAa,CAAC,WAAmB;IACxC,MAAM,EAAE,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,IAAI,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;IAC9D,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,QAAQ,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC1D,OAAO,QAAQ,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC;AACzE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,KAAoB;IACxC,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC;QAChC,GAAG,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IACtF,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,YAAY,GAAG,kBAAkB,CAAC;AACxC,MAAM,UAAU,GAAG,MAAM,CAAC;AAC1B,MAAM,YAAY,GAAG,QAAQ,CAAC;AAE9B;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAAC,MAAe,EAAE,QAAgB;IAC5D,IAAI,QAAQ,KAAK,UAAU,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,OAAO,YAAY,CAAC,MAAiC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,QAAQ,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAC9F,CAAC;AAuBD,MAAM,UAAU,eAAe,CAC7B,IAAc,EACd,UAAuB,YAAY,CAAC,MAAM;IAE1C,MAAM,QAAQ,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACjE,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,WAAW,CAAC,CAAC;IAC1C,mFAAmF;IACnF,MAAM,YAAY,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAmC,CAAC;IAExF,uGAAuG;IACvG,6FAA6F;IAC7F,iGAAiG;IACjG,MAAM,UAAU,GACd,OAAO,KAAK,YAAY,CAAC,OAAO;QAC9B,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC;QAC1B,CAAC,CAAC,OAAO,KAAK,YAAY,CAAC,MAAM;YAC/B,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;YACzE,CAAC,CAAC,WAAW,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACpC,MAAM,KAAK,GACT,OAAO,KAAK,YAAY,CAAC,IAAI;QAC7B,OAAO,KAAK,YAAY,CAAC,QAAQ;QACjC,OAAO,KAAK,YAAY,CAAC,MAAM,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG;YACb,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW;YACvE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW;YACtE,GAAG,CAAC,IAAI,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAChF,CAAC;QACF,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAA6B,EAAE,EAAE;YACtE,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;gBAC/C,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBAC5C,IAAI,IAAI,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;oBACpC,OAAO;wBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;wBAC1C,iBAAiB,EAAE,MAAiC;qBACrD,CAAC;gBACJ,CAAC;gBACD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;YACxD,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBACvE,GAAG,CAAC,YAAY,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;gBACvD,gFAAgF;gBAChF,OAAO;oBACL,OAAO,EAAE,IAAa;oBACtB,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;iBACvF,CAAC;YACJ,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-provisioned bridge pairing token. The daemon reads-or-creates a per-user secret at
|
|
3
|
+
* ~/.reticle/pairing-token; the bridge then requires it, so a rogue localhost app (which, running in a
|
|
4
|
+
* browser sandbox, cannot read the file) can no longer register/drive sessions just by being on a
|
|
5
|
+
* loopback origin. The build plugins read the same file Node-side and inject it into connect(), so a
|
|
6
|
+
* legitimately-served app stays zero-config.
|
|
7
|
+
*/
|
|
8
|
+
/** Injectable IO + randomness so the provisioner is unit-testable without touching the real home dir. */
|
|
9
|
+
export interface PairingTokenDeps {
|
|
10
|
+
readFile: (path: string) => Promise<string>;
|
|
11
|
+
writeFile: (path: string, data: string) => Promise<void>;
|
|
12
|
+
mkdir: (path: string) => Promise<void>;
|
|
13
|
+
randomToken: () => string;
|
|
14
|
+
}
|
|
15
|
+
/** Env override for the token directory (`RETICLE_PAIRING_TOKEN_DIR`) — relocate the secret off $HOME. */
|
|
16
|
+
export declare const PAIRING_TOKEN_DIR_ENV: "RETICLE_PAIRING_TOKEN_DIR";
|
|
17
|
+
/** The default directory that holds the token — the per-user ~/.reticle so it's shared across projects. */
|
|
18
|
+
export declare function defaultPairingTokenDir(): string;
|
|
19
|
+
export declare function pairingTokenPath(dir: string): string;
|
|
20
|
+
/** Production IO adapter: 0600 file + 0700 dir so only the owner can read the secret. */
|
|
21
|
+
export declare function nodePairingTokenDeps(): PairingTokenDeps;
|
|
22
|
+
/**
|
|
23
|
+
* Read the stored token, or create + persist one on first run. Stable across restarts so a
|
|
24
|
+
* plugin-injected page keeps working after the daemon bounces. Best-effort: returns undefined if IO
|
|
25
|
+
* fails, so the caller degrades to the prior tokenless behavior rather than bricking the daemon.
|
|
26
|
+
*/
|
|
27
|
+
export declare function readOrCreatePairingToken(dir: string, deps: PairingTokenDeps): Promise<string | undefined>;
|
|
28
|
+
//# sourceMappingURL=pairing-token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairing-token.d.ts","sourceRoot":"","sources":["../src/pairing-token.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AAEH,yGAAyG;AACzG,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACzD,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvC,WAAW,EAAE,MAAM,MAAM,CAAC;CAC3B;AAKD,0GAA0G;AAC1G,eAAO,MAAM,qBAAqB,6BAA+B,CAAC;AAElE,2GAA2G;AAC3G,wBAAgB,sBAAsB,IAAI,MAAM,CAI/C;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,yFAAyF;AACzF,wBAAgB,oBAAoB,IAAI,gBAAgB,CAavD;AAED;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAiB7B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { chmod, mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { randomBytes } from 'node:crypto';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { ReticleDir, ReticleEnv } from '@reticlehq/core';
|
|
6
|
+
/** 24 random bytes → 48 hex chars: well under MAX_TOKEN_LENGTH, ample entropy for a local secret. */
|
|
7
|
+
const TOKEN_BYTES = 24;
|
|
8
|
+
/** Env override for the token directory (`RETICLE_PAIRING_TOKEN_DIR`) — relocate the secret off $HOME. */
|
|
9
|
+
export const PAIRING_TOKEN_DIR_ENV = ReticleEnv.PAIRING_TOKEN_DIR;
|
|
10
|
+
/** The default directory that holds the token — the per-user ~/.reticle so it's shared across projects. */
|
|
11
|
+
export function defaultPairingTokenDir() {
|
|
12
|
+
const override = process.env[PAIRING_TOKEN_DIR_ENV];
|
|
13
|
+
if (override !== undefined && override.length > 0)
|
|
14
|
+
return override;
|
|
15
|
+
return join(homedir(), ReticleDir.ROOT);
|
|
16
|
+
}
|
|
17
|
+
export function pairingTokenPath(dir) {
|
|
18
|
+
return join(dir, ReticleDir.PAIRING_TOKEN_FILE);
|
|
19
|
+
}
|
|
20
|
+
/** Production IO adapter: 0600 file + 0700 dir so only the owner can read the secret. */
|
|
21
|
+
export function nodePairingTokenDeps() {
|
|
22
|
+
return {
|
|
23
|
+
readFile: (path) => readFile(path, 'utf8'),
|
|
24
|
+
writeFile: async (path, data) => {
|
|
25
|
+
await writeFile(path, data, { encoding: 'utf8', mode: 0o600 });
|
|
26
|
+
// Enforce perms even if the file pre-existed with a looser mode (writeFile keeps old perms).
|
|
27
|
+
await chmod(path, 0o600);
|
|
28
|
+
},
|
|
29
|
+
mkdir: async (path) => {
|
|
30
|
+
await mkdir(path, { recursive: true, mode: 0o700 });
|
|
31
|
+
},
|
|
32
|
+
randomToken: () => randomBytes(TOKEN_BYTES).toString('hex'),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read the stored token, or create + persist one on first run. Stable across restarts so a
|
|
37
|
+
* plugin-injected page keeps working after the daemon bounces. Best-effort: returns undefined if IO
|
|
38
|
+
* fails, so the caller degrades to the prior tokenless behavior rather than bricking the daemon.
|
|
39
|
+
*/
|
|
40
|
+
export async function readOrCreatePairingToken(dir, deps) {
|
|
41
|
+
const path = pairingTokenPath(dir);
|
|
42
|
+
try {
|
|
43
|
+
const existing = (await deps.readFile(path)).trim();
|
|
44
|
+
if (existing.length > 0)
|
|
45
|
+
return existing;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Missing/unreadable — fall through to create one.
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
const token = deps.randomToken().trim();
|
|
52
|
+
if (token.length === 0)
|
|
53
|
+
return undefined;
|
|
54
|
+
await deps.mkdir(dir);
|
|
55
|
+
await deps.writeFile(path, token);
|
|
56
|
+
return token;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=pairing-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pairing-token.js","sourceRoot":"","sources":["../src/pairing-token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAkBzD,qGAAqG;AACrG,MAAM,WAAW,GAAG,EAAE,CAAC;AAEvB,0GAA0G;AAC1G,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC,iBAAiB,CAAC;AAElE,2GAA2G;AAC3G,MAAM,UAAU,sBAAsB;IACpC,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IACpD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACnE,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,OAAO,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,kBAAkB,CAAC,CAAC;AAClD,CAAC;AAED,yFAAyF;AACzF,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAC1C,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;YAC9B,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;YAC/D,6FAA6F;YAC7F,MAAM,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3B,CAAC;QACD,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACpB,MAAM,KAAK,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,WAAW,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,wBAAwB,CAC5C,GAAW,EACX,IAAsB;IAEtB,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACpD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,QAAQ,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,mDAAmD;IACrD,CAAC;IACD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAC;QACzC,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtB,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAClC,OAAO,KAAK,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BrowserPool — one headless browser, many cheap isolated contexts.
|
|
3
|
+
*
|
|
4
|
+
* The "10 agents test 10 flows" scenario does NOT mean 10 Chromiums (each ~hundreds of MB). It means
|
|
5
|
+
* ONE launched browser and N `newContext()` calls (each ~a few MB, fully isolated cookies/storage).
|
|
6
|
+
* The pool owns that single browser, hands out per-flow leases, caps concurrency so a machine is
|
|
7
|
+
* never overwhelmed (over-cap acquires queue FIFO), and transparently relaunches if the browser dies.
|
|
8
|
+
*
|
|
9
|
+
* The browser is injected via a `Launcher` so all lifecycle logic is testable without real Chromium;
|
|
10
|
+
* the thin Playwright adapter that satisfies these interfaces lives separately.
|
|
11
|
+
*/
|
|
12
|
+
/** The minimal page surface the pool drives. Real Playwright `Page` satisfies this. */
|
|
13
|
+
export interface PooledPage {
|
|
14
|
+
goto(url: string, opts?: {
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}): Promise<unknown>;
|
|
17
|
+
close(): Promise<void>;
|
|
18
|
+
/** Fires when THIS page's renderer crashes — lets the pool reclaim just this lease, not the fleet. */
|
|
19
|
+
onCrash(handler: () => void): void;
|
|
20
|
+
}
|
|
21
|
+
/** An isolated browsing context (cookies/storage). Real Playwright `BrowserContext` satisfies this. */
|
|
22
|
+
export interface PooledContext {
|
|
23
|
+
newPage(): Promise<PooledPage>;
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/** The launched browser. Real Playwright `Browser` satisfies this. */
|
|
27
|
+
export interface PooledBrowser {
|
|
28
|
+
isConnected(): boolean;
|
|
29
|
+
newContext(): Promise<PooledContext>;
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
/** Fires when the browser process dies/crashes so the pool can relaunch on the next acquire. */
|
|
32
|
+
onDisconnected(handler: () => void): void;
|
|
33
|
+
}
|
|
34
|
+
/** Produces a freshly launched browser. Injected so tests can supply a fake. */
|
|
35
|
+
export type Launcher = () => Promise<PooledBrowser>;
|
|
36
|
+
/** A leased context+page for one flow. `release()` frees the slot and closes the context. */
|
|
37
|
+
export interface Lease {
|
|
38
|
+
readonly sessionId: string;
|
|
39
|
+
readonly url: string;
|
|
40
|
+
release(): Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
/** Default lease time-to-live: a lease untouched for this long is presumed orphaned and reclaimed. */
|
|
43
|
+
export declare const DEFAULT_LEASE_TTL_MS: number;
|
|
44
|
+
interface BrowserPoolOptions {
|
|
45
|
+
/** Max simultaneous leased contexts. Over-cap acquires queue. */
|
|
46
|
+
maxContexts: number;
|
|
47
|
+
/** Stable id generator for lease sessionIds (injected to stay clock-/random-free in logic). */
|
|
48
|
+
genSessionId: () => string;
|
|
49
|
+
/** Injected clock (ms). Defaults to Date.now; tests pass a controllable one. */
|
|
50
|
+
now?: () => number;
|
|
51
|
+
/** A lease untouched for longer than this is reclaimed by sweepExpired(). */
|
|
52
|
+
leaseTtlMs?: number;
|
|
53
|
+
/** Per-lease navigation timeout — a page that won't load fails its own lease, never blocks a slot. */
|
|
54
|
+
navTimeoutMs?: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Owns a single browser and leases isolated contexts out of it, capped at `maxContexts`.
|
|
58
|
+
* Not exported as a singleton — the daemon owns one instance.
|
|
59
|
+
*/
|
|
60
|
+
export declare class BrowserPool {
|
|
61
|
+
#private;
|
|
62
|
+
constructor(launch: Launcher, opts: BrowserPoolOptions);
|
|
63
|
+
/** Currently leased contexts. */
|
|
64
|
+
activeCount(): number;
|
|
65
|
+
/** Acquires waiting for a free slot. */
|
|
66
|
+
queuedCount(): number;
|
|
67
|
+
/** The sessionIds of every currently leased context — used to report/group leased sessions. */
|
|
68
|
+
leasedSessionIds(): string[];
|
|
69
|
+
/** Release a lease by its sessionId (closes the context, frees the slot). No-op if unknown. */
|
|
70
|
+
release(sessionId: string): Promise<void>;
|
|
71
|
+
/** Mark a lease as still in use (called on agent activity) so the reaper doesn't reclaim it. */
|
|
72
|
+
touch(sessionId: string): void;
|
|
73
|
+
/**
|
|
74
|
+
* Reclaim leases untouched for longer than the TTL — a hung/crashed agent never holds a slot
|
|
75
|
+
* forever. Returns the released sessionIds. This is the fault-tolerance backstop for the pool.
|
|
76
|
+
*/
|
|
77
|
+
sweepExpired(): Promise<string[]>;
|
|
78
|
+
/**
|
|
79
|
+
* Lease an isolated context, navigate it to `url`, and return a handle. If the pool is at capacity,
|
|
80
|
+
* waits FIFO until a slot frees (or until `signal` aborts, if provided).
|
|
81
|
+
*/
|
|
82
|
+
acquire(url: string, opts?: {
|
|
83
|
+
signal?: AbortSignal;
|
|
84
|
+
sessionId?: string;
|
|
85
|
+
}): Promise<Lease>;
|
|
86
|
+
/** Close every context and the browser. Pending waiters are rejected (the pool is terminal now). */
|
|
87
|
+
shutdown(): Promise<void>;
|
|
88
|
+
}
|
|
89
|
+
export {};
|
|
90
|
+
//# sourceMappingURL=browser-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-pool.d.ts","sourceRoot":"","sources":["../../src/pool/browser-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,uFAAuF;AACvF,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnE,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,sGAAsG;IACtG,OAAO,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CACpC;AAED,uGAAuG;AACvG,MAAM,WAAW,aAAa;IAC5B,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,sEAAsE;AACtE,MAAM,WAAW,aAAa;IAC5B,WAAW,IAAI,OAAO,CAAC;IACvB,UAAU,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IACrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,gGAAgG;IAChG,cAAc,CAAC,OAAO,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;CAC3C;AAED,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC,CAAC;AAEpD,6FAA6F;AAC7F,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAED,sGAAsG;AACtG,eAAO,MAAM,oBAAoB,QAAa,CAAC;AAK/C,UAAU,kBAAkB;IAC1B,iEAAiE;IACjE,WAAW,EAAE,MAAM,CAAC;IACpB,+FAA+F;IAC/F,YAAY,EAAE,MAAM,MAAM,CAAC;IAC3B,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,sGAAsG;IACtG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAUD;;;GAGG;AACH,qBAAa,WAAW;;gBAuBV,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAkB;IAUtD,iCAAiC;IACjC,WAAW,IAAI,MAAM;IAIrB,wCAAwC;IACxC,WAAW,IAAI,MAAM;IAIrB,+FAA+F;IAC/F,gBAAgB,IAAI,MAAM,EAAE;IAI5B,+FAA+F;IAC/F,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,gGAAgG;IAChG,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAK9B;;;OAGG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IASvC;;;OAGG;IACG,OAAO,CACX,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GACtD,OAAO,CAAC,KAAK,CAAC;IAgCjB,oGAAoG;IAC9F,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CA4FhC"}
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BrowserPool — one headless browser, many cheap isolated contexts.
|
|
3
|
+
*
|
|
4
|
+
* The "10 agents test 10 flows" scenario does NOT mean 10 Chromiums (each ~hundreds of MB). It means
|
|
5
|
+
* ONE launched browser and N `newContext()` calls (each ~a few MB, fully isolated cookies/storage).
|
|
6
|
+
* The pool owns that single browser, hands out per-flow leases, caps concurrency so a machine is
|
|
7
|
+
* never overwhelmed (over-cap acquires queue FIFO), and transparently relaunches if the browser dies.
|
|
8
|
+
*
|
|
9
|
+
* The browser is injected via a `Launcher` so all lifecycle logic is testable without real Chromium;
|
|
10
|
+
* the thin Playwright adapter that satisfies these interfaces lives separately.
|
|
11
|
+
*/
|
|
12
|
+
/** Default lease time-to-live: a lease untouched for this long is presumed orphaned and reclaimed. */
|
|
13
|
+
export const DEFAULT_LEASE_TTL_MS = 5 * 60_000;
|
|
14
|
+
/** Default cap on how long a lease's initial navigation may take before it fails (frees the slot). */
|
|
15
|
+
const DEFAULT_NAV_TIMEOUT_MS = 30_000;
|
|
16
|
+
/**
|
|
17
|
+
* Owns a single browser and leases isolated contexts out of it, capped at `maxContexts`.
|
|
18
|
+
* Not exported as a singleton — the daemon owns one instance.
|
|
19
|
+
*/
|
|
20
|
+
export class BrowserPool {
|
|
21
|
+
#launch;
|
|
22
|
+
#max;
|
|
23
|
+
#genId;
|
|
24
|
+
#now;
|
|
25
|
+
#ttl;
|
|
26
|
+
#navTimeout;
|
|
27
|
+
#browser;
|
|
28
|
+
#launching;
|
|
29
|
+
#closed = false;
|
|
30
|
+
#active = new Map();
|
|
31
|
+
/**
|
|
32
|
+
* Slots claimed-or-active — the real concurrency gate. Incremented SYNCHRONOUSLY the instant an
|
|
33
|
+
* acquire passes the cap check, BEFORE the async context creation, so a burst of concurrent
|
|
34
|
+
* acquires (the "10 agents at once" case) can't all slip through the gate before any has been
|
|
35
|
+
* recorded. `#active.size` only reflects fully-created leases; `#occupied` also counts in-flight
|
|
36
|
+
* ones, and is what the cap is enforced against.
|
|
37
|
+
*/
|
|
38
|
+
#occupied = 0;
|
|
39
|
+
/** FIFO of acquires waiting for a slot; each resolves when one frees. */
|
|
40
|
+
#waiters = [];
|
|
41
|
+
constructor(launch, opts) {
|
|
42
|
+
if (opts.maxContexts < 1)
|
|
43
|
+
throw new Error('maxContexts must be >= 1');
|
|
44
|
+
this.#launch = launch;
|
|
45
|
+
this.#max = opts.maxContexts;
|
|
46
|
+
this.#genId = opts.genSessionId;
|
|
47
|
+
this.#now = opts.now ?? (() => Date.now());
|
|
48
|
+
this.#ttl = opts.leaseTtlMs ?? DEFAULT_LEASE_TTL_MS;
|
|
49
|
+
this.#navTimeout = opts.navTimeoutMs ?? DEFAULT_NAV_TIMEOUT_MS;
|
|
50
|
+
}
|
|
51
|
+
/** Currently leased contexts. */
|
|
52
|
+
activeCount() {
|
|
53
|
+
return this.#active.size;
|
|
54
|
+
}
|
|
55
|
+
/** Acquires waiting for a free slot. */
|
|
56
|
+
queuedCount() {
|
|
57
|
+
return this.#waiters.length;
|
|
58
|
+
}
|
|
59
|
+
/** The sessionIds of every currently leased context — used to report/group leased sessions. */
|
|
60
|
+
leasedSessionIds() {
|
|
61
|
+
return [...this.#active.keys()];
|
|
62
|
+
}
|
|
63
|
+
/** Release a lease by its sessionId (closes the context, frees the slot). No-op if unknown. */
|
|
64
|
+
release(sessionId) {
|
|
65
|
+
return this.#release(sessionId);
|
|
66
|
+
}
|
|
67
|
+
/** Mark a lease as still in use (called on agent activity) so the reaper doesn't reclaim it. */
|
|
68
|
+
touch(sessionId) {
|
|
69
|
+
const lease = this.#active.get(sessionId);
|
|
70
|
+
if (lease !== undefined)
|
|
71
|
+
lease.touchedAt = this.#now();
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Reclaim leases untouched for longer than the TTL — a hung/crashed agent never holds a slot
|
|
75
|
+
* forever. Returns the released sessionIds. This is the fault-tolerance backstop for the pool.
|
|
76
|
+
*/
|
|
77
|
+
async sweepExpired() {
|
|
78
|
+
const now = this.#now();
|
|
79
|
+
const expired = [...this.#active.entries()]
|
|
80
|
+
.filter(([, lease]) => now - lease.touchedAt > this.#ttl)
|
|
81
|
+
.map(([sessionId]) => sessionId);
|
|
82
|
+
for (const sessionId of expired)
|
|
83
|
+
await this.#release(sessionId);
|
|
84
|
+
return expired;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Lease an isolated context, navigate it to `url`, and return a handle. If the pool is at capacity,
|
|
88
|
+
* waits FIFO until a slot frees (or until `signal` aborts, if provided).
|
|
89
|
+
*/
|
|
90
|
+
async acquire(url, opts = {}) {
|
|
91
|
+
if (this.#closed)
|
|
92
|
+
throw new Error('browser pool is shut down');
|
|
93
|
+
// #waitForSlot claims the slot synchronously (bumps #occupied) before returning, so the cap holds
|
|
94
|
+
// even when many acquires race through the gate in the same tick.
|
|
95
|
+
await this.#waitForSlot(opts.signal);
|
|
96
|
+
const sessionId = opts.sessionId ?? this.#genId();
|
|
97
|
+
let context;
|
|
98
|
+
try {
|
|
99
|
+
const browser = await this.#ensureBrowser();
|
|
100
|
+
context = await browser.newContext();
|
|
101
|
+
const page = await context.newPage();
|
|
102
|
+
// Per-page crash isolation: if THIS renderer dies, reclaim only this lease — the shared browser
|
|
103
|
+
// and every other agent's context keep running. (A full browser death is handled by #onCrash.)
|
|
104
|
+
page.onCrash(() => {
|
|
105
|
+
void this.#release(sessionId);
|
|
106
|
+
});
|
|
107
|
+
await page.goto(url, { timeoutMs: this.#navTimeout });
|
|
108
|
+
this.#active.set(sessionId, { context, page, url, touchedAt: this.#now() });
|
|
109
|
+
return {
|
|
110
|
+
sessionId,
|
|
111
|
+
url,
|
|
112
|
+
release: () => this.#release(sessionId),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
// Setup failed after we claimed the slot — give it back so a queued acquire isn't stuck, and
|
|
117
|
+
// close the half-open context.
|
|
118
|
+
if (context !== undefined)
|
|
119
|
+
await context.close().catch(() => undefined);
|
|
120
|
+
this.#releaseSlot();
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Close every context and the browser. Pending waiters are rejected (the pool is terminal now). */
|
|
125
|
+
async shutdown() {
|
|
126
|
+
this.#closed = true; // set first so any woken waiter rejects instead of relaunching a browser
|
|
127
|
+
const contexts = [...this.#active.values()].map((a) => a.context);
|
|
128
|
+
this.#active.clear();
|
|
129
|
+
this.#occupied = 0;
|
|
130
|
+
await Promise.all(contexts.map((c) => c.close().catch(() => undefined)));
|
|
131
|
+
const browser = this.#browser;
|
|
132
|
+
this.#browser = undefined;
|
|
133
|
+
if (browser !== undefined)
|
|
134
|
+
await browser.close().catch(() => undefined);
|
|
135
|
+
for (const waiter of this.#waiters.splice(0))
|
|
136
|
+
waiter();
|
|
137
|
+
}
|
|
138
|
+
async #release(sessionId) {
|
|
139
|
+
const lease = this.#active.get(sessionId);
|
|
140
|
+
if (lease === undefined)
|
|
141
|
+
return; // already released or lost to a crash
|
|
142
|
+
this.#active.delete(sessionId);
|
|
143
|
+
await lease.context.close().catch(() => undefined);
|
|
144
|
+
this.#releaseSlot();
|
|
145
|
+
}
|
|
146
|
+
/** Synchronously claim a slot if under the cap. Returns true on success (caller proceeds). */
|
|
147
|
+
#tryClaim() {
|
|
148
|
+
if (this.#occupied < this.#max) {
|
|
149
|
+
this.#occupied += 1;
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
#waitForSlot(signal) {
|
|
155
|
+
if (this.#tryClaim())
|
|
156
|
+
return Promise.resolve();
|
|
157
|
+
return new Promise((resolve, reject) => {
|
|
158
|
+
const onFree = () => {
|
|
159
|
+
// The pool shut down while we waited → reject rather than relaunch a browser.
|
|
160
|
+
if (this.#closed) {
|
|
161
|
+
reject(new Error('browser pool is shut down'));
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Claim the freed slot; if another woken waiter beat us to it, re-queue.
|
|
165
|
+
if (this.#tryClaim())
|
|
166
|
+
resolve();
|
|
167
|
+
else
|
|
168
|
+
this.#waiters.push(onFree);
|
|
169
|
+
};
|
|
170
|
+
if (signal !== undefined) {
|
|
171
|
+
if (signal.aborted) {
|
|
172
|
+
reject(new Error('acquire aborted'));
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
signal.addEventListener('abort', () => {
|
|
176
|
+
// Remove ourselves from the queue so a later wake doesn't claim a slot we'll never use.
|
|
177
|
+
const i = this.#waiters.indexOf(onFree);
|
|
178
|
+
if (i >= 0)
|
|
179
|
+
this.#waiters.splice(i, 1);
|
|
180
|
+
reject(new Error('acquire aborted'));
|
|
181
|
+
}, { once: true });
|
|
182
|
+
}
|
|
183
|
+
this.#waiters.push(onFree);
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
/** Give back one occupied slot and hand it to the next waiter (which re-claims it synchronously). */
|
|
187
|
+
#releaseSlot() {
|
|
188
|
+
if (this.#occupied > 0)
|
|
189
|
+
this.#occupied -= 1;
|
|
190
|
+
const next = this.#waiters.shift();
|
|
191
|
+
if (next !== undefined)
|
|
192
|
+
next();
|
|
193
|
+
}
|
|
194
|
+
async #ensureBrowser() {
|
|
195
|
+
if (this.#closed)
|
|
196
|
+
throw new Error('browser pool is shut down');
|
|
197
|
+
if (this.#browser !== undefined && this.#browser.isConnected())
|
|
198
|
+
return this.#browser;
|
|
199
|
+
// De-dupe concurrent launches: the first acquire to find no browser starts one; the rest await it.
|
|
200
|
+
if (this.#launching === undefined) {
|
|
201
|
+
this.#launching = this.#launch().then((b) => {
|
|
202
|
+
b.onDisconnected(() => this.#onCrash(b));
|
|
203
|
+
this.#browser = b;
|
|
204
|
+
this.#launching = undefined;
|
|
205
|
+
return b;
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
return this.#launching;
|
|
209
|
+
}
|
|
210
|
+
/** The browser process died: drop every lease (they're invalid) and clear so the next acquire relaunches. */
|
|
211
|
+
#onCrash(crashed) {
|
|
212
|
+
if (this.#browser !== crashed)
|
|
213
|
+
return; // a stale handler from a prior browser
|
|
214
|
+
this.#browser = undefined;
|
|
215
|
+
this.#active.clear();
|
|
216
|
+
this.#occupied = 0; // every slot is gone with the browser
|
|
217
|
+
for (const waiter of this.#waiters.splice(0))
|
|
218
|
+
waiter(); // let them re-claim + relaunch
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=browser-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-pool.js","sourceRoot":"","sources":["../../src/pool/browser-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LeaseReaper — periodic backstop that reclaims orphaned pool leases.
|
|
3
|
+
*
|
|
4
|
+
* A lease is "touched" on acquire and on every tool call that targets it. If an agent crashes or
|
|
5
|
+
* hangs mid-flow it stops touching its lease; after the pool's TTL the reaper closes that context and
|
|
6
|
+
* frees the slot for a queued acquire. This is what keeps "10 agents, headless" fault-tolerant: one
|
|
7
|
+
* dead agent can't starve the pool. Mirrors SessionReaper (unref'd interval, idempotent start).
|
|
8
|
+
*/
|
|
9
|
+
import type { BrowserPool } from './browser-pool.js';
|
|
10
|
+
export declare class LeaseReaper {
|
|
11
|
+
#private;
|
|
12
|
+
constructor(pool: BrowserPool, intervalMs?: number);
|
|
13
|
+
start(): void;
|
|
14
|
+
stop(): void;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=lease-reaper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lease-reaper.d.ts","sourceRoot":"","sources":["../../src/pool/lease-reaper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAMrD,qBAAa,WAAW;;gBAKV,IAAI,EAAE,WAAW,EAAE,UAAU,GAAE,MAA+B;IAK1E,KAAK,IAAI,IAAI;IAab,IAAI,IAAI,IAAI;CAKb"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LeaseReaper — periodic backstop that reclaims orphaned pool leases.
|
|
3
|
+
*
|
|
4
|
+
* A lease is "touched" on acquire and on every tool call that targets it. If an agent crashes or
|
|
5
|
+
* hangs mid-flow it stops touching its lease; after the pool's TTL the reaper closes that context and
|
|
6
|
+
* frees the slot for a queued acquire. This is what keeps "10 agents, headless" fault-tolerant: one
|
|
7
|
+
* dead agent can't starve the pool. Mirrors SessionReaper (unref'd interval, idempotent start).
|
|
8
|
+
*/
|
|
9
|
+
import { log } from '../log.js';
|
|
10
|
+
/** How often the reaper sweeps for expired leases. */
|
|
11
|
+
const LEASE_REAP_INTERVAL_MS = 30_000;
|
|
12
|
+
export class LeaseReaper {
|
|
13
|
+
#timer;
|
|
14
|
+
#pool;
|
|
15
|
+
#intervalMs;
|
|
16
|
+
constructor(pool, intervalMs = LEASE_REAP_INTERVAL_MS) {
|
|
17
|
+
this.#pool = pool;
|
|
18
|
+
this.#intervalMs = intervalMs;
|
|
19
|
+
}
|
|
20
|
+
start() {
|
|
21
|
+
if (this.#timer !== undefined)
|
|
22
|
+
return;
|
|
23
|
+
this.#timer = setInterval(() => {
|
|
24
|
+
this.#pool
|
|
25
|
+
.sweepExpired()
|
|
26
|
+
.then((reclaimed) => {
|
|
27
|
+
if (reclaimed.length > 0)
|
|
28
|
+
log('lease_reaped_expired', { leases: reclaimed });
|
|
29
|
+
})
|
|
30
|
+
.catch(() => undefined);
|
|
31
|
+
}, this.#intervalMs);
|
|
32
|
+
this.#timer.unref();
|
|
33
|
+
}
|
|
34
|
+
stop() {
|
|
35
|
+
if (this.#timer === undefined)
|
|
36
|
+
return;
|
|
37
|
+
clearInterval(this.#timer);
|
|
38
|
+
this.#timer = undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=lease-reaper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lease-reaper.js","sourceRoot":"","sources":["../../src/pool/lease-reaper.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAEhC,sDAAsD;AACtD,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAEtC,MAAM,OAAO,WAAW;IACtB,MAAM,CAA6C;IAC1C,KAAK,CAAc;IACnB,WAAW,CAAS;IAE7B,YAAY,IAAiB,EAAE,aAAqB,sBAAsB;QACxE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QAClB,IAAI,CAAC,WAAW,GAAG,UAAU,CAAC;IAChC,CAAC;IAED,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO;QACtC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC,GAAG,EAAE;YAC7B,IAAI,CAAC,KAAK;iBACP,YAAY,EAAE;iBACd,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;gBAClB,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;oBAAE,GAAG,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;YAC/E,CAAC,CAAC;iBACD,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5B,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACrB,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,OAAO;QACtC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The real Playwright adapter behind BrowserPool: wraps `chromium.launch` into the pool's small
|
|
3
|
+
* PooledBrowser/Context/Page interfaces. Kept thin and separate so the pool's lifecycle logic stays
|
|
4
|
+
* unit-tested with a fake while this glue is exercised only by the e2e battery (it needs Chromium).
|
|
5
|
+
*
|
|
6
|
+
* Headless by default — the pool exists for fault-tolerant headless multi-agent testing.
|
|
7
|
+
*/
|
|
8
|
+
import type { Launcher } from './browser-pool.js';
|
|
9
|
+
/** A Launcher that boots a real headless Chromium and adapts it to the pool's interface. */
|
|
10
|
+
export declare function playwrightLauncher(opts?: {
|
|
11
|
+
headless?: boolean;
|
|
12
|
+
}): Launcher;
|
|
13
|
+
/**
|
|
14
|
+
* Resolve the pool's concurrency cap. An explicit RETICLE_MAX_CONTEXTS wins (clamped to >=1); otherwise
|
|
15
|
+
* scale with the machine but never above a sane ceiling so a big box can't fan out into a fork bomb.
|
|
16
|
+
* Pure (env value + cpu count passed in) so it's testable.
|
|
17
|
+
*/
|
|
18
|
+
export declare function resolveMaxContexts(envValue: string | undefined, cpuCount: number): number;
|
|
19
|
+
//# sourceMappingURL=playwright-launcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"playwright-launcher.d.ts","sourceRoot":"","sources":["../../src/pool/playwright-launcher.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAA4C,MAAM,mBAAmB,CAAC;AA4B5F,4FAA4F;AAC5F,wBAAgB,kBAAkB,CAAC,IAAI,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,QAAQ,CAG9E;AAKD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOzF"}
|