@reticlehq/server 3.8.2 → 3.10.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/LICENSE +201 -104
- package/NOTICE +5 -0
- package/README.md +1 -1
- package/SKILL.md +13 -12
- package/bin/launch.js +13 -0
- package/bin/package.json +3 -0
- package/bin/reticle.js +66 -8
- package/dist/chromium-launch-options.d.ts +25 -0
- package/dist/chromium-launch-options.js +21 -1
- package/dist/command/cli/adhoc-suite.js +2 -0
- package/dist/command/cli/adhoc-verdict.d.ts +2 -43
- package/dist/command/cli/adhoc-verdict.js +50 -160
- package/dist/command/cli/answers/gate-exit.d.ts +6 -2
- package/dist/command/cli/answers/gate-exit.js +12 -2
- package/dist/command/cli/answers/mcp-connection-hint.d.ts +2 -0
- package/dist/command/cli/answers/mcp-connection-hint.js +6 -0
- package/dist/command/cli/ci-hint.d.ts +44 -0
- package/dist/command/cli/ci-hint.js +72 -0
- package/dist/command/cli/cli-doctor.d.ts +6 -1
- package/dist/command/cli/cli-doctor.js +46 -5
- package/dist/command/cli/cli-flow-commands.d.ts +7 -1
- package/dist/command/cli/cli-flow-commands.js +39 -24
- package/dist/command/cli/cli-kill.d.ts +21 -0
- package/dist/command/cli/cli-kill.js +47 -4
- package/dist/command/cli/cli-parse-compare.d.ts +22 -0
- package/dist/command/cli/cli-parse-compare.js +75 -0
- package/dist/command/cli/cli-parse-grade.d.ts +36 -0
- package/dist/command/cli/cli-parse-grade.js +75 -0
- package/dist/command/cli/cli-parse-grammar.d.ts +2 -0
- package/dist/command/cli/cli-parse-grammar.js +18 -20
- package/dist/command/cli/cli-parse-verify.d.ts +10 -0
- package/dist/command/cli/cli-parse-verify.js +63 -14
- package/dist/command/cli/cli-parse.d.ts +22 -17
- package/dist/command/cli/cli-parse.js +54 -32
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +29 -20
- package/dist/command/cli/cli-usage.js +61 -31
- package/dist/command/cli/cli-verify.d.ts +17 -3
- package/dist/command/cli/cli-verify.js +59 -21
- package/dist/command/cli/cloud-cli.js +2 -119
- package/dist/command/cli/daemon-link/daemon-client.d.ts +45 -0
- package/dist/command/cli/daemon-link/daemon-client.js +205 -0
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +6 -1
- package/dist/command/cli/doctor/browser/chromium-hint.js +11 -5
- package/dist/command/cli/doctor/doctor-daemon-line.js +6 -3
- package/dist/command/cli/doctor/doctor-fix.d.ts +44 -0
- package/dist/command/cli/doctor/doctor-fix.js +89 -0
- package/dist/command/cli/doctor/doctor-launcher-line.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-launcher-line.js +60 -0
- package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
- package/dist/command/cli/doctor/doctor-rows.js +4 -0
- package/dist/command/cli/doctor-repairs.d.ts +64 -0
- package/dist/command/cli/doctor-repairs.js +214 -0
- package/dist/command/cli/drive/drive-command.js +3 -7
- package/dist/command/cli/ensure-daemon.d.ts +26 -0
- package/dist/command/cli/ensure-daemon.js +57 -0
- package/dist/command/cli/finished-run/grade-command.d.ts +23 -0
- package/dist/command/cli/finished-run/grade-command.js +180 -0
- package/dist/command/cli/first-use-checks.d.ts +41 -0
- package/dist/command/cli/first-use-checks.js +127 -0
- package/dist/command/cli/first-verdict-node.d.ts +3 -0
- package/dist/command/cli/first-verdict-node.js +189 -0
- package/dist/command/cli/first-verdict.d.ts +126 -0
- package/dist/command/cli/first-verdict.js +267 -0
- package/dist/command/cli/launch/sdk-version-match.d.ts +3 -2
- package/dist/command/cli/launch/sdk-version-match.js +3 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +1 -1
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +7 -6
- package/dist/command/cli/mcp-command.js +13 -4
- package/dist/command/cli/ports/port-holder.d.ts +11 -0
- package/dist/command/cli/ports/port-holder.js +36 -4
- package/dist/command/cli/setup-mcp-cli.d.ts +27 -1
- package/dist/command/cli/setup-mcp-cli.js +98 -23
- package/dist/command/cli/status/status-lines.d.ts +2 -0
- package/dist/command/cli/status/status-lines.js +72 -17
- package/dist/command/cli/status-fields.d.ts +5 -1
- package/dist/command/cli/status-fields.js +24 -6
- package/dist/command/cli/try-command.d.ts +7 -0
- package/dist/command/cli/try-command.js +11 -3
- package/dist/command/cli/two-builds/compare-command.d.ts +48 -0
- package/dist/command/cli/two-builds/compare-command.js +314 -0
- package/dist/command/cli/verify-against.d.ts +61 -0
- package/dist/command/cli/verify-against.js +187 -0
- package/dist/command/cli/verify-no-session.d.ts +2 -0
- package/dist/command/cli/verify-no-session.js +13 -0
- package/dist/command/cli/verify-results.d.ts +35 -2
- package/dist/command/cli/verify-results.js +76 -10
- package/dist/command/cli.js +112 -70
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +3 -1
- package/dist/command/daemon/binding/daemon-status-probe.js +4 -2
- package/dist/command/daemon/daemon-argv.d.ts +9 -0
- package/dist/command/daemon/daemon-argv.js +11 -0
- package/dist/command/daemon/daemon-resolve.d.ts +8 -1
- package/dist/command/daemon/daemon-resolve.js +27 -1
- package/dist/command/daemon/daemon.d.ts +22 -4
- package/dist/command/daemon/daemon.js +52 -10
- package/dist/command/daemon/lifetime/daemon-exit.d.ts +24 -0
- package/dist/command/daemon/lifetime/daemon-exit.js +39 -0
- package/dist/command/daemon/lifetime/death-cause.d.ts +15 -0
- package/dist/command/daemon/lifetime/death-cause.js +149 -0
- package/dist/command/daemon/lifetime/heartbeat.d.ts +7 -15
- package/dist/command/daemon/lifetime/heartbeat.js +11 -15
- package/dist/command/daemon/lifetime/startup-failure.d.ts +29 -0
- package/dist/command/daemon/lifetime/startup-failure.js +62 -0
- package/dist/command/daemon/port-state.d.ts +14 -0
- package/dist/command/daemon/port-state.js +31 -0
- package/dist/command/setup/agent-configs.d.ts +2 -0
- package/dist/command/setup/agent-configs.js +42 -15
- package/dist/command/setup/agent-next-steps.d.ts +77 -0
- package/dist/command/setup/agent-next-steps.js +284 -0
- package/dist/command/setup/agent-writer.js +11 -6
- package/dist/command/setup/bringup/dev-server-files.d.ts +9 -0
- package/dist/command/setup/bringup/dev-server-files.js +17 -0
- package/dist/command/setup/bringup/static-page-server.d.ts +14 -2
- package/dist/command/setup/bringup/static-page-server.js +43 -9
- package/dist/command/setup/init/init-host.js +2 -0
- package/dist/command/setup/init/init-runtime.d.ts +6 -1
- package/dist/command/setup/init/init-runtime.js +63 -21
- package/dist/command/setup/mcp-launcher.d.ts +3 -0
- package/dist/command/setup/mcp-launcher.js +11 -0
- package/dist/command/setup/node-effects.d.ts +3 -2
- package/dist/command/setup/node-effects.js +9 -3
- package/dist/command/setup/remaining-steps.d.ts +8 -0
- package/dist/command/setup/remaining-steps.js +10 -0
- package/dist/command/setup/run-setup.d.ts +2 -0
- package/dist/command/setup/run-setup.js +9 -1
- package/dist/command/setup/setup-command.js +36 -15
- package/dist/command/setup/setup-mcp.d.ts +8 -0
- package/dist/command/setup/setup-mcp.js +47 -20
- package/dist/command/setup/start-dev-server.d.ts +8 -0
- package/dist/command/setup/start-dev-server.js +43 -0
- package/dist/command/update/updater.js +6 -0
- package/dist/command/version/identity/server-version.d.ts +2 -0
- package/dist/command/version/identity/server-version.js +2 -0
- package/dist/command/version/version-skew.d.ts +7 -0
- package/dist/command/version/version-skew.js +14 -3
- package/dist/features/compare/action-plan.d.ts +260 -0
- package/dist/features/compare/action-plan.js +543 -0
- package/dist/features/compare/behaviour-compare.d.ts +24 -0
- package/dist/features/compare/behaviour-compare.js +85 -0
- package/dist/features/compare/behaviour-diff.d.ts +97 -0
- package/dist/features/compare/behaviour-diff.js +202 -0
- package/dist/features/compare/behaviour-report.d.ts +40 -0
- package/dist/features/compare/behaviour-report.js +128 -0
- package/dist/features/compare/build-readings.d.ts +106 -0
- package/dist/features/compare/build-readings.js +250 -0
- package/dist/features/compare/compare-diff.d.ts +62 -0
- package/dist/features/compare/compare-diff.js +177 -0
- package/dist/features/compare/compare-report-html.d.ts +6 -0
- package/dist/features/compare/compare-report-html.js +102 -0
- package/dist/features/compare/compare-report.d.ts +15 -0
- package/dist/features/compare/compare-report.js +73 -0
- package/dist/features/compare/compare-run.d.ts +60 -0
- package/dist/features/compare/compare-run.js +123 -0
- package/dist/features/compare/outside/effect-lines.d.ts +26 -0
- package/dist/features/compare/outside/effect-lines.js +103 -0
- package/dist/features/compare/outside/state-sources.d.ts +76 -0
- package/dist/features/compare/outside/state-sources.js +164 -0
- package/dist/features/compare/outside/value-dictionary.d.ts +51 -0
- package/dist/features/compare/outside/value-dictionary.js +227 -0
- package/dist/features/compare/visible-content.d.ts +20 -0
- package/dist/features/compare/visible-content.js +125 -0
- package/dist/features/crawl/crawl-empty.js +2 -1
- package/dist/features/crawl/crawl-exhaustive.d.ts +55 -0
- package/dist/features/crawl/crawl-exhaustive.js +138 -0
- package/dist/features/crawl/crawl-tools.d.ts +9 -2
- package/dist/features/crawl/crawl-tools.js +28 -12
- package/dist/features/crawl/crawl.d.ts +8 -9
- package/dist/features/crawl/crawl.js +61 -65
- package/dist/features/exhaust/app-coverage.d.ts +5 -1
- package/dist/features/exhaust/app-coverage.js +3 -1
- package/dist/features/exhaust/code-coverage.js +8 -4
- package/dist/features/exhaust/edge-cases.d.ts +133 -0
- package/dist/features/exhaust/edge-cases.js +310 -0
- package/dist/features/exhaust/edges/edge-drive.d.ts +42 -0
- package/dist/features/exhaust/edges/edge-drive.js +364 -0
- package/dist/features/exhaust/edges/edge-run.d.ts +59 -0
- package/dist/features/exhaust/edges/edge-run.js +169 -0
- package/dist/features/exhaust/explorer.d.ts +87 -14
- package/dist/features/exhaust/explorer.js +159 -25
- package/dist/features/exhaust/failure-branches.d.ts +5 -0
- package/dist/features/exhaust/failure-branches.js +29 -11
- package/dist/features/exhaust/invariants.d.ts +112 -0
- package/dist/features/exhaust/invariants.js +188 -0
- package/dist/features/exhaust/ledger.d.ts +68 -0
- package/dist/features/exhaust/ledger.js +121 -13
- package/dist/features/exhaust/session-fold.d.ts +10 -0
- package/dist/features/exhaust/session-fold.js +46 -3
- package/dist/features/exhaust/session-port.d.ts +3 -1
- package/dist/features/exhaust/session-port.js +97 -28
- package/dist/features/grade/grade-answer.d.ts +99 -0
- package/dist/features/grade/grade-answer.js +112 -0
- package/dist/features/grade/grade-noise.d.ts +27 -0
- package/dist/features/grade/grade-noise.js +55 -0
- package/dist/features/grade/grade-renumber.d.ts +12 -0
- package/dist/features/grade/grade-renumber.js +86 -0
- package/dist/features/grade/grade-state.d.ts +50 -0
- package/dist/features/grade/grade-state.js +93 -0
- package/dist/features/grade/grade-suggest.d.ts +33 -0
- package/dist/features/grade/grade-suggest.js +98 -0
- package/dist/features/license/license.d.ts +11 -71
- package/dist/features/license/license.js +43 -136
- package/dist/features/visual/desktop-capture.d.ts +33 -0
- package/dist/features/visual/desktop-capture.js +94 -0
- package/dist/features/visual/step-shots.js +139 -35
- package/dist/features/visual/visual-tools.d.ts +0 -18
- package/dist/features/visual/visual-tools.js +67 -99
- package/dist/import-graph.js +5 -6
- package/dist/index.d.ts +3 -1
- package/dist/index.js +19 -7
- package/dist/judgement/capsule/causal-summary.js +9 -2
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +13 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +1 -1
- package/dist/judgement/runs/reticle-runner.js +16 -2
- package/dist/judgement/runs/run-ledger.d.ts +7 -5
- package/dist/judgement/runs/run-ledger.js +98 -69
- package/dist/judgement/runs/runner-port.d.ts +2 -0
- package/dist/judgement/runs/runner-port.js +23 -5
- package/dist/judgement/runs/verification-sync.d.ts +6 -3
- package/dist/judgement/runs/verification-sync.js +21 -10
- package/dist/language/flows/affected-tools.d.ts +1 -1
- package/dist/language/flows/affected-tools.js +49 -30
- package/dist/language/flows/change/git-changed.d.ts +2 -1
- package/dist/language/flows/change/git-changed.js +19 -2
- package/dist/language/flows/fields/flow-secret-field.d.ts +1 -13
- package/dist/language/flows/fields/flow-secret-field.js +77 -21
- package/dist/language/flows/flow-anchor.d.ts +60 -2
- package/dist/language/flows/flow-anchor.js +125 -20
- package/dist/language/flows/flow-classify.d.ts +20 -0
- package/dist/language/flows/flow-classify.js +90 -12
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +25 -1
- package/dist/language/flows/flow-journey.d.ts +38 -4
- package/dist/language/flows/flow-journey.js +138 -8
- package/dist/language/flows/flow-replay-run.d.ts +0 -16
- package/dist/language/flows/flow-replay-run.js +76 -14
- package/dist/language/flows/flow-replay-types.d.ts +4 -2
- package/dist/language/flows/flow-replay.d.ts +19 -1
- package/dist/language/flows/flow-replay.js +169 -52
- package/dist/language/flows/flow-replayable.js +7 -1
- package/dist/language/flows/flow-start-path.d.ts +34 -5
- package/dist/language/flows/flow-start-path.js +202 -15
- package/dist/language/flows/flow-step-runners.d.ts +14 -13
- package/dist/language/flows/flow-step-runners.js +184 -109
- package/dist/language/flows/flow-store-for-session.d.ts +26 -25
- package/dist/language/flows/flow-store-for-session.js +51 -5
- package/dist/language/flows/flow-tools.js +46 -33
- package/dist/language/flows/flows.js +176 -76
- package/dist/language/flows/recording/tape/recordings.d.ts +21 -16
- package/dist/language/flows/recording/tape/recordings.js +112 -49
- package/dist/language/flows/replay.d.ts +36 -12
- package/dist/language/flows/replay.js +193 -50
- package/dist/language/flows/steps/page-steps.d.ts +68 -0
- package/dist/language/flows/steps/page-steps.js +198 -0
- package/dist/language/flows/suite/sequential-run.d.ts +68 -0
- package/dist/language/flows/suite/sequential-run.js +96 -0
- package/dist/language/flows/verify-change-tools.js +26 -15
- package/dist/launch-chromium.d.ts +1 -0
- package/dist/launch-chromium.js +49 -12
- package/dist/memory/cloud/background-sync.d.ts +13 -0
- package/dist/memory/cloud/background-sync.js +24 -3
- package/dist/memory/cloud/sync-daemon.js +26 -27
- package/dist/memory/cloud/sync-screenshots.js +6 -1
- package/dist/memory/journal/attach-journal.js +2 -1
- package/dist/memory/journal/drive-flow.d.ts +7 -0
- package/dist/memory/journal/drive-flow.js +44 -13
- package/dist/memory/journal/journal-recorder.d.ts +4 -2
- package/dist/memory/journal/session-journal.d.ts +7 -0
- package/dist/memory/journal/session-journal.js +58 -10
- package/dist/memory/project/root-claims.d.ts +9 -0
- package/dist/memory/project/root-claims.js +9 -4
- package/dist/portal/bridge/bridge.d.ts +13 -4
- package/dist/portal/bridge/bridge.js +10 -9
- package/dist/portal/input/download-capture.d.ts +7 -0
- package/dist/portal/input/download-capture.js +92 -0
- package/dist/portal/input/network-detail.d.ts +6 -0
- package/dist/portal/input/network-detail.js +12 -1
- package/dist/portal/input/network-mock-tools.js +49 -13
- package/dist/portal/input/network-mock.d.ts +8 -0
- package/dist/portal/input/network-mock.js +30 -10
- package/dist/portal/input/page-capture.d.ts +24 -0
- package/dist/portal/input/page-capture.js +33 -0
- package/dist/portal/input/real-input.d.ts +35 -18
- package/dist/portal/input/real-input.js +99 -33
- package/dist/portal/input/viewport-tools.d.ts +8 -0
- package/dist/portal/input/viewport-tools.js +81 -21
- package/dist/portal/pool/browser-pool.d.ts +16 -30
- package/dist/portal/pool/browser-pool.js +64 -52
- package/dist/portal/pool/context-permissions.d.ts +34 -17
- package/dist/portal/pool/context-permissions.js +94 -1
- package/dist/portal/pool/csp-widen.d.ts +62 -0
- package/dist/portal/pool/csp-widen.js +132 -0
- package/dist/portal/pool/determinism.d.ts +52 -0
- package/dist/portal/pool/determinism.js +259 -0
- package/dist/portal/pool/lease-emulation.d.ts +34 -1
- package/dist/portal/pool/lease-emulation.js +18 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +6 -0
- package/dist/portal/pool/lease-marker-stamp.js +15 -1
- package/dist/portal/pool/lease-page-error.d.ts +56 -0
- package/dist/portal/pool/lease-page-error.js +160 -0
- package/dist/portal/pool/page-error-journal.d.ts +63 -0
- package/dist/portal/pool/page-error-journal.js +208 -0
- package/dist/portal/pool/playwright-launcher.js +71 -15
- package/dist/portal/pool/pool-contract.d.ts +49 -1
- package/dist/portal/pool/pool-lease.d.ts +70 -2
- package/dist/portal/pool/pool-lease.js +23 -0
- package/dist/portal/pool/zero-install.d.ts +8 -0
- package/dist/portal/pool/zero-install.js +91 -1
- package/dist/portal/session/dev-server/dev-command.d.ts +11 -2
- package/dist/portal/session/dev-server/dev-command.js +110 -16
- package/dist/portal/session/dev-server/dev-server-probe.d.ts +7 -0
- package/dist/portal/session/dev-server/dev-server-probe.js +9 -0
- package/dist/portal/session/dev-server/project-ports.d.ts +21 -0
- package/dist/portal/session/dev-server/project-ports.js +62 -0
- package/dist/portal/session/facts/departed-network.d.ts +66 -0
- package/dist/portal/session/facts/departed-network.js +142 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +9 -0
- package/dist/portal/session/no-session-diagnosis.js +76 -27
- package/dist/portal/session/no-session-next-action.d.ts +14 -0
- package/dist/portal/session/no-session-next-action.js +56 -7
- package/dist/portal/session/no-session-watch.d.ts +6 -0
- package/dist/portal/session/no-session-watch.js +41 -4
- package/dist/portal/session/page-commands/undeclared-command.d.ts +9 -3
- package/dist/portal/session/page-commands/undeclared-command.js +16 -7
- package/dist/portal/session/recorded-gaps.d.ts +1 -1
- package/dist/portal/session/recorded-gaps.js +5 -2
- package/dist/portal/session/serving-directory.d.ts +10 -0
- package/dist/portal/session/serving-directory.js +39 -8
- package/dist/portal/session/session-manager.d.ts +10 -0
- package/dist/portal/session/session-manager.js +211 -81
- package/dist/portal/session/session.js +4 -3
- package/dist/portal/session/zero-install-first-call.d.ts +20 -1
- package/dist/portal/session/zero-install-first-call.js +34 -2
- package/dist/start-wiring.d.ts +30 -2
- package/dist/start-wiring.js +74 -9
- package/dist/surface/mcp/mcp-proxy.js +10 -2
- package/dist/surface/mcp/mcp.js +8 -5
- package/dist/surface/mcp/peer/agents-connected.d.ts +6 -0
- package/dist/surface/mcp/peer/agents-connected.js +58 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +17 -5
- package/dist/surface/mcp/shared-params.d.ts +2 -0
- package/dist/surface/mcp/shared-params.js +31 -0
- package/dist/surface/tools/act/act-observation.d.ts +40 -2
- package/dist/surface/tools/act/act-observation.js +118 -12
- package/dist/surface/tools/act/act-preflight.js +38 -18
- package/dist/surface/tools/act/act-sequence-retry.d.ts +23 -2
- package/dist/surface/tools/act/act-sequence-retry.js +61 -5
- package/dist/surface/tools/act/act-target.js +3 -1
- package/dist/surface/tools/act/after-match.d.ts +10 -0
- package/dist/surface/tools/act/after-match.js +40 -0
- package/dist/surface/tools/act/already-true.js +1 -1
- package/dist/surface/tools/act/navigation/reload-result.d.ts +12 -1
- package/dist/surface/tools/act/navigation/reload-result.js +25 -2
- package/dist/surface/tools/act/resolve-target.d.ts +17 -1
- package/dist/surface/tools/act/resolve-target.js +59 -9
- package/dist/surface/tools/act/sequence-grade.d.ts +15 -1
- package/dist/surface/tools/act/sequence-grade.js +45 -27
- package/dist/surface/tools/act/settle-in-flight.js +27 -15
- package/dist/surface/tools/act-command.d.ts +23 -0
- package/dist/surface/tools/act-command.js +50 -0
- package/dist/surface/tools/act-sequence-tool.js +81 -50
- package/dist/surface/tools/act-tools.d.ts +1 -13
- package/dist/surface/tools/act-tools.js +83 -95
- package/dist/surface/tools/agent/build-staleness.d.ts +1 -1
- package/dist/surface/tools/agent/build-staleness.js +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +18 -12
- package/dist/surface/tools/browser-tools.js +87 -13
- package/dist/surface/tools/compare-tools.d.ts +11 -0
- package/dist/surface/tools/compare-tools.js +94 -0
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.js +11 -3
- package/dist/surface/tools/empty-session-list.d.ts +2 -0
- package/dist/surface/tools/empty-session-list.js +4 -2
- package/dist/surface/tools/error-recovery.d.ts +12 -1
- package/dist/surface/tools/error-recovery.js +131 -40
- package/dist/surface/tools/explore-tools.js +1 -1
- package/dist/surface/tools/invoke-tool.js +29 -21
- package/dist/surface/tools/lease-coverage-tools.d.ts +49 -0
- package/dist/surface/tools/lease-coverage-tools.js +128 -0
- package/dist/surface/tools/lease-hint.d.ts +42 -1
- package/dist/surface/tools/lease-hint.js +52 -3
- package/dist/surface/tools/lease-readiness.d.ts +47 -0
- package/dist/surface/tools/lease-readiness.js +126 -0
- package/dist/surface/tools/lease-seed.d.ts +16 -1
- package/dist/surface/tools/lease-seed.js +37 -4
- package/dist/surface/tools/lease-tools.d.ts +3 -41
- package/dist/surface/tools/lease-tools.js +104 -124
- package/dist/surface/tools/lease-url-identity.d.ts +46 -0
- package/dist/surface/tools/lease-url-identity.js +97 -0
- package/dist/surface/tools/merge-tools.js +99 -2
- package/dist/surface/tools/merged-name-redirect.js +5 -1
- package/dist/surface/tools/observe-tools.js +15 -9
- package/dist/surface/tools/read/console-pre-attach.d.ts +19 -0
- package/dist/surface/tools/read/console-pre-attach.js +23 -0
- package/dist/surface/tools/read-tools.js +33 -30
- package/dist/surface/tools/real-input-attempt.d.ts +0 -8
- package/dist/surface/tools/real-input-attempt.js +143 -28
- package/dist/surface/tools/repeat-hint.d.ts +40 -0
- package/dist/surface/tools/repeat-hint.js +171 -0
- package/dist/surface/tools/run-report.d.ts +2 -2
- package/dist/surface/tools/run-report.js +27 -15
- package/dist/surface/tools/session-ports.d.ts +14 -0
- package/dist/surface/tools/session-ports.js +53 -0
- package/dist/surface/tools/tool-kit.d.ts +18 -0
- package/dist/surface/tools/tool-kit.js +9 -3
- package/dist/surface/tools/tool-surface.js +0 -1
- package/dist/surface/tools/tools.js +54 -18
- package/dist/surface/tools/type-spelling.d.ts +13 -0
- package/dist/surface/tools/type-spelling.js +36 -0
- package/dist/telemetry/agent-client.d.ts +6 -0
- package/dist/telemetry/agent-client.js +10 -0
- package/dist/telemetry/argument-shape.js +17 -7
- package/dist/telemetry/cli-telemetry.d.ts +10 -1
- package/dist/telemetry/cli-telemetry.js +15 -0
- package/dist/telemetry/init-telemetry.d.ts +2 -1
- package/dist/telemetry/init-telemetry.js +47 -2
- package/dist/telemetry/install-trace.js +23 -4
- package/dist/telemetry/onboarding-funnel.d.ts +19 -2
- package/dist/telemetry/onboarding-funnel.js +25 -3
- package/dist/telemetry/proxy-telemetry.d.ts +2 -1
- package/dist/telemetry/proxy-telemetry.js +2 -2
- package/dist/telemetry/session-metrics.d.ts +1 -1
- package/dist/telemetry/session-metrics.js +67 -27
- package/dist/telemetry/telemetry.d.ts +3 -1
- package/dist/telemetry/telemetry.js +60 -28
- package/dist/telemetry/tool-refused.d.ts +6 -3
- package/dist/telemetry/tool-refused.js +15 -3
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +1 -1
- package/docs/architecture.md +3 -6
- package/docs/capabilities.mdx +61 -1
- package/docs/cli/affected.mdx +9 -7
- package/docs/cli/cloud.mdx +3 -3
- package/docs/cli/compare.mdx +94 -0
- package/docs/cli/doctor.mdx +41 -2
- package/docs/cli/grade.mdx +97 -0
- package/docs/cli/help.mdx +4 -2
- package/docs/cli/license.mdx +13 -12
- package/docs/cli/restart.mdx +7 -5
- package/docs/cli/rollback.mdx +5 -5
- package/docs/cli/setup.mdx +13 -2
- package/docs/cli/status.mdx +4 -0
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/update.mdx +2 -2
- package/docs/cli/verify.mdx +23 -1
- package/docs/cli.mdx +34 -24
- package/docs/deploy-checks.md +25 -0
- package/docs/desktop.mdx +1 -1
- package/docs/enterprise.md +17 -22
- package/docs/environment.mdx +1 -0
- package/docs/first-drive.md +1 -1
- package/docs/flows.md +11 -1
- package/docs/frameworks.mdx +9 -9
- package/docs/getting-started.md +1 -1
- package/docs/install-manual.mdx +16 -1
- package/docs/license-activation.mdx +3 -3
- package/docs/packages/engine.mdx +1 -1
- package/docs/packages/server.mdx +1 -1
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages/test.mdx +1 -1
- package/docs/packages.mdx +1 -1
- package/docs/platform-integration.md +1 -1
- package/docs/predicates.mdx +1 -1
- package/docs/quickstart.mdx +68 -49
- package/docs/skill-setup.md +1 -1
- package/docs/skill.md +14 -13
- package/docs/telemetry.md +6 -4
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/verify.mdx +4 -1
- package/docs/troubleshooting.mdx +1 -1
- package/docs/usage.md +17 -14
- package/package.json +18 -14
- package/LICENSE-ENTERPRISE +0 -37
- package/dist/features/ee/audit-log.d.ts +0 -14
- package/dist/features/ee/audit-log.js +0 -11
- package/dist/features/exhaust/exhaust-run.d.ts +0 -33
- package/dist/features/exhaust/exhaust-run.js +0 -82
|
@@ -1,142 +1,171 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The run ledger: what
|
|
2
|
+
* The run ledger: what each agent run checked, saved and read, kept until its report is taken.
|
|
3
3
|
*
|
|
4
|
-
* A run is
|
|
4
|
+
* A run is one agent's calls from its first Reticle call to the call that ends it (a session end, a
|
|
5
5
|
* yield, a released tab). The verdicts come from the journal records the agent's own calls wrote;
|
|
6
|
-
* the Harness's are never counted. Taking the report
|
|
7
|
-
* zero.
|
|
6
|
+
* the Harness's are never counted. Taking the report ends that run, so the agent's next run starts
|
|
7
|
+
* at zero.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
* call
|
|
9
|
+
* The ledger keeps one run for each MCP attach id. Two agents on one daemon (two worktrees of one
|
|
10
|
+
* project) call in turn. When the ledger kept one run, each call restarted the other agent's run,
|
|
11
|
+
* and a released lease reported the other agent's claims and none of its own. A record goes to the
|
|
12
|
+
* run of the connection that wrote it, and a call that ends a run takes the caller's run (#1900).
|
|
11
13
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
+
* A record from no connection (the HUD, the CLI, an agent record that ends outside its call
|
|
15
|
+
* context) goes to the run of the agent that called last. An agent that stops without a call that
|
|
16
|
+
* ends its run leaves its run here. That run is dropped when it is idle for `RUN_IDLE_LIMIT_MS`.
|
|
14
17
|
*/
|
|
15
18
|
import { supersededChecks } from '@reticlehq/engine/evidence/superseded-checks.js';
|
|
16
19
|
import { JournalVerdictEffectSchema, ReticleTool, Verified, } from '@reticlehq/core';
|
|
20
|
+
import { callingAttachId } from '../../hooks/coding-agents.js';
|
|
17
21
|
const SAW = 'saw ';
|
|
18
22
|
const FLOW = 'flow ';
|
|
23
|
+
/** A run with no agent call for this long is dropped. A working agent calls much more often. */
|
|
24
|
+
export const RUN_IDLE_LIMIT_MS = 6 * 60 * 60 * 1000;
|
|
19
25
|
/** One piece of evidence for a claim: what the check saw, else the source line it drove. */
|
|
20
26
|
function evidenceOf(effect) {
|
|
21
|
-
if (effect.observed !== undefined)
|
|
27
|
+
if (effect.observed !== undefined) {
|
|
22
28
|
return `${SAW}${effect.observed}`;
|
|
29
|
+
}
|
|
23
30
|
return effect.source;
|
|
24
31
|
}
|
|
25
32
|
/** `no` when anything failed, `yes` only when something held and nothing was undecided. */
|
|
26
33
|
function runVerified(all) {
|
|
27
|
-
if (all.includes(Verified.NO))
|
|
34
|
+
if (all.includes(Verified.NO)) {
|
|
28
35
|
return Verified.NO;
|
|
29
|
-
|
|
36
|
+
}
|
|
37
|
+
if (0 === all.length || all.some((v) => Verified.YES !== v)) {
|
|
30
38
|
return Verified.UNKNOWN;
|
|
39
|
+
}
|
|
31
40
|
return Verified.YES;
|
|
32
41
|
}
|
|
42
|
+
const openRun = (now) => ({
|
|
43
|
+
startedAt: now,
|
|
44
|
+
lastAt: now,
|
|
45
|
+
firstVerdictAt: undefined,
|
|
46
|
+
verdicts: [],
|
|
47
|
+
saved: new Set(),
|
|
48
|
+
replayed: new Map(),
|
|
49
|
+
written: 0,
|
|
50
|
+
read: new Set(),
|
|
51
|
+
});
|
|
33
52
|
export class RunLedger {
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
#verdicts = [];
|
|
38
|
-
#saved = new Set();
|
|
39
|
-
#replayed = new Map();
|
|
40
|
-
#written = 0;
|
|
41
|
-
#read = new Set();
|
|
42
|
-
/** An agent call starts. The first one starts the run, and a call from another agent starts a new one. */
|
|
53
|
+
#runs = new Map();
|
|
54
|
+
#last;
|
|
55
|
+
/** An agent call starts. The agent's first call starts its run. A run idle too long is dropped. */
|
|
43
56
|
begin(now, owner) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
for (const [id, run] of this.#runs) {
|
|
58
|
+
if (now - run.lastAt > RUN_IDLE_LIMIT_MS) {
|
|
59
|
+
this.#runs.delete(id);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
const run = this.#runs.get(owner) ?? openRun(now);
|
|
63
|
+
run.lastAt = now;
|
|
64
|
+
this.#runs.set(owner, run);
|
|
65
|
+
this.#last = owner;
|
|
48
66
|
}
|
|
49
67
|
/** An agent call ended. The first one that left a verdict sets the time to the first verdict. */
|
|
50
|
-
after(now) {
|
|
51
|
-
|
|
52
|
-
|
|
68
|
+
after(now, owner) {
|
|
69
|
+
const run = this.#run(owner);
|
|
70
|
+
if (run === undefined) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
run.lastAt = Math.max(run.lastAt, now);
|
|
74
|
+
if (0 < run.verdicts.length || 0 < run.replayed.size) {
|
|
75
|
+
run.firstVerdictAt ??= now;
|
|
76
|
+
}
|
|
53
77
|
}
|
|
54
78
|
/** A journal record from the agent's own call. A record with no verdict is not a claim. */
|
|
55
79
|
verdict(action) {
|
|
56
|
-
|
|
80
|
+
const run = this.#run();
|
|
81
|
+
if (run === undefined || action.drivenBy !== undefined) {
|
|
57
82
|
return;
|
|
83
|
+
}
|
|
58
84
|
// A replay is counted once, as a flow, decided as its run decides it (`replayed`). Its journal
|
|
59
85
|
// record said `unknown` where the run said `no`, and one report gave both answers.
|
|
60
|
-
if (ReticleTool.FLOW_REPLAY === action.tool)
|
|
86
|
+
if (ReticleTool.FLOW_REPLAY === action.tool) {
|
|
61
87
|
return;
|
|
88
|
+
}
|
|
62
89
|
const parsed = JournalVerdictEffectSchema.safeParse(action.effect);
|
|
63
|
-
if (parsed.success)
|
|
64
|
-
|
|
90
|
+
if (parsed.success) {
|
|
91
|
+
run.verdicts.push(parsed.data);
|
|
92
|
+
}
|
|
65
93
|
}
|
|
66
94
|
flowSaved(name) {
|
|
67
|
-
|
|
68
|
-
this.#saved.add(name);
|
|
95
|
+
this.#run()?.saved.add(name);
|
|
69
96
|
}
|
|
70
97
|
/** The last replay of a flow in this run is its verdict. */
|
|
71
98
|
replayed(name, verified) {
|
|
72
|
-
|
|
73
|
-
this.#replayed.set(name, verified);
|
|
99
|
+
this.#run()?.replayed.set(name, verified);
|
|
74
100
|
}
|
|
75
101
|
memoryWritten(count = 1) {
|
|
76
|
-
|
|
77
|
-
|
|
102
|
+
const run = this.#run();
|
|
103
|
+
if (run !== undefined) {
|
|
104
|
+
run.written += count;
|
|
105
|
+
}
|
|
78
106
|
}
|
|
79
107
|
/** Notes given to the agent. Each one counts once, however often it is shown. */
|
|
80
108
|
memoryRead(notes) {
|
|
81
|
-
|
|
109
|
+
const run = this.#run();
|
|
110
|
+
if (run === undefined) {
|
|
82
111
|
return;
|
|
83
|
-
|
|
84
|
-
|
|
112
|
+
}
|
|
113
|
+
for (const note of notes) {
|
|
114
|
+
run.read.add(note);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
isEmpty(owner) {
|
|
118
|
+
return this.#run(owner) === undefined;
|
|
85
119
|
}
|
|
86
|
-
|
|
87
|
-
|
|
120
|
+
/** The named owner, else the calling connection, else the agent that called last. */
|
|
121
|
+
#owner(owner) {
|
|
122
|
+
return owner ?? callingAttachId() ?? this.#last;
|
|
88
123
|
}
|
|
89
124
|
/**
|
|
90
|
-
*
|
|
91
|
-
*
|
|
125
|
+
* The run a record belongs to. None while no agent call has begun one: a CLI `reticle verify`
|
|
126
|
+
* replays through the same code, and what it did is not the next agent's run.
|
|
92
127
|
*/
|
|
93
|
-
#
|
|
94
|
-
|
|
128
|
+
#run(owner) {
|
|
129
|
+
const id = this.#owner(owner);
|
|
130
|
+
return id === undefined ? undefined : this.#runs.get(id);
|
|
95
131
|
}
|
|
96
|
-
/** The report, without the cloud line (the caller knows the project).
|
|
97
|
-
take(now) {
|
|
98
|
-
const
|
|
132
|
+
/** The owner's report, without the cloud line (the caller knows the project). Ends that run. */
|
|
133
|
+
take(now, owner) {
|
|
134
|
+
const id = this.#owner(owner);
|
|
135
|
+
const run = this.#run(owner) ?? openRun(now);
|
|
136
|
+
if (id !== undefined) {
|
|
137
|
+
this.#runs.delete(id);
|
|
138
|
+
}
|
|
139
|
+
const started = run.startedAt;
|
|
99
140
|
// A passive check that read too early is not counted: the rule every fold applies.
|
|
100
|
-
const superseded = supersededChecks(
|
|
141
|
+
const superseded = supersededChecks(run.verdicts.map((v) => ({
|
|
101
142
|
key: v.claim,
|
|
102
143
|
passive: false === v.declaredBeforeActing,
|
|
103
144
|
held: Verified.YES === v.verified,
|
|
104
145
|
failed: Verified.NO === v.verified,
|
|
105
146
|
})));
|
|
106
|
-
const counted =
|
|
147
|
+
const counted = run.verdicts.filter((_, at) => !superseded.has(at));
|
|
107
148
|
const claims = counted.map((v) => {
|
|
108
149
|
const evidence = evidenceOf(v);
|
|
109
150
|
return evidence === undefined
|
|
110
151
|
? { claim: v.claim, verified: v.verified }
|
|
111
152
|
: { claim: v.claim, verified: v.verified, evidence };
|
|
112
153
|
});
|
|
113
|
-
const replayed = [...
|
|
114
|
-
|
|
154
|
+
const replayed = [...run.replayed].map(([name, verified]) => ({ name, verified }));
|
|
155
|
+
return {
|
|
115
156
|
verified: runVerified([...claims.map((c) => c.verified), ...replayed.map((r) => r.verified)]),
|
|
116
157
|
claims,
|
|
117
158
|
caught: [
|
|
118
159
|
...claims.filter((c) => Verified.NO === c.verified).map((c) => c.claim),
|
|
119
160
|
...replayed.filter((r) => Verified.NO === r.verified).map((r) => `${FLOW}${r.name}`),
|
|
120
161
|
],
|
|
121
|
-
flows: { saved: [...
|
|
122
|
-
memory: { written:
|
|
162
|
+
flows: { saved: [...run.saved], replayed },
|
|
163
|
+
memory: { written: run.written, read: run.read.size },
|
|
123
164
|
wallMs: Math.max(0, now - started),
|
|
124
|
-
...(
|
|
165
|
+
...(run.firstVerdictAt === undefined
|
|
125
166
|
? {}
|
|
126
|
-
: { firstVerdictMs: Math.max(0,
|
|
167
|
+
: { firstVerdictMs: Math.max(0, run.firstVerdictAt - started) }),
|
|
127
168
|
};
|
|
128
|
-
this.#reset();
|
|
129
|
-
return report;
|
|
130
|
-
}
|
|
131
|
-
#reset() {
|
|
132
|
-
this.#owner = undefined;
|
|
133
|
-
this.#startedAt = undefined;
|
|
134
|
-
this.#firstVerdictAt = undefined;
|
|
135
|
-
this.#verdicts = [];
|
|
136
|
-
this.#saved = new Set();
|
|
137
|
-
this.#replayed = new Map();
|
|
138
|
-
this.#written = 0;
|
|
139
|
-
this.#read = new Set();
|
|
140
169
|
}
|
|
141
170
|
}
|
|
142
171
|
/** The daemon's ledger. */
|
|
@@ -12,4 +12,6 @@ export declare function createRunnerPort(deps: ToolDeps, sessionId?: string,
|
|
|
12
12
|
/** `reticle verify --confirm-dangerous`: this run acknowledges the steps held as destructive. */
|
|
13
13
|
opts?: {
|
|
14
14
|
confirmDangerous?: boolean;
|
|
15
|
+
requireStartControl?: boolean;
|
|
16
|
+
sweep?: boolean;
|
|
15
17
|
}): RunnerPort;
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
* and a uuid generator. The ReticleRunner core (tested with a fake port) holds all the orchestration and
|
|
5
5
|
* verdict logic, so this layer carries no decisions.
|
|
6
6
|
*/
|
|
7
|
+
import { ReplayStatus } from '@reticlehq/core';
|
|
7
8
|
import { replayAndLearn } from '../../language/flows/flow-learning.js';
|
|
9
|
+
import { sessionUrlOf } from '../../language/flows/flow-lease.js';
|
|
10
|
+
import { flowStartState } from '../../surface/tools/session-ports.js';
|
|
8
11
|
import { flowsForSession } from '../../language/flows/flow-store-for-session.js';
|
|
9
12
|
import { safeSessionTarget } from '../../memory/project/session-root.js';
|
|
10
13
|
import { defaultRunId } from './default-run-id.js';
|
|
@@ -13,17 +16,32 @@ export { defaultRunId } from './default-run-id.js';
|
|
|
13
16
|
export function createRunnerPort(deps, sessionId,
|
|
14
17
|
/** `reticle verify --confirm-dangerous`: this run acknowledges the steps held as destructive. */
|
|
15
18
|
opts = {}) {
|
|
19
|
+
// Each flow starts from the state the run started in, so one that signs out cannot fail the rest.
|
|
20
|
+
const startState = flowStartState(deps.realInput, () => sessionUrlOf(deps, sessionId));
|
|
16
21
|
return {
|
|
17
22
|
// Resolved as replay resolves it, so every listed name is one replay can load.
|
|
18
23
|
listFlows: () => {
|
|
19
24
|
const target = safeSessionTarget(deps, sessionId);
|
|
20
25
|
return flowsForSession(deps, target).flows.list(target.projectId);
|
|
21
26
|
},
|
|
22
|
-
replayFlow: (name) =>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
replayFlow: async (name) => {
|
|
28
|
+
const cannotStart = await startState();
|
|
29
|
+
if (cannotStart !== undefined) {
|
|
30
|
+
return {
|
|
31
|
+
name,
|
|
32
|
+
status: ReplayStatus.UNVERIFIABLE,
|
|
33
|
+
steps: [],
|
|
34
|
+
unverifiable: { reason: cannotStart },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
return await replayAndLearn(deps, {
|
|
38
|
+
flowName: name,
|
|
39
|
+
...(sessionId === undefined ? {} : { sessionId }),
|
|
40
|
+
...(true === opts.confirmDangerous ? { confirmDangerous: true } : {}),
|
|
41
|
+
...(true === opts.requireStartControl ? { requireStartControl: true } : {}),
|
|
42
|
+
...(true === opts.sweep ? { sweep: true } : {}),
|
|
43
|
+
});
|
|
44
|
+
},
|
|
27
45
|
now: () => deps.now(),
|
|
28
46
|
newRunId: defaultRunId,
|
|
29
47
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type FlowFile, type FlowReplayResult } from '@reticlehq/core';
|
|
2
2
|
import { type VerificationRunInput } from './artifact/build-verification-run.js';
|
|
3
|
+
import { AutomationHint } from '@reticlehq/core/telemetry';
|
|
3
4
|
import { type ProjectTarget } from '../../memory/project/session-root.js';
|
|
4
5
|
import type { ToolDeps } from '../../surface/tools/tool-kit.js';
|
|
5
6
|
/** A replay plus the wall-clock time it took — the shape the verify handler already collects. */
|
|
@@ -12,8 +13,10 @@ export interface TimedReplay {
|
|
|
12
13
|
/** The MCP client name `reticle verify` (the command line, CI's path) connects to a daemon as. */
|
|
13
14
|
export declare const CLI_CLIENT_NAME = "reticle-cli";
|
|
14
15
|
/**
|
|
15
|
-
* Who ran the command line, and why.
|
|
16
|
-
*
|
|
16
|
+
* Who ran the command line, and why. Off CI it is the person who holds the key, so the cloud
|
|
17
|
+
* credits them. On CI the `automation` hint says which kind: a CI vendor runner is the pipeline,
|
|
18
|
+
* trigger `ci`; a coding-agent sandbox is a coding agent. A container, or `CI` with no vendor,
|
|
19
|
+
* keeps trigger `oem`, because the cloud has no value for either yet.
|
|
17
20
|
*/
|
|
18
|
-
export declare function cliRunAuthor(env: NodeJS.ProcessEnv): Pick<VerificationRunInput, 'agent' | 'trigger'>;
|
|
21
|
+
export declare function cliRunAuthor(env: NodeJS.ProcessEnv, automation?: AutomationHint | undefined): Pick<VerificationRunInput, 'agent' | 'trigger'>;
|
|
19
22
|
export declare function persistAndSyncVerificationRun(deps: ToolDeps, timed: TimedReplay[], target: ProjectTarget): Promise<string | undefined>;
|
|
@@ -21,26 +21,37 @@ import { RunStore } from './artifact/run-store.js';
|
|
|
21
21
|
import { cloudFetch, syncRunToCloud, SyncOutcome } from '../../memory/cloud/cloud-sync.js';
|
|
22
22
|
import { resolveProjectCloud } from '../../memory/cloud/cloud-config.js';
|
|
23
23
|
import { log } from '../../log.js';
|
|
24
|
-
import { isCiEnv } from '../../telemetry/automation-hint.js';
|
|
24
|
+
import { currentAutomationHint, isCiEnv } from '../../telemetry/automation-hint.js';
|
|
25
|
+
import { AutomationHint } from '@reticlehq/core/telemetry';
|
|
25
26
|
import { rootForTarget } from '../../memory/project/session-root.js';
|
|
26
27
|
/** The author of record when no MCP peer introduced itself — a CLI run, or a client that skipped the handshake. */
|
|
27
28
|
const RETICLE_MCP_AGENT_ID = 'reticle-mcp';
|
|
28
29
|
/** The MCP client name `reticle verify` (the command line, CI's path) connects to a daemon as. */
|
|
29
30
|
export const CLI_CLIENT_NAME = 'reticle-cli';
|
|
30
31
|
/**
|
|
31
|
-
* Who ran the command line, and why.
|
|
32
|
-
*
|
|
32
|
+
* Who ran the command line, and why. Off CI it is the person who holds the key, so the cloud
|
|
33
|
+
* credits them. On CI the `automation` hint says which kind: a CI vendor runner is the pipeline,
|
|
34
|
+
* trigger `ci`; a coding-agent sandbox is a coding agent. A container, or `CI` with no vendor,
|
|
35
|
+
* keeps trigger `oem`, because the cloud has no value for either yet.
|
|
33
36
|
*/
|
|
34
|
-
export function cliRunAuthor(env) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
agent: { id: CLI_CLIENT_NAME, kind: RunAgentKind.OEM_PIPELINE },
|
|
38
|
-
trigger: { kind: RunTrigger.OEM },
|
|
39
|
-
}
|
|
40
|
-
: {
|
|
37
|
+
export function cliRunAuthor(env, automation = currentAutomationHint(env)) {
|
|
38
|
+
if (!isCiEnv(env)) {
|
|
39
|
+
return {
|
|
41
40
|
agent: { id: CLI_CLIENT_NAME, kind: RunAgentKind.HUMAN },
|
|
42
41
|
trigger: { kind: RunTrigger.MANUAL },
|
|
43
42
|
};
|
|
43
|
+
}
|
|
44
|
+
if (AutomationHint.AGENT_SANDBOX === automation) {
|
|
45
|
+
return {
|
|
46
|
+
agent: { id: CLI_CLIENT_NAME, kind: RunAgentKind.CODING_AGENT },
|
|
47
|
+
trigger: { kind: RunTrigger.MANUAL },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const trigger = AutomationHint.CI_RUNNER === automation ? RunTrigger.CI : RunTrigger.OEM;
|
|
51
|
+
return {
|
|
52
|
+
agent: { id: CLI_CLIENT_NAME, kind: RunAgentKind.OEM_PIPELINE },
|
|
53
|
+
trigger: { kind: trigger },
|
|
54
|
+
};
|
|
44
55
|
}
|
|
45
56
|
/** Who ran a suite, and why: the command line by `cliRunAuthor`, any other client as a coding agent. */
|
|
46
57
|
function agentAndTrigger(client) {
|
|
@@ -1,10 +1,40 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { ReticleTool } from '@reticlehq/core';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
2
|
+
import { asString, ReticleTool } from '@reticlehq/core';
|
|
3
|
+
import { sessionIdShape } from '../../surface/tools/tool-kit.js';
|
|
4
|
+
import { resolveChangedFiles } from '../../command/cli/cli-flow-commands.js';
|
|
5
|
+
import { namedFlowsForSession } from './flow-store-for-session.js';
|
|
6
6
|
import { affectedSavedFlows } from './change/flow-sources.js';
|
|
7
7
|
import { RECORD_A_FLOW } from './suite/coverage.js';
|
|
8
|
+
/**
|
|
9
|
+
* Why the answer is empty, when that needs saying.
|
|
10
|
+
*
|
|
11
|
+
* Several situations produced the same empty answer: no files changed, no flows saved, and a git
|
|
12
|
+
* ref that resolved to nothing. Only the first means "nothing to re-verify". The others mean the
|
|
13
|
+
* question could not be answered, and re-running nothing on that basis is how a regression ships.
|
|
14
|
+
*/
|
|
15
|
+
function emptyAnswerReason(facts) {
|
|
16
|
+
const { changed, since, fileCount, flowCount, changedCount, unmatchedRoot } = facts;
|
|
17
|
+
// No folder declares this project, so nothing here is about a checkout (#1550).
|
|
18
|
+
if (unmatchedRoot !== undefined) {
|
|
19
|
+
return `no flows here: no folder on disk declares this project, so its evidence goes to ${unmatchedRoot}. Run \`reticle init\` in the app's folder, or lease the tab from there.`;
|
|
20
|
+
}
|
|
21
|
+
// A git failure OUTRANKS every other explanation: the others describe a question that was
|
|
22
|
+
// answered, and this one is a question that was not. Reporting "nothing changed" over a mistyped
|
|
23
|
+
// ref or a shallow clone is how a regression ships past the tool meant to catch it.
|
|
24
|
+
if (true === changed.failed) {
|
|
25
|
+
return `could not read the diff for \`${String(since)}\`, so NOTHING was compared and this result proves nothing: ${changed.reason ?? 'git failed'}`;
|
|
26
|
+
}
|
|
27
|
+
if (0 === flowCount) {
|
|
28
|
+
return `no saved flows exist yet, so nothing COULD be affected. ${RECORD_A_FLOW}`;
|
|
29
|
+
}
|
|
30
|
+
if (0 !== changedCount) {
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
if (since === undefined && 0 === fileCount) {
|
|
34
|
+
return 'no files were given and no `since` ref was passed, so nothing was compared — pass the files you edited, or a git ref';
|
|
35
|
+
}
|
|
36
|
+
return 'nothing changed against that input, so no saved flow needs re-verifying';
|
|
37
|
+
}
|
|
8
38
|
/**
|
|
9
39
|
* `reticle_affected` — which saved flows must re-verify for a set of changed files.
|
|
10
40
|
*
|
|
@@ -27,6 +57,7 @@ export const AFFECTED_TOOLS = [
|
|
|
27
57
|
description: 'Which saved flows must re-verify for a set of changed files. Pass the files you edited (and/or `since` for a git ref to diff against). Returns { changedFiles, affected, unknownProvenance } — `affected` is what to re-run, and `unknownProvenance` are flows included only because Reticle cannot tell which sources they cover, so they are re-verified by default rather than silently skipped.',
|
|
28
58
|
example: { files: ['src/App.tsx'] },
|
|
29
59
|
inputSchema: {
|
|
60
|
+
...sessionIdShape,
|
|
30
61
|
files: z
|
|
31
62
|
.array(z.string())
|
|
32
63
|
.optional()
|
|
@@ -46,34 +77,22 @@ export const AFFECTED_TOOLS = [
|
|
|
46
77
|
? args['files'].filter((f) => 'string' === typeof f)
|
|
47
78
|
: [];
|
|
48
79
|
const since = 'string' === typeof args['since'] ? args['since'] : undefined;
|
|
49
|
-
//
|
|
50
|
-
//
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
80
|
+
// The project of the tab being driven, not the folder the daemon started in (#1550). The flows
|
|
81
|
+
// come from the store `flows` replays from, so a flow named here can be replayed by that name
|
|
82
|
+
// (#1996). `git diff` runs in the project directory that holds that store.
|
|
83
|
+
const { flows, projectDir, unmatchedRoot } = await namedFlowsForSession(deps, asString(args['sessionId']));
|
|
84
|
+
// A bucket of evidence is not a tree, so a `since` has nothing to diff against.
|
|
85
|
+
const changed = await resolveChangedFiles(files, unmatchedRoot === undefined ? since : undefined, projectDir);
|
|
54
86
|
const changedFiles = changed.files;
|
|
55
|
-
// No `sessionId` on this tool's surface, and it does not need one: passing `undefined`
|
|
56
|
-
// resolves the single connected session, and falls back exactly as before when it cannot.
|
|
57
|
-
// Adding an argument here would be a surface change to fix an addressing bug.
|
|
58
|
-
const flows = await loadNamedFlows(deps.fs, sessionRoot(deps, undefined), sessionProjectId(deps, undefined));
|
|
59
87
|
const result = affectedSavedFlows(flows, changedFiles);
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
changed.failed
|
|
69
|
-
? `could not read the diff for \`${String(since)}\`, so NOTHING was compared and this result proves nothing: ${changed.reason ?? 'git failed'}`
|
|
70
|
-
: 0 === flows.length
|
|
71
|
-
? `no saved flows exist yet, so nothing COULD be affected. ${RECORD_A_FLOW}`
|
|
72
|
-
: 0 === changedFiles.length
|
|
73
|
-
? since === undefined && 0 === files.length
|
|
74
|
-
? 'no files were given and no `since` ref was passed, so nothing was compared — pass the files you edited, or a git ref'
|
|
75
|
-
: 'nothing changed against that input, so no saved flow needs re-verifying'
|
|
76
|
-
: undefined;
|
|
88
|
+
const why = emptyAnswerReason({
|
|
89
|
+
changed,
|
|
90
|
+
since,
|
|
91
|
+
fileCount: files.length,
|
|
92
|
+
flowCount: flows.length,
|
|
93
|
+
changedCount: changedFiles.length,
|
|
94
|
+
unmatchedRoot,
|
|
95
|
+
});
|
|
77
96
|
return {
|
|
78
97
|
changedFiles,
|
|
79
98
|
...result,
|
|
@@ -17,7 +17,8 @@ export interface ChangedFiles {
|
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* Files changed since a git ref (`git diff --name-only <ref>`), so `reticle gate --since main` works
|
|
20
|
-
* from the real diff instead of hand-listed files.
|
|
20
|
+
* from the real diff instead of hand-listed files. Files under Reticle's own directory are left
|
|
21
|
+
* out: a replay writes them, and they are not a change to the app's code.
|
|
21
22
|
*
|
|
22
23
|
* Never throws, and never pretends. The CLI gate may still degrade to "no changes" and pass rather
|
|
23
24
|
* than crash CI — that reasoning was right and is unchanged — but it now has to opt into doing so by
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
|
+
import { ReticleDir } from '@reticlehq/core';
|
|
3
4
|
const run = promisify(execFile);
|
|
4
5
|
/** Parse `git diff --name-only` output into a clean file list. Pure; exported for testing. */
|
|
5
6
|
export function parseGitFiles(output) {
|
|
@@ -19,9 +20,22 @@ export function parseGitFiles(output) {
|
|
|
19
20
|
function refIsOptionLike(ref) {
|
|
20
21
|
return ref.startsWith('-');
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* True when a diff path sits under Reticle's own project directory.
|
|
25
|
+
*
|
|
26
|
+
* A replay writes intent, impact and episode files into that directory. Those writes are
|
|
27
|
+
* Reticle's output, not a change to the app's code. A flow with no source stamps reads any
|
|
28
|
+
* change as "affected", so counting them marked flows the gate had just proved as uncovered
|
|
29
|
+
* (#2050). The directory can sit below the repo root, so any path segment counts. `git diff`
|
|
30
|
+
* prints paths with `/` on every platform.
|
|
31
|
+
*/
|
|
32
|
+
function isReticleOwnPath(path) {
|
|
33
|
+
return path.split('/').includes(ReticleDir.ROOT);
|
|
34
|
+
}
|
|
22
35
|
/**
|
|
23
36
|
* Files changed since a git ref (`git diff --name-only <ref>`), so `reticle gate --since main` works
|
|
24
|
-
* from the real diff instead of hand-listed files.
|
|
37
|
+
* from the real diff instead of hand-listed files. Files under Reticle's own directory are left
|
|
38
|
+
* out: a replay writes them, and they are not a change to the app's code.
|
|
25
39
|
*
|
|
26
40
|
* Never throws, and never pretends. The CLI gate may still degrade to "no changes" and pass rather
|
|
27
41
|
* than crash CI — that reasoning was right and is unchanged — but it now has to opt into doing so by
|
|
@@ -38,7 +52,10 @@ export async function changedFilesSince(ref, cwd) {
|
|
|
38
52
|
}
|
|
39
53
|
try {
|
|
40
54
|
const { stdout } = await run('git', ['diff', '--name-only', ref], { cwd });
|
|
41
|
-
return {
|
|
55
|
+
return {
|
|
56
|
+
files: parseGitFiles(stdout).filter((file) => !isReticleOwnPath(file)),
|
|
57
|
+
failed: false,
|
|
58
|
+
};
|
|
42
59
|
}
|
|
43
60
|
catch (error) {
|
|
44
61
|
return {
|
|
@@ -41,7 +41,7 @@ export declare const SECRET_FIELD_ARG = "secretField";
|
|
|
41
41
|
* rules must not be able to drift. It used to sit in `replay.ts`, one import away from the sentence
|
|
42
42
|
* saying it had to stay together.
|
|
43
43
|
*/
|
|
44
|
-
export declare
|
|
44
|
+
export declare function secretEnvKey(field: string): string;
|
|
45
45
|
/** The schema of that argument, shared by every tool that replays a flow. */
|
|
46
46
|
export { CALL_SECRETS_ARG };
|
|
47
47
|
export declare const callSecretsArg: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
@@ -59,16 +59,4 @@ export interface UnsuppliedSecret {
|
|
|
59
59
|
field: string;
|
|
60
60
|
envKey: string;
|
|
61
61
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Every credential this flow will replay as the literal placeholder.
|
|
64
|
-
*
|
|
65
|
-
* Checked BEFORE a step runs, because the alternative is what shipped: the placeholder is typed
|
|
66
|
-
* into the password box, sign-in fails, and the flow reports that an element further down the
|
|
67
|
-
* journey has gone missing -- a `drift` verdict naming a component nobody touched, with an
|
|
68
|
-
* invitation to update a flow that was correct.
|
|
69
|
-
*
|
|
70
|
-
* The emptiness rule matches `replayActionArgs` exactly: it substitutes only for a value of
|
|
71
|
-
* non-zero length, so an empty variable leaves the placeholder and must count as unsupplied here.
|
|
72
|
-
* Two different answers to "is this supplied" is how the gate would pass and the replay still fail.
|
|
73
|
-
*/
|
|
74
62
|
export declare function unsuppliedSecrets(flow: FlowFile, env: Record<string, string | undefined>): UnsuppliedSecret[];
|