@reticlehq/server 2.11.0 → 2.13.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 +93 -111
- package/dist/bridge/auth-failure-reason.d.ts +6 -2
- package/dist/bridge/auth-failure-reason.js +15 -8
- package/dist/bridge/bridge.d.ts +18 -14
- package/dist/bridge/bridge.js +248 -165
- package/dist/bridge/bridge.test-harness.d.ts +2 -0
- package/dist/bridge/bridge.test-harness.js +8 -1
- package/dist/bridge/pairing-token.d.ts +5 -0
- package/dist/bridge/pairing-token.js +28 -0
- package/dist/bridge/protocol-skew.d.ts +37 -0
- package/dist/bridge/protocol-skew.js +45 -0
- package/dist/capsule/capsule-store.d.ts +8 -7
- package/dist/capsule/capsule-store.js +1 -1
- package/dist/capsule/causal-summary.d.ts +2 -2
- package/dist/capsule/causal-summary.js +7 -2
- package/dist/chromium-launch-options.d.ts +28 -0
- package/dist/chromium-launch-options.js +29 -0
- package/dist/cli/cli-doctor.js +39 -1
- package/dist/cli/cli-flow-commands.d.ts +3 -1
- package/dist/cli/cli-flow-commands.js +34 -4
- package/dist/cli/cli-kill.d.ts +2 -1
- package/dist/cli/cli-launch.d.ts +11 -1
- package/dist/cli/cli-launch.js +59 -10
- package/dist/cli/cli-parse.d.ts +17 -1
- package/dist/cli/cli-parse.js +238 -12
- package/dist/cli/cli-update-commands.js +20 -1
- package/dist/cli/cli-verify.d.ts +2 -1
- package/dist/cli/cli-verify.js +5 -4
- package/dist/cli/cloud-cli.js +428 -253
- package/dist/cli/cloud-keystore.d.ts +37 -0
- package/dist/cli/cloud-keystore.js +97 -0
- package/dist/cli/cloud-kit.d.ts +37 -0
- package/dist/cli/cloud-kit.js +121 -0
- package/dist/cli/cloud-login.d.ts +17 -0
- package/dist/cli/cloud-login.js +183 -0
- package/dist/cli/cloud-session.d.ts +48 -0
- package/dist/cli/cloud-session.js +53 -0
- package/dist/cli/config-discovery.d.ts +2 -1
- package/dist/cli/config-discovery.js +1 -0
- package/dist/cli/daemon-start-options.d.ts +32 -0
- package/dist/cli/daemon-start-options.js +38 -0
- package/dist/cli/device-flow.d.ts +76 -0
- package/dist/cli/device-flow.js +56 -0
- package/dist/cli/doctor-rows.d.ts +12 -1
- package/dist/cli/doctor-rows.js +12 -1
- package/dist/cli/drive-attach.d.ts +13 -0
- package/dist/cli/drive-attach.js +18 -0
- package/dist/cli/drive-command.js +7 -3
- package/dist/cli/gate-exit.d.ts +21 -0
- package/dist/cli/gate-exit.js +21 -0
- package/dist/cli/gate-hook-message.d.ts +33 -0
- package/dist/cli/gate-hook-message.js +46 -0
- package/dist/cli/mcp-command.d.ts +25 -0
- package/dist/cli/mcp-command.js +174 -0
- package/dist/cli/project-name.d.ts +30 -0
- package/dist/cli/project-name.js +44 -0
- package/dist/cli/sibling-ports.d.ts +37 -0
- package/dist/cli/sibling-ports.js +56 -0
- package/dist/cli/status-next-action.d.ts +14 -0
- package/dist/cli/status-next-action.js +4 -4
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +167 -186
- package/dist/cloud/cloud-config.d.ts +24 -2
- package/dist/cloud/cloud-config.js +64 -5
- package/dist/cloud/cloud-sync.d.ts +16 -5
- package/dist/cloud/cloud-sync.js +64 -1
- package/dist/cloud/sync-cycle.d.ts +110 -0
- package/dist/cloud/sync-cycle.js +270 -0
- package/dist/cloud/sync-daemon.d.ts +69 -0
- package/dist/cloud/sync-daemon.js +260 -0
- package/dist/cloud/sync-disk.d.ts +9 -0
- package/dist/cloud/sync-disk.js +191 -0
- package/dist/cloud/sync-hash.d.ts +2 -0
- package/dist/cloud/sync-hash.js +35 -0
- package/dist/crawl/crawl-tools.js +5 -3
- package/dist/crawl/crawl.d.ts +12 -13
- package/dist/crawl/crawl.js +25 -3
- package/dist/daemon/daemon-resolve.d.ts +122 -0
- package/dist/daemon/daemon-resolve.js +187 -0
- package/dist/daemon/dev-servers.d.ts +15 -0
- package/dist/daemon/dev-servers.js +68 -0
- package/dist/daemon/free-port.d.ts +29 -0
- package/dist/daemon/free-port.js +55 -0
- package/dist/daemon/heartbeat.d.ts +0 -4
- package/dist/daemon/heartbeat.js +2 -2
- package/dist/daemon/wake-decision.d.ts +32 -0
- package/dist/daemon/wake-decision.js +38 -0
- package/dist/dev/stale-issue-guard.d.ts +0 -2
- package/dist/dev/stale-issue-guard.js +1 -1
- package/dist/domain/domain-tools.js +2 -2
- package/dist/events/contradictions.d.ts +59 -0
- package/dist/events/contradictions.js +253 -27
- package/dist/events/declared.d.ts +17 -0
- package/dist/events/declared.js +43 -1
- package/dist/events/echo-mismatch.js +65 -1
- package/dist/events/event-filters.d.ts +8 -0
- package/dist/events/event-filters.js +19 -2
- package/dist/events/observed-in-window.d.ts +12 -0
- package/dist/events/observed-in-window.js +17 -0
- package/dist/events/predicate-asks.d.ts +13 -0
- package/dist/events/predicate-asks.js +22 -0
- package/dist/events/predicate-eval.js +117 -27
- package/dist/events/predicate-parse.d.ts +0 -6
- package/dist/events/predicate-parse.js +43 -3
- package/dist/events/predicate-precheck.d.ts +8 -0
- package/dist/events/predicate-precheck.js +41 -0
- package/dist/events/predicate-route.d.ts +14 -0
- package/dist/events/predicate-route.js +36 -8
- package/dist/events/predicate-schema.d.ts +44 -0
- package/dist/events/predicate-schema.js +126 -23
- package/dist/events/predicate.d.ts +20 -0
- package/dist/events/predicate.js +77 -6
- package/dist/events/split-text-miss.d.ts +30 -0
- package/dist/events/split-text-miss.js +44 -0
- package/dist/flows/coverage.d.ts +0 -8
- package/dist/flows/coverage.js +1 -1
- package/dist/flows/decision.d.ts +5 -1
- package/dist/flows/decision.js +33 -7
- package/dist/flows/flake.d.ts +6 -8
- package/dist/flows/flake.js +1 -1
- package/dist/flows/flow-intent.d.ts +52 -0
- package/dist/flows/flow-intent.js +123 -0
- package/dist/flows/flow-memory-consult.d.ts +55 -0
- package/dist/flows/flow-memory-consult.js +38 -0
- package/dist/flows/flow-replay-run.d.ts +18 -7
- package/dist/flows/flow-replay-run.js +263 -23
- package/dist/flows/flow-replay.js +11 -2
- package/dist/flows/flow-step-runners.d.ts +8 -0
- package/dist/flows/flow-step-runners.js +8 -2
- package/dist/flows/flow-store-for-session.d.ts +31 -0
- package/dist/flows/flow-store-for-session.js +33 -0
- package/dist/flows/flow-success.js +15 -3
- package/dist/flows/flow-tools.js +87 -33
- package/dist/flows/flows.d.ts +14 -1
- package/dist/flows/flows.js +502 -24
- package/dist/flows/heal-run.js +5 -2
- package/dist/flows/predicate-to-expect.d.ts +17 -12
- package/dist/flows/predicate-to-expect.js +36 -15
- package/dist/flows/recordings.d.ts +13 -1
- package/dist/flows/recordings.js +17 -2
- package/dist/flows/replay.d.ts +22 -2
- package/dist/flows/replay.js +28 -2
- package/dist/flows/server-verify.js +16 -2
- package/dist/flows/verify-change-tools.js +9 -3
- package/dist/honesty/blind-spots.d.ts +51 -15
- package/dist/honesty/blind-spots.js +64 -4
- package/dist/honesty/feature-capture.d.ts +150 -0
- package/dist/honesty/feature-capture.js +233 -0
- package/dist/honesty/honesty.d.ts +24 -0
- package/dist/honesty/honesty.js +25 -1
- package/dist/honesty/instrumentation-gaps.d.ts +39 -6
- package/dist/honesty/instrumentation-gaps.js +88 -5
- package/dist/honesty/tool-hit-rate.d.ts +86 -0
- package/dist/honesty/tool-hit-rate.js +90 -0
- package/dist/honesty/undeclared-change.d.ts +51 -0
- package/dist/honesty/undeclared-change.js +56 -0
- package/dist/honesty/verified.d.ts +16 -0
- package/dist/honesty/verified.js +84 -5
- package/dist/http-server.d.ts +0 -1
- package/dist/http-server.js +13 -1
- package/dist/hunt/hunt-report.d.ts +0 -2
- package/dist/hunt/hunt-report.js +1 -1
- package/dist/impact/impact-recorder.d.ts +31 -8
- package/dist/impact/impact-recorder.js +104 -21
- package/dist/impact/impact-store.d.ts +13 -4
- package/dist/impact/impact-store.js +44 -3
- package/dist/index.d.ts +4 -1
- package/dist/index.js +113 -7
- package/dist/init/agent-rules.d.ts +30 -6
- package/dist/init/agent-rules.js +54 -13
- package/dist/init/astro-patch.d.ts +16 -0
- package/dist/init/astro-patch.js +28 -0
- package/dist/init/capabilities.d.ts +4 -3
- package/dist/init/capabilities.js +23 -3
- package/dist/init/closing-hint.d.ts +36 -0
- package/dist/init/closing-hint.js +120 -0
- package/dist/init/confirm.d.ts +27 -28
- package/dist/init/confirm.js +51 -11
- package/dist/init/cra.d.ts +34 -5
- package/dist/init/cra.js +96 -25
- package/dist/init/csp-check.js +17 -2
- package/dist/init/csp-doctor.d.ts +8 -1
- package/dist/init/csp-doctor.js +8 -3
- package/dist/init/dev-script.d.ts +50 -0
- package/dist/init/dev-script.js +66 -0
- package/dist/init/format-generated.d.ts +18 -0
- package/dist/init/format-generated.js +39 -0
- package/dist/init/install-hint.d.ts +9 -0
- package/dist/init/install-hint.js +29 -0
- package/dist/init/mcp-clients.d.ts +7 -0
- package/dist/init/mcp-clients.js +7 -0
- package/dist/init/mcp.d.ts +17 -6
- package/dist/init/mcp.js +27 -11
- package/dist/init/node-io.js +11 -1
- package/dist/init/plan-framework.d.ts +0 -5
- package/dist/init/plan-framework.js +147 -37
- package/dist/init/plan.d.ts +30 -37
- package/dist/init/plan.js +50 -60
- package/dist/init/preflight.d.ts +28 -0
- package/dist/init/preflight.js +38 -0
- package/dist/init/refresh-rules.d.ts +39 -0
- package/dist/init/refresh-rules.js +51 -0
- package/dist/init/run.d.ts +32 -35
- package/dist/init/run.js +151 -202
- package/dist/init/slash-command.d.ts +1 -1
- package/dist/init/snippets.js +90 -31
- package/dist/init/vite-config.d.ts +1 -1
- package/dist/init/vite-config.js +39 -25
- package/dist/init/workspace-apps.d.ts +17 -10
- package/dist/init/workspace-apps.js +110 -0
- package/dist/input/network-mock-tools.js +3 -6
- package/dist/input/real-input.d.ts +2 -0
- package/dist/input/real-input.js +28 -7
- package/dist/input/scroll-find.d.ts +7 -4
- package/dist/input/scroll-find.js +63 -25
- package/dist/input/scroll-tools.js +4 -6
- package/dist/input/viewport-tools.js +5 -4
- package/dist/intent/inline-intent.d.ts +37 -0
- package/dist/intent/inline-intent.js +193 -0
- package/dist/intent/intent-shard-store.d.ts +72 -0
- package/dist/intent/intent-shard-store.js +203 -0
- package/dist/intent/intent-shard.d.ts +411 -0
- package/dist/intent/intent-shard.js +176 -0
- package/dist/intent/intent-store.d.ts +49 -0
- package/dist/intent/intent-store.js +133 -0
- package/dist/intent/intent-subject.d.ts +45 -0
- package/dist/intent/intent-subject.js +177 -0
- package/dist/intent/intent-tools.d.ts +2 -0
- package/dist/intent/intent-tools.js +143 -0
- package/dist/intent/open-intents.d.ts +42 -0
- package/dist/intent/open-intents.js +40 -0
- package/dist/journal/envelope.d.ts +26 -26
- package/dist/journal/journal-recorder.d.ts +23 -0
- package/dist/journal/journal-recorder.js +35 -0
- package/dist/license/license-env.d.ts +29 -0
- package/dist/license/license-env.js +148 -0
- package/dist/loopback-agent.d.ts +31 -0
- package/dist/loopback-agent.js +57 -0
- package/dist/mcp/attach-memory.d.ts +83 -0
- package/dist/mcp/attach-memory.js +185 -0
- package/dist/mcp/client-identity.d.ts +31 -0
- package/dist/mcp/client-identity.js +51 -0
- package/dist/mcp/mcp-post-transport.d.ts +26 -0
- package/dist/mcp/mcp-post-transport.js +109 -0
- package/dist/mcp/mcp-proxy.d.ts +2 -8
- package/dist/mcp/mcp-proxy.js +64 -62
- package/dist/mcp/mcp.d.ts +2 -0
- package/dist/mcp/mcp.js +52 -24
- package/dist/mcp/proxy-backoff.d.ts +11 -0
- package/dist/mcp/proxy-backoff.js +13 -0
- package/dist/mcp/proxy-daemon-probe.d.ts +1 -0
- package/dist/mcp/proxy-daemon-probe.js +7 -1
- package/dist/mcp/proxy-handshake.d.ts +23 -0
- package/dist/mcp/proxy-handshake.js +31 -0
- package/dist/mcp/server-instructions.js +45 -3
- package/dist/mcp/tool-catalog-cache.d.ts +16 -0
- package/dist/mcp/tool-catalog-cache.js +22 -0
- package/dist/memory/memory-tools.d.ts +2 -0
- package/dist/memory/memory-tools.js +82 -0
- package/dist/memory/project-memory.d.ts +34 -0
- package/dist/memory/project-memory.js +96 -0
- package/dist/oracles/flow-instrument-gaps.d.ts +4 -4
- package/dist/oracles/flow-instrument-gaps.js +4 -5
- package/dist/oracles/propose-consequences.js +12 -3
- package/dist/oracles/self-instrument.d.ts +9 -9
- package/dist/oracles/self-instrument.js +19 -13
- package/dist/pool/browser-pool.d.ts +75 -5
- package/dist/pool/browser-pool.js +144 -5
- package/dist/pool/playwright-launcher.js +12 -1
- package/dist/project/fs-port.d.ts +3 -0
- package/dist/project/fs-port.js +3 -2
- package/dist/project/memory-fs.js +6 -1
- package/dist/project/project-tools.js +6 -35
- package/dist/project/reticle-dir.d.ts +17 -2
- package/dist/project/reticle-dir.js +22 -4
- package/dist/runs/context-tools.d.ts +2 -0
- package/dist/runs/context-tools.js +89 -0
- package/dist/runs/run-context.d.ts +40 -0
- package/dist/runs/run-context.js +158 -0
- package/dist/runs/run-diff.d.ts +2 -1
- package/dist/runs/run-store.d.ts +10 -0
- package/dist/runs/run-store.js +10 -0
- package/dist/runs/verification-sync.d.ts +0 -11
- package/dist/runs/verification-sync.js +24 -3
- package/dist/runs/verify-server.d.ts +8 -1
- package/dist/runs/verify-server.js +14 -2
- package/dist/session/command-timeout.d.ts +5 -2
- package/dist/session/command-timeout.js +5 -4
- package/dist/session/dev-server-probe.d.ts +0 -8
- package/dist/session/dev-server-probe.js +1 -1
- package/dist/session/last-act.d.ts +7 -1
- package/dist/session/last-act.js +2 -2
- package/dist/session/lease-visibility.d.ts +67 -0
- package/dist/session/lease-visibility.js +76 -0
- package/dist/session/live-control-tools.js +1 -42
- package/dist/session/no-session-diagnosis.d.ts +33 -0
- package/dist/session/no-session-diagnosis.js +82 -24
- package/dist/session/no-session-next-action.d.ts +12 -0
- package/dist/session/no-session-next-action.js +77 -6
- package/dist/session/no-session-watch.d.ts +18 -6
- package/dist/session/no-session-watch.js +125 -75
- package/dist/session/output-budget.js +4 -1
- package/dist/session/pending-commands.d.ts +11 -1
- package/dist/session/pending-commands.js +12 -2
- package/dist/session/resolve-within.d.ts +34 -0
- package/dist/session/resolve-within.js +53 -0
- package/dist/session/session-health.d.ts +9 -0
- package/dist/session/session-health.js +23 -0
- package/dist/session/session-info.d.ts +18 -0
- package/dist/session/session-info.js +11 -0
- package/dist/session/session-manager.d.ts +14 -0
- package/dist/session/session-manager.js +111 -4
- package/dist/session/session-mirror.d.ts +16 -0
- package/dist/session/session-mirror.js +22 -0
- package/dist/session/session-recommendation.d.ts +19 -5
- package/dist/session/session-recommendation.js +25 -9
- package/dist/session/session-successor.d.ts +37 -0
- package/dist/session/session-successor.js +113 -0
- package/dist/session/session-tools.js +2 -2
- package/dist/session/session.d.ts +53 -3
- package/dist/session/session.js +162 -9
- package/dist/session/wall-clock.d.ts +12 -0
- package/dist/session/wall-clock.js +14 -0
- package/dist/setup/agent-configs.d.ts +96 -0
- package/dist/setup/agent-configs.js +333 -0
- package/dist/setup/agent-io.d.ts +9 -0
- package/dist/setup/agent-io.js +16 -0
- package/dist/setup/agent-writer.d.ts +51 -0
- package/dist/setup/agent-writer.js +115 -0
- package/dist/setup/approval-migration.d.ts +47 -0
- package/dist/setup/approval-migration.js +68 -0
- package/dist/setup/auto-approve.d.ts +85 -0
- package/dist/setup/auto-approve.js +150 -0
- package/dist/setup/bridge-port.d.ts +15 -0
- package/dist/setup/bridge-port.js +24 -0
- package/dist/setup/desktop-shape.d.ts +57 -0
- package/dist/setup/desktop-shape.js +63 -0
- package/dist/setup/dev-server-wait.d.ts +60 -0
- package/dist/setup/dev-server-wait.js +65 -0
- package/dist/setup/drive-agent.d.ts +71 -0
- package/dist/setup/drive-agent.js +171 -0
- package/dist/setup/drive-plan.d.ts +68 -0
- package/dist/setup/drive-plan.js +130 -0
- package/dist/setup/ensure-daemon.d.ts +29 -0
- package/dist/setup/ensure-daemon.js +58 -0
- package/dist/setup/init-runtime.d.ts +47 -0
- package/dist/setup/init-runtime.js +160 -0
- package/dist/setup/interrupt.d.ts +25 -0
- package/dist/setup/interrupt.js +40 -0
- package/dist/setup/license-key.d.ts +39 -0
- package/dist/setup/license-key.js +72 -0
- package/dist/setup/listeners.d.ts +37 -0
- package/dist/setup/listeners.js +85 -0
- package/dist/setup/node-effects.d.ts +60 -0
- package/dist/setup/node-effects.js +210 -0
- package/dist/setup/page-probe.d.ts +39 -0
- package/dist/setup/page-probe.js +49 -0
- package/dist/setup/relaunch.d.ts +36 -0
- package/dist/setup/relaunch.js +57 -0
- package/dist/setup/remaining-steps.d.ts +19 -0
- package/dist/setup/remaining-steps.js +31 -0
- package/dist/setup/run-setup.d.ts +99 -0
- package/dist/setup/run-setup.js +187 -0
- package/dist/setup/session-pick.d.ts +47 -0
- package/dist/setup/session-pick.js +51 -0
- package/dist/setup/setup-command.d.ts +45 -0
- package/dist/setup/setup-command.js +199 -0
- package/dist/setup/setup-options.d.ts +74 -0
- package/dist/setup/setup-options.js +67 -0
- package/dist/setup/transcripts.d.ts +16 -0
- package/dist/setup/transcripts.js +43 -0
- package/dist/status-payload.d.ts +14 -1
- package/dist/status-payload.js +23 -1
- package/dist/telemetry/automation-hint.d.ts +2 -1
- package/dist/telemetry/daemon-telemetry.d.ts +8 -1
- package/dist/telemetry/daemon-telemetry.js +52 -5
- package/dist/telemetry/error-class.js +1 -1
- package/dist/telemetry/feedback-context.d.ts +9 -1
- package/dist/telemetry/feedback-context.js +60 -29
- package/dist/telemetry/feedback-local.d.ts +15 -0
- package/dist/telemetry/feedback-local.js +56 -0
- package/dist/telemetry/feedback-outbox.d.ts +2 -1
- package/dist/telemetry/feedback.d.ts +11 -0
- package/dist/telemetry/feedback.js +19 -6
- package/dist/telemetry/init-telemetry.d.ts +2 -0
- package/dist/telemetry/init-telemetry.js +2 -0
- package/dist/telemetry/install-source.d.ts +14 -0
- package/dist/telemetry/install-source.js +30 -0
- package/dist/telemetry/license-activation.d.ts +7 -1
- package/dist/telemetry/license-activation.js +9 -5
- package/dist/telemetry/mcp-connection.js +7 -0
- package/dist/telemetry/project-profile.d.ts +12 -9
- package/dist/telemetry/project-profile.js +12 -7
- package/dist/telemetry/proxy-telemetry.d.ts +3 -0
- package/dist/telemetry/proxy-telemetry.js +21 -0
- package/dist/telemetry/run-telemetry.d.ts +0 -2
- package/dist/telemetry/run-telemetry.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +12 -0
- package/dist/telemetry/session-metrics.js +35 -1
- package/dist/telemetry/telemetry.js +17 -2
- package/dist/telemetry/tool-refused.d.ts +3 -1
- package/dist/telemetry/tool-refused.js +34 -2
- package/dist/telemetry/verification-of.js +2 -2
- package/dist/tools/act-capsule.d.ts +10 -0
- package/dist/tools/act-capsule.js +8 -2
- package/dist/tools/act-danger.d.ts +2 -1
- package/dist/tools/act-danger.js +11 -3
- package/dist/tools/act-observation.d.ts +41 -0
- package/dist/tools/act-observation.js +36 -0
- package/dist/tools/act-preflight.d.ts +20 -0
- package/dist/tools/act-preflight.js +98 -0
- package/dist/tools/act-sequence-retry.d.ts +45 -0
- package/dist/tools/act-sequence-retry.js +58 -0
- package/dist/tools/act-sequence-tool.d.ts +13 -0
- package/dist/tools/act-sequence-tool.js +135 -0
- package/dist/tools/act-target.d.ts +14 -0
- package/dist/tools/act-target.js +47 -0
- package/dist/tools/act-tools.d.ts +21 -1
- package/dist/tools/act-tools.js +196 -204
- package/dist/tools/assert-source.d.ts +22 -0
- package/dist/tools/assert-source.js +53 -0
- package/dist/tools/assert-verdict.d.ts +20 -3
- package/dist/tools/assert-verdict.js +58 -20
- package/dist/tools/browser-tools.js +6 -22
- package/dist/tools/complete-snapshot.d.ts +48 -0
- package/dist/tools/complete-snapshot.js +75 -0
- package/dist/tools/coverage-tools.d.ts +10 -1
- package/dist/tools/coverage-tools.js +123 -69
- package/dist/tools/dynamic-tools.js +53 -13
- package/dist/tools/error-recovery.d.ts +25 -14
- package/dist/tools/error-recovery.js +78 -9
- package/dist/tools/feedback-tools.d.ts +1 -1
- package/dist/tools/feedback-tools.js +2 -2
- package/dist/tools/invoke-tool.js +121 -11
- package/dist/tools/lease-hint.d.ts +10 -0
- package/dist/tools/lease-hint.js +53 -4
- package/dist/tools/lease-tools.d.ts +35 -5
- package/dist/tools/lease-tools.js +191 -13
- package/dist/tools/merged-name-redirect.d.ts +13 -0
- package/dist/tools/merged-name-redirect.js +22 -0
- package/dist/tools/navigate-arrival.d.ts +0 -2
- package/dist/tools/navigate-arrival.js +1 -1
- package/dist/tools/numeric-bounds.d.ts +100 -0
- package/dist/tools/numeric-bounds.js +125 -0
- package/dist/tools/observe-tools.js +109 -65
- package/dist/tools/read-tools.js +31 -8
- package/dist/tools/real-input-attempt.d.ts +32 -0
- package/dist/tools/real-input-attempt.js +212 -2
- package/dist/tools/reconcile-tools.js +22 -8
- package/dist/tools/resolve-target.d.ts +0 -7
- package/dist/tools/sdk-marker-probe.d.ts +29 -0
- package/dist/tools/sdk-marker-probe.js +57 -0
- package/dist/tools/snapshot-delta.d.ts +1 -1
- package/dist/tools/tool-kit.d.ts +24 -0
- package/dist/tools/tool-kit.js +21 -0
- package/dist/tools/tool-names.d.ts +5 -0
- package/dist/tools/tool-names.js +5 -0
- package/dist/tools/tool-surface.d.ts +85 -6
- package/dist/tools/tool-surface.js +122 -2
- package/dist/tools/tools-helpers.d.ts +19 -0
- package/dist/tools/tools-helpers.js +46 -0
- package/dist/tools/tools.d.ts +2 -0
- package/dist/tools/tools.js +78 -12
- package/dist/tools/unadvertised-help.js +4 -4
- package/dist/tools/verify-next-baton.d.ts +53 -0
- package/dist/tools/verify-next-baton.js +52 -0
- package/dist/update/reticle-deps.d.ts +9 -0
- package/dist/update/reticle-deps.js +27 -0
- package/dist/update/sdk-sync.d.ts +1 -2
- package/dist/update/sdk-sync.js +1 -21
- package/dist/update/update-nudge.d.ts +25 -10
- package/dist/update/update-nudge.js +32 -3
- package/dist/update/updater.d.ts +1 -1
- package/dist/version/peer-announce.js +4 -2
- package/dist/version/sdk-fix.d.ts +47 -0
- package/dist/version/sdk-fix.js +127 -0
- package/dist/version/version-nudge.d.ts +14 -0
- package/dist/version/version-nudge.js +21 -0
- package/dist/version/version-skew.d.ts +38 -3
- package/dist/version/version-skew.js +83 -7
- package/dist/visual/visual-store.d.ts +6 -6
- package/dist/visual/visual-store.js +18 -16
- package/dist/visual/visual-tools.js +57 -12
- package/docs/README.md +2 -1
- package/docs/cli/cloud.mdx +1 -1
- package/docs/cli/doctor.mdx +2 -0
- package/docs/cli/serve.mdx +4 -2
- package/docs/cli/verify.mdx +4 -5
- package/docs/cli.mdx +7 -3
- package/docs/desktop.mdx +1 -1
- package/docs/docs.json +2 -2
- package/docs/gates.md +1 -1
- package/docs/getting-started.md +19 -3
- package/docs/index.mdx +9 -6
- package/docs/install-agentic.mdx +38 -12
- package/docs/install-manual.mdx +1 -1
- package/docs/packages/browser.mdx +2 -2
- package/docs/packages/server.mdx +1 -1
- package/docs/packages.mdx +8 -6
- package/docs/platform-integration.md +17 -0
- package/docs/predicates.mdx +8 -0
- package/docs/reticle-manual.md +106 -0
- package/docs/skill-file.mdx +3 -3
- package/docs/telemetry-contract.md +108 -4
- package/docs/tools-act-sequence.mdx +16 -0
- package/docs/tools-tools-and-run.mdx +2 -4
- package/docs/troubleshooting.mdx +9 -0
- package/docs/usage.md +4 -3
- package/package.json +4 -3
- package/dist/init/cursor.d.ts +0 -24
- package/dist/init/cursor.js +0 -80
- package/dist/session/session-readiness.d.ts +0 -34
- package/dist/session/session-readiness.js +0 -36
|
@@ -103,6 +103,37 @@ export function toolsChangedNotification(catalogWasLocal) {
|
|
|
103
103
|
return null;
|
|
104
104
|
return JSON.stringify({ jsonrpc: '2.0', method: TOOLS_CHANGED_NOTIFICATION });
|
|
105
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* What a locally-answered handshake must say about itself.
|
|
108
|
+
*
|
|
109
|
+
* The proxy answering `initialize` is right — a hang gives the agent no tools AND no diagnosis — but
|
|
110
|
+
* the response it sent was INDISTINGUISHABLE from a daemon's. Same `serverInfo`, same capabilities,
|
|
111
|
+
* same `instructions`. So the client marked the server installed and enabled, the agent got a tool
|
|
112
|
+
* list that was cached at best and empty at worst, and nothing anywhere connected the two facts.
|
|
113
|
+
*
|
|
114
|
+
* Reported from the field, from two different agent hosts at once: the marketplace showed Reticle
|
|
115
|
+
* installed with the whole tool surface enabled, and the agent asked to verify a flow reported that
|
|
116
|
+
* RETICLE WAS NOT PRESENT ON THE MACHINE — while the daemon was running and a browser session was
|
|
117
|
+
* live. That conclusion is the reasonable reading of an empty surface with no explanation attached,
|
|
118
|
+
* and it is unrecoverable: the proxy's own recovery is "the next client request re-probes the port",
|
|
119
|
+
* and a client holding zero tools never makes another request.
|
|
120
|
+
*
|
|
121
|
+
* `instructions` is the channel because it is the only one that survives an empty catalog. It rides
|
|
122
|
+
* on the initialize result, which SUCCEEDED, and every host we target puts it in front of the model.
|
|
123
|
+
* A tool description cannot reach an agent that was handed no tools.
|
|
124
|
+
*
|
|
125
|
+
* The healthy block is kept underneath rather than replaced: an agent that IS about to get a working
|
|
126
|
+
* surface (the common case — the first call wakes a daemon) still needs to know how to drive it.
|
|
127
|
+
*/
|
|
128
|
+
export function degradedInstructions(healthy, port, reason) {
|
|
129
|
+
return `DEGRADED SURFACE — READ THIS BEFORE ANY reticle_* CALL: no Reticle daemon answered on port ${String(port)} (${reason}), so this handshake was completed by the Reticle MCP proxy itself, not by Reticle's daemon. Any tool list you were handed came from a cache or is empty — it is not evidence that anything is behind it.
|
|
130
|
+
|
|
131
|
+
Reticle IS installed: this process is Reticle. Do NOT report it as missing, not present, or not installed — that is the wrong diagnosis and it is the one this state reliably produces. The right one is that the daemon is not reachable yet.
|
|
132
|
+
|
|
133
|
+
Your next reticle_* call starts a daemon and then either works or fails with the specific reason. If you have NO reticle_* tools at all, say exactly that to the user and tell them to run \`reticle doctor\` in a terminal — it reports what is holding port ${String(port)} and whether a daemon can start at all.
|
|
134
|
+
|
|
135
|
+
${healthy}`;
|
|
136
|
+
}
|
|
106
137
|
/**
|
|
107
138
|
* The largest single JSON-RPC line the proxy will accumulate from a client.
|
|
108
139
|
*
|
|
@@ -18,11 +18,31 @@ import { SHARED_PARAM_GUIDANCE } from './shared-params.js';
|
|
|
18
18
|
* So the lead is state-dependent. A project that has never had an app connect is told the one thing
|
|
19
19
|
* it needs; a project that has is not nagged about a step it already took. The verdict discipline
|
|
20
20
|
* and the feedback ask are constant, because they matter in both states.
|
|
21
|
+
*
|
|
22
|
+
* The stopping rule is here for a measured reason. On a HEALTHY app in the competitor benchmark,
|
|
23
|
+
* this agent spent 22 turns and roughly 3.5x the cheapest competitor's tokens confirming that
|
|
24
|
+
* nothing was wrong — and it was not payload, which was the smallest of its five runs. It was
|
|
25
|
+
* turns: three navigations, four queries, a console read, a network read and an assert, on a page
|
|
26
|
+
* whose first verdict had already come back "yes" over a clean capture. Nothing anywhere told it
|
|
27
|
+
* when it was finished. Every other instruction here pushes toward MORE checking, which is right
|
|
28
|
+
* when something is broken and is the whole bill when nothing is.
|
|
29
|
+
*
|
|
30
|
+
* The diagnose-from-source rule has the same provenance and a bigger number behind it. Measured on
|
|
31
|
+
* a fix-and-verify benchmark, split at the call that writes the fix: this agent spent 14 and 18
|
|
32
|
+
* calls BEFORE its first edit where chrome-devtools-mcp spent 8 and 9 — and the sequences say why.
|
|
33
|
+
* It drove the app to understand it (snapshot, act, wait_for, snapshot, act, act_and_wait) and only
|
|
34
|
+
* then opened a file, while the competitor read six files and then looked once. Per-turn cost was
|
|
35
|
+
* IDENTICAL on the hardest cell (22,575 against 22,466), so the whole gap was turns, and most of
|
|
36
|
+
* those turns were spent asking a browser a question that only source can answer.
|
|
21
37
|
*/
|
|
22
38
|
/** The tools, and the rule that only two of them decide anything. Constant across both states. */
|
|
23
|
-
const VERDICT_DISCIPLINE = `Reticle verifies a running web app from the inside: look (reticle_snapshot / reticle_query), act and prove in one hop (reticle_act_and_wait), observe (reticle_state / reticle_network / reticle_console), assert (reticle_assert). Verify a user-facing change against the real app before you call it done, and never weaken a check to make it pass.
|
|
39
|
+
const VERDICT_DISCIPLINE = `Reticle verifies a running web app from the inside: go (reticle_navigate), look (reticle_snapshot / reticle_query), act and prove in one hop (reticle_act_and_wait), observe (reticle_observe / reticle_state / reticle_network / reticle_console), assert (reticle_assert). Verify a user-facing change against the real app before you call it done, and never weaken a check to make it pass.
|
|
40
|
+
|
|
41
|
+
Only reticle_act_and_wait and reticle_assert produce a verdict. reticle_act and everything else move or read the app and prove nothing, so a drive that ends without one of those two has no result however many tools it used. Prefer reticle_act_and_wait({ ref, action, until }) — it names the expected consequence BEFORE the action, which is the difference between a check and a rationalisation. Only verified:"yes" is a pass — "unknown" means Reticle could not tell what happened, "no-fault" means nothing was declared to prove. Report either as not proved.
|
|
24
42
|
|
|
25
|
-
|
|
43
|
+
A "yes" over a clean capture IS the answer — re-reading the page after one finds the same state. When every consequence you set out to check has one, stop.
|
|
44
|
+
|
|
45
|
+
DIAGNOSING a bug? Read the source first — Reticle proves what the app DOES, not why. Drive to CONFIRM a fix, not to find one.`;
|
|
26
46
|
/**
|
|
27
47
|
* The first move, for a project no app has ever connected to.
|
|
28
48
|
*
|
|
@@ -35,6 +55,28 @@ Only reticle_act_and_wait and reticle_assert produce a verdict. reticle_act and
|
|
|
35
55
|
const FIRST_MOVE = `FIRST: no app has ever connected to Reticle in this project, so nothing here can be verified yet. Having these tools is not the same as being set up — the tools reach a daemon, and the daemon has nothing to look at until the app itself is instrumented.
|
|
36
56
|
|
|
37
57
|
Fix that before anything else: run \`npx @reticlehq/server init\` in the project, then RESTART the dev server (a plugin added to a config the running server already read is not in the bundle), then load the app in a browser. Confirm with reticle_sessions — a session listed there is the proof, and until one appears no other tool can tell you anything about this app.`;
|
|
58
|
+
/**
|
|
59
|
+
* When to reach for the tools that are advertised but never explained, and how to reach the two
|
|
60
|
+
* that are explained but not advertised. Both halves of the same defect.
|
|
61
|
+
*
|
|
62
|
+
* An advertised tool arrives as a name and one line of description. That is enough to USE and not
|
|
63
|
+
* enough to CHOOSE, and `reticle_observe` is the case that proves it costs something: the
|
|
64
|
+
* measurement recorded on TOOL_SURFACE.VERIFY is that dropping the observation tools TRIPLED false
|
|
65
|
+
* alarms, because the model stops observing and reaches for the verdict without the evidence. So
|
|
66
|
+
* observe gets a reason, not a listing.
|
|
67
|
+
*
|
|
68
|
+
* The other direction: `reticle_context` and `reticle_intent` sit on the EXTENDED surface, so they
|
|
69
|
+
* are not in the list an agent is handed. Naming them without their call shape sent an agent at a
|
|
70
|
+
* tool it could not call, which is worse than silence — it teaches distrust of everything else
|
|
71
|
+
* here. They are now written the way the skill writes them, as the `reticle_run` call that works.
|
|
72
|
+
*
|
|
73
|
+
* Only in the connected state, and that is not a budget trick: an agent whose app has never
|
|
74
|
+
* connected has nothing to observe, no run to carry forward and nothing to declare an intent
|
|
75
|
+
* against. Its one instruction is the first move, and adding a second would compete with it.
|
|
76
|
+
*/
|
|
77
|
+
const REACH_FOR = `reticle_observe is the evidence channel: everything the page did since a cursor, in one read. Take it BEFORE you call a build broken — measured, stripping the observation tools TRIPLED false alarms, because an agent that stops observing reaches for the verdict without the evidence. reticle_wait_for settles a page that is changing without you; reticle_inspect maps an element to its source file:line, which turns a finding into an edit; reticle_session {action:"yield"} hands the tab back to the human.
|
|
78
|
+
|
|
79
|
+
Everything else is one hop: reticle_tools lists it, reticle_run calls it. Two to know early: reticle_run({ tool: "reticle_context", args: {} }) returns what this run already established, after a compaction or handover, and reticle_run({ tool: "reticle_intent", args: { action: "declare", ... } }) declares what a change was MEANT to do, so the verdict has something to check against other than itself.`;
|
|
38
80
|
/** The feedback ask. Constant: an agent that cannot get set up is the report we most need. */
|
|
39
81
|
const FEEDBACK_ASK = `Feedback is first-class here, not a courtesy. Reticle is built FOR agents, so your experience is the only signal that decides what gets built or fixed — and it disappears when your context does. Send it with \`reticle_feedback\` the moment you notice, then carry on with your task:
|
|
40
82
|
- Reticle broke, lied, or could not see something you needed (\`bug\` / \`gap\` / \`ambiguity\`).
|
|
@@ -50,7 +92,7 @@ Nothing is too minor, and a report costs one call. If the tools are unreachable
|
|
|
50
92
|
*/
|
|
51
93
|
export function buildServerInstructions(state) {
|
|
52
94
|
const base = state.previouslyConnected
|
|
53
|
-
? `${VERDICT_DISCIPLINE}\n\n${FEEDBACK_ASK}`
|
|
95
|
+
? `${VERDICT_DISCIPLINE}\n\n${REACH_FOR}\n\n${FEEDBACK_ASK}`
|
|
54
96
|
: `${FIRST_MOVE}\n\n${VERDICT_DISCIPLINE}\n\n${FEEDBACK_ASK}`;
|
|
55
97
|
return `${base}\n\n${SHARED_PARAM_GUIDANCE}`;
|
|
56
98
|
}
|
|
@@ -15,6 +15,22 @@
|
|
|
15
15
|
* its own confidently-wrong answer, and a proxy that has never seen one has nothing honest to serve —
|
|
16
16
|
* so it says nothing rather than inventing a list the agent would then call into.
|
|
17
17
|
*/
|
|
18
|
+
/**
|
|
19
|
+
* Is this client line a request for the tool list?
|
|
20
|
+
*
|
|
21
|
+
* Lives here because this module already owns the method name and the tolerant parse. The caller is
|
|
22
|
+
* the proxy's stdin reader, which records the arrival as the one observable fact behind `reticle
|
|
23
|
+
* status`'s "registered, never enumerated" state — see attach-memory.ts.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isToolsListRequest(line: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Is this line a client CALLING a tool?
|
|
28
|
+
*
|
|
29
|
+
* The one fact that separates a working agent link from a merely-registered one. Listing the tools
|
|
30
|
+
* proves a client read the catalogue; it proves nothing about whether a request can cross to the
|
|
31
|
+
* daemon, and the field reports those two states looking identical from every other angle.
|
|
32
|
+
*/
|
|
33
|
+
export declare function isToolCallRequest(line: string): boolean;
|
|
18
34
|
export declare class ToolCatalogCache {
|
|
19
35
|
#private;
|
|
20
36
|
/** Watch a line coming BACK from the daemon; remember it if it is a tool catalog. */
|
|
@@ -25,6 +25,28 @@ function parse(line) {
|
|
|
25
25
|
return null;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Is this client line a request for the tool list?
|
|
30
|
+
*
|
|
31
|
+
* Lives here because this module already owns the method name and the tolerant parse. The caller is
|
|
32
|
+
* the proxy's stdin reader, which records the arrival as the one observable fact behind `reticle
|
|
33
|
+
* status`'s "registered, never enumerated" state — see attach-memory.ts.
|
|
34
|
+
*/
|
|
35
|
+
export function isToolsListRequest(line) {
|
|
36
|
+
return parse(line)?.method === LIST_METHOD;
|
|
37
|
+
}
|
|
38
|
+
/** The JSON-RPC method a client sends to actually USE a tool, as opposed to listing them. */
|
|
39
|
+
const CALL_METHOD = 'tools/call';
|
|
40
|
+
/**
|
|
41
|
+
* Is this line a client CALLING a tool?
|
|
42
|
+
*
|
|
43
|
+
* The one fact that separates a working agent link from a merely-registered one. Listing the tools
|
|
44
|
+
* proves a client read the catalogue; it proves nothing about whether a request can cross to the
|
|
45
|
+
* daemon, and the field reports those two states looking identical from every other angle.
|
|
46
|
+
*/
|
|
47
|
+
export function isToolCallRequest(line) {
|
|
48
|
+
return parse(line)?.method === CALL_METHOD;
|
|
49
|
+
}
|
|
28
50
|
export class ToolCatalogCache {
|
|
29
51
|
#tools;
|
|
30
52
|
/** Watch a line coming BACK from the daemon; remember it if it is a tool catalog. */
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `reticle_memory` — ask the project what it already knows.
|
|
3
|
+
*
|
|
4
|
+
* Shared memory reached three callers before this one: the sync writes it, flow replay consults it
|
|
5
|
+
* automatically, and `reticle memory` prints it at a terminal. The one who could not ask was the
|
|
6
|
+
* agent doing the work — mid-drive, holding a question, with a whole tool surface and nothing on it
|
|
7
|
+
* for "what has this team already established about checkout?".
|
|
8
|
+
*
|
|
9
|
+
* That matters twice over. An agent that can read the corpus stops re-deriving what a colleague
|
|
10
|
+
* proved last week; and because the read is attributed, the coverage map's fetch counts finally
|
|
11
|
+
* measure something — they were zero across an entire real corpus, not because the knowledge was
|
|
12
|
+
* useless but because consulting it was a separate act nobody performed.
|
|
13
|
+
*/
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { ReticleTool } from '../tools/tool-names.js';
|
|
16
|
+
import { countSchema } from '../tools/numeric-bounds.js';
|
|
17
|
+
import { sessionIdShape } from '../tools/tool-kit.js';
|
|
18
|
+
import { asNumber, asString } from '../tools/tools-helpers.js';
|
|
19
|
+
import { sessionRoot } from '../project/session-root.js';
|
|
20
|
+
import { MemoryUnavailable, readProjectMemory } from './project-memory.js';
|
|
21
|
+
import { homedir } from 'node:os';
|
|
22
|
+
/**
|
|
23
|
+
* Enough to orient on, not enough to flood a context.
|
|
24
|
+
*
|
|
25
|
+
* A busy subject on a real project runs to dozens of statements; an agent asking a question wants
|
|
26
|
+
* the ones that settle it. `total` always rides along, so the cap is never silent.
|
|
27
|
+
*/
|
|
28
|
+
const DEFAULT_LIMIT = 10;
|
|
29
|
+
/** What to do next, per reason. A refusal that does not say how to fix it is a dead end. */
|
|
30
|
+
const ADVICE = {
|
|
31
|
+
[MemoryUnavailable.NOT_LINKED]: 'this project is not linked to a Reticle workspace, so there is no shared memory to read. Run `npx @reticlehq/server login` in the project to link it.',
|
|
32
|
+
[MemoryUnavailable.DISABLED]: 'this project is linked but memory sync is turned off in .reticle/cloud.json, so nothing is being shared. Enable `sync.memory` to use it.',
|
|
33
|
+
[MemoryUnavailable.UNREACHABLE]: 'the workspace could not be reached, or refused the key. Nothing is wrong with this project — try again, or check the link with `reticle status`.',
|
|
34
|
+
};
|
|
35
|
+
export const MEMORY_TOOLS = [
|
|
36
|
+
{
|
|
37
|
+
name: ReticleTool.MEMORY,
|
|
38
|
+
description: 'Ask what THIS PROJECT already knows — the shared memory its team has built up, written by every engineer who verified something and readable by every agent since. Use it BEFORE re-deriving how a feature is supposed to behave: a colleague may already have proved it, and a statement marked `proved` was established by a real verdict rather than written down. With { subject } it narrows to one area (a flow name, or a route like "checkout"); without, it returns across the project. Each entry carries the flow and the source file it is about, so a claim can be checked. The read is recorded as an agent consultation, which is what the dashboard\'s per-flow fetch counts are built from. Returns { subject, known, total } or { error, reason, advice } when this project is not linked to a workspace.',
|
|
39
|
+
inputSchema: {
|
|
40
|
+
subject: z
|
|
41
|
+
.string()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe('Narrow to one area — a flow name ("checkout-pay") or a route segment ("issues"). Omit to read across the whole project. Subjects come from the coverage map; an unknown one returns nothing rather than erroring.'),
|
|
44
|
+
limit: countSchema
|
|
45
|
+
.optional()
|
|
46
|
+
.describe(`Most relevant N statements. Defaults to ${String(DEFAULT_LIMIT)}. Proved statements rank first, so a small limit still returns the settled ones. \`total\` always reports the true count.`),
|
|
47
|
+
...sessionIdShape,
|
|
48
|
+
},
|
|
49
|
+
outputSchema: {
|
|
50
|
+
subject: z.string().nullable().optional(),
|
|
51
|
+
known: z.array(z.unknown()).optional(),
|
|
52
|
+
total: z.number().optional(),
|
|
53
|
+
error: z.string().optional(),
|
|
54
|
+
reason: z.string().optional(),
|
|
55
|
+
advice: z.string().optional(),
|
|
56
|
+
},
|
|
57
|
+
handler: async (deps, args) => {
|
|
58
|
+
/*
|
|
59
|
+
* The APP's root, not the daemon's.
|
|
60
|
+
*
|
|
61
|
+
* `deps.reticleRoot` is wherever the daemon was launched, which for a user-scoped MCP
|
|
62
|
+
* registration is almost never the project being driven — so the link file it reads is the
|
|
63
|
+
* wrong one or absent, and every project silently reads as "not attached". The same defect
|
|
64
|
+
* has now been fixed three times in this codebase; routing through sessionRoot is what stops
|
|
65
|
+
* a fourth.
|
|
66
|
+
*/
|
|
67
|
+
const root = sessionRoot(deps, asString(args['sessionId']));
|
|
68
|
+
const subject = asString(args['subject']);
|
|
69
|
+
const result = await readProjectMemory(deps.fs, root, homedir(), process.env, {
|
|
70
|
+
subject,
|
|
71
|
+
limit: asNumber(args['limit']) ?? DEFAULT_LIMIT,
|
|
72
|
+
});
|
|
73
|
+
if (!result.ok)
|
|
74
|
+
return {
|
|
75
|
+
error: 'no shared memory available for this project',
|
|
76
|
+
reason: result.reason,
|
|
77
|
+
advice: ADVICE[result.reason],
|
|
78
|
+
};
|
|
79
|
+
return { subject: result.subject, known: result.known, total: result.total };
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { FileSystemPort } from '../project/fs-port.js';
|
|
2
|
+
/** Named so a read from the tool surface is distinguishable from the CLI's and from replay's. */
|
|
3
|
+
export declare const MCP_AGENT_ID = "reticle-mcp";
|
|
4
|
+
/** Why a lookup returned nothing. Each one is a different thing for the agent to do next. */
|
|
5
|
+
export declare const MemoryUnavailable: {
|
|
6
|
+
/** No `.reticle/cloud.json` — this project has never been linked to a workspace. */
|
|
7
|
+
readonly NOT_LINKED: "not-linked";
|
|
8
|
+
/** Linked, but the link says not to sync memory. A setting, not a failure. */
|
|
9
|
+
readonly DISABLED: "memory-sync-disabled";
|
|
10
|
+
/** The server was reached and said no, or could not be reached at all. */
|
|
11
|
+
readonly UNREACHABLE: "unreachable";
|
|
12
|
+
};
|
|
13
|
+
export type MemoryUnavailable = (typeof MemoryUnavailable)[keyof typeof MemoryUnavailable];
|
|
14
|
+
export interface KnownThing {
|
|
15
|
+
statement: string;
|
|
16
|
+
status: string;
|
|
17
|
+
flowName: string | null;
|
|
18
|
+
sourceFile: string | null;
|
|
19
|
+
subject: string;
|
|
20
|
+
}
|
|
21
|
+
export type ProjectMemoryResult = {
|
|
22
|
+
ok: true;
|
|
23
|
+
subject: string | null;
|
|
24
|
+
known: KnownThing[];
|
|
25
|
+
total: number;
|
|
26
|
+
} | {
|
|
27
|
+
ok: false;
|
|
28
|
+
reason: MemoryUnavailable;
|
|
29
|
+
};
|
|
30
|
+
export declare const rankKnown: (things: readonly KnownThing[]) => KnownThing[];
|
|
31
|
+
export declare function readProjectMemory(fs: FileSystemPort, root: string, home: string, env: NodeJS.ProcessEnv, opts: {
|
|
32
|
+
subject?: string | undefined;
|
|
33
|
+
limit: number;
|
|
34
|
+
}): Promise<ProjectMemoryResult>;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the PROJECT knows, read on demand.
|
|
3
|
+
*
|
|
4
|
+
* Shared memory reached three places before this one: the sync writes it, flow replay consults it
|
|
5
|
+
* automatically, and `reticle memory` prints it at a terminal. The one caller who could not ask was
|
|
6
|
+
* the agent actually doing the work — mid-drive, holding a question, with 44 tools and none of them
|
|
7
|
+
* "what does this team already know about checkout?". That is the gap this closes, and it is the
|
|
8
|
+
* difference between a corpus and a wiki nobody opens.
|
|
9
|
+
*
|
|
10
|
+
* The read is ATTRIBUTED. It carries an agent header, so the coverage map counts it as a
|
|
11
|
+
* consultation and a manager can see which flows are actually being pulled and by whom — the
|
|
12
|
+
* question the fetch counters exist to answer and could not while nothing was reading.
|
|
13
|
+
*/
|
|
14
|
+
import { cloudFetch } from '../cloud/cloud-sync.js';
|
|
15
|
+
import { resolveProjectCloud } from '../cloud/cloud-config.js';
|
|
16
|
+
/** Named so a read from the tool surface is distinguishable from the CLI's and from replay's. */
|
|
17
|
+
export const MCP_AGENT_ID = 'reticle-mcp';
|
|
18
|
+
/** Why a lookup returned nothing. Each one is a different thing for the agent to do next. */
|
|
19
|
+
export const MemoryUnavailable = {
|
|
20
|
+
/** No `.reticle/cloud.json` — this project has never been linked to a workspace. */
|
|
21
|
+
NOT_LINKED: 'not-linked',
|
|
22
|
+
/** Linked, but the link says not to sync memory. A setting, not a failure. */
|
|
23
|
+
DISABLED: 'memory-sync-disabled',
|
|
24
|
+
/** The server was reached and said no, or could not be reached at all. */
|
|
25
|
+
UNREACHABLE: 'unreachable',
|
|
26
|
+
};
|
|
27
|
+
/** Defensive: the wire is somebody else's server, so every field is checked before it is trusted. */
|
|
28
|
+
const asKnown = (raw) => {
|
|
29
|
+
if (null === raw || typeof raw !== 'object')
|
|
30
|
+
return null;
|
|
31
|
+
const r = raw;
|
|
32
|
+
const statement = r['statement'];
|
|
33
|
+
if (typeof statement !== 'string' || 0 === statement.length)
|
|
34
|
+
return null;
|
|
35
|
+
return {
|
|
36
|
+
statement,
|
|
37
|
+
status: 'string' === typeof r['status'] ? r['status'] : 'unknown',
|
|
38
|
+
flowName: 'string' === typeof r['flowName'] ? r['flowName'] : null,
|
|
39
|
+
sourceFile: 'string' === typeof r['sourceFile'] ? r['sourceFile'] : null,
|
|
40
|
+
subject: 'string' === typeof r['subject'] ? r['subject'] : 'unsorted',
|
|
41
|
+
};
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Proved first, then the rest.
|
|
45
|
+
*
|
|
46
|
+
* An agent reading this is about to act on it, and a statement a verdict has actually established
|
|
47
|
+
* is worth more than one somebody merely wrote down. Stable within each group so the same call
|
|
48
|
+
* twice returns the same order — an unstable list reads as the corpus churning when it has not.
|
|
49
|
+
*/
|
|
50
|
+
const PROVED = 'proved';
|
|
51
|
+
export const rankKnown = (things) => [
|
|
52
|
+
...things.filter((t) => PROVED === t.status),
|
|
53
|
+
...things.filter((t) => PROVED !== t.status),
|
|
54
|
+
];
|
|
55
|
+
export async function readProjectMemory(fs, root, home, env, opts) {
|
|
56
|
+
const cloud = await resolveProjectCloud(fs, root, home, env);
|
|
57
|
+
if (null === cloud.config)
|
|
58
|
+
return { ok: false, reason: MemoryUnavailable.NOT_LINKED };
|
|
59
|
+
if (!cloud.policy.memory)
|
|
60
|
+
return { ok: false, reason: MemoryUnavailable.DISABLED };
|
|
61
|
+
const query = opts.subject === undefined ? '' : `?subject=${encodeURIComponent(opts.subject)}`;
|
|
62
|
+
try {
|
|
63
|
+
const res = await cloudFetch(`${cloud.config.url}/v1/memory${query}`, {
|
|
64
|
+
method: 'GET',
|
|
65
|
+
headers: {
|
|
66
|
+
authorization: `Bearer ${cloud.config.apiKey}`,
|
|
67
|
+
// What makes this read COUNT as an agent consulting the corpus rather than a human
|
|
68
|
+
// browsing — the distinction the dashboard's "times an agent consulted it" rests on.
|
|
69
|
+
'x-reticle-agent': MCP_AGENT_ID,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
if (200 !== res.status)
|
|
73
|
+
return { ok: false, reason: MemoryUnavailable.UNREACHABLE };
|
|
74
|
+
// `cloudFetch` returns a real Response, so the body is a METHOD. Reading `res.json` as a
|
|
75
|
+
// property yields the function, and every downstream field is undefined — a silent "the project
|
|
76
|
+
// knows nothing" that is indistinguishable from the honest empty case. It cost a live drive to
|
|
77
|
+
// find once already.
|
|
78
|
+
const body = (await res.json());
|
|
79
|
+
const entries = body?.entries;
|
|
80
|
+
if (!Array.isArray(entries))
|
|
81
|
+
return { ok: false, reason: MemoryUnavailable.UNREACHABLE };
|
|
82
|
+
const known = entries.map(asKnown).filter((k) => k !== null);
|
|
83
|
+
return {
|
|
84
|
+
ok: true,
|
|
85
|
+
subject: opts.subject ?? null,
|
|
86
|
+
// Capped for the agent's context, but `total` always reports the truth so the cap is never
|
|
87
|
+
// silent — a truncated list that looks complete is how an agent concludes a project knows
|
|
88
|
+
// less than it does.
|
|
89
|
+
known: rankKnown(known).slice(0, opts.limit),
|
|
90
|
+
total: known.length,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return { ok: false, reason: MemoryUnavailable.UNREACHABLE };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type FlowStep } from '@reticlehq/core';
|
|
2
|
-
import {
|
|
2
|
+
import type { LocatedGap } from './self-instrument.js';
|
|
3
3
|
/**
|
|
4
4
|
* Bridge domain gaps → LOCATED instrumentation gaps. A flow that asserts no consequence should emit one —
|
|
5
5
|
* and the flow's own step anchors carry the source file:line the babel/next plugin stamped, so we know
|
|
@@ -12,7 +12,7 @@ export declare function lastSource(steps: readonly FlowStep[]): {
|
|
|
12
12
|
line: number;
|
|
13
13
|
} | undefined;
|
|
14
14
|
/**
|
|
15
|
-
* Turn unasserted flows into
|
|
16
|
-
* source are skipped (no location to propose). The suggested signal name is `<flow>:done`.
|
|
15
|
+
* Turn unasserted flows into no-signal-on-mutation gaps at each flow's source location. Flows with
|
|
16
|
+
* no stamped source are skipped (no location to propose). The suggested signal name is `<flow>:done`.
|
|
17
17
|
*/
|
|
18
|
-
export declare function instrumentationGapsForFlows(unassertedFlows: readonly string[], flowStepsByName: ReadonlyMap<string, readonly FlowStep[]>):
|
|
18
|
+
export declare function instrumentationGapsForFlows(unassertedFlows: readonly string[], flowStepsByName: ReadonlyMap<string, readonly FlowStep[]>): LocatedGap[];
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { AnchorKind } from '@reticlehq/core';
|
|
2
|
-
import { InstrumentationGapKind } from './self-instrument.js';
|
|
1
|
+
import { AnchorKind, InstrumentationGapKind } from '@reticlehq/core';
|
|
3
2
|
/**
|
|
4
3
|
* Bridge domain gaps → LOCATED instrumentation gaps. A flow that asserts no consequence should emit one —
|
|
5
4
|
* and the flow's own step anchors carry the source file:line the babel/next plugin stamped, so we know
|
|
@@ -22,8 +21,8 @@ export function lastSource(steps) {
|
|
|
22
21
|
return found;
|
|
23
22
|
}
|
|
24
23
|
/**
|
|
25
|
-
* Turn unasserted flows into
|
|
26
|
-
* source are skipped (no location to propose). The suggested signal name is `<flow>:done`.
|
|
24
|
+
* Turn unasserted flows into no-signal-on-mutation gaps at each flow's source location. Flows with
|
|
25
|
+
* no stamped source are skipped (no location to propose). The suggested signal name is `<flow>:done`.
|
|
27
26
|
*/
|
|
28
27
|
export function instrumentationGapsForFlows(unassertedFlows, flowStepsByName) {
|
|
29
28
|
const gaps = [];
|
|
@@ -33,7 +32,7 @@ export function instrumentationGapsForFlows(unassertedFlows, flowStepsByName) {
|
|
|
33
32
|
if (source === undefined)
|
|
34
33
|
continue;
|
|
35
34
|
gaps.push({
|
|
36
|
-
kind: InstrumentationGapKind.
|
|
35
|
+
kind: InstrumentationGapKind.NO_SIGNAL_ON_MUTATION,
|
|
37
36
|
file: source.file,
|
|
38
37
|
line: source.line,
|
|
39
38
|
name: `${name}:done`,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EventType, PredicateKind } from '@reticlehq/core';
|
|
2
|
+
import { routePathOf } from '../events/predicate-route.js';
|
|
2
3
|
const TIER = { SIGNAL: 0, CONSEQUENCE: 1, PRESENCE: 2 };
|
|
3
4
|
function pathname(url) {
|
|
4
5
|
if (typeof url !== 'string')
|
|
@@ -66,10 +67,18 @@ export function proposeConsequences(events) {
|
|
|
66
67
|
break;
|
|
67
68
|
}
|
|
68
69
|
case EventType.ROUTE_CHANGE: {
|
|
69
|
-
const
|
|
70
|
-
if ('string' === typeof
|
|
70
|
+
const docPath = data['pathname'];
|
|
71
|
+
if ('string' === typeof docPath) {
|
|
72
|
+
// `pathname`, not `to`: the evaluator has never accepted `to`, so this surface was handing
|
|
73
|
+
// the agent a predicate reticle_assert refuses with "unknown field to". A proposal that
|
|
74
|
+
// cannot be evaluated is worse than no proposal — see the schema check in the test.
|
|
75
|
+
//
|
|
76
|
+
// And the ROUTER's path, not the document's: under a hash router the document pathname is
|
|
77
|
+
// `/` on every page, so proposing it proposes an assertion that says nothing about where
|
|
78
|
+
// the app went.
|
|
79
|
+
const to = routePathOf(docPath, 'string' === typeof data['hash'] ? data['hash'] : '');
|
|
71
80
|
add(`route:${to}`, {
|
|
72
|
-
predicate: { kind: PredicateKind.ROUTE, to },
|
|
81
|
+
predicate: { kind: PredicateKind.ROUTE, pathname: to },
|
|
73
82
|
tier: TIER.CONSEQUENCE,
|
|
74
83
|
label: `route changes to ${to}`,
|
|
75
84
|
weak: false,
|
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
* apply instrumentation proposals as concrete diffs, so the AGENT closes the gap and the app's
|
|
5
5
|
* observability compounds run over run — instead of a human being a prerequisite. Deterministic mapping
|
|
6
6
|
* from a located gap to the code to insert; pure and testable. Result-enrichment wiring is a later step.
|
|
7
|
+
*
|
|
8
|
+
* Kinds come from `@reticlehq/core`. A second enum here is how `reticle_domain` used to say
|
|
9
|
+
* `missing-signal` while honesty said `no-signal-on-mutation` for the same absence.
|
|
7
10
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export type InstrumentationGapKind = (typeof InstrumentationGapKind)[keyof typeof InstrumentationGapKind];
|
|
14
|
-
export interface InstrumentationGap {
|
|
15
|
-
kind: InstrumentationGapKind;
|
|
11
|
+
import { InstrumentationGapKind } from '@reticlehq/core';
|
|
12
|
+
/** The three core kinds a located proposal can close. Other kinds are verdict-side, not insert-side. */
|
|
13
|
+
export type LocatableGapKind = typeof InstrumentationGapKind.NO_SIGNAL_ON_MUTATION | typeof InstrumentationGapKind.NO_STORE_REGISTERED | typeof InstrumentationGapKind.MISSING_TESTID;
|
|
14
|
+
export interface LocatedGap {
|
|
15
|
+
kind: LocatableGapKind;
|
|
16
16
|
file: string;
|
|
17
17
|
line: number;
|
|
18
18
|
/** The name to instrument with — a signal name, store name, or testid. */
|
|
@@ -28,5 +28,5 @@ interface InstrumentationProposal {
|
|
|
28
28
|
rationale: string;
|
|
29
29
|
}
|
|
30
30
|
/** Turn located capability gaps into ready-to-apply instrumentation proposals. Deterministic. */
|
|
31
|
-
export declare function proposeInstrumentation(gaps: readonly
|
|
31
|
+
export declare function proposeInstrumentation(gaps: readonly LocatedGap[]): InstrumentationProposal[];
|
|
32
32
|
export {};
|
|
@@ -4,33 +4,39 @@
|
|
|
4
4
|
* apply instrumentation proposals as concrete diffs, so the AGENT closes the gap and the app's
|
|
5
5
|
* observability compounds run over run — instead of a human being a prerequisite. Deterministic mapping
|
|
6
6
|
* from a located gap to the code to insert; pure and testable. Result-enrichment wiring is a later step.
|
|
7
|
+
*
|
|
8
|
+
* Kinds come from `@reticlehq/core`. A second enum here is how `reticle_domain` used to say
|
|
9
|
+
* `missing-signal` while honesty said `no-signal-on-mutation` for the same absence.
|
|
7
10
|
*/
|
|
8
|
-
|
|
9
|
-
MISSING_SIGNAL: 'missing-signal',
|
|
10
|
-
UNREGISTERED_STORE: 'unregistered-store',
|
|
11
|
-
MISSING_TESTID: 'missing-testid',
|
|
12
|
-
};
|
|
11
|
+
import { InstrumentationGapKind } from '@reticlehq/core';
|
|
13
12
|
/** PascalCase a store name for a `useX.getState` hint (cart → Cart). */
|
|
14
13
|
function pascal(name) {
|
|
15
14
|
return 0 === name.length ? name : name[0]?.toUpperCase() + name.slice(1);
|
|
16
15
|
}
|
|
17
16
|
function insertFor(gap) {
|
|
18
17
|
switch (gap.kind) {
|
|
19
|
-
case InstrumentationGapKind.
|
|
18
|
+
case InstrumentationGapKind.NO_SIGNAL_ON_MUTATION:
|
|
20
19
|
return `reticle.signal('${gap.name}');`;
|
|
21
|
-
case InstrumentationGapKind.
|
|
20
|
+
case InstrumentationGapKind.NO_STORE_REGISTERED:
|
|
22
21
|
return `registerStore('${gap.name}', () => use${pascal(gap.name)}.getState());`;
|
|
23
22
|
case InstrumentationGapKind.MISSING_TESTID:
|
|
24
23
|
return `data-testid="${gap.name}"`;
|
|
25
24
|
}
|
|
26
25
|
}
|
|
27
26
|
function rationaleFor(gap) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
let base;
|
|
28
|
+
switch (gap.kind) {
|
|
29
|
+
case InstrumentationGapKind.NO_SIGNAL_ON_MUTATION:
|
|
30
|
+
base = `emit a consequence signal so verification proves the outcome, not just presence`;
|
|
31
|
+
break;
|
|
32
|
+
case InstrumentationGapKind.NO_STORE_REGISTERED:
|
|
33
|
+
base = `register the store so state assertions can read the source of truth`;
|
|
34
|
+
break;
|
|
35
|
+
case InstrumentationGapKind.MISSING_TESTID:
|
|
36
|
+
base = `add a stable testid so the anchor survives refactors`;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
return undefined === gap.context ? base : `${base} — ${gap.context}`;
|
|
34
40
|
}
|
|
35
41
|
/** Turn located capability gaps into ready-to-apply instrumentation proposals. Deterministic. */
|
|
36
42
|
export function proposeInstrumentation(gaps) {
|