@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
|
@@ -13,61 +13,99 @@ async function queryFirst(session, q) {
|
|
|
13
13
|
return undefined;
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
|
-
* A note attached to `{ found: false, exhausted: true }` only when the failure is
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* A note attached to `{ found: false, exhausted: true }` only when the failure is actually
|
|
17
|
+
* informative: nothing in the container ever moved (so the "list" being searched was never
|
|
18
|
+
* scrollable and the target is likely inside one with its own scroll container). Reaching the
|
|
19
|
+
* genuine ends of a container that DID scroll stays quiet — that is exhaustion, not confusion.
|
|
20
20
|
*/
|
|
21
|
-
function exhaustNote(q, data) {
|
|
21
|
+
function exhaustNote(q, data, nothingEverScrolled) {
|
|
22
22
|
if (q.container !== undefined)
|
|
23
23
|
return {};
|
|
24
|
-
if (
|
|
24
|
+
if (true === data['scrolled'] || !nothingEverScrolled)
|
|
25
25
|
return {};
|
|
26
26
|
return {
|
|
27
27
|
note: "The document did not scroll — the target may be inside a list with its own scroll container. Pass that container's ref as `container`.",
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
+
/** One viewport-height step upward when the last result carried no clientHeight to size it by. */
|
|
31
|
+
const UP_STEP_FALLBACK_PX = 400;
|
|
30
32
|
/**
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
* Size the upward step off the container the SCROLL result just described, falling back to a
|
|
34
|
+
* plain viewport height when the result did not carry one.
|
|
35
|
+
*/
|
|
36
|
+
function upStepPx(last) {
|
|
37
|
+
const h = last['clientHeight'];
|
|
38
|
+
return 'number' === typeof h && h > 0 ? h : UP_STEP_FALLBACK_PX;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Reveal an element that a windowed/virtualized list has not mounted yet. Queries once (it may
|
|
42
|
+
* already be visible), optionally jumps straight to a bisection estimate, then walks the container
|
|
43
|
+
* a viewport at a time re-querying after each step. Downward first; when the bottom is reached the
|
|
44
|
+
* walk TURNS AROUND and continues upward, because a list that is already scrolled to its end keeps
|
|
45
|
+
* its earlier rows mounted above the viewport and a downward-only search answered "exhausted" on
|
|
46
|
+
* its first step (#505). `exhausted` therefore means BOTH directions are spent, not "the bottom is
|
|
47
|
+
* here". Pure orchestration over the session command seam — fully unit-testable with a fake.
|
|
35
48
|
*/
|
|
36
49
|
export async function scrollToFind(session, q, opts = {}) {
|
|
37
50
|
const max = opts.maxScrolls ?? SCROLL_FIND_DEFAULTS.MAX_SCROLLS;
|
|
38
51
|
const first = await queryFirst(session, q);
|
|
39
52
|
if (first !== undefined)
|
|
40
53
|
return { found: true, element: first, scrolls: 0, exhausted: false };
|
|
41
|
-
|
|
42
|
-
// in one scroll command rather than stepping a viewport at a time. Then refine linearly.
|
|
54
|
+
const baseArgs = () => q.container !== undefined ? { ref: q.container } : {};
|
|
43
55
|
let scrolls = 0;
|
|
56
|
+
let last = {};
|
|
57
|
+
// Bisection: if the caller knows the target index and list size, jump to the estimated offset in
|
|
58
|
+
// one scroll command rather than stepping a viewport at a time. The estimate can land on either
|
|
59
|
+
// side of the target, so refinement below still searches both directions from wherever this put us.
|
|
44
60
|
if (q.targetIndex !== undefined && q.totalCount !== undefined && q.totalCount > 1) {
|
|
45
61
|
const fraction = Math.min(1, Math.max(0, q.targetIndex / q.totalCount));
|
|
46
|
-
const sr = await session.command(ReticleCommand.SCROLL, {
|
|
47
|
-
...(q.container !== undefined ? { ref: q.container } : {}),
|
|
48
|
-
fraction,
|
|
49
|
-
});
|
|
62
|
+
const sr = await session.command(ReticleCommand.SCROLL, { ...baseArgs(), fraction });
|
|
50
63
|
scrolls += 1;
|
|
64
|
+
last = asRecord(sr.result);
|
|
51
65
|
const hit = await queryFirst(session, q);
|
|
52
66
|
if (hit !== undefined)
|
|
53
67
|
return { found: true, element: hit, scrolls, exhausted: false };
|
|
54
|
-
|
|
68
|
+
}
|
|
69
|
+
let downwardSpent = false;
|
|
70
|
+
let everScrolled = false;
|
|
71
|
+
// The downward pass. Spending its whole budget without reaching the end means rows may remain
|
|
72
|
+
// further down, so that answer is `exhausted:false` and the upward pass never runs.
|
|
73
|
+
for (let i = 0; i < max && !downwardSpent; i += 1) {
|
|
74
|
+
const sr = await session.command(ReticleCommand.SCROLL, baseArgs());
|
|
75
|
+
scrolls += 1;
|
|
55
76
|
const data = asRecord(sr.result);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
77
|
+
last = data;
|
|
78
|
+
if (true === data['scrolled'])
|
|
79
|
+
everScrolled = true;
|
|
80
|
+
const hit = await queryFirst(session, q);
|
|
81
|
+
if (hit !== undefined)
|
|
82
|
+
return { found: true, element: hit, scrolls, exhausted: false };
|
|
83
|
+
// Reached the bottom, or the container would not move downward — turn around before giving up.
|
|
84
|
+
if (true === data['atEnd'] || true !== data['scrolled'])
|
|
85
|
+
downwardSpent = true;
|
|
86
|
+
}
|
|
87
|
+
// If the downward pass spent its budget it never saw the end, so there is nothing to turn around
|
|
88
|
+
// for; report honestly rather than doubling a call whose caller asked for `max` steps.
|
|
89
|
+
if (!downwardSpent) {
|
|
90
|
+
return { found: false, scrolls, exhausted: false };
|
|
59
91
|
}
|
|
92
|
+
// The upward pass gets the caller's budget again, not what is left of it: a list at the bottom of
|
|
93
|
+
// 14k px needs ~90 scrolls to reach its end and ~90 more to get back, so sharing one budget would
|
|
94
|
+
// strand the search halfway and answer `exhausted:false` about a list both of whose ends are known.
|
|
60
95
|
for (let i = 0; i < max; i += 1) {
|
|
61
|
-
const sr = await session.command(ReticleCommand.SCROLL,
|
|
96
|
+
const sr = await session.command(ReticleCommand.SCROLL, { ...baseArgs(), dy: -upStepPx(last) });
|
|
62
97
|
scrolls += 1;
|
|
63
98
|
const data = asRecord(sr.result);
|
|
99
|
+
last = data;
|
|
100
|
+
if (true === data['scrolled'])
|
|
101
|
+
everScrolled = true;
|
|
64
102
|
const hit = await queryFirst(session, q);
|
|
65
103
|
if (hit !== undefined)
|
|
66
104
|
return { found: true, element: hit, scrolls, exhausted: false };
|
|
67
|
-
//
|
|
68
|
-
if (true
|
|
69
|
-
return { found: false, scrolls, exhausted: true, ...exhaustNote(q, data) };
|
|
105
|
+
// The top refusing to move means both directions are spent.
|
|
106
|
+
if (true !== data['scrolled']) {
|
|
107
|
+
return { found: false, scrolls, exhausted: true, ...exhaustNote(q, data, !everScrolled) };
|
|
70
108
|
}
|
|
71
109
|
}
|
|
72
|
-
return { found: false, scrolls, exhausted: false }; // spent the budget; more may lie
|
|
110
|
+
return { found: false, scrolls, exhausted: false }; // spent the upward budget; more may lie above
|
|
73
111
|
}
|
|
@@ -2,6 +2,7 @@ import { z } from 'zod';
|
|
|
2
2
|
import { QueryBy } from '@reticlehq/core';
|
|
3
3
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
4
4
|
import { asNumber, asString } from '../tools/tools-helpers.js';
|
|
5
|
+
import { listIndexSchema, scrollCountSchema } from '../tools/numeric-bounds.js';
|
|
5
6
|
import { scrollToFind } from './scroll-find.js';
|
|
6
7
|
/**
|
|
7
8
|
* reticle_scroll_to — the windowed/virtualized-list escape hatch. A plain reticle_query
|
|
@@ -30,16 +31,13 @@ export const SCROLL_TOOLS = [
|
|
|
30
31
|
.string()
|
|
31
32
|
.optional()
|
|
32
33
|
.describe('Element ref for the scrollable container. Omit to scroll the document.'),
|
|
33
|
-
maxScrolls:
|
|
34
|
-
.number()
|
|
34
|
+
maxScrolls: scrollCountSchema
|
|
35
35
|
.optional()
|
|
36
36
|
.describe('Maximum number of scroll steps before giving up. Default: 20.'),
|
|
37
|
-
targetIndex:
|
|
38
|
-
.number()
|
|
37
|
+
targetIndex: listIndexSchema
|
|
39
38
|
.optional()
|
|
40
39
|
.describe('Known row index of the target in the list. Combine with totalCount for bisection — jumps directly to the estimated offset.'),
|
|
41
|
-
totalCount:
|
|
42
|
-
.number()
|
|
40
|
+
totalCount: listIndexSchema
|
|
43
41
|
.optional()
|
|
44
42
|
.describe('Total item count in the virtualized list. Required for bisection with targetIndex.'),
|
|
45
43
|
sessionId: z
|
|
@@ -2,10 +2,11 @@ import { z } from 'zod';
|
|
|
2
2
|
import { CDP_NO_PROVIDER_REASON, CDP_NO_PROVIDER_RECOMMENDATION } from '@reticlehq/core';
|
|
3
3
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
4
4
|
import { sessionIdShape } from '../tools/tool-kit.js';
|
|
5
|
+
import { MAX_VIEWPORT_PX, MIN_VIEWPORT_PX, viewportPxSchema } from '../tools/numeric-bounds.js';
|
|
5
6
|
import { asString } from '../tools/tools-helpers.js';
|
|
6
7
|
/** Bounds so a viewport request stays sane (and a typo can't ask for a 1px or 100k-px window). */
|
|
7
|
-
const MIN_DIM =
|
|
8
|
-
const MAX_DIM =
|
|
8
|
+
const MIN_DIM = MIN_VIEWPORT_PX;
|
|
9
|
+
const MAX_DIM = MAX_VIEWPORT_PX;
|
|
9
10
|
function viewportProvider(deps) {
|
|
10
11
|
const p = deps.realInput;
|
|
11
12
|
return p !== undefined && 'function' === typeof p.setViewport
|
|
@@ -20,8 +21,8 @@ export const VIEWPORT_TOOLS = [
|
|
|
20
21
|
'reticle_visual_diff `masks` and a frozen clock (reticle_clock). Set it once before reticle_screenshot / ' +
|
|
21
22
|
'reticle_visual_diff. Returns { applied, width, height } or the no-provider recommendation.',
|
|
22
23
|
inputSchema: {
|
|
23
|
-
width:
|
|
24
|
-
height:
|
|
24
|
+
width: viewportPxSchema.describe('Viewport width in CSS px (e.g. 1280).'),
|
|
25
|
+
height: viewportPxSchema.describe('Viewport height in CSS px (e.g. 800).'),
|
|
25
26
|
...sessionIdShape,
|
|
26
27
|
},
|
|
27
28
|
outputSchema: {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ToolDeps } from '../tools/tool-kit.js';
|
|
2
|
+
/**
|
|
3
|
+
* The ledger id a piece of inline prose is declared under.
|
|
4
|
+
*
|
|
5
|
+
* Derived from the statement rather than minted, so the same sentence declared on five verdicts is
|
|
6
|
+
* one row rather than five, and a DIFFERENT sentence is a different row rather than a false
|
|
7
|
+
* amendment of the first. The slug is there because the id is what an agent later types to reference
|
|
8
|
+
* the intent, and a bare digest is unreadable; the digest is there because the slug is truncated and
|
|
9
|
+
* two long statements sharing a prefix must not share a row.
|
|
10
|
+
*/
|
|
11
|
+
export declare function inlineIntentId(statement: string): string;
|
|
12
|
+
/** What `provenBy` records: which tool drew the verdict, and when. */
|
|
13
|
+
export declare function inlineVerdictId(tool: string, at: number): string;
|
|
14
|
+
export declare function surfaceForInlineIntent(url: string | undefined, flow: string | undefined,
|
|
15
|
+
/** `file` or `file:line` for the element the verdict acted on, when it had one. */
|
|
16
|
+
sourceLabel?: string): {
|
|
17
|
+
route?: string;
|
|
18
|
+
flow?: string;
|
|
19
|
+
files?: string[];
|
|
20
|
+
} | undefined;
|
|
21
|
+
export declare function linkInlineIntent(deps: ToolDeps, sessionId: string | undefined, intent: string | undefined,
|
|
22
|
+
/** The predicate this verdict will evaluate, or undefined when it proves nothing (a bare settle). */
|
|
23
|
+
binding: unknown): Promise<string | undefined>;
|
|
24
|
+
/**
|
|
25
|
+
* Record that this verdict proved the intent. Call only for a verdict that actually proved something.
|
|
26
|
+
*
|
|
27
|
+
* The ledger's own rule does the rest: `dischargeIntent` refuses an intent with no binding, so an
|
|
28
|
+
* intent declared inline on a wait that asserted no consequence stays open and honest instead of
|
|
29
|
+
* collecting a proof nothing earned.
|
|
30
|
+
*/
|
|
31
|
+
export declare function dischargeInlineIntent(deps: ToolDeps, sessionId: string | undefined, id: string | undefined, proof: {
|
|
32
|
+
verdictId: string;
|
|
33
|
+
grade: string;
|
|
34
|
+
at: number;
|
|
35
|
+
},
|
|
36
|
+
/** `file:line` of the element this verdict acted on, when there was one. */
|
|
37
|
+
sourceLabel?: string): Promise<void>;
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { IntentStore } from './intent-store.js';
|
|
3
|
+
import { sessionRoot } from '../project/session-root.js';
|
|
4
|
+
/**
|
|
5
|
+
* Intent declared INLINE, on the tool that is already drawing the verdict.
|
|
6
|
+
*
|
|
7
|
+
* `reticle_intent` is on the extended surface, so declaring intent costs an agent a discovery, a
|
|
8
|
+
* decision and a round trip before it has done anything — three places the capture silently fails,
|
|
9
|
+
* and it does. `reticle_act_and_wait` and `reticle_assert` are in every agent's tool list already,
|
|
10
|
+
* so one optional argument there makes the declaration free and discoverable by construction.
|
|
11
|
+
*
|
|
12
|
+
* This is a shortcut into the EXISTING ledger, never a second one. It writes `.reticle/intent.json`
|
|
13
|
+
* through `IntentStore` exactly as `reticle_intent { action: "declare" }` does, so a reviewer reads
|
|
14
|
+
* one file in one vocabulary and cannot tell from the row which door the intent came in by. The
|
|
15
|
+
* pattern is `flows/flow-intent.ts`, which does the same job for a saved flow.
|
|
16
|
+
*/
|
|
17
|
+
/** Namespaced like `flow:`, so an inline id never collides with one an agent chose by hand. */
|
|
18
|
+
const INLINE_INTENT_ID_PREFIX = 'inline:';
|
|
19
|
+
const ID_SEPARATOR = ':';
|
|
20
|
+
const SLUG_SEPARATOR = '-';
|
|
21
|
+
const SLUG_MAX = 48;
|
|
22
|
+
const HASH_LENGTH = 8;
|
|
23
|
+
const HASH_ALGORITHM = 'sha1';
|
|
24
|
+
const NON_SLUG = /[^a-z0-9]+/g;
|
|
25
|
+
const SLUG_EDGES = /^-+|-+$/g;
|
|
26
|
+
/**
|
|
27
|
+
* The ledger id a piece of inline prose is declared under.
|
|
28
|
+
*
|
|
29
|
+
* Derived from the statement rather than minted, so the same sentence declared on five verdicts is
|
|
30
|
+
* one row rather than five, and a DIFFERENT sentence is a different row rather than a false
|
|
31
|
+
* amendment of the first. The slug is there because the id is what an agent later types to reference
|
|
32
|
+
* the intent, and a bare digest is unreadable; the digest is there because the slug is truncated and
|
|
33
|
+
* two long statements sharing a prefix must not share a row.
|
|
34
|
+
*/
|
|
35
|
+
export function inlineIntentId(statement) {
|
|
36
|
+
const slug = statement
|
|
37
|
+
.toLowerCase()
|
|
38
|
+
.replace(NON_SLUG, SLUG_SEPARATOR)
|
|
39
|
+
.replace(SLUG_EDGES, '')
|
|
40
|
+
.slice(0, SLUG_MAX)
|
|
41
|
+
.replace(SLUG_EDGES, '');
|
|
42
|
+
const digest = createHash(HASH_ALGORITHM).update(statement).digest('hex').slice(0, HASH_LENGTH);
|
|
43
|
+
return `${INLINE_INTENT_ID_PREFIX}${slug}${SLUG_SEPARATOR}${digest}`;
|
|
44
|
+
}
|
|
45
|
+
/** What `provenBy` records: which tool drew the verdict, and when. */
|
|
46
|
+
export function inlineVerdictId(tool, at) {
|
|
47
|
+
return `${tool}${ID_SEPARATOR}${String(at)}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Put an inline intent in the ledger and attach the predicate about to be evaluated. Returns the id
|
|
51
|
+
* the verdict may later discharge, or undefined when there was no intent to record.
|
|
52
|
+
*
|
|
53
|
+
* `intent` carries EITHER prose OR the id of an intent already in the ledger. One field rather than
|
|
54
|
+
* two because the surface is the scarce thing here and the two cases are told apart by the ledger
|
|
55
|
+
* itself: a string that names an existing row is a reference, anything else is prose. A statement
|
|
56
|
+
* that happens to equal an existing id is the same intent said twice, so pointing at the row is the
|
|
57
|
+
* right answer there too, not a collision.
|
|
58
|
+
*
|
|
59
|
+
* A referenced intent is never re-declared, which would overwrite the agent's own words with an id,
|
|
60
|
+
* and its binding is left alone when it already has one — a predicate bound deliberately through
|
|
61
|
+
* `reticle_intent { action: "bind" }` is a stronger statement than whatever this one call asserts,
|
|
62
|
+
* and quietly replacing it is exactly the narrowing the ledger exists to make visible.
|
|
63
|
+
*
|
|
64
|
+
* Best-effort by construction: a ledger that cannot be written is a small problem, and a verdict
|
|
65
|
+
* that fails to return because of one is a large problem.
|
|
66
|
+
*/
|
|
67
|
+
/**
|
|
68
|
+
* The surface an inline intent was captured on, so the store can FILE it.
|
|
69
|
+
*
|
|
70
|
+
* Measured on a real corpus: 167 of 173 things a project knew landed in `unsorted`, because
|
|
71
|
+
* `act_and_wait({ intent })` declared a statement and nothing else. The subject ladder had no flow,
|
|
72
|
+
* no route and no explicit subject to work from, so every record fell to the bucket of last resort
|
|
73
|
+
* — and a coverage map that is one pile with six labels tells a manager the team knows nothing,
|
|
74
|
+
* when the truth is that it knows a great deal and none of it is filed.
|
|
75
|
+
*
|
|
76
|
+
* The ROUTE is what makes this work at all, because it is always available: an agent asserting
|
|
77
|
+
* something is always somewhere. A flow name is better when there is one, and `subjectFor` already
|
|
78
|
+
* prefers it — this only has to supply both and let that ladder decide.
|
|
79
|
+
*
|
|
80
|
+
* Query and hash are dropped. `/issues?category=severe` and `/issues` are the same subject seen
|
|
81
|
+
* twice; keeping the query would shard one area of the product across every filter anybody used.
|
|
82
|
+
*
|
|
83
|
+
* Returns undefined rather than an empty object when there is nothing to record. A surface that
|
|
84
|
+
* says nothing reads as a capture that looked for a location and found none, rather than one that
|
|
85
|
+
* never had one — and the second is the truth.
|
|
86
|
+
*/
|
|
87
|
+
/**
|
|
88
|
+
* Strip a trailing `:line` from a `file:line` label.
|
|
89
|
+
*
|
|
90
|
+
* Anchored to the END and to digits, because a Windows path carries its own colon: splitting on the
|
|
91
|
+
* first one turns `C:\\app\\src\\cart.tsx:12` into `C`, which is a path to nothing and would be
|
|
92
|
+
* filed as though it were real.
|
|
93
|
+
*/
|
|
94
|
+
const SOURCE_LINE_SUFFIX = /:\d+$/;
|
|
95
|
+
export function surfaceForInlineIntent(url, flow,
|
|
96
|
+
/** `file` or `file:line` for the element the verdict acted on, when it had one. */
|
|
97
|
+
sourceLabel) {
|
|
98
|
+
let route;
|
|
99
|
+
if (url !== undefined) {
|
|
100
|
+
try {
|
|
101
|
+
const path = new URL(url).pathname;
|
|
102
|
+
// A bare origin has no path worth filing under: `/` would put every record in one bucket,
|
|
103
|
+
// which is the problem this exists to fix rather than a solution to it.
|
|
104
|
+
if (path.length > 1)
|
|
105
|
+
route = path;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
route = undefined;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/*
|
|
112
|
+
* The file, without its line.
|
|
113
|
+
*
|
|
114
|
+
* A record is about a FILE; the line is where one verdict happened to touch it, and keeping it
|
|
115
|
+
* would make the same rule look like a different one every time the file was edited above it.
|
|
116
|
+
*/
|
|
117
|
+
const file = sourceLabel === undefined || 0 === sourceLabel.length
|
|
118
|
+
? undefined
|
|
119
|
+
: sourceLabel.replace(SOURCE_LINE_SUFFIX, '');
|
|
120
|
+
if (route === undefined && flow === undefined && file === undefined)
|
|
121
|
+
return undefined;
|
|
122
|
+
return {
|
|
123
|
+
...(route === undefined ? {} : { route }),
|
|
124
|
+
...(flow === undefined ? {} : { flow }),
|
|
125
|
+
...(file === undefined ? {} : { files: [file] }),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The session's live URL, or undefined when no session can be named.
|
|
130
|
+
*
|
|
131
|
+
* `sessions.resolve` throws for every "cannot tell which tab" case, and none of them is a reason to
|
|
132
|
+
* fail the caller's verdict — a missing surface costs a filing, not a result.
|
|
133
|
+
*/
|
|
134
|
+
function sessionUrl(deps, sessionId) {
|
|
135
|
+
try {
|
|
136
|
+
return deps.sessions.resolve(sessionId).url;
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
return undefined;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
export async function linkInlineIntent(deps, sessionId, intent,
|
|
143
|
+
/** The predicate this verdict will evaluate, or undefined when it proves nothing (a bare settle). */
|
|
144
|
+
binding) {
|
|
145
|
+
if (intent === undefined || 0 === intent.trim().length)
|
|
146
|
+
return undefined;
|
|
147
|
+
try {
|
|
148
|
+
const store = new IntentStore(deps.fs, sessionRoot(deps, sessionId), { now: deps.now });
|
|
149
|
+
const existing = (await store.read()).find((row) => row.id === intent);
|
|
150
|
+
const id = existing?.id ?? inlineIntentId(intent);
|
|
151
|
+
// Declared WITHOUT a surface on purpose: see dischargeInlineIntent for why the route that
|
|
152
|
+
// describes this record only exists after the action it is about.
|
|
153
|
+
if (existing === undefined)
|
|
154
|
+
await store.declare([{ id, statement: intent }]);
|
|
155
|
+
if (binding !== undefined && existing?.binding === undefined)
|
|
156
|
+
await store.bind(id, binding);
|
|
157
|
+
return id;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
return undefined;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Record that this verdict proved the intent. Call only for a verdict that actually proved something.
|
|
165
|
+
*
|
|
166
|
+
* The ledger's own rule does the rest: `dischargeIntent` refuses an intent with no binding, so an
|
|
167
|
+
* intent declared inline on a wait that asserted no consequence stays open and honest instead of
|
|
168
|
+
* collecting a proof nothing earned.
|
|
169
|
+
*/
|
|
170
|
+
export async function dischargeInlineIntent(deps, sessionId, id, proof,
|
|
171
|
+
/** `file:line` of the element this verdict acted on, when there was one. */
|
|
172
|
+
sourceLabel) {
|
|
173
|
+
if (id === undefined)
|
|
174
|
+
return;
|
|
175
|
+
try {
|
|
176
|
+
const store = new IntentStore(deps.fs, sessionRoot(deps, sessionId), { now: deps.now });
|
|
177
|
+
/*
|
|
178
|
+
* File it HERE, not at declaration.
|
|
179
|
+
*
|
|
180
|
+
* The intent is declared before the action so a verdict can see it open, and at that instant the
|
|
181
|
+
* agent is still on the page it is leaving — clicking through to /issues from / would have filed
|
|
182
|
+
* the record under the page it left, or under nothing at all. The route that describes what the
|
|
183
|
+
* intent is about is the one that exists once the consequence has landed.
|
|
184
|
+
*/
|
|
185
|
+
const surface = surfaceForInlineIntent(sessionUrl(deps, sessionId), undefined, sourceLabel);
|
|
186
|
+
if (surface !== undefined)
|
|
187
|
+
await store.place(id, surface);
|
|
188
|
+
await store.discharge(id, proof);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// The verdict already stood. The proof is simply not recorded — see dischargeFlowIntent.
|
|
192
|
+
}
|
|
193
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading and writing the sharded intent store, and migrating the flat one into it.
|
|
3
|
+
*
|
|
4
|
+
* The operations an agent actually performs, and what each is allowed to cost:
|
|
5
|
+
*
|
|
6
|
+
* index() every id + one line, always affordable — the session-start read
|
|
7
|
+
* subject(name) the full records for one subject, when it is about to work on that
|
|
8
|
+
* get(id) one record, via the index rather than by scanning shards
|
|
9
|
+
* record()/update() a write that touches ONE shard file plus the index
|
|
10
|
+
*
|
|
11
|
+
* The last one is the reason for the whole design. Under the flat file, changing one intent rewrote
|
|
12
|
+
* all 141, so two sessions touching unrelated subjects raced each other and the loser's write
|
|
13
|
+
* vanished. Sharded, they only collide when they genuinely edit the same subject.
|
|
14
|
+
*
|
|
15
|
+
* ## Migration is automatic, and it does not delete
|
|
16
|
+
*
|
|
17
|
+
* `.reticle/intent.json` is read on every load and folded in when the sharded copy has nothing for
|
|
18
|
+
* an id. That makes the move invisible: an agent on the new store sees old intents immediately, and
|
|
19
|
+
* an older build still reading the flat file keeps working, because nothing removes it. Deleting it
|
|
20
|
+
* is a separate decision somebody can take once they believe the migration.
|
|
21
|
+
*/
|
|
22
|
+
import { type Intent } from '@reticlehq/core';
|
|
23
|
+
import type { FileSystemPort } from '../project/fs-port.js';
|
|
24
|
+
import { IntentStatus, type IntentIndex, type IntentRecord } from './intent-shard.js';
|
|
25
|
+
export interface Clock {
|
|
26
|
+
now: () => number;
|
|
27
|
+
}
|
|
28
|
+
/** What a caller supplies to write an intent. Everything optional is genuinely optional. */
|
|
29
|
+
export interface IntentInput {
|
|
30
|
+
id: string;
|
|
31
|
+
statement: string;
|
|
32
|
+
subject?: string | undefined;
|
|
33
|
+
why?: string | undefined;
|
|
34
|
+
source?: string | undefined;
|
|
35
|
+
status?: IntentStatus | undefined;
|
|
36
|
+
surface?: Intent['surface'];
|
|
37
|
+
binding?: unknown;
|
|
38
|
+
}
|
|
39
|
+
export declare class IntentShardStore {
|
|
40
|
+
#private;
|
|
41
|
+
constructor(fs: FileSystemPort, root: string, clock: Clock);
|
|
42
|
+
/**
|
|
43
|
+
* The cheap read: one line per intent, and the call an agent makes at the start of a session.
|
|
44
|
+
*
|
|
45
|
+
* Includes anything still only in the legacy flat file, so the very first call on an unmigrated
|
|
46
|
+
* project already answers completely — which is what makes the migration invisible rather than a
|
|
47
|
+
* step somebody has to remember to run.
|
|
48
|
+
*/
|
|
49
|
+
index(): Promise<IntentIndex>;
|
|
50
|
+
/** Every record for one subject — the working read, once an agent knows what it is touching. */
|
|
51
|
+
subject(name: string): Promise<IntentRecord[]>;
|
|
52
|
+
/** One record by id, or null. */
|
|
53
|
+
get(id: string): Promise<IntentRecord | null>;
|
|
54
|
+
/**
|
|
55
|
+
* Write one intent, creating or updating it.
|
|
56
|
+
*
|
|
57
|
+
* Merges onto whatever is already stored, so a caller adding a `why` to a migrated record does not
|
|
58
|
+
* have to restate its binding — and cannot silently drop it by omission, which is the failure mode
|
|
59
|
+
* that makes agents afraid to touch a store.
|
|
60
|
+
*/
|
|
61
|
+
record(input: IntentInput): Promise<IntentRecord>;
|
|
62
|
+
/**
|
|
63
|
+
* Fold the flat file into shards on disk, so the move is visible in a diff rather than implicit.
|
|
64
|
+
*
|
|
65
|
+
* Idempotent, and it does not delete `.reticle/intent.json`: an older build still reads it, and a
|
|
66
|
+
* migration that removes its own source cannot be checked afterwards.
|
|
67
|
+
*/
|
|
68
|
+
migrate(): Promise<{
|
|
69
|
+
migrated: number;
|
|
70
|
+
subjects: string[];
|
|
71
|
+
}>;
|
|
72
|
+
}
|