@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
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { span } from '../trace.js';
|
|
2
|
+
import { routePathOf } from '../events/predicate-route.js';
|
|
2
3
|
import { AnchorKind, DriftReason, EventType, ReticleCommand, QueryBy, PredicateKind, } from '@reticlehq/core';
|
|
3
4
|
import { asRecord, asString } from '../tools/tools-helpers.js';
|
|
4
5
|
import { replayActionArgs, ambiguousTestidNote, queryRefs } from './replay.js';
|
|
@@ -198,8 +199,14 @@ function currentRoute(session) {
|
|
|
198
199
|
if (last === undefined)
|
|
199
200
|
return undefined;
|
|
200
201
|
const data = last.data ?? {};
|
|
202
|
+
// The ROUTER's path. This field answers "which page did this step run on", and the document
|
|
203
|
+
// pathname is `/` on every page of a hash-routed app — so a whole desktop replay reported `/` for
|
|
204
|
+
// every step. Sixth place the same reading was wrong; see routePathOf.
|
|
201
205
|
const pathname = asString(data['pathname']) ?? asString(data['to']);
|
|
202
|
-
|
|
206
|
+
if (pathname === undefined || 0 === pathname.length)
|
|
207
|
+
return undefined;
|
|
208
|
+
const routed = routePathOf(pathname, asString(data['hash']) ?? '');
|
|
209
|
+
return routed.length > 0 ? routed : undefined;
|
|
203
210
|
}
|
|
204
211
|
/** Pathname only (drop origin + query) so a net URL stays terse in the journey. */
|
|
205
212
|
function trimUrl(url) {
|
|
@@ -294,7 +301,9 @@ async function runTestidStep(session, step, index, value, dynamic, confirmDanger
|
|
|
294
301
|
act = await session.command(ReticleCommand.ACT, {
|
|
295
302
|
ref,
|
|
296
303
|
action: step.action ?? '',
|
|
297
|
-
|
|
304
|
+
// `value` is the anchor's own name — the field this step types into — so a redacted fill can
|
|
305
|
+
// be supplied from RETICLE_SECRET_<FIELD> without the flow carrying the secret.
|
|
306
|
+
args: replayActionArgs(step.args, confirmDangerous, value),
|
|
298
307
|
});
|
|
299
308
|
}
|
|
300
309
|
finally {
|
|
@@ -30,6 +30,14 @@ export declare function runComponentStep(session: FlowReplaySession, step: FlowS
|
|
|
30
30
|
*/
|
|
31
31
|
export declare function isDegradedAnchor(anchor: FlowAnchor): boolean;
|
|
32
32
|
export declare function degradedStepResult(step: FlowStep, index: number, label: string): FlowStepResult;
|
|
33
|
+
/**
|
|
34
|
+
* QUERY args for an element anchor — null when the anchor addresses no element.
|
|
35
|
+
*
|
|
36
|
+
* Exported for `arriveAtStartPath`, which has to ask "can step 1 resolve where we already are?"
|
|
37
|
+
* before deciding to navigate. Sharing this mapping rather than repeating it keeps that question and
|
|
38
|
+
* the step runner's own resolution asking the same thing of the same anchor.
|
|
39
|
+
*/
|
|
40
|
+
export declare function anchorQueryArgs(anchor: FlowAnchor): Record<string, unknown> | null;
|
|
33
41
|
/**
|
|
34
42
|
* Run an act_sequence step: resolve every sub-step's OWN anchor, then dispatch the whole thing as one
|
|
35
43
|
* ACT_SEQUENCE — the same shape `replayProgram` already uses, so a recorded sequence and a saved one
|
|
@@ -181,8 +181,14 @@ export function degradedStepResult(step, index, label) {
|
|
|
181
181
|
},
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
|
-
/**
|
|
185
|
-
|
|
184
|
+
/**
|
|
185
|
+
* QUERY args for an element anchor — null when the anchor addresses no element.
|
|
186
|
+
*
|
|
187
|
+
* Exported for `arriveAtStartPath`, which has to ask "can step 1 resolve where we already are?"
|
|
188
|
+
* before deciding to navigate. Sharing this mapping rather than repeating it keeps that question and
|
|
189
|
+
* the step runner's own resolution asking the same thing of the same anchor.
|
|
190
|
+
*/
|
|
191
|
+
export function anchorQueryArgs(anchor) {
|
|
186
192
|
if (anchor.kind === AnchorKind.TESTID)
|
|
187
193
|
return { by: QueryBy.TESTID, value: anchor.value };
|
|
188
194
|
if (anchor.kind === AnchorKind.COMPONENT)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flow store a SESSION's flows belong in.
|
|
3
|
+
*
|
|
4
|
+
* `deps.flows` is bound to the daemon's own root at construction, which is right only when the
|
|
5
|
+
* daemon happens to have been started in the project it is driving. A user-scoped MCP registration
|
|
6
|
+
* is the common case and the editor starts it wherever it likes, so "where the daemon was launched"
|
|
7
|
+
* and "which app is being verified" are usually different directories.
|
|
8
|
+
*
|
|
9
|
+
* This used to live inside flow-tools and was applied at exactly ONE of ten call sites. The result
|
|
10
|
+
* is the half-applied state `sessionRoot` warns about in its own comment, reached in practice:
|
|
11
|
+
*
|
|
12
|
+
* - the HUD listed the daemon repo's flows while driving somebody else's app — Electron and Tauri
|
|
13
|
+
* flows shown over a React dashboard, none of which existed in the checkout being verified
|
|
14
|
+
* - `flow_replay` answered `flow_not_found` for a flow sitting on disk, because it looked in the
|
|
15
|
+
* daemon's root while `reticle verify` (which roots itself at cwd) replayed the same flow fine
|
|
16
|
+
* - and the two save paths disagreed with each other, so where a flow landed depended on which
|
|
17
|
+
* tool wrote it
|
|
18
|
+
*
|
|
19
|
+
* Reported as "running the daemon from here but taking the directory from there", which is exactly
|
|
20
|
+
* what it was.
|
|
21
|
+
*
|
|
22
|
+
* Rebinding is cheap — a FlowStore is a filesystem port, a root and a clock — and the common case
|
|
23
|
+
* allocates nothing: when no resolver is wired, or it names the root already in use, `deps.flows` is
|
|
24
|
+
* returned unchanged.
|
|
25
|
+
*/
|
|
26
|
+
import { FlowStore } from './flows.js';
|
|
27
|
+
import type { ToolDeps } from '../tools/tool-kit.js';
|
|
28
|
+
export declare function flowsForSession(deps: ToolDeps, projectId: string | undefined): {
|
|
29
|
+
flows: FlowStore;
|
|
30
|
+
root: string;
|
|
31
|
+
};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flow store a SESSION's flows belong in.
|
|
3
|
+
*
|
|
4
|
+
* `deps.flows` is bound to the daemon's own root at construction, which is right only when the
|
|
5
|
+
* daemon happens to have been started in the project it is driving. A user-scoped MCP registration
|
|
6
|
+
* is the common case and the editor starts it wherever it likes, so "where the daemon was launched"
|
|
7
|
+
* and "which app is being verified" are usually different directories.
|
|
8
|
+
*
|
|
9
|
+
* This used to live inside flow-tools and was applied at exactly ONE of ten call sites. The result
|
|
10
|
+
* is the half-applied state `sessionRoot` warns about in its own comment, reached in practice:
|
|
11
|
+
*
|
|
12
|
+
* - the HUD listed the daemon repo's flows while driving somebody else's app — Electron and Tauri
|
|
13
|
+
* flows shown over a React dashboard, none of which existed in the checkout being verified
|
|
14
|
+
* - `flow_replay` answered `flow_not_found` for a flow sitting on disk, because it looked in the
|
|
15
|
+
* daemon's root while `reticle verify` (which roots itself at cwd) replayed the same flow fine
|
|
16
|
+
* - and the two save paths disagreed with each other, so where a flow landed depended on which
|
|
17
|
+
* tool wrote it
|
|
18
|
+
*
|
|
19
|
+
* Reported as "running the daemon from here but taking the directory from there", which is exactly
|
|
20
|
+
* what it was.
|
|
21
|
+
*
|
|
22
|
+
* Rebinding is cheap — a FlowStore is a filesystem port, a root and a clock — and the common case
|
|
23
|
+
* allocates nothing: when no resolver is wired, or it names the root already in use, `deps.flows` is
|
|
24
|
+
* returned unchanged.
|
|
25
|
+
*/
|
|
26
|
+
import { FlowStore } from './flows.js';
|
|
27
|
+
export function flowsForSession(deps, projectId) {
|
|
28
|
+
const resolved = deps.artifactRootFor?.(projectId);
|
|
29
|
+
if (resolved === undefined || resolved.root === deps.reticleRoot) {
|
|
30
|
+
return { flows: deps.flows, root: deps.reticleRoot };
|
|
31
|
+
}
|
|
32
|
+
return { flows: new FlowStore(deps.fs, resolved.root, { now: deps.now }), root: resolved.root };
|
|
33
|
+
}
|
|
@@ -38,9 +38,21 @@ export function successLabel(success) {
|
|
|
38
38
|
export function successToPredicate(success, dynamic) {
|
|
39
39
|
const parts = [];
|
|
40
40
|
if (success.signal !== undefined) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
const signal = {
|
|
42
|
+
kind: PredicateKind.SIGNAL,
|
|
43
|
+
name: success.signal,
|
|
44
|
+
};
|
|
45
|
+
if (success.signalData !== undefined)
|
|
46
|
+
signal.dataMatches = success.signalData;
|
|
47
|
+
if (success.signalCount !== undefined) {
|
|
48
|
+
signal.count = success.signalCount;
|
|
49
|
+
// Same post-settle reasoning as net.count: the success waiter is wait-until-true, so an exact
|
|
50
|
+
// count is transiently satisfied the instant the FIRST matching signal fires — before a
|
|
51
|
+
// double-fire's duplicate arrives. Gating on `settled` forces the count to be read only after
|
|
52
|
+
// the app goes quiet, by which point the duplicate IS counted and the over-count fails.
|
|
53
|
+
parts.push({ kind: PredicateKind.SETTLED });
|
|
54
|
+
}
|
|
55
|
+
parts.push(signal);
|
|
44
56
|
}
|
|
45
57
|
if (success.net !== undefined) {
|
|
46
58
|
const net = { kind: PredicateKind.NET };
|
package/dist/flows/flow-tools.js
CHANGED
|
@@ -5,8 +5,9 @@ import { FlowErrorCode, RecordedSaveError, ReplayStatus, } from '@reticlehq/core
|
|
|
5
5
|
import { recordSuiteFlakes } from './suite-flakes.js';
|
|
6
6
|
import { ReticleTool } from '../tools/tool-names.js';
|
|
7
7
|
import { asNumber, asString } from '../tools/tools-helpers.js';
|
|
8
|
+
import { workerCountSchema } from '../tools/numeric-bounds.js';
|
|
8
9
|
import { log } from '../log.js';
|
|
9
|
-
import { syncFlowToCloud, SyncOutcome } from '../cloud/cloud-sync.js';
|
|
10
|
+
import { cloudFetch, syncFlowToCloud, SyncOutcome } from '../cloud/cloud-sync.js';
|
|
10
11
|
import { mapWithConcurrency, resolveConcurrency } from './parallel-suite.js';
|
|
11
12
|
import { acquireLeasedSession } from '../tools/lease-tools.js';
|
|
12
13
|
import { homedir } from 'node:os';
|
|
@@ -14,14 +15,15 @@ import { resolveProjectCloud } from '../cloud/cloud-config.js';
|
|
|
14
15
|
import { buildSuiteVerdict } from './decision.js';
|
|
15
16
|
import { classifyFlowAssertions } from './flow-classify.js';
|
|
16
17
|
import { isValidFlowName, flowPath } from '../project/reticle-dir.js';
|
|
17
|
-
import {
|
|
18
|
+
import {} from './flows.js';
|
|
19
|
+
import { flowsForSession } from './flow-store-for-session.js';
|
|
18
20
|
import { replayNamedFlow, flowErrorMessage, latestRecordedFlow, sessionProjectId, } from './flow-replay-run.js';
|
|
19
21
|
import { persistAndSyncVerificationRun } from '../runs/verification-sync.js';
|
|
20
22
|
import { runServerVerify } from './server-verify.js';
|
|
21
23
|
import { healFlow } from './heal-run.js';
|
|
22
24
|
export { replayNamedFlow } from './flow-replay-run.js';
|
|
23
25
|
/**
|
|
24
|
-
* Best-effort mirror of a just-saved flow to Reticle
|
|
26
|
+
* Best-effort mirror of a just-saved flow to Reticle (only when logged in — both cloud env vars
|
|
25
27
|
* set). Fire-and-forget: resolves the config, POSTs via the platform fetch, and logs the outcome. Any
|
|
26
28
|
* failure is swallowed so a network hiccup never affects the local save.
|
|
27
29
|
*/
|
|
@@ -30,7 +32,7 @@ async function syncSavedFlowToCloud(deps, flow, projectId) {
|
|
|
30
32
|
const cloud = await resolveProjectCloud(deps.fs, deps.reticleRoot, homedir(), process.env);
|
|
31
33
|
if (null === cloud.config || !cloud.policy.flows)
|
|
32
34
|
return; // not attached / flows disabled → local only
|
|
33
|
-
const result = await syncFlowToCloud(flow, cloud.config, projectId,
|
|
35
|
+
const result = await syncFlowToCloud(flow, cloud.config, projectId, cloudFetch);
|
|
34
36
|
if (result.outcome !== SyncOutcome.SYNCED) {
|
|
35
37
|
log('cloud-flow-sync-failed', { flow: flow.name, status: result.status, error: result.error });
|
|
36
38
|
}
|
|
@@ -69,23 +71,16 @@ export function leaseFailureReplay(name, error) {
|
|
|
69
71
|
/** Stand-in path for a flow whose name fails the path-segment guard — never a real join. */
|
|
70
72
|
const INVALID_FLOW_NAME_PATH = '(invalid flow name — not a usable path)';
|
|
71
73
|
/**
|
|
72
|
-
*
|
|
74
|
+
* How a save reports that nobody said what the flow is for.
|
|
73
75
|
*
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
* call. Rebinding is cheap: a FlowStore is a filesystem port, a root and a clock.
|
|
78
|
-
*
|
|
79
|
-
* Returns `deps.flows` unchanged when nothing is wired or the roots already agree, so the common
|
|
80
|
-
* case allocates nothing and behaves exactly as before.
|
|
76
|
+
* Declared once and shared by every save tool: an undeclared field is stripped from
|
|
77
|
+
* `structuredContent` by a schema-strict MCP client, so a save path that forgot this line would
|
|
78
|
+
* report the nudge to the unit tests and to nobody else.
|
|
81
79
|
*/
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
return { flows: new FlowStore(deps.fs, resolved.root, { now: deps.now }), root: resolved.root };
|
|
88
|
-
}
|
|
80
|
+
const INTENT_GAP_FIELD = z
|
|
81
|
+
.unknown()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe('Present ONLY when the flow was saved with nothing saying what it is for: { kind, missing, cost, fix }. The flow is on disk either way — this never blocks a save. Close it by saving again with `intent`, or by setting the flow file’s `intentId` to an intent already in the ledger. Nothing here is ever derived from the flow name, the steps or the assertions: a guessed goal reads as the author’s own words.');
|
|
89
84
|
export const FLOW_TOOLS = [
|
|
90
85
|
{
|
|
91
86
|
name: ReticleTool.FLOW_SAVE,
|
|
@@ -97,7 +92,15 @@ export const FLOW_TOOLS = [
|
|
|
97
92
|
.describe('Alias for `flowName` (the name reticle_annotate uses).'),
|
|
98
93
|
flowName: z
|
|
99
94
|
.string()
|
|
100
|
-
.describe('
|
|
95
|
+
.describe('Which RECORDING to save — the name reticle_record{start} was called with. This is a lookup key, not the filename: pass `saveAs` to choose that.'),
|
|
96
|
+
saveAs: z
|
|
97
|
+
.string()
|
|
98
|
+
.optional()
|
|
99
|
+
.describe('Name for the flow file (.reticle/flows/<saveAs>.json), and the name reticle_flow{action:"load"} / reticle_flow_replay take. Omit to reuse the recording name.'),
|
|
100
|
+
intent: z
|
|
101
|
+
.string()
|
|
102
|
+
.optional()
|
|
103
|
+
.describe('What this flow is FOR, in prose: which user does what, and what should become true. Answer it here rather than in a second call. Without it the flow still saves, but the day it goes red the report can only name the step that broke, not the thing that stopped being true.'),
|
|
101
104
|
sessionId: z
|
|
102
105
|
.string()
|
|
103
106
|
.optional()
|
|
@@ -124,6 +127,7 @@ export const FLOW_TOOLS = [
|
|
|
124
127
|
warning: z.string().optional(),
|
|
125
128
|
})
|
|
126
129
|
.optional(),
|
|
130
|
+
intentGap: INTENT_GAP_FIELD,
|
|
127
131
|
error: z.string().optional(),
|
|
128
132
|
code: z.string().optional(),
|
|
129
133
|
},
|
|
@@ -131,14 +135,44 @@ export const FLOW_TOOLS = [
|
|
|
131
135
|
const name = asString(aliasParam(args, 'flowName', ['flow'])['flowName']) ?? '';
|
|
132
136
|
const program = deps.recordings.getCompiled(name);
|
|
133
137
|
if (program === undefined) {
|
|
138
|
+
/*
|
|
139
|
+
* Name what DOES exist.
|
|
140
|
+
*
|
|
141
|
+
* `flowName` here is the RECORDING's name, while every other flow tool reads it as the name
|
|
142
|
+
* to save AS — so recording `default` and saving as `sign-in` looks obviously right and
|
|
143
|
+
* answers "no compiled recording by that name". The old message then said "record one
|
|
144
|
+
* first", which is advice to repeat the step that just succeeded. Cost a real investigation
|
|
145
|
+
* before the names were compared.
|
|
146
|
+
*/
|
|
147
|
+
const held = deps.recordings.compiled();
|
|
134
148
|
return Promise.resolve({
|
|
135
|
-
error:
|
|
149
|
+
error: 0 === held.length
|
|
150
|
+
? flowErrorMessage(FlowErrorCode.NO_RECORDING)
|
|
151
|
+
: `no recording named '${name}'. This is the name the RECORDING was made under, not ` +
|
|
152
|
+
`the name to save it as — stopped and ready to save: ${held.map((n) => `'${n}'`).join(', ')}.`,
|
|
136
153
|
code: FlowErrorCode.NO_RECORDING,
|
|
137
154
|
});
|
|
138
155
|
}
|
|
156
|
+
// The name to save AS, which is not the name looked up above.
|
|
157
|
+
//
|
|
158
|
+
// `flowName` selects the recording; a recording is named at `record{start}`, often `default`
|
|
159
|
+
// or whatever the drive began as. Every other flow tool reads a flow name as the thing you
|
|
160
|
+
// load and replay, so a caller naming their flow at save time had no way to do it and had to
|
|
161
|
+
// `mv` the file on disk. The error message below already had to explain this ambiguity; that
|
|
162
|
+
// it needed explaining is the bug (#698).
|
|
163
|
+
const saveAs = asString(args['saveAs']);
|
|
164
|
+
if (saveAs !== undefined && !isValidFlowName(saveAs)) {
|
|
165
|
+
return Promise.resolve({
|
|
166
|
+
error: `'${saveAs}' is not a usable flow name — it becomes a filename under .reticle/flows/.`,
|
|
167
|
+
code: FlowErrorCode.INVALID_NAME,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
139
170
|
// fold any structured annotations (expect/dynamic/success/intent) onto the saved flow.
|
|
171
|
+
// Keyed by the RECORDING name: annotations were left against the recording, not the file.
|
|
140
172
|
const success = deps.annotations.success(name);
|
|
141
|
-
|
|
173
|
+
// The inline argument wins over an annotation left from an earlier call: it is the more recent
|
|
174
|
+
// statement, and it is the one the author just typed.
|
|
175
|
+
const intent = asString(args['intent']) ?? deps.annotations.intent(name);
|
|
142
176
|
const annotations = {
|
|
143
177
|
stepExpect: deps.annotations.stepExpect(name),
|
|
144
178
|
dynamic: deps.annotations.dynamic(name),
|
|
@@ -152,7 +186,8 @@ export const FLOW_TOOLS = [
|
|
|
152
186
|
if (emptyRefusal !== undefined)
|
|
153
187
|
return Promise.resolve(emptyRefusal);
|
|
154
188
|
const { flows, root } = flowsForSession(deps, projectId);
|
|
155
|
-
|
|
189
|
+
const toSave = saveAs === undefined ? program : { ...program, name: saveAs };
|
|
190
|
+
return flows.save(toSave, annotations, projectId).then(async (res) => {
|
|
156
191
|
if (!res.ok)
|
|
157
192
|
return { error: flowErrorMessage(res.code), code: res.code };
|
|
158
193
|
deps.annotations.clear(name);
|
|
@@ -193,7 +228,10 @@ export const FLOW_TOOLS = [
|
|
|
193
228
|
// received string") — caught driving the live demo.
|
|
194
229
|
handler: (deps, args) => {
|
|
195
230
|
const projectId = sessionProjectId(deps, asString(args['sessionId']));
|
|
196
|
-
|
|
231
|
+
// The APP's flows, not the daemon's. Listing where the daemon was launched is what showed a
|
|
232
|
+
// React dashboard a HUD full of Electron and Tauri flows from an unrelated checkout.
|
|
233
|
+
const { flows: store, root } = flowsForSession(deps, projectId);
|
|
234
|
+
return store.list(projectId).then((names) => ({
|
|
197
235
|
// `list` deliberately returns invalid names so they are reported rather than silently
|
|
198
236
|
// dropped — but the declared outputSchema requires `path` on EVERY entry, and omitting it made
|
|
199
237
|
// a strict MCP client reject the whole listing (the agent then sees no flows at all, which is
|
|
@@ -201,7 +239,7 @@ export const FLOW_TOOLS = [
|
|
|
201
239
|
// gets an explanatory marker instead of a joined filesystem path, which is what must never
|
|
202
240
|
// happen for a traversal-shaped name.
|
|
203
241
|
flows: names.map((name) => isValidFlowName(name)
|
|
204
|
-
? { name, path: flowPath(
|
|
242
|
+
? { name, path: flowPath(root, name, projectId) }
|
|
205
243
|
: { name, path: INVALID_FLOW_NAME_PATH }),
|
|
206
244
|
}));
|
|
207
245
|
},
|
|
@@ -350,8 +388,7 @@ export const FLOW_TOOLS = [
|
|
|
350
388
|
.array(z.string())
|
|
351
389
|
.optional()
|
|
352
390
|
.describe('Flow names to verify. Omit to verify every saved flow.'),
|
|
353
|
-
parallel:
|
|
354
|
-
.number()
|
|
391
|
+
parallel: workerCountSchema
|
|
355
392
|
.optional()
|
|
356
393
|
.describe('Run this many flows at once, each in its own isolated leased browser context (needs the browser pool). Clamped to the pool capacity and the flow count. Omit for the sequential single-tab run.'),
|
|
357
394
|
sessionId: z
|
|
@@ -380,7 +417,7 @@ export const FLOW_TOOLS = [
|
|
|
380
417
|
const projectId = sessionProjectId(deps, sessionId);
|
|
381
418
|
const requested = Array.isArray(args['names'])
|
|
382
419
|
? args['names'].filter((n) => 'string' === typeof n)
|
|
383
|
-
: await deps.flows.list(projectId);
|
|
420
|
+
: await flowsForSession(deps, projectId).flows.list(projectId);
|
|
384
421
|
// verify:server — hand the whole suite to the hosted runner; it records the verification itself.
|
|
385
422
|
const cloud = await resolveProjectCloud(deps.fs, deps.reticleRoot, homedir(), process.env);
|
|
386
423
|
const server = await runServerVerify(deps, cloud, sessionId, requested);
|
|
@@ -417,7 +454,9 @@ export const FLOW_TOOLS = [
|
|
|
417
454
|
const parallelRuns = await Promise.all(outcomes.map(async (o, i) => {
|
|
418
455
|
const name = requested[i] ?? '';
|
|
419
456
|
const replay = o.ok && o.value !== undefined ? o.value.replay : leaseFailureReplay(name, o.error);
|
|
420
|
-
const loaded = await deps
|
|
457
|
+
const loaded = await flowsForSession(deps, projectId)
|
|
458
|
+
.flows.load(name, projectId)
|
|
459
|
+
.catch(() => null);
|
|
421
460
|
const flow = loaded !== null && loaded.ok ? loaded.value : undefined;
|
|
422
461
|
return flow === undefined ? { replay } : { replay, flow };
|
|
423
462
|
}));
|
|
@@ -441,7 +480,9 @@ export const FLOW_TOOLS = [
|
|
|
441
480
|
for (const flowName of requested) {
|
|
442
481
|
const start = deps.now();
|
|
443
482
|
const replay = await replayNamedFlow(deps, { flowName, sessionId });
|
|
444
|
-
const loaded = await deps
|
|
483
|
+
const loaded = await flowsForSession(deps, projectId)
|
|
484
|
+
.flows.load(flowName, projectId)
|
|
485
|
+
.catch(() => null);
|
|
445
486
|
const flow = loaded !== null && loaded.ok ? loaded.value : undefined;
|
|
446
487
|
runs.push(flow === undefined ? { replay } : { replay, flow });
|
|
447
488
|
timed.push({ replay, durationMs: deps.now() - start });
|
|
@@ -477,6 +518,10 @@ export const FLOW_TOOLS = [
|
|
|
477
518
|
.string()
|
|
478
519
|
.optional()
|
|
479
520
|
.describe('Override the flow name embedded in the recorded flow. Omit to use the recorder-assigned name.'),
|
|
521
|
+
intent: z
|
|
522
|
+
.string()
|
|
523
|
+
.optional()
|
|
524
|
+
.describe('What this flow is FOR, in prose: which user does what, and what should become true. The recorder captures clicks, not goals, so this is the only place the goal can come from. Without it the flow still saves, but the day it goes red the report can only name the step that broke.'),
|
|
480
525
|
...{
|
|
481
526
|
sessionId: z
|
|
482
527
|
.string()
|
|
@@ -491,6 +536,7 @@ export const FLOW_TOOLS = [
|
|
|
491
536
|
stepCount: z.number().optional(),
|
|
492
537
|
degraded: z.number().optional(),
|
|
493
538
|
empty: z.boolean().optional(),
|
|
539
|
+
intentGap: INTENT_GAP_FIELD,
|
|
494
540
|
error: z.string().optional(),
|
|
495
541
|
code: z.string().optional(),
|
|
496
542
|
},
|
|
@@ -504,16 +550,24 @@ export const FLOW_TOOLS = [
|
|
|
504
550
|
};
|
|
505
551
|
}
|
|
506
552
|
const override = asString(aliasParam(args, 'flowName', ['flow'])['flowName']);
|
|
507
|
-
const
|
|
553
|
+
const intent = asString(args['intent']);
|
|
554
|
+
const flow = {
|
|
555
|
+
...recorded.flow,
|
|
556
|
+
...(override === undefined ? {} : { name: override }),
|
|
557
|
+
...(intent === undefined ? {} : { intent }),
|
|
558
|
+
};
|
|
508
559
|
// The store stamps the project into the file AND routes it to the per-project subdir (a shared
|
|
509
560
|
// daemon serves many apps), so location and content agree from one source of truth.
|
|
510
561
|
const emptyRecorded = emptyFlowRefusal(flow.steps.length, flow.name);
|
|
511
562
|
if (emptyRecorded !== undefined)
|
|
512
563
|
return emptyRecorded;
|
|
513
|
-
|
|
564
|
+
// Resolved like every other path now. This save used to go to the daemon's root while the
|
|
565
|
+
// recorded-flow save resolved per session, so where a flow landed depended on which tool wrote
|
|
566
|
+
// it — and the pair that disagreed were the two ways to save the same thing.
|
|
567
|
+
const res = await flowsForSession(deps, session.projectId).flows.saveFlow(flow, session.projectId);
|
|
514
568
|
if (!res.ok)
|
|
515
569
|
return { error: flowErrorMessage(res.code), code: res.code };
|
|
516
|
-
// If logged
|
|
570
|
+
// If logged in to Reticle, mirror the saved flow to the team's regression suite. Best-effort
|
|
517
571
|
// and non-blocking: the flow is already on disk, so a sync failure never fails the save.
|
|
518
572
|
void syncSavedFlowToCloud(deps, flow, session.projectId);
|
|
519
573
|
// Return the SaveSummary as-is ({ name, stepCount, degraded, empty }) — the outputSchema
|
package/dist/flows/flows.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FlowErrorCode } from '@reticlehq/core';
|
|
2
|
-
import type { FlowAnchor, FlowExpect, FlowFile, FlowStep, HealChange } from '@reticlehq/core';
|
|
2
|
+
import type { FlowAnchor, FlowExpect, FlowFile, FlowStep, HealChange, InstrumentationGap } from '@reticlehq/core';
|
|
3
3
|
import type { CompiledProgram, RecordedStep } from './recordings.js';
|
|
4
4
|
import type { FileSystemPort } from '../project/fs-port.js';
|
|
5
5
|
/** A monotonic clock injected for createdAt — never call Date.now inside the store (rule 7). */
|
|
@@ -19,6 +19,14 @@ export declare function anchorForStep(args: Record<string, unknown>): {
|
|
|
19
19
|
anchor: FlowAnchor;
|
|
20
20
|
degraded: boolean;
|
|
21
21
|
};
|
|
22
|
+
/**
|
|
23
|
+
* What a redacted fill value is replaced WITH.
|
|
24
|
+
*
|
|
25
|
+
* Replaced, never dropped. Replay still needs a step there, and a flow that silently loses its
|
|
26
|
+
* password step drifts at sign-in forever with no explanation of why. The placeholder also tells a
|
|
27
|
+
* reader what to do: the value belongs in the environment, not in a file they are about to commit.
|
|
28
|
+
*/
|
|
29
|
+
export declare const REDACTED_FILL = "<redacted: supply at replay>";
|
|
22
30
|
/**
|
|
23
31
|
* Pure: map one normalized RecordedStep → FlowStep with a semantic anchor (+ degraded marker).
|
|
24
32
|
* A ref-only (stable:false) step is recorded with a best-effort anchor and degraded:true —
|
|
@@ -30,6 +38,11 @@ interface SaveSummary {
|
|
|
30
38
|
stepCount: number;
|
|
31
39
|
degraded: number;
|
|
32
40
|
empty: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Present only when the flow was saved with nothing saying what it is for. Never blocks the save,
|
|
43
|
+
* and absent the moment the flow carries prose or an `intentId`. See `flowIntentGap`.
|
|
44
|
+
*/
|
|
45
|
+
intentGap?: InstrumentationGap;
|
|
33
46
|
}
|
|
34
47
|
/**
|
|
35
48
|
* The structured annotations folded onto a flow at save time: per-step
|