@reticlehq/server 2.4.0 → 2.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +719 -0
- package/dist/bridge/auth-failure-reason.d.ts +19 -0
- package/dist/bridge/auth-failure-reason.js +29 -0
- package/dist/{bridge-security.d.ts → bridge/bridge-security.d.ts} +1 -1
- package/dist/{bridge-security.js → bridge/bridge-security.js} +1 -1
- package/dist/{bridge.d.ts → bridge/bridge.d.ts} +13 -1
- package/dist/{bridge.js → bridge/bridge.js} +95 -15
- package/dist/{bridge.test-harness.d.ts → bridge/bridge.test-harness.d.ts} +9 -11
- package/dist/{bridge.test-harness.js → bridge/bridge.test-harness.js} +18 -10
- package/dist/{pairing-token.js → bridge/pairing-token.js} +1 -1
- package/dist/capsule/capsule-store.d.ts +8 -3
- package/dist/capsule/capsule-store.js +7 -2
- package/dist/capsule/capsule.js +3 -3
- package/dist/capsule/causal-summary.d.ts +8 -0
- package/dist/capsule/causal-summary.js +22 -12
- package/dist/capsule/divergence.d.ts +9 -4
- package/dist/capsule/divergence.js +8 -8
- package/dist/capsule/predicate-to-links.js +11 -8
- package/dist/cli/cli-doctor.d.ts +1 -0
- package/dist/cli/cli-doctor.js +135 -0
- package/dist/{cli-flow-commands.d.ts → cli/cli-flow-commands.d.ts} +2 -2
- package/dist/{cli-flow-commands.js → cli/cli-flow-commands.js} +15 -15
- package/dist/{cli-launch.d.ts → cli/cli-launch.d.ts} +32 -3
- package/dist/cli/cli-launch.js +171 -0
- package/dist/cli/cli-parse-feedback.d.ts +31 -0
- package/dist/cli/cli-parse-feedback.js +56 -0
- package/dist/{cli-parse.d.ts → cli/cli-parse.d.ts} +6 -19
- package/dist/{cli-parse.js → cli/cli-parse.js} +118 -81
- package/dist/{cli-port.d.ts → cli/cli-port.d.ts} +12 -0
- package/dist/{cli-port.js → cli/cli-port.js} +9 -9
- package/dist/cli/cli-update-commands.d.ts +4 -0
- package/dist/cli/cli-update-commands.js +93 -0
- package/dist/{cli-verify.js → cli/cli-verify.js} +14 -14
- package/dist/{cloud-cli.js → cli/cloud-cli.js} +29 -24
- package/dist/cli/doctor-daemon-line.d.ts +37 -0
- package/dist/cli/doctor-daemon-line.js +35 -0
- package/dist/cli/port-holder.d.ts +43 -0
- package/dist/cli/port-holder.js +99 -0
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +302 -100
- package/dist/cloud/cloud-config.d.ts +0 -1
- package/dist/cloud/cloud-config.js +9 -9
- package/dist/cloud/cloud-sync.d.ts +1 -7
- package/dist/cloud/cloud-sync.js +12 -12
- package/dist/crawl/crawl-empty.d.ts +16 -0
- package/dist/crawl/crawl-empty.js +24 -0
- package/dist/crawl/crawl-tools.js +4 -1
- package/dist/crawl/crawl.js +26 -7
- package/dist/daemon/daemon-resilience.d.ts +73 -0
- package/dist/daemon/daemon-resilience.js +279 -0
- package/dist/daemon/daemon-usefulness.d.ts +61 -0
- package/dist/daemon/daemon-usefulness.js +62 -0
- package/dist/{daemon.d.ts → daemon/daemon.d.ts} +33 -8
- package/dist/{daemon.js → daemon/daemon.js} +105 -48
- package/dist/daemon/heartbeat.d.ts +115 -0
- package/dist/daemon/heartbeat.js +141 -0
- package/dist/daemon/idle-grace.d.ts +32 -0
- package/dist/daemon/idle-grace.js +41 -0
- package/dist/{idle-shutdown.d.ts → daemon/idle-shutdown.d.ts} +23 -2
- package/dist/{idle-shutdown.js → daemon/idle-shutdown.js} +37 -6
- package/dist/daemon/port-presence.d.ts +76 -0
- package/dist/daemon/port-presence.js +93 -0
- package/dist/daemon/state-dir.d.ts +7 -0
- package/dist/daemon/state-dir.js +59 -0
- package/dist/daemon/unclean-predecessor.d.ts +23 -0
- package/dist/daemon/unclean-predecessor.js +27 -0
- package/dist/domain/domain-model.js +2 -2
- package/dist/events/body-failures.js +8 -8
- package/dist/events/contradictions.d.ts +1 -1
- package/dist/events/contradictions.js +60 -10
- package/dist/events/echo-mismatch.js +10 -10
- package/dist/events/event-filters.js +6 -6
- package/dist/events/json-salvage.d.ts +2 -1
- package/dist/events/json-salvage.js +6 -6
- package/dist/events/observed-in-window.d.ts +12 -0
- package/dist/events/observed-in-window.js +21 -0
- package/dist/events/predicate-eval.d.ts +53 -20
- package/dist/events/predicate-eval.js +179 -55
- package/dist/events/predicate-parse.d.ts +23 -0
- package/dist/events/predicate-parse.js +54 -0
- package/dist/events/predicate.d.ts +7 -2
- package/dist/events/predicate.js +126 -35
- package/dist/events/reconcile.js +5 -5
- package/dist/events/ring-buffer.js +2 -17
- package/dist/events/stale-response.js +6 -6
- package/dist/events/testid-near-miss.d.ts +22 -0
- package/dist/events/testid-near-miss.js +33 -0
- package/dist/events/unit-mismatch.js +8 -8
- package/dist/flows/affected-tools.js +19 -4
- package/dist/flows/affected.js +1 -1
- package/dist/flows/annotate-target.d.ts +1 -0
- package/dist/flows/annotate-target.js +20 -0
- package/dist/flows/annotate-tools.js +25 -3
- package/dist/flows/annotate.js +17 -4
- package/dist/flows/assertion-integrity.d.ts +2 -1
- package/dist/flows/assertion-tiers-store.d.ts +3 -66
- package/dist/flows/assertion-tiers-store.js +2 -2
- package/dist/flows/attributed-failure.d.ts +17 -0
- package/dist/flows/attributed-failure.js +20 -0
- package/dist/flows/buddy-status.d.ts +2 -1
- package/dist/flows/buddy-status.js +2 -2
- package/dist/flows/coverage.d.ts +3 -2
- package/dist/flows/coverage.js +2 -2
- package/dist/flows/decision.js +24 -9
- package/dist/flows/empty-flow.d.ts +6 -0
- package/dist/flows/empty-flow.js +24 -0
- package/dist/flows/flake-store.d.ts +0 -1
- package/dist/flows/flake-store.js +1 -1
- package/dist/flows/flake.d.ts +2 -1
- package/dist/flows/flake.js +2 -2
- package/dist/flows/flow-classify.js +12 -0
- package/dist/flows/flow-replay-run.js +4 -4
- package/dist/flows/flow-replay.d.ts +6 -8
- package/dist/flows/flow-replay.js +132 -48
- package/dist/flows/flow-report.js +1 -1
- package/dist/flows/flow-scope.d.ts +1 -6
- package/dist/flows/flow-step-runners.d.ts +26 -6
- package/dist/flows/flow-step-runners.js +156 -6
- package/dist/flows/flow-success.js +20 -15
- package/dist/flows/flow-tools.js +63 -21
- package/dist/flows/flows.js +15 -11
- package/dist/flows/gate.d.ts +4 -3
- package/dist/flows/gate.js +1 -1
- package/dist/flows/heal-run.d.ts +0 -8
- package/dist/flows/heal-run.js +5 -5
- package/dist/flows/heal.js +3 -3
- package/dist/flows/predicate-to-expect.d.ts +38 -0
- package/dist/flows/predicate-to-expect.js +95 -0
- package/dist/flows/replay.d.ts +16 -1
- package/dist/flows/replay.js +58 -22
- package/dist/flows/role-anchor-nearest.d.ts +6 -0
- package/dist/flows/role-anchor-nearest.js +45 -0
- package/dist/flows/role-drift-reason.d.ts +20 -0
- package/dist/flows/role-drift-reason.js +39 -0
- package/dist/flows/server-verify.d.ts +1 -1
- package/dist/flows/server-verify.js +5 -5
- package/dist/flows/suite-flakes.d.ts +33 -0
- package/dist/flows/suite-flakes.js +32 -0
- package/dist/flows/verify-change-tools.js +32 -10
- package/dist/flows/verify-change-verdict.d.ts +15 -0
- package/dist/flows/verify-change-verdict.js +25 -0
- package/dist/flows/watch-batcher.d.ts +3 -2
- package/dist/honesty/already-true.d.ts +2 -0
- package/dist/honesty/already-true.js +31 -0
- package/dist/honesty/blind-spots.d.ts +35 -3
- package/dist/honesty/blind-spots.js +57 -12
- package/dist/honesty/honesty.d.ts +3 -2
- package/dist/honesty/honesty.js +4 -4
- package/dist/honesty/uncaptured-bodies.js +1 -1
- package/dist/honesty/unread-outcome.js +2 -2
- package/dist/honesty/verified.d.ts +31 -3
- package/dist/honesty/verified.js +64 -8
- package/dist/http-server.js +23 -7
- package/dist/hunt/hunt-report.d.ts +2 -1
- package/dist/hunt/hunt-report.js +2 -2
- package/dist/index.d.ts +9 -6
- package/dist/index.js +41 -25
- package/dist/init/agent-rules.d.ts +20 -1
- package/dist/init/agent-rules.js +64 -8
- package/dist/init/app-choice.d.ts +20 -0
- package/dist/init/app-choice.js +25 -0
- package/dist/init/astro-host.d.ts +21 -0
- package/dist/init/astro-host.js +27 -0
- package/dist/init/astro-patch.d.ts +16 -0
- package/dist/init/astro-patch.js +240 -0
- package/dist/init/capabilities.js +4 -1
- package/dist/init/cra.d.ts +50 -0
- package/dist/init/cra.js +106 -0
- package/dist/init/cursor.js +39 -4
- package/dist/init/desktop-doctor.d.ts +3 -2
- package/dist/init/desktop-doctor.js +4 -4
- package/dist/init/detect.d.ts +9 -2
- package/dist/init/detect.js +24 -5
- package/dist/init/mcp-clients.d.ts +81 -0
- package/dist/init/mcp-clients.js +248 -0
- package/dist/init/mcp-registered.d.ts +12 -0
- package/dist/init/mcp-registered.js +14 -0
- package/dist/init/mcp.d.ts +27 -2
- package/dist/init/mcp.js +40 -4
- package/dist/init/next-patch.d.ts +2 -4
- package/dist/init/next-patch.js +109 -19
- package/dist/init/node-io.js +29 -6
- package/dist/init/plan-framework.d.ts +16 -1
- package/dist/init/plan-framework.js +166 -8
- package/dist/init/plan.d.ts +85 -6
- package/dist/init/plan.js +196 -33
- package/dist/init/project-id.d.ts +5 -9
- package/dist/init/project-id.js +10 -22
- package/dist/init/run.d.ts +23 -1
- package/dist/init/run.js +338 -47
- package/dist/init/slash-command.d.ts +9 -0
- package/dist/init/slash-command.js +10 -1
- package/dist/init/snippets.d.ts +7 -10
- package/dist/init/snippets.js +44 -15
- package/dist/init/vite-config.js +1 -1
- package/dist/init/windows-quote.d.ts +38 -0
- package/dist/init/windows-quote.js +70 -0
- package/dist/init/workspace-apps.d.ts +23 -0
- package/dist/init/workspace-apps.js +68 -0
- package/dist/input/driven-redaction.js +1 -1
- package/dist/input/network-detail.js +8 -8
- package/dist/input/network-mock-tools.js +2 -2
- package/dist/input/network-mock.js +4 -4
- package/dist/input/real-input.js +8 -3
- package/dist/input/scroll-find.js +2 -2
- package/dist/input/scroll-tools.d.ts +0 -5
- package/dist/input/scroll-tools.js +11 -4
- package/dist/input/viewport-tools.js +2 -2
- package/dist/journal/ambient-store.d.ts +0 -2
- package/dist/journal/ambient-store.js +1 -1
- package/dist/journal/ambient.js +1 -1
- package/dist/journal/attach-journal.d.ts +2 -1
- package/dist/journal/deviation-report.js +6 -6
- package/dist/journal/deviation-service.js +1 -1
- package/dist/journal/envelope-store.d.ts +0 -2
- package/dist/journal/envelope-store.js +1 -1
- package/dist/journal/envelope.d.ts +2 -3
- package/dist/journal/envelope.js +3 -3
- package/dist/journal/journal-query.js +1 -1
- package/dist/journal/journal-recorder.d.ts +2 -1
- package/dist/journal/journal-recorder.js +2 -2
- package/dist/journal/rollups.js +9 -9
- package/dist/journal/session-end.d.ts +2 -1
- package/dist/journal/session-journal.js +4 -4
- package/dist/license/license.d.ts +0 -14
- package/dist/license/license.js +8 -8
- package/dist/log.d.ts +10 -0
- package/dist/log.js +11 -1
- package/dist/mcp/mcp-is-error.d.ts +13 -0
- package/dist/mcp/mcp-is-error.js +18 -0
- package/dist/mcp/mcp-outage.d.ts +32 -0
- package/dist/mcp/mcp-outage.js +55 -0
- package/dist/mcp/mcp-proxy.d.ts +134 -0
- package/dist/mcp/mcp-proxy.js +720 -0
- package/dist/{mcp.d.ts → mcp/mcp.d.ts} +13 -10
- package/dist/{mcp.js → mcp/mcp.js} +139 -37
- package/dist/mcp/proxy-handshake.d.ts +3 -0
- package/dist/mcp/proxy-handshake.js +54 -0
- package/dist/mcp/proxy-lifecycle.d.ts +64 -0
- package/dist/mcp/proxy-lifecycle.js +70 -0
- package/dist/mcp/tool-catalog-cache.d.ts +29 -0
- package/dist/mcp/tool-catalog-cache.js +55 -0
- package/dist/oracles/propose-consequences.d.ts +2 -1
- package/dist/oracles/propose-consequences.js +16 -11
- package/dist/oracles/self-instrument.d.ts +2 -1
- package/dist/oracles/self-instrument.js +1 -1
- package/dist/phenomena/phenomena.js +3 -3
- package/dist/platform.d.ts +16 -0
- package/dist/platform.js +16 -0
- package/dist/pool/browser-pool.d.ts +9 -0
- package/dist/pool/browser-pool.js +38 -9
- package/dist/pool/playwright-launcher.d.ts +15 -2
- package/dist/pool/playwright-launcher.js +21 -2
- package/dist/project/fs-port.js +1 -1
- package/dist/project/project-tools.js +2 -2
- package/dist/runs/build-verification-run.js +1 -1
- package/dist/runs/repair-prompt.d.ts +0 -6
- package/dist/runs/repair-prompt.js +3 -3
- package/dist/runs/risk-classify.js +1 -1
- package/dist/runs/run-diff.d.ts +0 -2
- package/dist/runs/run-diff.js +3 -3
- package/dist/runs/run-tools.js +2 -2
- package/dist/runs/verification-sync.js +2 -2
- package/dist/runs/verify-http.js +1 -1
- package/dist/runs/verify-server.js +1 -1
- package/dist/session/attachment-history.d.ts +46 -0
- package/dist/session/attachment-history.js +65 -0
- package/dist/session/command-timeout.d.ts +11 -3
- package/dist/session/command-timeout.js +2 -2
- package/dist/session/control-envelope.d.ts +6 -0
- package/dist/session/control-envelope.js +7 -1
- package/dist/session/dev-server-probe.d.ts +13 -0
- package/dist/session/dev-server-probe.js +52 -0
- package/dist/session/last-act.d.ts +17 -3
- package/dist/session/last-act.js +16 -4
- package/dist/session/live-control-tools.js +7 -2
- package/dist/session/live-control.js +1 -1
- package/dist/session/looks-like-dev-server.d.ts +14 -0
- package/dist/session/looks-like-dev-server.js +25 -0
- package/dist/session/no-session-diagnosis.d.ts +45 -0
- package/dist/session/no-session-diagnosis.js +120 -0
- package/dist/session/no-session-watch.d.ts +21 -0
- package/dist/session/no-session-watch.js +69 -0
- package/dist/session/observed-state.d.ts +4 -0
- package/dist/session/observed-state.js +19 -1
- package/dist/session/output-budget.js +1 -1
- package/dist/session/pending-commands.js +1 -0
- package/dist/session/session-health.d.ts +8 -1
- package/dist/session/session-health.js +8 -7
- package/dist/session/session-info.d.ts +43 -8
- package/dist/session/session-info.js +46 -1
- package/dist/session/session-lease.d.ts +0 -11
- package/dist/session/session-lease.js +1 -1
- package/dist/session/session-manager.d.ts +6 -0
- package/dist/session/session-manager.js +124 -12
- package/dist/session/session-readiness.d.ts +1 -1
- package/dist/session/session-readiness.js +6 -1
- package/dist/session/session-reaper.js +1 -1
- package/dist/session/session-reconnect.d.ts +32 -0
- package/dist/session/session-reconnect.js +42 -0
- package/dist/session/session.d.ts +15 -2
- package/dist/session/session.js +77 -26
- package/dist/session/state-select.d.ts +1 -1
- package/dist/session/state-select.js +1 -1
- package/dist/status-payload.d.ts +19 -0
- package/dist/status-payload.js +11 -0
- package/dist/telemetry/argument-shape.js +10 -1
- package/dist/telemetry/browser-mode.d.ts +27 -0
- package/dist/telemetry/browser-mode.js +33 -0
- package/dist/telemetry/bug-found.d.ts +17 -21
- package/dist/telemetry/bug-found.js +120 -8
- package/dist/telemetry/cli-telemetry.d.ts +2 -12
- package/dist/telemetry/cli-telemetry.js +27 -4
- package/dist/telemetry/crash-cause.d.ts +47 -0
- package/dist/telemetry/crash-cause.js +104 -0
- package/dist/telemetry/daemon-telemetry.d.ts +38 -1
- package/dist/telemetry/daemon-telemetry.js +37 -12
- package/dist/telemetry/dev-repo.js +4 -4
- package/dist/telemetry/error-class.d.ts +26 -0
- package/dist/telemetry/error-class.js +52 -0
- package/dist/telemetry/error-fingerprint.js +21 -2
- package/dist/telemetry/feedback-cli.d.ts +8 -3
- package/dist/telemetry/feedback-cli.js +52 -8
- package/dist/telemetry/feedback-context.d.ts +23 -6
- package/dist/telemetry/feedback-context.js +105 -5
- package/dist/telemetry/feedback-delivery.d.ts +20 -0
- package/dist/telemetry/feedback-delivery.js +30 -0
- package/dist/telemetry/feedback-outbox.d.ts +22 -0
- package/dist/telemetry/feedback-outbox.js +87 -0
- package/dist/telemetry/feedback.d.ts +22 -1
- package/dist/telemetry/feedback.js +67 -8
- package/dist/telemetry/git-facts.d.ts +7 -0
- package/dist/telemetry/git-facts.js +5 -5
- package/dist/telemetry/project-profile.js +2 -1
- package/dist/telemetry/session-metrics.d.ts +47 -3
- package/dist/telemetry/session-metrics.js +315 -15
- package/dist/telemetry/telemetry.d.ts +45 -2
- package/dist/telemetry/telemetry.js +150 -37
- package/dist/telemetry/verification-of.d.ts +22 -0
- package/dist/telemetry/verification-of.js +84 -0
- package/dist/tools/act-capsule.js +2 -2
- package/dist/tools/act-danger.d.ts +12 -0
- package/dist/tools/act-danger.js +20 -3
- package/dist/tools/act-helpers.js +4 -4
- package/dist/tools/act-tools.d.ts +0 -8
- package/dist/tools/act-tools.js +114 -118
- package/dist/tools/act-view.js +7 -7
- package/dist/tools/alias-args.d.ts +17 -0
- package/dist/tools/alias-args.js +25 -0
- package/dist/tools/assert-grade.js +9 -9
- package/dist/tools/assert-verdict.d.ts +9 -1
- package/dist/tools/assert-verdict.js +21 -6
- package/dist/tools/browser-tools.js +36 -11
- package/dist/tools/contract-tools.d.ts +0 -5
- package/dist/tools/contract-tools.js +27 -1
- package/dist/tools/coverage-identity.d.ts +34 -0
- package/dist/tools/coverage-identity.js +46 -0
- package/dist/tools/coverage-tools.js +10 -14
- package/dist/tools/dynamic-tools.d.ts +2 -1
- package/dist/tools/dynamic-tools.js +96 -19
- package/dist/tools/error-recovery.d.ts +34 -2
- package/dist/tools/error-recovery.js +255 -4
- package/dist/tools/feedback-invite.d.ts +48 -0
- package/dist/tools/feedback-invite.js +71 -0
- package/dist/tools/feedback-tools.d.ts +12 -1
- package/dist/tools/feedback-tools.js +28 -5
- package/dist/tools/invoke-tool.d.ts +0 -12
- package/dist/tools/invoke-tool.js +126 -33
- package/dist/tools/lease-hint.d.ts +17 -0
- package/dist/tools/lease-hint.js +24 -0
- package/dist/tools/lease-tools.js +6 -5
- package/dist/tools/merge-tools.d.ts +10 -1
- package/dist/tools/merge-tools.js +9 -3
- package/dist/tools/merged-name-redirect.d.ts +13 -0
- package/dist/tools/merged-name-redirect.js +55 -0
- package/dist/tools/navigate-arrival.d.ts +26 -0
- package/dist/tools/navigate-arrival.js +60 -0
- package/dist/tools/navigate-result.d.ts +31 -0
- package/dist/tools/navigate-result.js +38 -0
- package/dist/tools/observe-tools.js +72 -20
- package/dist/tools/observed-nothing.d.ts +25 -0
- package/dist/tools/observed-nothing.js +33 -0
- package/dist/tools/query-paginate.js +2 -2
- package/dist/tools/query-shape.d.ts +18 -0
- package/dist/tools/query-shape.js +39 -0
- package/dist/tools/read-tools.js +81 -20
- package/dist/tools/real-input-attempt.d.ts +28 -0
- package/dist/tools/real-input-attempt.js +93 -0
- package/dist/tools/reconcile-tools.js +7 -7
- package/dist/tools/reload-result.d.ts +14 -0
- package/dist/tools/reload-result.js +29 -0
- package/dist/tools/snapshot-delta.d.ts +4 -5
- package/dist/tools/snapshot-delta.js +0 -0
- package/dist/tools/tool-kit.d.ts +16 -0
- package/dist/tools/tool-surface.d.ts +83 -0
- package/dist/tools/tool-surface.js +217 -0
- package/dist/tools/tools-helpers.js +6 -6
- package/dist/tools/tools.d.ts +15 -0
- package/dist/tools/tools.js +53 -17
- package/dist/tools/unadvertised-help.d.ts +5 -0
- package/dist/tools/unadvertised-help.js +39 -0
- package/dist/trace.d.ts +69 -0
- package/dist/trace.js +150 -0
- package/dist/update/nudge-credit.d.ts +4 -0
- package/dist/update/nudge-credit.js +53 -0
- package/dist/update/sdk-sync.d.ts +21 -0
- package/dist/update/sdk-sync.js +42 -0
- package/dist/update/update-checker.js +3 -3
- package/dist/update/update-nudge.d.ts +63 -6
- package/dist/update/update-nudge.js +128 -15
- package/dist/update/updater.d.ts +1 -9
- package/dist/update/updater.js +13 -8
- package/dist/version/peer-announce.d.ts +4 -0
- package/dist/version/peer-announce.js +30 -0
- package/dist/{server-version.js → version/server-version.js} +5 -1
- package/dist/version/version-nudge.d.ts +28 -0
- package/dist/version/version-nudge.js +40 -0
- package/dist/version/version-skew.d.ts +66 -0
- package/dist/version/version-skew.js +71 -0
- package/dist/visual/visual-diff.js +2 -2
- package/dist/visual/visual-tools.js +4 -4
- package/docs/README.md +55 -0
- package/docs/agent-cheatsheet.md +85 -0
- package/docs/architecture.md +113 -0
- package/docs/benchmarks.md +255 -0
- package/docs/debugging.md +102 -0
- package/docs/deploy-checks.md +69 -0
- package/docs/desktop-apps.md +256 -0
- package/docs/enterprise.md +62 -0
- package/docs/fixtures-dispatch-receiver.yml +76 -0
- package/docs/fixtures.md +45 -0
- package/docs/flows.md +166 -0
- package/docs/gate-plan.md +98 -0
- package/docs/gates.md +117 -0
- package/docs/getting-started.md +469 -0
- package/docs/human-control.md +63 -0
- package/docs/integration-patterns.md +171 -0
- package/docs/local-registry.md +126 -0
- package/docs/matrix/2.5.0/claude-code-machine.json +19 -0
- package/docs/matrix/2.5.0/codex-machine.json +20 -0
- package/docs/matrix/2.5.0/cursor-machine.json +22 -0
- package/docs/matrix/2.5.0/gemini-machine.json +22 -0
- package/docs/matrix/2.5.0/opencode-machine.json +22 -0
- package/docs/matrix/2.5.0/vscode-machine.json +22 -0
- package/docs/matrix/2.5.0/windsurf-machine.json +22 -0
- package/docs/matrix/MATRIX.md +26 -0
- package/docs/matrix/README.md +59 -0
- package/docs/mint.json +61 -0
- package/docs/multi-agent-testing.md +55 -0
- package/docs/platform-integration.md +122 -0
- package/docs/system-map.md +152 -0
- package/docs/telemetry-contract.md +214 -0
- package/docs/telemetry.md +191 -0
- package/docs/testing.md +82 -0
- package/docs/token-efficiency.md +80 -0
- package/docs/usage.md +1046 -0
- package/package.json +8 -5
- package/dist/cli-doctor.d.ts +0 -6
- package/dist/cli-doctor.js +0 -60
- package/dist/cli-launch.js +0 -112
- package/dist/daemon-resilience.d.ts +0 -22
- package/dist/daemon-resilience.js +0 -85
- package/dist/mcp-proxy.d.ts +0 -67
- package/dist/mcp-proxy.js +0 -337
- package/dist/tools/profiles.d.ts +0 -37
- package/dist/tools/profiles.js +0 -139
- /package/dist/{pairing-token.d.ts → bridge/pairing-token.d.ts} +0 -0
- /package/dist/{token-auth.d.ts → bridge/token-auth.d.ts} +0 -0
- /package/dist/{token-auth.js → bridge/token-auth.js} +0 -0
- /package/dist/{cli-verify.d.ts → cli/cli-verify.d.ts} +0 -0
- /package/dist/{cloud-cli.d.ts → cli/cloud-cli.d.ts} +0 -0
- /package/dist/{server-version.d.ts → version/server-version.d.ts} +0 -0
package/dist/mcp-proxy.js
DELETED
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
import * as http from 'node:http';
|
|
2
|
-
import * as net from 'node:net';
|
|
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';
|
|
7
|
-
import { log } from './log.js';
|
|
8
|
-
const DEFAULT_DAEMON_READY_TIMEOUT_MS = 10_000;
|
|
9
|
-
/**
|
|
10
|
-
* How long to wait for the spawned daemon's port to accept connections before giving up. The default
|
|
11
|
-
* suits a normal machine; a slow CI/VM (heavy headless-browser launch) can raise it via the
|
|
12
|
-
* RETICLE_DAEMON_READY_TIMEOUT_MS env var. Invalid/absent values fall back to the default.
|
|
13
|
-
*/
|
|
14
|
-
const envDaemonReadyTimeoutMs = Number(process.env['RETICLE_DAEMON_READY_TIMEOUT_MS']);
|
|
15
|
-
const DAEMON_READY_TIMEOUT_MS = Number.isFinite(envDaemonReadyTimeoutMs) && envDaemonReadyTimeoutMs > 0
|
|
16
|
-
? envDaemonReadyTimeoutMs
|
|
17
|
-
: DEFAULT_DAEMON_READY_TIMEOUT_MS;
|
|
18
|
-
const DAEMON_POLL_INTERVAL_MS = 100;
|
|
19
|
-
function delay(ms) {
|
|
20
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
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
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* Incremental SSE frame parser for the MCP front door.
|
|
117
|
-
*
|
|
118
|
-
* A single SSE field can split across TCP reads (`da` in one chunk, `ta: {...}` in the next), and a
|
|
119
|
-
* server may send CRLF or bare CR line endings — so the framing is stateful and edge-case-prone, yet it
|
|
120
|
-
* carried every MCP message the agent sends and was only ever exercised end-to-end. Pulled out of the
|
|
121
|
-
* socket handler as a pure, chunk-fed parser so those boundaries are unit-testable: feed raw chunks,
|
|
122
|
-
* get back each complete frame (a blank line terminates a frame; `event:` names it, `data:` lines
|
|
123
|
-
* accumulate newline-joined; `id:`/`retry:`/comments are ignored — not needed for the bridge).
|
|
124
|
-
*/
|
|
125
|
-
export class SseFrameParser {
|
|
126
|
-
#buffer = '';
|
|
127
|
-
#event = '';
|
|
128
|
-
#data = '';
|
|
129
|
-
push(chunk) {
|
|
130
|
-
this.#buffer += chunk;
|
|
131
|
-
// Normalise CRLF/CR so the splitter only handles \n, then hold the trailing partial line for the
|
|
132
|
-
// next chunk (it may complete later).
|
|
133
|
-
const normalised = this.#buffer.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
134
|
-
const lines = normalised.split('\n');
|
|
135
|
-
this.#buffer = lines.pop() ?? '';
|
|
136
|
-
const frames = [];
|
|
137
|
-
for (const line of lines) {
|
|
138
|
-
if (line === '') {
|
|
139
|
-
if (this.#data !== '') {
|
|
140
|
-
frames.push({ event: this.#event !== '' ? this.#event : 'message', data: this.#data });
|
|
141
|
-
}
|
|
142
|
-
this.#event = '';
|
|
143
|
-
this.#data = '';
|
|
144
|
-
}
|
|
145
|
-
else if (line.startsWith('event:')) {
|
|
146
|
-
this.#event = line.slice(6).trim();
|
|
147
|
-
}
|
|
148
|
-
else if (line.startsWith('data:')) {
|
|
149
|
-
const val = line.slice(5).trim();
|
|
150
|
-
this.#data = this.#data !== '' ? `${this.#data}\n${val}` : val;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
return frames;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
/**
|
|
157
|
-
* Returns true if something is already listening on the reticle port.
|
|
158
|
-
* Uses a plain TCP probe so we don't create a side-effectful SSE session
|
|
159
|
-
* inside the daemon just to check reachability.
|
|
160
|
-
*/
|
|
161
|
-
export function probeDaemon(port) {
|
|
162
|
-
return new Promise((resolve) => {
|
|
163
|
-
const socket = new net.Socket();
|
|
164
|
-
socket.setTimeout(500);
|
|
165
|
-
socket.on('connect', () => {
|
|
166
|
-
socket.destroy();
|
|
167
|
-
resolve(true);
|
|
168
|
-
});
|
|
169
|
-
socket.on('error', () => resolve(false));
|
|
170
|
-
socket.on('timeout', () => {
|
|
171
|
-
socket.destroy();
|
|
172
|
-
resolve(false);
|
|
173
|
-
});
|
|
174
|
-
socket.connect(port, LOOPBACK_HOST);
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
/** Poll until the daemon's HTTP port accepts connections or the deadline is reached. */
|
|
178
|
-
export async function waitForDaemon(port) {
|
|
179
|
-
const deadline = Date.now() + DAEMON_READY_TIMEOUT_MS;
|
|
180
|
-
while (Date.now() < deadline) {
|
|
181
|
-
const reachable = await probeDaemon(port);
|
|
182
|
-
if (reachable)
|
|
183
|
-
return;
|
|
184
|
-
await delay(DAEMON_POLL_INTERVAL_MS);
|
|
185
|
-
}
|
|
186
|
-
throw new Error(`reticle daemon did not become ready on port ${port} within ${DAEMON_READY_TIMEOUT_MS}ms`);
|
|
187
|
-
}
|
|
188
|
-
function postToSession(url, body) {
|
|
189
|
-
return new Promise((resolve) => {
|
|
190
|
-
const parsed = new URL(url);
|
|
191
|
-
const bodyBuf = Buffer.from(body, 'utf8');
|
|
192
|
-
const options = {
|
|
193
|
-
host: parsed.hostname,
|
|
194
|
-
port: parsed.port !== '' ? parseInt(parsed.port, 10) : 80,
|
|
195
|
-
path: `${parsed.pathname}${parsed.search}`,
|
|
196
|
-
method: 'POST',
|
|
197
|
-
headers: {
|
|
198
|
-
'Content-Type': 'application/json',
|
|
199
|
-
'Content-Length': bodyBuf.byteLength,
|
|
200
|
-
},
|
|
201
|
-
};
|
|
202
|
-
const req = http.request(options, (res) => {
|
|
203
|
-
const status = res.statusCode ?? 0;
|
|
204
|
-
if (status < 200 || status >= 300) {
|
|
205
|
-
// A non-2xx from the daemon MCP endpoint used to be swallowed, hanging the JSON-RPC call
|
|
206
|
-
// client-side with no diagnostic. Surface it (the forward is still fire-and-forget).
|
|
207
|
-
log('reticle_mcp_proxy_post_non2xx', { status, path: options.path });
|
|
208
|
-
}
|
|
209
|
-
res.resume(); // drain so the socket is reused
|
|
210
|
-
resolve();
|
|
211
|
-
});
|
|
212
|
-
req.on('error', (err) => {
|
|
213
|
-
log('reticle_mcp_proxy_post_error', { error: err.message });
|
|
214
|
-
resolve();
|
|
215
|
-
});
|
|
216
|
-
req.write(bodyBuf);
|
|
217
|
-
req.end();
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
export function buildSessionUrl(rawData, port) {
|
|
221
|
-
return rawData.startsWith('/') ? `http://${LOOPBACK_HOST}:${port}${rawData}` : rawData;
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Bridge stdio ↔ SSE: connects to the running daemon's MCP endpoint and forwards
|
|
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.
|
|
231
|
-
*/
|
|
232
|
-
export function startMcpProxy(port) {
|
|
233
|
-
return new Promise((_resolve, reject) => {
|
|
234
|
-
let postUrl = null;
|
|
235
|
-
const stdinQueue = [];
|
|
236
|
-
const replay = new HandshakeReplay();
|
|
237
|
-
let stopped = false;
|
|
238
|
-
let attempts = 0;
|
|
239
|
-
function onSseEvent(event, data, p) {
|
|
240
|
-
if (event === 'endpoint') {
|
|
241
|
-
const url = buildSessionUrl(data, p);
|
|
242
|
-
postUrl = url;
|
|
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))
|
|
248
|
-
void postToSession(url, queued);
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
if (event === 'message' && !replay.shouldSuppressInbound(data)) {
|
|
252
|
-
process.stdout.write(`${data}\n`);
|
|
253
|
-
}
|
|
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);
|
|
311
|
-
// ── stdin reader ─────────────────────────────────────────────────────────
|
|
312
|
-
process.stdin.setEncoding('utf8');
|
|
313
|
-
let stdinBuffer = '';
|
|
314
|
-
process.stdin.on('data', (chunk) => {
|
|
315
|
-
stdinBuffer += chunk;
|
|
316
|
-
const lines = stdinBuffer.split('\n');
|
|
317
|
-
stdinBuffer = lines.pop() ?? '';
|
|
318
|
-
for (const line of lines) {
|
|
319
|
-
const trimmed = line.trim();
|
|
320
|
-
if (trimmed === '')
|
|
321
|
-
continue;
|
|
322
|
-
replay.observeOutbound(trimmed);
|
|
323
|
-
if (postUrl === null) {
|
|
324
|
-
stdinQueue.push(trimmed);
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
void postToSession(postUrl, trimmed);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
});
|
|
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
|
-
});
|
|
336
|
-
});
|
|
337
|
-
}
|
package/dist/tools/profiles.d.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import type { ToolDef } from './tools.js';
|
|
2
|
-
/**
|
|
3
|
-
* Which MCP tool surface to expose. The advertised tool DEFINITIONS are re-sent to the model on
|
|
4
|
-
* every turn, so a smaller surface is a per-turn token saving that compounds across a loop. Fewer
|
|
5
|
-
* tools also makes the model wander less (fewer turns, higher accuracy). See bench/agent-loop-and-replay.md.
|
|
6
|
-
*
|
|
7
|
-
* MEASURED surface sizes (assert them with profile-reachability.test.ts rather than trusting prose —
|
|
8
|
-
* every count previously written here was wrong, and the token figures below derive from those counts):
|
|
9
|
-
* core 15 · standard 32 · hybrid 15 · full 43 · dynamic 2
|
|
10
|
-
* core and hybrid are both 14 because a trimmed profile now also advertises the two meta-tools, which
|
|
11
|
-
* is what keeps an un-advertised tool reachable through reticle_run.
|
|
12
|
-
*
|
|
13
|
-
* core — the verify loop a coding agent actually needs: navigate→look→act→observe→assert,
|
|
14
|
-
* WITH direct network + console + state observability (the highest-signal checks).
|
|
15
|
-
* The recommended profile for agent-driven verification.
|
|
16
|
-
* standard — core + common extras (inspect, sequences, animations, flows, session lifecycle,
|
|
17
|
-
* scroll, baselines, …). For agents that need more than the bare loop.
|
|
18
|
-
* hybrid — THE DEFAULT: core verify+oracle tools advertised directly + 2 meta-tools for on-demand
|
|
19
|
-
* reach to everything else. Core accuracy/detection at ~64% less schema tax than full.
|
|
20
|
-
* full — all tools advertised directly. Opt in via RETICLE_TOOL_PROFILE=full for hard-call scripts.
|
|
21
|
-
*/
|
|
22
|
-
export declare const TOOL_PROFILE: {
|
|
23
|
-
/** dynamic — advertise only 2 meta-tools (reticle_tools + reticle_run); load real tools on demand.
|
|
24
|
-
* Fixed ~hundreds of tokens/turn regardless of how many tools exist. See dynamic-tools.ts. */
|
|
25
|
-
readonly DYNAMIC: "dynamic";
|
|
26
|
-
/** hybrid — the core verify tools advertised directly (so the agent acts reliably) PLUS the 2
|
|
27
|
-
* meta-tools for on-demand reach to every other tool. Core accuracy + full reach at ~core cost. */
|
|
28
|
-
readonly HYBRID: "hybrid";
|
|
29
|
-
readonly CORE: "core";
|
|
30
|
-
readonly STANDARD: "standard";
|
|
31
|
-
readonly FULL: "full";
|
|
32
|
-
};
|
|
33
|
-
export type ToolProfile = (typeof TOOL_PROFILE)[keyof typeof TOOL_PROFILE];
|
|
34
|
-
export declare const TOOL_PROFILE_ENV = "RETICLE_TOOL_PROFILE";
|
|
35
|
-
export declare const CORE_TOOL_NAMES: ReadonlySet<string>;
|
|
36
|
-
export declare function resolveToolProfile(explicit?: string): ToolProfile;
|
|
37
|
-
export declare function filterTools(tools: ToolDef[], profile: ToolProfile): ToolDef[];
|
package/dist/tools/profiles.js
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import { ReticleTool } from './tool-names.js';
|
|
2
|
-
/**
|
|
3
|
-
* Which MCP tool surface to expose. The advertised tool DEFINITIONS are re-sent to the model on
|
|
4
|
-
* every turn, so a smaller surface is a per-turn token saving that compounds across a loop. Fewer
|
|
5
|
-
* tools also makes the model wander less (fewer turns, higher accuracy). See bench/agent-loop-and-replay.md.
|
|
6
|
-
*
|
|
7
|
-
* MEASURED surface sizes (assert them with profile-reachability.test.ts rather than trusting prose —
|
|
8
|
-
* every count previously written here was wrong, and the token figures below derive from those counts):
|
|
9
|
-
* core 15 · standard 32 · hybrid 15 · full 43 · dynamic 2
|
|
10
|
-
* core and hybrid are both 14 because a trimmed profile now also advertises the two meta-tools, which
|
|
11
|
-
* is what keeps an un-advertised tool reachable through reticle_run.
|
|
12
|
-
*
|
|
13
|
-
* core — the verify loop a coding agent actually needs: navigate→look→act→observe→assert,
|
|
14
|
-
* WITH direct network + console + state observability (the highest-signal checks).
|
|
15
|
-
* The recommended profile for agent-driven verification.
|
|
16
|
-
* standard — core + common extras (inspect, sequences, animations, flows, session lifecycle,
|
|
17
|
-
* scroll, baselines, …). For agents that need more than the bare loop.
|
|
18
|
-
* hybrid — THE DEFAULT: core verify+oracle tools advertised directly + 2 meta-tools for on-demand
|
|
19
|
-
* reach to everything else. Core accuracy/detection at ~64% less schema tax than full.
|
|
20
|
-
* full — all tools advertised directly. Opt in via RETICLE_TOOL_PROFILE=full for hard-call scripts.
|
|
21
|
-
*/
|
|
22
|
-
export const TOOL_PROFILE = {
|
|
23
|
-
/** dynamic — advertise only 2 meta-tools (reticle_tools + reticle_run); load real tools on demand.
|
|
24
|
-
* Fixed ~hundreds of tokens/turn regardless of how many tools exist. See dynamic-tools.ts. */
|
|
25
|
-
DYNAMIC: 'dynamic',
|
|
26
|
-
/** hybrid — the core verify tools advertised directly (so the agent acts reliably) PLUS the 2
|
|
27
|
-
* meta-tools for on-demand reach to every other tool. Core accuracy + full reach at ~core cost. */
|
|
28
|
-
HYBRID: 'hybrid',
|
|
29
|
-
CORE: 'core',
|
|
30
|
-
STANDARD: 'standard',
|
|
31
|
-
FULL: 'full',
|
|
32
|
-
};
|
|
33
|
-
export const TOOL_PROFILE_ENV = 'RETICLE_TOOL_PROFILE';
|
|
34
|
-
// The set an agent needs to verify a change end-to-end. Tool DEFINITIONS are re-sent every turn, so a
|
|
35
|
-
// smaller surface compounds.
|
|
36
|
-
//
|
|
37
|
-
// MEASURED per-turn `tools/list` cost — the bytes an MCP client re-sends EVERY turn — taken off the
|
|
38
|
-
// real wire (spawn `mcp`, read tools/list, measure the serialized result), not estimated:
|
|
39
|
-
//
|
|
40
|
-
// dynamic 2 tools 1,531 B ~383 tok/turn
|
|
41
|
-
// core 15 tools 14,104 B ~3,526 tok/turn
|
|
42
|
-
// hybrid 15 tools 14,104 B ~3,526 tok/turn
|
|
43
|
-
// standard 32 tools 26,769 B ~6,692 tok/turn
|
|
44
|
-
// full 43 tools 105,061 B ~26,265 tok/turn
|
|
45
|
-
//
|
|
46
|
-
// These REPLACE the previous figures (core 6,479 / standard 13,951 / full 20,441), which the comment
|
|
47
|
-
// itself flagged as stale. Two of the three moved in opposite directions, which is why re-measuring
|
|
48
|
-
// mattered: the lean profiles got much CHEAPER because they now drop the advertised outputSchema,
|
|
49
|
-
// while `full` got much more EXPENSIVE because it still carries it — the gap between lean and full is
|
|
50
|
-
// 7.4x, not the ~3x the old numbers implied.
|
|
51
|
-
//
|
|
52
|
-
// Where the remaining cost sits, on the hybrid default: inputSchema is 76% of the payload (parameter
|
|
53
|
-
// descriptions are half of that), tool descriptions are 12%, and outputSchema is already ~0. So the
|
|
54
|
-
// next real saving is in parameter prose, not in dropping more tools.
|
|
55
|
-
//
|
|
56
|
-
// There is a floor, though: an 8-tool cut (dropping act/navigate/wait_for/sessions) was MEASURED to
|
|
57
|
-
// regress real-agent accuracy 5/5 -> 3/5, because the model loses scaffolding and wanders on harder
|
|
58
|
-
// flows. Direct network/console stay (far more discoverable than observe-with-filters -> fewer turns,
|
|
59
|
-
// better verdicts).
|
|
60
|
-
//
|
|
61
|
-
// Evidence status: the 5/5 figure came from a single gpt-4o run and is STALE as a justification.
|
|
62
|
-
// Current-model evidence is indirect but real — the cost-delta run (bench/fix-loop/COST-DELTA.md)
|
|
63
|
-
// drove this hybrid default on a current model and fixed 4/4 cells with ~25% FEWER tool calls than
|
|
64
|
-
// the baseline. A formal core-vs-hybrid A/B on a current model is still UNRUN; do not quote the 5/5
|
|
65
|
-
// number as if it were current. See bench/agent-loop-and-replay.md.
|
|
66
|
-
export const CORE_TOOL_NAMES = new Set([
|
|
67
|
-
ReticleTool.SESSIONS,
|
|
68
|
-
ReticleTool.NAVIGATE,
|
|
69
|
-
ReticleTool.SNAPSHOT,
|
|
70
|
-
ReticleTool.QUERY,
|
|
71
|
-
ReticleTool.ACT,
|
|
72
|
-
ReticleTool.ACT_AND_WAIT,
|
|
73
|
-
ReticleTool.OBSERVE,
|
|
74
|
-
ReticleTool.NETWORK,
|
|
75
|
-
ReticleTool.CONSOLE,
|
|
76
|
-
ReticleTool.WAIT_FOR,
|
|
77
|
-
ReticleTool.ASSERT,
|
|
78
|
-
ReticleTool.STATE,
|
|
79
|
-
// INSPECT is what turns a finding into an EDIT: it maps a DOM node to `src/App.tsx:104`. Finding a
|
|
80
|
-
// bug is half the job; knowing which file to open is the half that makes the agent useful, and it
|
|
81
|
-
// is the one capability here with no substitute in any other verification tool. It sat in
|
|
82
|
-
// `standard`, so under the default profile an agent had to already know it existed and reach it
|
|
83
|
-
// through reticle_run — which, observed over a full 43-tool drive, means it never gets called.
|
|
84
|
-
// The measured floor that justifies a lean core was about CUTTING to 8 (accuracy 5/5 → 3/5), not
|
|
85
|
-
// about holding at 12; one tool of schema tax to close the find→fix loop is the right trade.
|
|
86
|
-
ReticleTool.INSPECT,
|
|
87
|
-
// FEEDBACK is in every profile for the same reason INSPECT is: a tool an agent has to already know
|
|
88
|
-
// about, and reach through reticle_run, is a tool that never gets called. That is fatal here in a way
|
|
89
|
-
// it is not elsewhere — an unadvertised feedback channel collects nothing, which is indistinguishable
|
|
90
|
-
// from not having built one. It is also the cheapest tool on the surface to carry (three params) and
|
|
91
|
-
// the only one whose whole purpose is telling us which of the other fifteen are failing.
|
|
92
|
-
ReticleTool.FEEDBACK,
|
|
93
|
-
]);
|
|
94
|
-
const STANDARD_TOOL_NAMES = new Set([
|
|
95
|
-
...CORE_TOOL_NAMES,
|
|
96
|
-
ReticleTool.ACT_SEQUENCE,
|
|
97
|
-
ReticleTool.NETWORK,
|
|
98
|
-
ReticleTool.CONSOLE,
|
|
99
|
-
ReticleTool.ANIMATIONS,
|
|
100
|
-
ReticleTool.FLOW_SAVE,
|
|
101
|
-
ReticleTool.FLOW_REPLAY,
|
|
102
|
-
ReticleTool.FLOW_VERIFY,
|
|
103
|
-
ReticleTool.FLOW_HEAL,
|
|
104
|
-
ReticleTool.SESSION, // merged lifecycle/human-channel family
|
|
105
|
-
ReticleTool.FLOW, // merged flow list/load/delete
|
|
106
|
-
ReticleTool.RECORD, // merged record start/stop
|
|
107
|
-
ReticleTool.BASELINE, // merged baseline save/list/diff
|
|
108
|
-
ReticleTool.SCROLL_TO,
|
|
109
|
-
ReticleTool.CRAWL,
|
|
110
|
-
ReticleTool.REPLAY,
|
|
111
|
-
ReticleTool.EXPLORE,
|
|
112
|
-
ReticleTool.CONTRACT_SAVE,
|
|
113
|
-
ReticleTool.NETWORK_MOCK,
|
|
114
|
-
ReticleTool.VIEWPORT,
|
|
115
|
-
]);
|
|
116
|
-
export function resolveToolProfile(explicit) {
|
|
117
|
-
const raw = explicit ?? process.env[TOOL_PROFILE_ENV];
|
|
118
|
-
if (raw === TOOL_PROFILE.DYNAMIC)
|
|
119
|
-
return TOOL_PROFILE.DYNAMIC;
|
|
120
|
-
if (raw === TOOL_PROFILE.HYBRID)
|
|
121
|
-
return TOOL_PROFILE.HYBRID;
|
|
122
|
-
if (raw === TOOL_PROFILE.CORE)
|
|
123
|
-
return TOOL_PROFILE.CORE;
|
|
124
|
-
if (raw === TOOL_PROFILE.STANDARD)
|
|
125
|
-
return TOOL_PROFILE.STANDARD;
|
|
126
|
-
if (raw === TOOL_PROFILE.FULL)
|
|
127
|
-
return TOOL_PROFILE.FULL;
|
|
128
|
-
// Default: hybrid — the core verify+oracle tools advertised directly (no detection loss, verified
|
|
129
|
-
// 10/10 on the regression bench) PLUS the 2 meta-tools for on-demand reach to every other tool. ~64%
|
|
130
|
-
// less per-turn schema than `full` at the same accuracy. Explicit `full` still opts into all tools.
|
|
131
|
-
return TOOL_PROFILE.HYBRID;
|
|
132
|
-
}
|
|
133
|
-
export function filterTools(tools, profile) {
|
|
134
|
-
if (profile === TOOL_PROFILE.CORE)
|
|
135
|
-
return tools.filter((t) => CORE_TOOL_NAMES.has(t.name));
|
|
136
|
-
if (profile === TOOL_PROFILE.STANDARD)
|
|
137
|
-
return tools.filter((t) => STANDARD_TOOL_NAMES.has(t.name));
|
|
138
|
-
return tools;
|
|
139
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|