@reticlehq/server 2.2.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/bridge-security.d.ts +0 -1
- package/dist/bridge-security.js +0 -1
- package/dist/bridge.d.ts +0 -1
- package/dist/bridge.js +102 -12
- package/dist/bridge.test-harness.d.ts +5 -1
- package/dist/bridge.test-harness.js +12 -1
- package/dist/capsule/capsule-store.d.ts +2 -3
- package/dist/capsule/capsule-store.js +0 -1
- package/dist/capsule/capsule.d.ts +0 -1
- package/dist/capsule/capsule.js +0 -1
- package/dist/capsule/causal-summary.d.ts +21 -1
- package/dist/capsule/causal-summary.js +20 -2
- package/dist/capsule/divergence.d.ts +0 -1
- package/dist/capsule/divergence.js +0 -1
- package/dist/capsule/minimize.d.ts +0 -1
- package/dist/capsule/minimize.js +0 -1
- package/dist/capsule/predicate-to-links.d.ts +0 -1
- package/dist/capsule/predicate-to-links.js +0 -1
- package/dist/cli-doctor.d.ts +6 -0
- package/dist/cli-doctor.js +60 -0
- package/dist/cli-flow-commands.d.ts +0 -1
- package/dist/cli-flow-commands.js +0 -1
- package/dist/cli-launch.d.ts +0 -1
- package/dist/cli-launch.js +7 -3
- package/dist/cli-parse.d.ts +47 -3
- package/dist/cli-parse.js +147 -13
- package/dist/cli-port.d.ts +3 -1
- package/dist/cli-port.js +21 -1
- package/dist/cli-verify.d.ts +0 -1
- package/dist/cli-verify.js +1 -2
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +88 -69
- package/dist/cloud/cloud-config.d.ts +0 -1
- package/dist/cloud/cloud-config.js +0 -1
- package/dist/cloud/cloud-sync.d.ts +4 -5
- package/dist/cloud/cloud-sync.js +0 -1
- package/dist/cloud-cli.d.ts +0 -1
- package/dist/cloud-cli.js +9 -2
- package/dist/crawl/crawl-tools.d.ts +0 -1
- package/dist/crawl/crawl-tools.js +1 -2
- package/dist/crawl/crawl.d.ts +17 -3
- package/dist/crawl/crawl.js +43 -4
- package/dist/daemon-resilience.d.ts +6 -1
- package/dist/daemon-resilience.js +63 -1
- package/dist/daemon.d.ts +23 -3
- package/dist/daemon.js +36 -24
- package/dist/domain/domain-model.d.ts +0 -1
- package/dist/domain/domain-model.js +1 -2
- package/dist/domain/domain-tools.d.ts +0 -7
- package/dist/domain/domain-tools.js +21 -4
- package/dist/domain/flow-risk.d.ts +0 -1
- package/dist/domain/flow-risk.js +0 -1
- package/dist/ee/audit-log.d.ts +0 -1
- package/dist/ee/audit-log.js +0 -1
- package/dist/events/body-failures.d.ts +4 -0
- package/dist/events/body-failures.js +113 -0
- package/dist/events/contradictions.d.ts +53 -0
- package/dist/events/contradictions.js +282 -0
- package/dist/events/echo-mismatch.d.ts +4 -0
- package/dist/events/echo-mismatch.js +138 -0
- package/dist/events/event-filters.d.ts +17 -3
- package/dist/events/event-filters.js +13 -3
- package/dist/events/json-salvage.d.ts +32 -0
- package/dist/events/json-salvage.js +96 -0
- package/dist/events/predicate-eval.d.ts +2 -1
- package/dist/events/predicate-eval.js +56 -9
- package/dist/events/predicate.d.ts +0 -1
- package/dist/events/predicate.js +56 -2
- package/dist/events/reaction.d.ts +0 -1
- package/dist/events/reaction.js +0 -1
- package/dist/events/reconcile.d.ts +39 -0
- package/dist/events/reconcile.js +211 -0
- package/dist/events/ring-buffer.d.ts +0 -1
- package/dist/events/ring-buffer.js +0 -1
- package/dist/events/stale-response.d.ts +4 -0
- package/dist/events/stale-response.js +139 -0
- package/dist/events/unit-mismatch.d.ts +16 -0
- package/dist/events/unit-mismatch.js +167 -0
- package/dist/flows/affected-tools.d.ts +18 -0
- package/dist/flows/affected-tools.js +52 -0
- package/dist/flows/affected.d.ts +0 -1
- package/dist/flows/affected.js +0 -1
- package/dist/flows/annotate-tools.d.ts +0 -1
- package/dist/flows/annotate-tools.js +21 -3
- package/dist/flows/annotate.d.ts +0 -1
- package/dist/flows/annotate.js +0 -1
- package/dist/flows/annotation-store.d.ts +0 -1
- package/dist/flows/annotation-store.js +0 -1
- package/dist/flows/assertion-integrity.d.ts +0 -1
- package/dist/flows/assertion-integrity.js +0 -1
- package/dist/flows/assertion-tiers-store.d.ts +0 -1
- package/dist/flows/assertion-tiers-store.js +0 -1
- package/dist/flows/buddy-status.d.ts +0 -1
- package/dist/flows/buddy-status.js +0 -1
- package/dist/flows/coverage.d.ts +0 -1
- package/dist/flows/coverage.js +0 -1
- package/dist/flows/decision.d.ts +0 -7
- package/dist/flows/decision.js +47 -7
- package/dist/flows/flake-store.d.ts +0 -1
- package/dist/flows/flake-store.js +0 -1
- package/dist/flows/flake.d.ts +0 -1
- package/dist/flows/flake.js +0 -1
- package/dist/flows/flow-classify.d.ts +0 -1
- package/dist/flows/flow-classify.js +0 -1
- package/dist/flows/flow-replay-run.d.ts +0 -1
- package/dist/flows/flow-replay-run.js +2 -3
- package/dist/flows/flow-replay.d.ts +20 -4
- package/dist/flows/flow-replay.js +9 -43
- package/dist/flows/flow-report.d.ts +0 -1
- package/dist/flows/flow-report.js +0 -1
- package/dist/flows/flow-scope.d.ts +0 -1
- package/dist/flows/flow-scope.js +0 -1
- package/dist/flows/flow-sources.d.ts +0 -1
- package/dist/flows/flow-sources.js +0 -1
- package/dist/flows/flow-step-runners.d.ts +23 -0
- package/dist/flows/flow-step-runners.js +102 -0
- package/dist/flows/flow-success.d.ts +0 -1
- package/dist/flows/flow-success.js +0 -1
- package/dist/flows/flow-tools.d.ts +0 -1
- package/dist/flows/flow-tools.js +44 -14
- package/dist/flows/flows.d.ts +6 -2
- package/dist/flows/flows.js +15 -2
- package/dist/flows/gate.d.ts +0 -1
- package/dist/flows/gate.js +0 -1
- package/dist/flows/git-changed.d.ts +0 -1
- package/dist/flows/git-changed.js +0 -1
- package/dist/flows/heal-run.d.ts +0 -1
- package/dist/flows/heal-run.js +0 -1
- package/dist/flows/heal.d.ts +0 -1
- package/dist/flows/heal.js +0 -1
- package/dist/flows/parallel-suite.d.ts +0 -1
- package/dist/flows/parallel-suite.js +0 -1
- package/dist/flows/recordings.d.ts +0 -1
- package/dist/flows/recordings.js +0 -1
- package/dist/flows/replay.d.ts +0 -1
- package/dist/flows/replay.js +71 -4
- package/dist/flows/server-verify.d.ts +0 -1
- package/dist/flows/server-verify.js +0 -1
- package/dist/flows/verify-change-tools.d.ts +2 -0
- package/dist/flows/verify-change-tools.js +187 -0
- package/dist/flows/watch-batcher.d.ts +0 -1
- package/dist/flows/watch-batcher.js +0 -1
- package/dist/honesty/accepted-write.d.ts +14 -0
- package/dist/honesty/accepted-write.js +17 -0
- package/dist/honesty/blind-spots.d.ts +18 -1
- package/dist/honesty/blind-spots.js +47 -5
- package/dist/honesty/honesty.d.ts +0 -1
- package/dist/honesty/honesty.js +0 -1
- package/dist/honesty/uncaptured-bodies.d.ts +19 -0
- package/dist/honesty/uncaptured-bodies.js +30 -0
- package/dist/honesty/unread-outcome.d.ts +2 -0
- package/dist/honesty/unread-outcome.js +50 -0
- package/dist/honesty/verified.d.ts +40 -0
- package/dist/honesty/verified.js +86 -0
- package/dist/http-server.d.ts +0 -1
- package/dist/http-server.js +5 -1
- package/dist/hunt/hunt-report.d.ts +50 -0
- package/dist/hunt/hunt-report.js +84 -0
- package/dist/idle-shutdown.d.ts +0 -1
- package/dist/idle-shutdown.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/init/agent-rules.d.ts +0 -1
- package/dist/init/agent-rules.js +4 -2
- package/dist/init/capabilities.d.ts +17 -0
- package/dist/init/capabilities.js +51 -0
- package/dist/init/cursor.d.ts +0 -1
- package/dist/init/cursor.js +0 -1
- package/dist/init/desktop-doctor.d.ts +40 -0
- package/dist/init/desktop-doctor.js +198 -0
- package/dist/init/detect.d.ts +25 -1
- package/dist/init/detect.js +65 -4
- package/dist/init/mcp.d.ts +0 -1
- package/dist/init/mcp.js +0 -1
- package/dist/init/next-patch.d.ts +41 -0
- package/dist/init/next-patch.js +106 -0
- package/dist/init/node-io.d.ts +0 -1
- package/dist/init/node-io.js +25 -1
- package/dist/init/patch-kind.d.ts +20 -0
- package/dist/init/patch-kind.js +10 -0
- package/dist/init/plan-framework.d.ts +35 -0
- package/dist/init/plan-framework.js +217 -0
- package/dist/init/plan.d.ts +55 -4
- package/dist/init/plan.js +130 -112
- package/dist/init/project-id.d.ts +0 -1
- package/dist/init/project-id.js +0 -1
- package/dist/init/run.d.ts +17 -1
- package/dist/init/run.js +237 -18
- package/dist/init/slash-command.d.ts +18 -0
- package/dist/init/slash-command.js +52 -0
- package/dist/init/snippets.d.ts +48 -3
- package/dist/init/snippets.js +156 -6
- package/dist/init/vite-config.d.ts +4 -11
- package/dist/init/vite-config.js +15 -8
- package/dist/input/driven-redaction.d.ts +15 -0
- package/dist/input/driven-redaction.js +76 -0
- package/dist/input/network-detail.d.ts +9 -4
- package/dist/input/network-detail.js +35 -16
- package/dist/input/network-mock-tools.d.ts +0 -1
- package/dist/input/network-mock-tools.js +3 -4
- package/dist/input/network-mock.d.ts +0 -1
- package/dist/input/network-mock.js +0 -1
- package/dist/input/real-input.d.ts +14 -1
- package/dist/input/real-input.js +45 -3
- package/dist/input/scroll-find.d.ts +0 -1
- package/dist/input/scroll-find.js +0 -1
- package/dist/input/scroll-tools.d.ts +0 -1
- package/dist/input/scroll-tools.js +0 -1
- package/dist/input/viewport-tools.d.ts +0 -1
- package/dist/input/viewport-tools.js +3 -4
- package/dist/journal/ambient-store.d.ts +0 -1
- package/dist/journal/ambient-store.js +0 -1
- package/dist/journal/ambient.d.ts +0 -1
- package/dist/journal/ambient.js +0 -1
- package/dist/journal/attach-journal.d.ts +0 -1
- package/dist/journal/attach-journal.js +0 -1
- package/dist/journal/deviation-report.d.ts +0 -1
- package/dist/journal/deviation-report.js +0 -1
- package/dist/journal/deviation-service.d.ts +0 -1
- package/dist/journal/deviation-service.js +0 -1
- package/dist/journal/envelope-store.d.ts +0 -1
- package/dist/journal/envelope-store.js +0 -1
- package/dist/journal/envelope.d.ts +8 -9
- package/dist/journal/envelope.js +0 -1
- package/dist/journal/journal-query.d.ts +0 -1
- package/dist/journal/journal-query.js +0 -1
- package/dist/journal/journal-recorder.d.ts +0 -1
- package/dist/journal/journal-recorder.js +0 -1
- package/dist/journal/retention.d.ts +0 -1
- package/dist/journal/retention.js +0 -1
- package/dist/journal/rollups.d.ts +0 -1
- package/dist/journal/rollups.js +0 -1
- package/dist/journal/session-end.d.ts +0 -1
- package/dist/journal/session-end.js +0 -1
- package/dist/journal/session-journal.d.ts +0 -1
- package/dist/journal/session-journal.js +0 -1
- package/dist/license/license.d.ts +0 -1
- package/dist/license/license.js +0 -1
- package/dist/log.d.ts +0 -1
- package/dist/log.js +0 -1
- package/dist/mcp-proxy.d.ts +35 -4
- package/dist/mcp-proxy.js +174 -28
- package/dist/mcp.d.ts +15 -1
- package/dist/mcp.js +145 -17
- package/dist/oracles/flow-instrument-gaps.d.ts +0 -1
- package/dist/oracles/flow-instrument-gaps.js +0 -1
- package/dist/oracles/propose-consequences.d.ts +0 -1
- package/dist/oracles/propose-consequences.js +0 -1
- package/dist/oracles/self-instrument.d.ts +0 -1
- package/dist/oracles/self-instrument.js +0 -1
- package/dist/pairing-token.d.ts +0 -1
- package/dist/pairing-token.js +0 -1
- package/dist/phenomena/phenomena.d.ts +0 -1
- package/dist/phenomena/phenomena.js +0 -1
- package/dist/pool/browser-pool.d.ts +0 -1
- package/dist/pool/browser-pool.js +0 -1
- package/dist/pool/lease-reaper.d.ts +0 -1
- package/dist/pool/lease-reaper.js +0 -1
- package/dist/pool/playwright-launcher.d.ts +0 -1
- package/dist/pool/playwright-launcher.js +10 -2
- package/dist/project/baselines.d.ts +0 -1
- package/dist/project/baselines.js +0 -1
- package/dist/project/file-lock.d.ts +2 -1
- package/dist/project/file-lock.js +12 -2
- package/dist/project/fs-port.d.ts +0 -1
- package/dist/project/fs-port.js +0 -1
- package/dist/project/project-store.d.ts +0 -1
- package/dist/project/project-store.js +0 -1
- package/dist/project/project-tools.d.ts +0 -1
- package/dist/project/project-tools.js +29 -4
- package/dist/project/reticle-dir.d.ts +0 -1
- package/dist/project/reticle-dir.js +0 -1
- package/dist/runs/build-verification-run.d.ts +0 -1
- package/dist/runs/build-verification-run.js +0 -1
- package/dist/runs/profile-redact.d.ts +0 -1
- package/dist/runs/profile-redact.js +0 -1
- package/dist/runs/render-report.d.ts +0 -1
- package/dist/runs/render-report.js +0 -1
- package/dist/runs/repair-prompt.d.ts +0 -1
- package/dist/runs/repair-prompt.js +0 -1
- package/dist/runs/replay-mapping.d.ts +0 -1
- package/dist/runs/replay-mapping.js +0 -1
- package/dist/runs/reticle-runner.d.ts +0 -1
- package/dist/runs/reticle-runner.js +4 -2
- package/dist/runs/risk-classify.d.ts +0 -1
- package/dist/runs/risk-classify.js +0 -1
- package/dist/runs/run-diff.d.ts +0 -1
- package/dist/runs/run-diff.js +0 -1
- package/dist/runs/run-store.d.ts +0 -1
- package/dist/runs/run-store.js +0 -1
- package/dist/runs/run-tools.d.ts +0 -1
- package/dist/runs/run-tools.js +0 -1
- package/dist/runs/runner-port.d.ts +0 -1
- package/dist/runs/runner-port.js +0 -1
- package/dist/runs/verification-sync.d.ts +0 -1
- package/dist/runs/verification-sync.js +0 -1
- package/dist/runs/verify-http.d.ts +0 -1
- package/dist/runs/verify-http.js +0 -1
- package/dist/runs/verify-server.d.ts +0 -1
- package/dist/runs/verify-server.js +0 -1
- package/dist/server-version.d.ts +0 -1
- package/dist/server-version.js +0 -1
- package/dist/session/command-timeout.d.ts +35 -0
- package/dist/session/command-timeout.js +41 -0
- package/dist/session/control-envelope.d.ts +2 -3
- package/dist/session/control-envelope.js +2 -3
- package/dist/session/last-act.d.ts +31 -0
- package/dist/session/last-act.js +24 -0
- package/dist/session/live-control-tools.d.ts +0 -1
- package/dist/session/live-control-tools.js +3 -4
- package/dist/session/live-control.d.ts +0 -1
- package/dist/session/live-control.js +0 -1
- package/dist/session/observed-state.d.ts +12 -2
- package/dist/session/observed-state.js +29 -2
- package/dist/session/output-budget.d.ts +0 -1
- package/dist/session/output-budget.js +0 -1
- package/dist/session/pending-commands.d.ts +12 -0
- package/dist/session/pending-commands.js +36 -0
- package/dist/session/presenter-args.d.ts +0 -1
- package/dist/session/presenter-args.js +0 -1
- package/dist/session/review-store.d.ts +0 -1
- package/dist/session/review-store.js +0 -1
- package/dist/session/session-health.d.ts +26 -2
- package/dist/session/session-health.js +13 -1
- package/dist/session/session-info.d.ts +29 -0
- package/dist/session/session-info.js +1 -0
- package/dist/session/session-lease.d.ts +25 -0
- package/dist/session/session-lease.js +14 -0
- package/dist/session/session-manager.d.ts +7 -19
- package/dist/session/session-manager.js +35 -2
- package/dist/session/session-readiness.d.ts +0 -1
- package/dist/session/session-readiness.js +3 -4
- package/dist/session/session-reaper.d.ts +0 -1
- package/dist/session/session-reaper.js +0 -1
- package/dist/session/session-recommendation.d.ts +0 -1
- package/dist/session/session-recommendation.js +0 -1
- package/dist/session/session-tools.d.ts +0 -1
- package/dist/session/session-tools.js +2 -3
- package/dist/session/session.d.ts +33 -53
- package/dist/session/session.js +102 -66
- package/dist/session/state-select.d.ts +0 -1
- package/dist/session/state-select.js +0 -1
- package/dist/telemetry/argument-shape.d.ts +41 -0
- package/dist/telemetry/argument-shape.js +87 -0
- package/dist/telemetry/bug-found.d.ts +33 -0
- package/dist/telemetry/bug-found.js +95 -0
- package/dist/telemetry/cli-telemetry.d.ts +13 -0
- package/dist/telemetry/cli-telemetry.js +43 -0
- package/dist/telemetry/connect-failure.d.ts +16 -0
- package/dist/telemetry/connect-failure.js +44 -0
- package/dist/telemetry/daemon-telemetry.d.ts +19 -0
- package/dist/telemetry/daemon-telemetry.js +76 -0
- package/dist/telemetry/dev-repo.d.ts +10 -0
- package/dist/telemetry/dev-repo.js +80 -0
- package/dist/telemetry/error-fingerprint.d.ts +24 -0
- package/dist/telemetry/error-fingerprint.js +88 -0
- package/dist/telemetry/feedback-cli.d.ts +31 -0
- package/dist/telemetry/feedback-cli.js +102 -0
- package/dist/telemetry/feedback-context.d.ts +32 -0
- package/dist/telemetry/feedback-context.js +143 -0
- package/dist/telemetry/feedback.d.ts +66 -0
- package/dist/telemetry/feedback.js +175 -0
- package/dist/telemetry/git-facts.d.ts +21 -0
- package/dist/telemetry/git-facts.js +109 -0
- package/dist/telemetry/identify.d.ts +22 -0
- package/dist/telemetry/identify.js +73 -0
- package/dist/telemetry/init-telemetry.d.ts +26 -0
- package/dist/telemetry/init-telemetry.js +33 -0
- package/dist/telemetry/machine-snapshot.d.ts +6 -0
- package/dist/telemetry/machine-snapshot.js +39 -0
- package/dist/telemetry/mcp-connection.d.ts +5 -0
- package/dist/telemetry/mcp-connection.js +44 -0
- package/dist/telemetry/project-profile.d.ts +44 -0
- package/dist/telemetry/project-profile.js +205 -0
- package/dist/telemetry/run-telemetry.d.ts +21 -0
- package/dist/telemetry/run-telemetry.js +62 -0
- package/dist/telemetry/session-metrics.d.ts +103 -0
- package/dist/telemetry/session-metrics.js +329 -0
- package/dist/telemetry/telemetry.d.ts +35 -8
- package/dist/telemetry/telemetry.js +105 -12
- package/dist/token-auth.d.ts +0 -1
- package/dist/token-auth.js +0 -1
- package/dist/tools/act-capsule.d.ts +23 -0
- package/dist/tools/act-capsule.js +47 -0
- package/dist/tools/act-danger.d.ts +7 -0
- package/dist/tools/act-danger.js +44 -0
- package/dist/tools/act-helpers.d.ts +17 -0
- package/dist/tools/act-helpers.js +40 -0
- package/dist/tools/act-tools.d.ts +8 -1
- package/dist/tools/act-tools.js +96 -98
- package/dist/tools/act-view.d.ts +7 -1
- package/dist/tools/act-view.js +13 -1
- package/dist/tools/assert-grade.d.ts +22 -1
- package/dist/tools/assert-grade.js +46 -1
- package/dist/tools/assert-verdict.d.ts +21 -0
- package/dist/tools/assert-verdict.js +62 -0
- package/dist/tools/browser-tools.d.ts +0 -1
- package/dist/tools/browser-tools.js +2 -2
- package/dist/tools/contract-tools.d.ts +0 -1
- package/dist/tools/contract-tools.js +0 -1
- package/dist/tools/coverage-tools.d.ts +9 -0
- package/dist/tools/coverage-tools.js +92 -0
- package/dist/tools/dynamic-tools.d.ts +0 -1
- package/dist/tools/dynamic-tools.js +21 -2
- package/dist/tools/error-recovery.d.ts +18 -2
- package/dist/tools/error-recovery.js +42 -7
- package/dist/tools/feedback-tools.d.ts +24 -0
- package/dist/tools/feedback-tools.js +180 -0
- package/dist/tools/invoke-tool.d.ts +0 -1
- package/dist/tools/invoke-tool.js +115 -5
- package/dist/tools/lease-tools.d.ts +0 -1
- package/dist/tools/lease-tools.js +6 -5
- package/dist/tools/merge-tools.d.ts +0 -1
- package/dist/tools/merge-tools.js +0 -1
- package/dist/tools/observe-tools.d.ts +0 -1
- package/dist/tools/observe-tools.js +91 -39
- package/dist/tools/profiles.d.ts +1 -2
- package/dist/tools/profiles.js +43 -16
- package/dist/tools/query-paginate.d.ts +0 -1
- package/dist/tools/query-paginate.js +0 -1
- package/dist/tools/read-tools.d.ts +0 -1
- package/dist/tools/read-tools.js +14 -8
- package/dist/tools/reconcile-tools.d.ts +2 -0
- package/dist/tools/reconcile-tools.js +111 -0
- package/dist/tools/snapshot-delta.d.ts +0 -1
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/tool-invoker.d.ts +0 -1
- package/dist/tools/tool-invoker.js +0 -1
- package/dist/tools/tool-kit.d.ts +16 -1
- package/dist/tools/tool-kit.js +8 -2
- package/dist/tools/tool-names.d.ts +6 -1
- package/dist/tools/tool-names.js +6 -1
- package/dist/tools/tools-helpers.d.ts +0 -1
- package/dist/tools/tools-helpers.js +0 -1
- package/dist/tools/tools.d.ts +0 -1
- package/dist/tools/tools.js +24 -4
- package/dist/update/update-checker.d.ts +0 -1
- package/dist/update/update-checker.js +0 -1
- package/dist/update/update-nudge.d.ts +20 -0
- package/dist/update/update-nudge.js +72 -0
- package/dist/update/updater.d.ts +14 -1
- package/dist/update/updater.js +33 -2
- package/dist/visual/visual-diff.d.ts +0 -1
- package/dist/visual/visual-diff.js +0 -1
- package/dist/visual/visual-store.d.ts +0 -1
- package/dist/visual/visual-store.js +0 -1
- package/dist/visual/visual-tools.d.ts +0 -1
- package/dist/visual/visual-tools.js +103 -16
- package/package.json +2 -2
- package/dist/bridge-security.d.ts.map +0 -1
- package/dist/bridge-security.js.map +0 -1
- package/dist/bridge.d.ts.map +0 -1
- package/dist/bridge.js.map +0 -1
- package/dist/bridge.test-harness.d.ts.map +0 -1
- package/dist/bridge.test-harness.js.map +0 -1
- package/dist/capsule/capsule-store.d.ts.map +0 -1
- package/dist/capsule/capsule-store.js.map +0 -1
- package/dist/capsule/capsule.d.ts.map +0 -1
- package/dist/capsule/capsule.js.map +0 -1
- package/dist/capsule/causal-summary.d.ts.map +0 -1
- package/dist/capsule/causal-summary.js.map +0 -1
- package/dist/capsule/divergence.d.ts.map +0 -1
- package/dist/capsule/divergence.js.map +0 -1
- package/dist/capsule/minimize.d.ts.map +0 -1
- package/dist/capsule/minimize.js.map +0 -1
- package/dist/capsule/predicate-to-links.d.ts.map +0 -1
- package/dist/capsule/predicate-to-links.js.map +0 -1
- package/dist/cli-flow-commands.d.ts.map +0 -1
- package/dist/cli-flow-commands.js.map +0 -1
- package/dist/cli-launch.d.ts.map +0 -1
- package/dist/cli-launch.js.map +0 -1
- package/dist/cli-parse.d.ts.map +0 -1
- package/dist/cli-parse.js.map +0 -1
- package/dist/cli-port.d.ts.map +0 -1
- package/dist/cli-port.js.map +0 -1
- package/dist/cli-verify.d.ts.map +0 -1
- package/dist/cli-verify.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cloud/cloud-config.d.ts.map +0 -1
- package/dist/cloud/cloud-config.js.map +0 -1
- package/dist/cloud/cloud-sync.d.ts.map +0 -1
- package/dist/cloud/cloud-sync.js.map +0 -1
- package/dist/cloud-cli.d.ts.map +0 -1
- package/dist/cloud-cli.js.map +0 -1
- package/dist/crawl/crawl-tools.d.ts.map +0 -1
- package/dist/crawl/crawl-tools.js.map +0 -1
- package/dist/crawl/crawl.d.ts.map +0 -1
- package/dist/crawl/crawl.js.map +0 -1
- package/dist/daemon-resilience.d.ts.map +0 -1
- package/dist/daemon-resilience.js.map +0 -1
- package/dist/daemon.d.ts.map +0 -1
- package/dist/daemon.js.map +0 -1
- package/dist/domain/domain-model.d.ts.map +0 -1
- package/dist/domain/domain-model.js.map +0 -1
- package/dist/domain/domain-tools.d.ts.map +0 -1
- package/dist/domain/domain-tools.js.map +0 -1
- package/dist/domain/flow-risk.d.ts.map +0 -1
- package/dist/domain/flow-risk.js.map +0 -1
- package/dist/ee/audit-log.d.ts.map +0 -1
- package/dist/ee/audit-log.js.map +0 -1
- package/dist/events/event-filters.d.ts.map +0 -1
- package/dist/events/event-filters.js.map +0 -1
- package/dist/events/predicate-eval.d.ts.map +0 -1
- package/dist/events/predicate-eval.js.map +0 -1
- package/dist/events/predicate.d.ts.map +0 -1
- package/dist/events/predicate.js.map +0 -1
- package/dist/events/reaction.d.ts.map +0 -1
- package/dist/events/reaction.js.map +0 -1
- package/dist/events/ring-buffer.d.ts.map +0 -1
- package/dist/events/ring-buffer.js.map +0 -1
- package/dist/flows/affected.d.ts.map +0 -1
- package/dist/flows/affected.js.map +0 -1
- package/dist/flows/annotate-tools.d.ts.map +0 -1
- package/dist/flows/annotate-tools.js.map +0 -1
- package/dist/flows/annotate.d.ts.map +0 -1
- package/dist/flows/annotate.js.map +0 -1
- package/dist/flows/annotation-store.d.ts.map +0 -1
- package/dist/flows/annotation-store.js.map +0 -1
- package/dist/flows/assertion-integrity.d.ts.map +0 -1
- package/dist/flows/assertion-integrity.js.map +0 -1
- package/dist/flows/assertion-tiers-store.d.ts.map +0 -1
- package/dist/flows/assertion-tiers-store.js.map +0 -1
- package/dist/flows/buddy-status.d.ts.map +0 -1
- package/dist/flows/buddy-status.js.map +0 -1
- package/dist/flows/coverage.d.ts.map +0 -1
- package/dist/flows/coverage.js.map +0 -1
- package/dist/flows/decision.d.ts.map +0 -1
- package/dist/flows/decision.js.map +0 -1
- package/dist/flows/flake-store.d.ts.map +0 -1
- package/dist/flows/flake-store.js.map +0 -1
- package/dist/flows/flake.d.ts.map +0 -1
- package/dist/flows/flake.js.map +0 -1
- package/dist/flows/flow-classify.d.ts.map +0 -1
- package/dist/flows/flow-classify.js.map +0 -1
- package/dist/flows/flow-replay-run.d.ts.map +0 -1
- package/dist/flows/flow-replay-run.js.map +0 -1
- package/dist/flows/flow-replay.d.ts.map +0 -1
- package/dist/flows/flow-replay.js.map +0 -1
- package/dist/flows/flow-report.d.ts.map +0 -1
- package/dist/flows/flow-report.js.map +0 -1
- package/dist/flows/flow-scope.d.ts.map +0 -1
- package/dist/flows/flow-scope.js.map +0 -1
- package/dist/flows/flow-sources.d.ts.map +0 -1
- package/dist/flows/flow-sources.js.map +0 -1
- package/dist/flows/flow-success.d.ts.map +0 -1
- package/dist/flows/flow-success.js.map +0 -1
- package/dist/flows/flow-tools.d.ts.map +0 -1
- package/dist/flows/flow-tools.js.map +0 -1
- package/dist/flows/flows.d.ts.map +0 -1
- package/dist/flows/flows.js.map +0 -1
- package/dist/flows/gate.d.ts.map +0 -1
- package/dist/flows/gate.js.map +0 -1
- package/dist/flows/git-changed.d.ts.map +0 -1
- package/dist/flows/git-changed.js.map +0 -1
- package/dist/flows/heal-run.d.ts.map +0 -1
- package/dist/flows/heal-run.js.map +0 -1
- package/dist/flows/heal.d.ts.map +0 -1
- package/dist/flows/heal.js.map +0 -1
- package/dist/flows/parallel-suite.d.ts.map +0 -1
- package/dist/flows/parallel-suite.js.map +0 -1
- package/dist/flows/recordings.d.ts.map +0 -1
- package/dist/flows/recordings.js.map +0 -1
- package/dist/flows/replay.d.ts.map +0 -1
- package/dist/flows/replay.js.map +0 -1
- package/dist/flows/server-verify.d.ts.map +0 -1
- package/dist/flows/server-verify.js.map +0 -1
- package/dist/flows/watch-batcher.d.ts.map +0 -1
- package/dist/flows/watch-batcher.js.map +0 -1
- package/dist/honesty/blind-spots.d.ts.map +0 -1
- package/dist/honesty/blind-spots.js.map +0 -1
- package/dist/honesty/honesty.d.ts.map +0 -1
- package/dist/honesty/honesty.js.map +0 -1
- package/dist/http-server.d.ts.map +0 -1
- package/dist/http-server.js.map +0 -1
- package/dist/idle-shutdown.d.ts.map +0 -1
- package/dist/idle-shutdown.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/init/agent-rules.d.ts.map +0 -1
- package/dist/init/agent-rules.js.map +0 -1
- package/dist/init/cursor.d.ts.map +0 -1
- package/dist/init/cursor.js.map +0 -1
- package/dist/init/detect.d.ts.map +0 -1
- package/dist/init/detect.js.map +0 -1
- package/dist/init/mcp.d.ts.map +0 -1
- package/dist/init/mcp.js.map +0 -1
- package/dist/init/node-io.d.ts.map +0 -1
- package/dist/init/node-io.js.map +0 -1
- package/dist/init/plan.d.ts.map +0 -1
- package/dist/init/plan.js.map +0 -1
- package/dist/init/project-id.d.ts.map +0 -1
- package/dist/init/project-id.js.map +0 -1
- package/dist/init/run.d.ts.map +0 -1
- package/dist/init/run.js.map +0 -1
- package/dist/init/snippets.d.ts.map +0 -1
- package/dist/init/snippets.js.map +0 -1
- package/dist/init/vite-config.d.ts.map +0 -1
- package/dist/init/vite-config.js.map +0 -1
- package/dist/input/network-detail.d.ts.map +0 -1
- package/dist/input/network-detail.js.map +0 -1
- package/dist/input/network-mock-tools.d.ts.map +0 -1
- package/dist/input/network-mock-tools.js.map +0 -1
- package/dist/input/network-mock.d.ts.map +0 -1
- package/dist/input/network-mock.js.map +0 -1
- package/dist/input/real-input.d.ts.map +0 -1
- package/dist/input/real-input.js.map +0 -1
- package/dist/input/scroll-find.d.ts.map +0 -1
- package/dist/input/scroll-find.js.map +0 -1
- package/dist/input/scroll-tools.d.ts.map +0 -1
- package/dist/input/scroll-tools.js.map +0 -1
- package/dist/input/viewport-tools.d.ts.map +0 -1
- package/dist/input/viewport-tools.js.map +0 -1
- package/dist/journal/ambient-store.d.ts.map +0 -1
- package/dist/journal/ambient-store.js.map +0 -1
- package/dist/journal/ambient.d.ts.map +0 -1
- package/dist/journal/ambient.js.map +0 -1
- package/dist/journal/attach-journal.d.ts.map +0 -1
- package/dist/journal/attach-journal.js.map +0 -1
- package/dist/journal/deviation-report.d.ts.map +0 -1
- package/dist/journal/deviation-report.js.map +0 -1
- package/dist/journal/deviation-service.d.ts.map +0 -1
- package/dist/journal/deviation-service.js.map +0 -1
- package/dist/journal/envelope-store.d.ts.map +0 -1
- package/dist/journal/envelope-store.js.map +0 -1
- package/dist/journal/envelope.d.ts.map +0 -1
- package/dist/journal/envelope.js.map +0 -1
- package/dist/journal/journal-query.d.ts.map +0 -1
- package/dist/journal/journal-query.js.map +0 -1
- package/dist/journal/journal-recorder.d.ts.map +0 -1
- package/dist/journal/journal-recorder.js.map +0 -1
- package/dist/journal/retention.d.ts.map +0 -1
- package/dist/journal/retention.js.map +0 -1
- package/dist/journal/rollups.d.ts.map +0 -1
- package/dist/journal/rollups.js.map +0 -1
- package/dist/journal/session-end.d.ts.map +0 -1
- package/dist/journal/session-end.js.map +0 -1
- package/dist/journal/session-journal.d.ts.map +0 -1
- package/dist/journal/session-journal.js.map +0 -1
- package/dist/license/license.d.ts.map +0 -1
- package/dist/license/license.js.map +0 -1
- package/dist/log.d.ts.map +0 -1
- package/dist/log.js.map +0 -1
- package/dist/mcp-proxy.d.ts.map +0 -1
- package/dist/mcp-proxy.js.map +0 -1
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js.map +0 -1
- package/dist/oracles/flow-instrument-gaps.d.ts.map +0 -1
- package/dist/oracles/flow-instrument-gaps.js.map +0 -1
- package/dist/oracles/propose-consequences.d.ts.map +0 -1
- package/dist/oracles/propose-consequences.js.map +0 -1
- package/dist/oracles/self-instrument.d.ts.map +0 -1
- package/dist/oracles/self-instrument.js.map +0 -1
- package/dist/pairing-token.d.ts.map +0 -1
- package/dist/pairing-token.js.map +0 -1
- package/dist/phenomena/phenomena.d.ts.map +0 -1
- package/dist/phenomena/phenomena.js.map +0 -1
- package/dist/pool/browser-pool.d.ts.map +0 -1
- package/dist/pool/browser-pool.js.map +0 -1
- package/dist/pool/lease-reaper.d.ts.map +0 -1
- package/dist/pool/lease-reaper.js.map +0 -1
- package/dist/pool/playwright-launcher.d.ts.map +0 -1
- package/dist/pool/playwright-launcher.js.map +0 -1
- package/dist/project/baselines.d.ts.map +0 -1
- package/dist/project/baselines.js.map +0 -1
- package/dist/project/file-lock.d.ts.map +0 -1
- package/dist/project/file-lock.js.map +0 -1
- package/dist/project/fs-port.d.ts.map +0 -1
- package/dist/project/fs-port.js.map +0 -1
- package/dist/project/project-store.d.ts.map +0 -1
- package/dist/project/project-store.js.map +0 -1
- package/dist/project/project-tools.d.ts.map +0 -1
- package/dist/project/project-tools.js.map +0 -1
- package/dist/project/reticle-dir.d.ts.map +0 -1
- package/dist/project/reticle-dir.js.map +0 -1
- package/dist/runs/build-verification-run.d.ts.map +0 -1
- package/dist/runs/build-verification-run.js.map +0 -1
- package/dist/runs/profile-redact.d.ts.map +0 -1
- package/dist/runs/profile-redact.js.map +0 -1
- package/dist/runs/render-report.d.ts.map +0 -1
- package/dist/runs/render-report.js.map +0 -1
- package/dist/runs/repair-prompt.d.ts.map +0 -1
- package/dist/runs/repair-prompt.js.map +0 -1
- package/dist/runs/replay-mapping.d.ts.map +0 -1
- package/dist/runs/replay-mapping.js.map +0 -1
- package/dist/runs/reticle-runner.d.ts.map +0 -1
- package/dist/runs/reticle-runner.js.map +0 -1
- package/dist/runs/risk-classify.d.ts.map +0 -1
- package/dist/runs/risk-classify.js.map +0 -1
- package/dist/runs/run-diff.d.ts.map +0 -1
- package/dist/runs/run-diff.js.map +0 -1
- package/dist/runs/run-store.d.ts.map +0 -1
- package/dist/runs/run-store.js.map +0 -1
- package/dist/runs/run-tools.d.ts.map +0 -1
- package/dist/runs/run-tools.js.map +0 -1
- package/dist/runs/runner-port.d.ts.map +0 -1
- package/dist/runs/runner-port.js.map +0 -1
- package/dist/runs/verification-sync.d.ts.map +0 -1
- package/dist/runs/verification-sync.js.map +0 -1
- package/dist/runs/verify-http.d.ts.map +0 -1
- package/dist/runs/verify-http.js.map +0 -1
- package/dist/runs/verify-server.d.ts.map +0 -1
- package/dist/runs/verify-server.js.map +0 -1
- package/dist/server-version.d.ts.map +0 -1
- package/dist/server-version.js.map +0 -1
- package/dist/session/control-envelope.d.ts.map +0 -1
- package/dist/session/control-envelope.js.map +0 -1
- package/dist/session/live-control-tools.d.ts.map +0 -1
- package/dist/session/live-control-tools.js.map +0 -1
- package/dist/session/live-control.d.ts.map +0 -1
- package/dist/session/live-control.js.map +0 -1
- package/dist/session/observed-state.d.ts.map +0 -1
- package/dist/session/observed-state.js.map +0 -1
- package/dist/session/output-budget.d.ts.map +0 -1
- package/dist/session/output-budget.js.map +0 -1
- package/dist/session/presenter-args.d.ts.map +0 -1
- package/dist/session/presenter-args.js.map +0 -1
- package/dist/session/review-store.d.ts.map +0 -1
- package/dist/session/review-store.js.map +0 -1
- package/dist/session/session-health.d.ts.map +0 -1
- package/dist/session/session-health.js.map +0 -1
- package/dist/session/session-manager.d.ts.map +0 -1
- package/dist/session/session-manager.js.map +0 -1
- package/dist/session/session-readiness.d.ts.map +0 -1
- package/dist/session/session-readiness.js.map +0 -1
- package/dist/session/session-reaper.d.ts.map +0 -1
- package/dist/session/session-reaper.js.map +0 -1
- package/dist/session/session-recommendation.d.ts.map +0 -1
- package/dist/session/session-recommendation.js.map +0 -1
- package/dist/session/session-tools.d.ts.map +0 -1
- package/dist/session/session-tools.js.map +0 -1
- package/dist/session/session.d.ts.map +0 -1
- package/dist/session/session.js.map +0 -1
- package/dist/session/state-select.d.ts.map +0 -1
- package/dist/session/state-select.js.map +0 -1
- package/dist/telemetry/telemetry.d.ts.map +0 -1
- package/dist/telemetry/telemetry.js.map +0 -1
- package/dist/token-auth.d.ts.map +0 -1
- package/dist/token-auth.js.map +0 -1
- package/dist/tools/act-tools.d.ts.map +0 -1
- package/dist/tools/act-tools.js.map +0 -1
- package/dist/tools/act-view.d.ts.map +0 -1
- package/dist/tools/act-view.js.map +0 -1
- package/dist/tools/assert-grade.d.ts.map +0 -1
- package/dist/tools/assert-grade.js.map +0 -1
- package/dist/tools/browser-tools.d.ts.map +0 -1
- package/dist/tools/browser-tools.js.map +0 -1
- package/dist/tools/contract-tools.d.ts.map +0 -1
- package/dist/tools/contract-tools.js.map +0 -1
- package/dist/tools/dynamic-tools.d.ts.map +0 -1
- package/dist/tools/dynamic-tools.js.map +0 -1
- package/dist/tools/error-recovery.d.ts.map +0 -1
- package/dist/tools/error-recovery.js.map +0 -1
- package/dist/tools/invoke-tool.d.ts.map +0 -1
- package/dist/tools/invoke-tool.js.map +0 -1
- package/dist/tools/lease-tools.d.ts.map +0 -1
- package/dist/tools/lease-tools.js.map +0 -1
- package/dist/tools/merge-tools.d.ts.map +0 -1
- package/dist/tools/merge-tools.js.map +0 -1
- package/dist/tools/observe-tools.d.ts.map +0 -1
- package/dist/tools/observe-tools.js.map +0 -1
- package/dist/tools/profiles.d.ts.map +0 -1
- package/dist/tools/profiles.js.map +0 -1
- package/dist/tools/query-paginate.d.ts.map +0 -1
- package/dist/tools/query-paginate.js.map +0 -1
- package/dist/tools/read-tools.d.ts.map +0 -1
- package/dist/tools/read-tools.js.map +0 -1
- package/dist/tools/snapshot-delta.d.ts.map +0 -1
- package/dist/tools/snapshot-delta.js.map +0 -1
- package/dist/tools/tool-invoker.d.ts.map +0 -1
- package/dist/tools/tool-invoker.js.map +0 -1
- package/dist/tools/tool-kit.d.ts.map +0 -1
- package/dist/tools/tool-kit.js.map +0 -1
- package/dist/tools/tool-names.d.ts.map +0 -1
- package/dist/tools/tool-names.js.map +0 -1
- package/dist/tools/tools-helpers.d.ts.map +0 -1
- package/dist/tools/tools-helpers.js.map +0 -1
- package/dist/tools/tools.d.ts.map +0 -1
- package/dist/tools/tools.js.map +0 -1
- package/dist/update/update-checker.d.ts.map +0 -1
- package/dist/update/update-checker.js.map +0 -1
- package/dist/update/updater.d.ts.map +0 -1
- package/dist/update/updater.js.map +0 -1
- package/dist/visual/visual-diff.d.ts.map +0 -1
- package/dist/visual/visual-diff.js.map +0 -1
- package/dist/visual/visual-store.d.ts.map +0 -1
- package/dist/visual/visual-store.js.map +0 -1
- package/dist/visual/visual-tools.d.ts.map +0 -1
- package/dist/visual/visual-tools.js.map +0 -1
package/dist/mcp-proxy.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import * as http from 'node:http';
|
|
2
2
|
import * as net from 'node:net';
|
|
3
|
-
import {
|
|
3
|
+
import { appendFileSync, mkdirSync } from 'node:fs';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { LOOPBACK_HOST, MCP_SSE_PATH, ReticleDir } from '@reticlehq/core';
|
|
4
7
|
import { log } from './log.js';
|
|
5
8
|
const DEFAULT_DAEMON_READY_TIMEOUT_MS = 10_000;
|
|
6
9
|
/**
|
|
@@ -16,6 +19,99 @@ const DAEMON_POLL_INTERVAL_MS = 100;
|
|
|
16
19
|
function delay(ms) {
|
|
17
20
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
21
|
}
|
|
22
|
+
/** Reconnect backoff: linear, capped, so a briefly-restarting daemon is picked up fast. */
|
|
23
|
+
const RECONNECT_BASE_MS = 250;
|
|
24
|
+
const RECONNECT_CAP_MS = 5_000;
|
|
25
|
+
/**
|
|
26
|
+
* How many consecutive failed reconnects before the proxy gives up and exits. At the capped backoff
|
|
27
|
+
* this is a few minutes — long enough to ride out a daemon restart, short enough that a genuinely
|
|
28
|
+
* dead daemon lets the agent host respawn the proxy (which spawns a fresh daemon) instead of hanging.
|
|
29
|
+
*/
|
|
30
|
+
export const MAX_RECONNECT_ATTEMPTS = 60;
|
|
31
|
+
export function reconnectDelayMs(attempt) {
|
|
32
|
+
return Math.min(RECONNECT_BASE_MS * attempt, RECONNECT_CAP_MS);
|
|
33
|
+
}
|
|
34
|
+
/** JSON-RPC id the proxy uses for its own replayed `initialize` — never one the client could send. */
|
|
35
|
+
export const RECONNECT_INITIALIZE_ID = '__reticle_proxy_reinit';
|
|
36
|
+
/** The proxy's own log file, so a silent drop leaves a readable trace the agent can go read. */
|
|
37
|
+
export function proxyLogPath() {
|
|
38
|
+
return join(homedir(), ReticleDir.ROOT, 'mcp-proxy.log');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Log to stderr (which the agent host usually swallows) AND to ~/.reticle/mcp-proxy.log, which it
|
|
42
|
+
* does not. A dropped MCP connection is invisible from the agent's side — no message, no exit code —
|
|
43
|
+
* so the one thing that makes it diagnosable at all is a file somebody can read afterwards.
|
|
44
|
+
*/
|
|
45
|
+
function proxyLog(event, fields = {}) {
|
|
46
|
+
log(event, fields);
|
|
47
|
+
try {
|
|
48
|
+
const dir = join(homedir(), ReticleDir.ROOT);
|
|
49
|
+
mkdirSync(dir, { recursive: true });
|
|
50
|
+
appendFileSync(proxyLogPath(), `${JSON.stringify({ event, ...fields })}\n`, 'utf8');
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Logging must never be the thing that kills the proxy.
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
function parseJsonRpc(line) {
|
|
57
|
+
try {
|
|
58
|
+
const parsed = JSON.parse(line);
|
|
59
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : null;
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const INITIALIZE_METHOD = 'initialize';
|
|
66
|
+
const INITIALIZED_METHOD = 'notifications/initialized';
|
|
67
|
+
/**
|
|
68
|
+
* Makes a reconnect invisible to the client.
|
|
69
|
+
*
|
|
70
|
+
* The daemon builds a FRESH `McpServer` per SSE connection, so a reconnected session has never seen
|
|
71
|
+
* the client's `initialize` — every subsequent `tools/call` would hit an uninitialized server. The
|
|
72
|
+
* proxy therefore remembers the handshake the client sent once and replays it into each new session.
|
|
73
|
+
* The replay is re-issued under a reserved id so the daemon's response to it can be dropped rather
|
|
74
|
+
* than reaching the client's stdout, where a duplicate JSON-RPC id would be a protocol violation.
|
|
75
|
+
*/
|
|
76
|
+
export class HandshakeReplay {
|
|
77
|
+
#initialize = null;
|
|
78
|
+
#initialized = null;
|
|
79
|
+
#pendingReplayId = null;
|
|
80
|
+
/** Record one outbound client line. Cheap enough to call for every stdin message. */
|
|
81
|
+
observeOutbound(line) {
|
|
82
|
+
const msg = parseJsonRpc(line);
|
|
83
|
+
if (msg === null)
|
|
84
|
+
return;
|
|
85
|
+
// The first initialize is the session's identity; a client re-issuing one does not change it.
|
|
86
|
+
if (msg.method === INITIALIZE_METHOD && this.#initialize === null)
|
|
87
|
+
this.#initialize = line;
|
|
88
|
+
else if (msg.method === INITIALIZED_METHOD)
|
|
89
|
+
this.#initialized = line;
|
|
90
|
+
}
|
|
91
|
+
/** Lines to POST into a freshly-established session, before any queued client traffic. */
|
|
92
|
+
replayLines() {
|
|
93
|
+
if (this.#initialize === null)
|
|
94
|
+
return [];
|
|
95
|
+
const msg = parseJsonRpc(this.#initialize);
|
|
96
|
+
if (msg === null)
|
|
97
|
+
return [];
|
|
98
|
+
this.#pendingReplayId = RECONNECT_INITIALIZE_ID;
|
|
99
|
+
const reinit = { ...msg, id: RECONNECT_INITIALIZE_ID };
|
|
100
|
+
return this.#initialized === null
|
|
101
|
+
? [JSON.stringify(reinit)]
|
|
102
|
+
: [JSON.stringify(reinit), this.#initialized];
|
|
103
|
+
}
|
|
104
|
+
/** True when this inbound daemon line is the echo of our replayed handshake and must not be forwarded. */
|
|
105
|
+
shouldSuppressInbound(line) {
|
|
106
|
+
if (this.#pendingReplayId === null)
|
|
107
|
+
return false;
|
|
108
|
+
const msg = parseJsonRpc(line);
|
|
109
|
+
if (msg === null || msg.id !== this.#pendingReplayId)
|
|
110
|
+
return false;
|
|
111
|
+
this.#pendingReplayId = null; // one response per replay — anything later is not ours to swallow
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
19
115
|
/**
|
|
20
116
|
* Incremental SSE frame parser for the MCP front door.
|
|
21
117
|
*
|
|
@@ -126,46 +222,92 @@ export function buildSessionUrl(rawData, port) {
|
|
|
126
222
|
}
|
|
127
223
|
/**
|
|
128
224
|
* Bridge stdio ↔ SSE: connects to the running daemon's MCP endpoint and forwards
|
|
129
|
-
* Claude Code's stdin/stdout JSON-RPC through it. Never resolves — runs until
|
|
130
|
-
*
|
|
131
|
-
*
|
|
225
|
+
* Claude Code's stdin/stdout JSON-RPC through it. Never resolves — runs until stdin closes.
|
|
226
|
+
*
|
|
227
|
+
* A dropped SSE stream used to exit the process, which is what made the agent's `reticle_*` tools
|
|
228
|
+
* vanish mid-session with no message and no way for the agent to get them back — only a human running
|
|
229
|
+
* `/mcp` could. The daemon demonstrably stays up across these drops, so the stream ending is a
|
|
230
|
+
* transport event, not a shutdown: reconnect to it and replay the handshake instead of dying.
|
|
132
231
|
*/
|
|
133
232
|
export function startMcpProxy(port) {
|
|
134
233
|
return new Promise((_resolve, reject) => {
|
|
135
234
|
let postUrl = null;
|
|
136
235
|
const stdinQueue = [];
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const sse = new SseFrameParser();
|
|
141
|
-
res.on('data', (chunk) => {
|
|
142
|
-
for (const frame of sse.push(chunk))
|
|
143
|
-
onSseEvent(frame.event, frame.data, port);
|
|
144
|
-
});
|
|
145
|
-
res.on('end', () => {
|
|
146
|
-
log('reticle_mcp_proxy_sse_ended', { port });
|
|
147
|
-
process.exit(0);
|
|
148
|
-
});
|
|
149
|
-
res.on('error', (err) => {
|
|
150
|
-
log('reticle_mcp_proxy_sse_error', { error: err.message });
|
|
151
|
-
process.exit(1);
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
req.on('error', (err) => reject(err));
|
|
236
|
+
const replay = new HandshakeReplay();
|
|
237
|
+
let stopped = false;
|
|
238
|
+
let attempts = 0;
|
|
155
239
|
function onSseEvent(event, data, p) {
|
|
156
240
|
if (event === 'endpoint') {
|
|
157
241
|
const url = buildSessionUrl(data, p);
|
|
158
242
|
postUrl = url;
|
|
159
|
-
//
|
|
160
|
-
|
|
243
|
+
// The new session's McpServer has never seen the client's initialize — replay it first, then
|
|
244
|
+
// flush whatever the client sent while we were reconnecting.
|
|
245
|
+
for (const line of replay.replayLines())
|
|
246
|
+
void postToSession(url, line);
|
|
247
|
+
for (const queued of stdinQueue.splice(0))
|
|
161
248
|
void postToSession(url, queued);
|
|
162
|
-
}
|
|
163
249
|
return;
|
|
164
250
|
}
|
|
165
|
-
if (event === 'message') {
|
|
251
|
+
if (event === 'message' && !replay.shouldSuppressInbound(data)) {
|
|
166
252
|
process.stdout.write(`${data}\n`);
|
|
167
253
|
}
|
|
168
254
|
}
|
|
255
|
+
function scheduleReconnect(reason, detail) {
|
|
256
|
+
if (stopped)
|
|
257
|
+
return;
|
|
258
|
+
postUrl = null;
|
|
259
|
+
attempts++;
|
|
260
|
+
if (attempts > MAX_RECONNECT_ATTEMPTS) {
|
|
261
|
+
proxyLog('reticle_mcp_proxy_gave_up', {
|
|
262
|
+
port,
|
|
263
|
+
reason,
|
|
264
|
+
attempts,
|
|
265
|
+
...(detail !== undefined ? { detail } : {}),
|
|
266
|
+
});
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
const wait = reconnectDelayMs(attempts);
|
|
270
|
+
proxyLog('reticle_mcp_proxy_reconnecting', {
|
|
271
|
+
port,
|
|
272
|
+
reason,
|
|
273
|
+
attempt: attempts,
|
|
274
|
+
retryInMs: wait,
|
|
275
|
+
...(detail !== undefined ? { detail } : {}),
|
|
276
|
+
});
|
|
277
|
+
setTimeout(() => connect(false), wait).unref();
|
|
278
|
+
}
|
|
279
|
+
function connect(first) {
|
|
280
|
+
const req = http.get({ host: LOOPBACK_HOST, port, path: MCP_SSE_PATH }, (res) => {
|
|
281
|
+
attempts = 0; // a stream we actually established resets the budget
|
|
282
|
+
if (!first)
|
|
283
|
+
proxyLog('reticle_mcp_proxy_reconnected', { port });
|
|
284
|
+
res.setEncoding('utf8');
|
|
285
|
+
// `end` and `error` can both fire on one response; only the first should drive a reconnect.
|
|
286
|
+
let settled = false;
|
|
287
|
+
const drop = (reason, detail) => {
|
|
288
|
+
if (settled)
|
|
289
|
+
return;
|
|
290
|
+
settled = true;
|
|
291
|
+
scheduleReconnect(reason, detail);
|
|
292
|
+
};
|
|
293
|
+
const sse = new SseFrameParser();
|
|
294
|
+
res.on('data', (chunk) => {
|
|
295
|
+
for (const frame of sse.push(chunk))
|
|
296
|
+
onSseEvent(frame.event, frame.data, port);
|
|
297
|
+
});
|
|
298
|
+
res.on('end', () => drop('sse_ended'));
|
|
299
|
+
res.on('error', (err) => drop('sse_error', err.message));
|
|
300
|
+
// A socket dying under us (daemon killed, network stack reset) emits NEITHER `end` nor
|
|
301
|
+
// `error` — only `aborted`/`close`. Listening for just the first two is why the proxy sat
|
|
302
|
+
// there afterwards holding a dead stream. `settled` keeps the clean case single-fire.
|
|
303
|
+
res.on('aborted', () => drop('sse_aborted'));
|
|
304
|
+
res.on('close', () => drop('sse_closed'));
|
|
305
|
+
});
|
|
306
|
+
// The very first connect failing means there is no daemon to talk to — that is a startup
|
|
307
|
+
// failure the caller handles. Later ones are just the daemon bouncing: keep retrying.
|
|
308
|
+
req.on('error', (err) => (first ? reject(err) : scheduleReconnect('connect_error', err.message)));
|
|
309
|
+
}
|
|
310
|
+
connect(true);
|
|
169
311
|
// ── stdin reader ─────────────────────────────────────────────────────────
|
|
170
312
|
process.stdin.setEncoding('utf8');
|
|
171
313
|
let stdinBuffer = '';
|
|
@@ -177,6 +319,7 @@ export function startMcpProxy(port) {
|
|
|
177
319
|
const trimmed = line.trim();
|
|
178
320
|
if (trimmed === '')
|
|
179
321
|
continue;
|
|
322
|
+
replay.observeOutbound(trimmed);
|
|
180
323
|
if (postUrl === null) {
|
|
181
324
|
stdinQueue.push(trimmed);
|
|
182
325
|
}
|
|
@@ -185,7 +328,10 @@ export function startMcpProxy(port) {
|
|
|
185
328
|
}
|
|
186
329
|
}
|
|
187
330
|
});
|
|
188
|
-
|
|
331
|
+
// The client going away is the one clean shutdown — stop reconnecting and exit.
|
|
332
|
+
process.stdin.on('end', () => {
|
|
333
|
+
stopped = true;
|
|
334
|
+
process.exit(0);
|
|
335
|
+
});
|
|
189
336
|
});
|
|
190
337
|
}
|
|
191
|
-
//# sourceMappingURL=mcp-proxy.js.map
|
package/dist/mcp.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { type ToolProfile } from './tools/profiles.js';
|
|
|
10
10
|
* Non-session-bound tools (and tools with no outputSchema) are returned unchanged.
|
|
11
11
|
*/
|
|
12
12
|
export declare function withSessionEnvelope(name: string, outputSchema: z.ZodRawShape | undefined): z.ZodRawShape | undefined;
|
|
13
|
+
export declare function firstSentence(description: string): string;
|
|
13
14
|
/**
|
|
14
15
|
* Serialize a tool result to the MCP `text` content block. The agent consumes this text — the
|
|
15
16
|
* typed contract travels separately as `structuredContent`, unchanged by encoding — so the text
|
|
@@ -32,5 +33,18 @@ export declare function encodeResult(result: unknown, encoding: string): string;
|
|
|
32
33
|
* call. `full` advertises everything and needs no hatch.
|
|
33
34
|
*/
|
|
34
35
|
export declare function advertisedTools(profile: ToolProfile): ToolDef[];
|
|
36
|
+
/**
|
|
37
|
+
* Exactly what gets advertised for one tool under a profile: trimmed description, lean input shape,
|
|
38
|
+
* and (non-lean only) the output schema.
|
|
39
|
+
*
|
|
40
|
+
* Exported so tests assert on the REAL advertised text rather than on the tool definitions, which
|
|
41
|
+
* are trimmed later and would make a guard that cannot fail — a mistake already made once here, with
|
|
42
|
+
* an abbreviation test that read raw defs and would have passed with the bug fully present.
|
|
43
|
+
*/
|
|
44
|
+
export declare function advertisedConfig(tool: ToolDef, advertised: readonly ToolDef[], profile: ToolProfile): {
|
|
45
|
+
description: string;
|
|
46
|
+
inputSchema: z.ZodRawShape;
|
|
47
|
+
outputSchema?: z.ZodRawShape;
|
|
48
|
+
};
|
|
49
|
+
export declare function installFriendlyArgErrors(server: McpServer, examples: Map<string, string>, allowedKeys?: Map<string, ReadonlySet<string>>): void;
|
|
35
50
|
export declare function createMcpServer(deps: ToolDeps, profile?: ToolProfile): McpServer;
|
|
36
|
-
//# sourceMappingURL=mcp.d.ts.map
|
package/dist/mcp.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
|
|
2
3
|
import { z } from 'zod';
|
|
3
4
|
import { isToonable, resultToToon } from '@reticlehq/core';
|
|
4
5
|
import { TOOLS } from './tools/tools.js';
|
|
@@ -10,6 +11,8 @@ import { buildErrorPayload } from './tools/error-recovery.js';
|
|
|
10
11
|
import { log } from './log.js';
|
|
11
12
|
import { SERVER_VERSION } from './server-version.js';
|
|
12
13
|
import { MCP_SERVER_NAME } from './init/mcp.js';
|
|
14
|
+
import { setMcpClientNameHook } from './telemetry/feedback-context.js';
|
|
15
|
+
import { getSessionMetrics } from './telemetry/session-metrics.js';
|
|
13
16
|
/**
|
|
14
17
|
* Merge the runtime-spliced envelope (health/lease/age/control) into a session-bound tool's declared
|
|
15
18
|
* outputSchema so structuredContent validation keeps those fields instead of dropping them. The tool's
|
|
@@ -25,10 +28,31 @@ const SERVER_INFO = { name: MCP_SERVER_NAME, version: SERVER_VERSION };
|
|
|
25
28
|
/** First sentence of a description (purpose only) for lean profiles — keeps per-turn def cost
|
|
26
29
|
* down. Cuts at the first sentence-ending period or newline; falls back to a 160-char cap. The
|
|
27
30
|
* first clause retains the essentials (enum hints like "role | text | label" live there). */
|
|
28
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Append the tool's example call to whatever description survived trimming.
|
|
33
|
+
*
|
|
34
|
+
* Costs a handful of tokens per turn and buys back the failed round trips an agent spends guessing
|
|
35
|
+
* how the fields compose — which is a far worse trade in the other direction.
|
|
36
|
+
*/
|
|
37
|
+
function withExample(description, example) {
|
|
38
|
+
return example === undefined ? description : `${description} e.g. ${JSON.stringify(example)}`;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Abbreviations whose internal period is NOT a sentence end.
|
|
42
|
+
*
|
|
43
|
+
* The splitter looked for the first `". "`, which "e.g. " satisfies — so every lean-profile
|
|
44
|
+
* description containing one was cut off mid-abbreviation. `reticle_act`'s ref parameter reached the
|
|
45
|
+
* agent as "Element ref from reticle_snapshot or reticle_query (e.g." and stopped: the example gone,
|
|
46
|
+
* and any contract stated after it gone too. Silent, and it degraded the DEFAULT profile only, which
|
|
47
|
+
* is the one nobody reads the raw strings for.
|
|
48
|
+
*/
|
|
49
|
+
const ABBREVIATIONS = ['e.g.', 'i.e.', 'etc.', 'vs.', 'cf.'];
|
|
50
|
+
export function firstSentence(description) {
|
|
29
51
|
const nl = description.indexOf('\n');
|
|
30
52
|
const base = nl >= 0 ? description.slice(0, nl) : description;
|
|
31
|
-
|
|
53
|
+
// Mask abbreviations with an equal-length filler so offsets stay valid in the original string.
|
|
54
|
+
const masked = ABBREVIATIONS.reduce((text, abbr) => text.split(abbr).join('\u0000'.repeat(abbr.length)), base);
|
|
55
|
+
const dot = masked.search(/\.\s/);
|
|
32
56
|
const sentence = dot >= 0 ? base.slice(0, dot + 1) : base;
|
|
33
57
|
return sentence.length > 160 ? `${sentence.slice(0, 159)}…` : sentence;
|
|
34
58
|
}
|
|
@@ -52,9 +76,34 @@ const PREDICATE_PARAMS = new Set(['predicate', 'until']);
|
|
|
52
76
|
* grammar up front versus letting the agent fetch it from `reticle_tools` when it needs a variant it
|
|
53
77
|
* has not used before.
|
|
54
78
|
*/
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The kind list — the part an agent needs to WRITE a predicate. Carried on every predicate parameter.
|
|
81
|
+
*
|
|
82
|
+
* An earlier version put this on one tool and pointed the other five at it ("same grammar as
|
|
83
|
+
* reticle_act_and_wait's"), which saved 790 B/turn. It was the wrong trade: it made writing a
|
|
84
|
+
* predicate require joining two tool descriptions, and accuracy is worth more here than the bytes.
|
|
85
|
+
* Only the "where to get field details" sentence is stated once now — that one IS a pointer, so
|
|
86
|
+
* making it a pointer costs nothing.
|
|
87
|
+
*/
|
|
88
|
+
const PREDICATE_KINDS = 'Predicate object: { kind, ...fields }. kind is one of element | text | net | route | console | ' +
|
|
89
|
+
'animation | signal | state | settled | allOf | anyOf | not.';
|
|
90
|
+
/**
|
|
91
|
+
* Said once per turn: the bug-catching options, and where to get the rest of the field grammar.
|
|
92
|
+
*
|
|
93
|
+
* `net.count`, `console.absent` and `absent` are the three predicate options that catch a class of
|
|
94
|
+
* bug rather than confirm an expectation — a double-submit, an action that "worked" while logging a
|
|
95
|
+
* caught error, something that should have disappeared and did not. They sat behind a
|
|
96
|
+
* `reticle_tools` round trip, so an agent only found them if it already knew to look, which is the
|
|
97
|
+
* wrong way round for the checks most likely to catch what nobody suspected.
|
|
98
|
+
*
|
|
99
|
+
* Anchored to one tool rather than repeated on all six: these are ADDITIONAL capability, not what
|
|
100
|
+
* makes a basic predicate correct, so one mention per turn is enough to make them reachable without
|
|
101
|
+
* paying for six.
|
|
102
|
+
*/
|
|
103
|
+
const PREDICATE_FIELD_GRAMMAR_HINT = ' Bug-catching options: net.count (exact request count — catches double-submit), ' +
|
|
104
|
+
'console.absent:true (action completed with a CLEAN console), absent:true on element/text ' +
|
|
105
|
+
'(it should be gone). Call reticle_tools for the full field grammar of a kind.';
|
|
106
|
+
const COMPACT_PREDICATE_DESCRIPTION = `${PREDICATE_KINDS}${PREDICATE_FIELD_GRAMMAR_HINT}`;
|
|
58
107
|
/**
|
|
59
108
|
* Lean copy of a tool's zod input shape for lean profiles: each parameter's description is
|
|
60
109
|
* truncated to its first sentence via zod's own `.describe` (which returns a new schema, so the
|
|
@@ -62,11 +111,14 @@ const COMPACT_PREDICATE_DESCRIPTION = 'Predicate object: { kind, ...fields }. ki
|
|
|
62
111
|
* schema cost; the first clause keeps each param's purpose and any enum hints. Params without a
|
|
63
112
|
* description pass through unchanged. Predicate params are replaced wholesale — see above.
|
|
64
113
|
*/
|
|
65
|
-
function leanZodShape(shape) {
|
|
114
|
+
function leanZodShape(shape, predicateAnchor) {
|
|
66
115
|
const out = {};
|
|
67
116
|
for (const [key, schema] of Object.entries(shape)) {
|
|
68
117
|
if (PREDICATE_PARAMS.has(key)) {
|
|
69
|
-
|
|
118
|
+
// Every tool keeps the kinds; only the navigation hint is anchored to one.
|
|
119
|
+
const compact = z
|
|
120
|
+
.record(z.unknown())
|
|
121
|
+
.describe(predicateAnchor === undefined ? COMPACT_PREDICATE_DESCRIPTION : PREDICATE_KINDS);
|
|
70
122
|
out[key] = schema.isOptional() ? compact.optional() : compact;
|
|
71
123
|
continue;
|
|
72
124
|
}
|
|
@@ -112,9 +164,84 @@ export function advertisedTools(profile) {
|
|
|
112
164
|
const base = filterTools(TOOLS, profile === TOOL_PROFILE.HYBRID ? TOOL_PROFILE.CORE : profile);
|
|
113
165
|
return [...base, ...buildDynamicTools(TOOLS)];
|
|
114
166
|
}
|
|
167
|
+
/**
|
|
168
|
+
* Exactly what gets advertised for one tool under a profile: trimmed description, lean input shape,
|
|
169
|
+
* and (non-lean only) the output schema.
|
|
170
|
+
*
|
|
171
|
+
* Exported so tests assert on the REAL advertised text rather than on the tool definitions, which
|
|
172
|
+
* are trimmed later and would make a guard that cannot fail — a mistake already made once here, with
|
|
173
|
+
* an abbreviation test that read raw defs and would have passed with the bug fully present.
|
|
174
|
+
*/
|
|
175
|
+
export function advertisedConfig(tool, advertised, profile) {
|
|
176
|
+
const terse = profile === TOOL_PROFILE.CORE ||
|
|
177
|
+
profile === TOOL_PROFILE.STANDARD ||
|
|
178
|
+
profile === TOOL_PROFILE.HYBRID;
|
|
179
|
+
// The first advertised tool carrying a predicate spells the grammar out; the rest point at it.
|
|
180
|
+
const anchor = advertised.find((t) => Object.keys(t.inputSchema).some((k) => PREDICATE_PARAMS.has(k)))?.name;
|
|
181
|
+
const outputSchema = terse ? undefined : withSessionEnvelope(tool.name, tool.outputSchema);
|
|
182
|
+
return {
|
|
183
|
+
description: withExample(terse ? firstSentence(tool.description) : tool.description, tool.example),
|
|
184
|
+
inputSchema: terse
|
|
185
|
+
? leanZodShape(tool.inputSchema, tool.name === anchor ? undefined : anchor)
|
|
186
|
+
: tool.inputSchema,
|
|
187
|
+
...(outputSchema !== undefined ? { outputSchema } : {}),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Argument keys the tool never declared. Empty when the tool's shape is unknown to us. */
|
|
191
|
+
function unknownKeys(args, allowed) {
|
|
192
|
+
if (allowed === undefined || typeof args !== 'object' || args === null)
|
|
193
|
+
return [];
|
|
194
|
+
return Object.keys(args).filter((key) => !allowed.has(key));
|
|
195
|
+
}
|
|
196
|
+
export function installFriendlyArgErrors(server, examples, allowedKeys = new Map()) {
|
|
197
|
+
const target = server;
|
|
198
|
+
const original = target.validateToolInput;
|
|
199
|
+
if (typeof original !== 'function')
|
|
200
|
+
return;
|
|
201
|
+
target.validateToolInput = async (tool, args, toolName) => {
|
|
202
|
+
// An UNKNOWN key is the failure zod cannot catch, because object schemas are non-strict: the key
|
|
203
|
+
// is silently dropped and the tool answers as if it had not been asked. Measured live —
|
|
204
|
+
// `reticle_clock { action: "freeze" }` returned `{"frozen":false}`, which reads as a fact about
|
|
205
|
+
// the app ("the clock is not frozen") when it means "you named the parameter wrong". That is a
|
|
206
|
+
// false NEGATIVE the caller cannot detect from the reply, in every tool at once.
|
|
207
|
+
const unknown = unknownKeys(args, allowedKeys.get(toolName));
|
|
208
|
+
if (unknown.length > 0) {
|
|
209
|
+
const example = examples.get(toolName);
|
|
210
|
+
throw new McpError(ErrorCode.InvalidParams, `Unknown ${unknown.length === 1 ? 'parameter' : 'parameters'} for ${toolName}: ${unknown.join(', ')}. ` +
|
|
211
|
+
`They were NOT applied — a result computed without them would look like an answer. ` +
|
|
212
|
+
(example === undefined
|
|
213
|
+
? `Call reticle_tools { names: ["${toolName}"] } for its parameters.`
|
|
214
|
+
: `A valid call looks like: ${toolName} ${example}`));
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
return await original.call(server, tool, args, toolName);
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
// McpError.message already carries "MCP error -32602: "; re-wrapping would print it twice.
|
|
221
|
+
const raw = error instanceof Error ? error.message : String(error);
|
|
222
|
+
const detail = raw.replace(/^MCP error -?\d+:\s*/, '');
|
|
223
|
+
const example = examples.get(toolName);
|
|
224
|
+
const help = example === undefined
|
|
225
|
+
? ` Call reticle_tools { names: ["${toolName}"] } for its parameters.`
|
|
226
|
+
: ` A valid call looks like: ${toolName} ${example}`;
|
|
227
|
+
throw new McpError(ErrorCode.InvalidParams, `${detail}${help}`);
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
}
|
|
115
231
|
export function createMcpServer(deps, profile = TOOL_PROFILE.HYBRID) {
|
|
116
232
|
const encoding = (process.env[ENCODING_ENV] ?? '').toLowerCase();
|
|
117
233
|
const server = new McpServer(SERVER_INFO);
|
|
234
|
+
// Which agent is on the other end, taken from its own `initialize` handshake. Registered as a lazy
|
|
235
|
+
// hook rather than read here: the handshake has not happened yet at construction time, and a
|
|
236
|
+
// feedback report filed twenty tool calls later is exactly when we want the answer.
|
|
237
|
+
setMcpClientNameHook(() => {
|
|
238
|
+
const info = server.server.getClientVersion();
|
|
239
|
+
// Record it as a side effect of the first read so the session summary can report WHICH agents
|
|
240
|
+
// drove this daemon — the multi-agent story, visible without a second plumbing path.
|
|
241
|
+
if (info?.name !== undefined)
|
|
242
|
+
getSessionMetrics().recordClient(info.name);
|
|
243
|
+
return info === undefined ? undefined : { name: info.name, version: info.version };
|
|
244
|
+
});
|
|
118
245
|
// Cast once to our bridge type so every per-tool call site is typed without `any`.
|
|
119
246
|
const registerTool = server.registerTool.bind(server);
|
|
120
247
|
// `dynamic` advertises only the 2 meta-tools (reticle_tools + reticle_run); real tools load on demand.
|
|
@@ -126,9 +253,12 @@ export function createMcpServer(deps, profile = TOOL_PROFILE.HYBRID) {
|
|
|
126
253
|
// reticle_flow_save's own description instructs the agent to call. `full` advertises everything
|
|
127
254
|
// directly and needs no hatch.
|
|
128
255
|
const advertised = advertisedTools(profile);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
256
|
+
installFriendlyArgErrors(server, new Map(advertised
|
|
257
|
+
.filter((tool) => tool.example !== undefined)
|
|
258
|
+
.map((tool) => [tool.name, JSON.stringify(tool.example)])),
|
|
259
|
+
// Every tool in TOOLS, not just the advertised ones: reticle_run dispatches to the full table,
|
|
260
|
+
// so an unadvertised tool reached through the hatch must be just as strict.
|
|
261
|
+
new Map(TOOLS.map((tool) => [tool.name, new Set(Object.keys(tool.inputSchema))])));
|
|
132
262
|
for (const tool of advertised) {
|
|
133
263
|
// Output schemas are now the largest slice of the per-request tax (55.6% of the hybrid payload
|
|
134
264
|
// after the predicate fix) and we are the only one of the three MCP servers that sends them.
|
|
@@ -150,12 +280,7 @@ export function createMcpServer(deps, profile = TOOL_PROFILE.HYBRID) {
|
|
|
150
280
|
// handler below is unchanged, so `full`/`dynamic` (non-terse) keep the schema for validating
|
|
151
281
|
// clients. This removes the single largest remaining slice of the per-request tax (~36% of the
|
|
152
282
|
// hybrid payload) with no loss the agent can observe.
|
|
153
|
-
const
|
|
154
|
-
const config = {
|
|
155
|
-
description: terse ? firstSentence(tool.description) : tool.description,
|
|
156
|
-
inputSchema: terse ? leanZodShape(tool.inputSchema) : tool.inputSchema,
|
|
157
|
-
...(outputSchema !== undefined ? { outputSchema } : {}),
|
|
158
|
-
};
|
|
283
|
+
const config = advertisedConfig(tool, advertised, profile);
|
|
159
284
|
registerTool(tool.name, config, async (args) => {
|
|
160
285
|
try {
|
|
161
286
|
const result = await runTool(tool, deps, args);
|
|
@@ -171,6 +296,10 @@ export function createMcpServer(deps, profile = TOOL_PROFILE.HYBRID) {
|
|
|
171
296
|
catch (error) {
|
|
172
297
|
const message = error instanceof Error ? error.message : String(error);
|
|
173
298
|
log('tool_error', { tool: tool.name, error: message });
|
|
299
|
+
// Counted by FINGERPRINT, never by message — see error-fingerprint.ts. This is the single
|
|
300
|
+
// boundary every agent-visible tool failure crosses, so it is the one place "which error is
|
|
301
|
+
// hurting people most" can be answered without instrumenting every handler.
|
|
302
|
+
getSessionMetrics().recordToolError(message, tool.name);
|
|
174
303
|
// Every error the agent hits should answer "what next?", not just "what broke".
|
|
175
304
|
return {
|
|
176
305
|
isError: true,
|
|
@@ -181,4 +310,3 @@ export function createMcpServer(deps, profile = TOOL_PROFILE.HYBRID) {
|
|
|
181
310
|
}
|
|
182
311
|
return server;
|
|
183
312
|
}
|
|
184
|
-
//# sourceMappingURL=mcp.js.map
|
|
@@ -16,4 +16,3 @@ export declare function lastSource(steps: readonly FlowStep[]): {
|
|
|
16
16
|
* source are skipped (no location to propose). The suggested signal name is `<flow>:done`.
|
|
17
17
|
*/
|
|
18
18
|
export declare function instrumentationGapsForFlows(unassertedFlows: readonly string[], flowStepsByName: ReadonlyMap<string, readonly FlowStep[]>): InstrumentationGap[];
|
|
19
|
-
//# sourceMappingURL=flow-instrument-gaps.d.ts.map
|
|
@@ -19,4 +19,3 @@ export interface ProposedConsequence {
|
|
|
19
19
|
}
|
|
20
20
|
/** Propose ranked consequences from a recorded event window. Deduped; strongest first. */
|
|
21
21
|
export declare function proposeConsequences(events: readonly ReticleEvent[]): ProposedConsequence[];
|
|
22
|
-
//# sourceMappingURL=propose-consequences.d.ts.map
|
|
@@ -29,4 +29,3 @@ export interface InstrumentationProposal {
|
|
|
29
29
|
}
|
|
30
30
|
/** Turn located capability gaps into ready-to-apply instrumentation proposals. Deterministic. */
|
|
31
31
|
export declare function proposeInstrumentation(gaps: readonly InstrumentationGap[]): InstrumentationProposal[];
|
|
32
|
-
//# sourceMappingURL=self-instrument.d.ts.map
|
package/dist/pairing-token.d.ts
CHANGED
|
@@ -25,4 +25,3 @@ export declare function nodePairingTokenDeps(): PairingTokenDeps;
|
|
|
25
25
|
* fails, so the caller degrades to the prior tokenless behavior rather than bricking the daemon.
|
|
26
26
|
*/
|
|
27
27
|
export declare function readOrCreatePairingToken(dir: string, deps: PairingTokenDeps): Promise<string | undefined>;
|
|
28
|
-
//# sourceMappingURL=pairing-token.d.ts.map
|
package/dist/pairing-token.js
CHANGED
|
@@ -24,4 +24,3 @@ export declare function detectPreHydrationClicks(events: readonly ReticleEvent[]
|
|
|
24
24
|
export declare function detectSwallowedErrors(events: readonly ReticleEvent[]): Finding[];
|
|
25
25
|
/** Run every journal-only matcher over a session's events + actions. */
|
|
26
26
|
export declare function detectPhenomena(events: readonly ReticleEvent[], actions: readonly JournalAction[]): Finding[];
|
|
27
|
-
//# sourceMappingURL=phenomena.d.ts.map
|
|
@@ -18,4 +18,3 @@ export declare function playwrightLauncher(opts?: {
|
|
|
18
18
|
* Pure (env value + cpu count passed in) so it's testable.
|
|
19
19
|
*/
|
|
20
20
|
export declare function resolveMaxContexts(envValue: string | undefined, cpuCount: number): number;
|
|
21
|
-
//# sourceMappingURL=playwright-launcher.d.ts.map
|
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Headless by default — the pool exists for fault-tolerant headless multi-agent testing.
|
|
7
7
|
*/
|
|
8
|
+
import { BrowserLaunchKind } from '@reticlehq/core';
|
|
9
|
+
import { getSessionMetrics } from '../telemetry/session-metrics.js';
|
|
10
|
+
import { classifyConnectFailure } from '../telemetry/connect-failure.js';
|
|
8
11
|
function wrapBrowser(browser) {
|
|
9
12
|
return {
|
|
10
13
|
isConnected: () => browser.isConnected(),
|
|
@@ -38,10 +41,16 @@ export function playwrightLauncher(opts = {}) {
|
|
|
38
41
|
// (where it's meaningful) instead of at import-time (where it kills unrelated features).
|
|
39
42
|
return async () => {
|
|
40
43
|
const { chromium } = await import('playwright');
|
|
44
|
+
// A pooled launch serves N parallel leases, so this counts BROWSERS, not contexts — which is the
|
|
45
|
+
// number that actually costs memory and the one that explains a slow machine.
|
|
46
|
+
const settle = getSessionMetrics().recordConnectAttempt(BrowserLaunchKind.POOLED);
|
|
41
47
|
try {
|
|
42
|
-
|
|
48
|
+
const browser = wrapBrowser(await chromium.launch({ headless }));
|
|
49
|
+
settle();
|
|
50
|
+
return browser;
|
|
43
51
|
}
|
|
44
52
|
catch (err) {
|
|
53
|
+
settle(classifyConnectFailure(err));
|
|
45
54
|
// Turn Playwright's raw "Executable doesn't exist" into the one command that fixes it.
|
|
46
55
|
const msg = err instanceof Error ? err.message : String(err);
|
|
47
56
|
if (/executable doesn.?t exist|playwright install|browsertype\.launch/i.test(msg)) {
|
|
@@ -74,4 +83,3 @@ export function resolveMaxContexts(envValue, cpuCount) {
|
|
|
74
83
|
const byCpu = Math.max(MAX_CONTEXTS_FLOOR, cpuCount - 1);
|
|
75
84
|
return Math.min(MAX_CONTEXTS_CEILING, byCpu);
|
|
76
85
|
}
|
|
77
|
-
//# sourceMappingURL=playwright-launcher.js.map
|