@reticlehq/server 3.7.0 → 3.8.1
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 +59 -68
- package/bin/reticle.js +9 -2
- package/dist/command/cli/adhoc-suite.js +1 -1
- package/dist/command/cli/adhoc-verdict.d.ts +12 -0
- package/dist/command/cli/adhoc-verdict.js +62 -4
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +5 -1
- package/dist/command/cli/auth/cloud-session.d.ts +11 -19
- package/dist/command/cli/auth/cloud-session.js +23 -0
- package/dist/command/cli/auth/device-flow.d.ts +3 -37
- package/dist/command/cli/cli-doctor.js +66 -21
- package/dist/command/cli/cli-flow-commands.js +53 -11
- package/dist/command/cli/cli-kill.d.ts +8 -0
- package/dist/command/cli/cli-kill.js +43 -3
- package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
- package/dist/command/cli/cli-parse-feedback.js +13 -1
- package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
- package/dist/command/cli/cli-parse-grammar.js +1 -6
- package/dist/command/cli/cli-parse-serve.d.ts +24 -0
- package/dist/command/cli/cli-parse-serve.js +124 -0
- package/dist/command/cli/cli-parse.d.ts +12 -11
- package/dist/command/cli/cli-parse.js +100 -123
- package/dist/command/cli/cli-usage.d.ts +0 -11
- package/dist/command/cli/cli-usage.js +43 -16
- package/dist/command/cli/cli-verify.d.ts +1 -1
- package/dist/command/cli/cli-verify.js +29 -14
- package/dist/command/cli/cloud-cli.js +27 -9
- package/dist/command/cli/cloud-kit.js +3 -3
- package/dist/command/cli/cloud-link.d.ts +1 -20
- package/dist/command/cli/cloud-link.js +2 -0
- package/dist/command/cli/cloud-login.d.ts +6 -2
- package/dist/command/cli/cloud-login.js +13 -41
- package/dist/command/cli/config/checkout.d.ts +10 -0
- package/dist/command/cli/config/checkout.js +78 -0
- package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
- package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
- 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/drive/drive-attach.d.ts +5 -0
- package/dist/command/cli/drive/drive-attach.js +21 -1
- package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
- package/dist/command/cli/hook/codex-transcript.js +224 -0
- package/dist/command/cli/hook/episode-structure.d.ts +24 -0
- package/dist/command/cli/hook/episode-structure.js +138 -0
- package/dist/command/cli/hook/hook-command.d.ts +9 -0
- package/dist/command/cli/hook/hook-command.js +211 -0
- package/dist/command/cli/hook/hook-fast.d.ts +31 -0
- package/dist/command/cli/hook/hook-fast.js +136 -0
- package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
- package/dist/command/cli/hook/prompt-hook.js +199 -0
- package/dist/command/cli/hook/tool-hook.d.ts +21 -0
- package/dist/command/cli/hook/tool-hook.js +259 -0
- package/dist/command/cli/launch/cli-launch.d.ts +2 -0
- package/dist/command/cli/launch/cli-launch.js +22 -2
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
- package/dist/command/cli/mcp-command.d.ts +9 -0
- package/dist/command/cli/mcp-command.js +127 -41
- package/dist/command/cli/open-navigate.d.ts +43 -0
- package/dist/command/cli/open-navigate.js +85 -0
- package/dist/command/cli/ports/port-holder.d.ts +16 -4
- package/dist/command/cli/ports/port-holder.js +58 -12
- package/dist/command/cli/ports/resolve/cli-port.js +18 -2
- package/dist/command/cli/project-name.d.ts +1 -7
- package/dist/command/cli/project-name.js +1 -0
- package/dist/command/cli/report-command.d.ts +8 -2
- package/dist/command/cli/report-command.js +95 -18
- package/dist/command/cli/status-fields.d.ts +9 -2
- package/dist/command/cli/status-fields.js +148 -4
- package/dist/command/cli/try-command.d.ts +3 -4
- package/dist/command/cli/try-command.js +6 -11
- package/dist/command/cli/verify-results.d.ts +4 -1
- package/dist/command/cli/verify-results.js +3 -1
- package/dist/command/cli.d.ts +1 -7
- package/dist/command/cli.js +79 -160
- package/dist/command/daemon/daemon-resilience.d.ts +6 -1
- package/dist/command/daemon/daemon-resilience.js +31 -18
- package/dist/command/daemon/daemon.d.ts +11 -0
- package/dist/command/daemon/daemon.js +70 -2
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
- package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
- package/dist/command/daemon/wake-decision.js +4 -2
- package/dist/command/daemon/win32-escape.d.ts +32 -0
- package/dist/command/daemon/win32-escape.js +119 -0
- package/dist/command/setup/agent-configs.d.ts +9 -0
- package/dist/command/setup/agent-configs.js +9 -0
- package/dist/command/setup/auto-approve.d.ts +10 -3
- package/dist/command/setup/auto-approve.js +51 -3
- package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
- package/dist/command/setup/bringup/dev-server-wait.js +5 -1
- package/dist/command/setup/bringup/ensure-daemon.js +4 -7
- package/dist/command/setup/init/init-host.js +6 -0
- package/dist/command/setup/init/init-port.js +5 -4
- package/dist/command/setup/init/init-runtime.js +7 -1
- package/dist/command/setup/node-effects.d.ts +8 -0
- package/dist/command/setup/node-effects.js +36 -4
- package/dist/command/setup/probe/dev-port.d.ts +26 -0
- package/dist/command/setup/probe/dev-port.js +117 -0
- package/dist/command/setup/probe/page-probe.d.ts +1 -1
- package/dist/command/setup/probe/page-probe.js +11 -3
- package/dist/command/setup/remaining-steps.d.ts +0 -7
- package/dist/command/setup/remaining-steps.js +3 -2
- package/dist/command/setup/run-setup.d.ts +11 -0
- package/dist/command/setup/run-setup.js +33 -5
- package/dist/command/setup/setup-command.d.ts +2 -0
- package/dist/command/setup/setup-command.js +22 -4
- package/dist/command/update/updater.d.ts +1 -6
- package/dist/command/update/updater.js +4 -5
- package/dist/command/update/version-seen.d.ts +24 -0
- package/dist/command/update/version-seen.js +65 -0
- package/dist/command/version/peer-announce.d.ts +9 -1
- package/dist/command/version/peer-announce.js +25 -2
- package/dist/command/version/sdk-fix.d.ts +5 -6
- package/dist/command/version/sdk-fix.js +17 -32
- package/dist/command/version/version-skew.d.ts +16 -1
- package/dist/command/version/version-skew.js +84 -10
- package/dist/features/crawl/crawl-tools.js +2 -2
- package/dist/features/crawl/crawl.js +2 -0
- package/dist/features/exhaust/ledger.d.ts +15 -96
- package/dist/features/exhaust/ledger.js +3 -3
- package/dist/features/harness/drive-runs.d.ts +28 -4
- package/dist/features/harness/drive-runs.js +99 -7
- package/dist/features/harness/drivers.d.ts +1 -1
- package/dist/features/harness/drivers.js +1 -1
- package/dist/features/harness/harness.d.ts +5 -0
- package/dist/features/harness/harness.js +24 -12
- package/dist/features/harness/platform/platform-drives.d.ts +7 -1
- package/dist/features/harness/platform/platform-drives.js +12 -7
- package/dist/features/harness/platform/refusal.d.ts +1 -1
- package/dist/features/harness/platform/refusal.js +4 -4
- package/dist/features/harness/platform/remote-drive.js +70 -28
- package/dist/features/harness/platform/server-driver.js +22 -1
- package/dist/features/harness/platform-config.d.ts +1 -10
- package/dist/features/harness/platform-config.js +0 -20
- package/dist/features/license/license.d.ts +2 -14
- package/dist/features/visual/step-shots.d.ts +33 -1
- package/dist/features/visual/step-shots.js +155 -1
- package/dist/features/visual/visual-tools.js +12 -4
- package/dist/hooks/coding-agents.d.ts +6 -0
- package/dist/hooks/coding-agents.js +24 -3
- package/dist/hooks/episode-stamp.d.ts +32 -0
- package/dist/hooks/episode-stamp.js +61 -0
- package/dist/hooks/hook-commands.js +19 -9
- package/dist/index.d.ts +5 -1
- package/dist/index.js +66 -24
- package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
- package/dist/judgement/app-graph/journal-steps.js +92 -0
- package/dist/judgement/capsule/capsule-store.d.ts +2 -39
- package/dist/judgement/domain/domain-model.js +1 -10
- package/dist/judgement/domain/domain-tools.js +4 -2
- package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
- package/dist/judgement/runs/artifact/run-store.js +153 -28
- package/dist/judgement/runs/default-run-id.d.ts +3 -1
- package/dist/judgement/runs/default-run-id.js +15 -3
- package/dist/judgement/runs/drive-run.d.ts +3 -3
- package/dist/judgement/runs/drive-run.js +11 -7
- package/dist/judgement/runs/run-ledger.d.ts +21 -0
- package/dist/judgement/runs/run-ledger.js +143 -0
- package/dist/judgement/runs/runner-port.d.ts +1 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +4 -3
- package/dist/judgement/runs/verification-sync.js +27 -5
- package/dist/language/flows/affected-tools.js +2 -1
- package/dist/language/flows/annotate-notes/annotate.js +8 -3
- package/dist/language/flows/annotate-tools.js +1 -1
- package/dist/language/flows/change/affected.d.ts +8 -0
- package/dist/language/flows/change/affected.js +20 -7
- package/dist/language/flows/decision.js +19 -4
- package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
- package/dist/language/flows/fields/flow-secret-field.js +67 -5
- package/dist/language/flows/flow-anchor.d.ts +5 -0
- package/dist/language/flows/flow-anchor.js +4 -0
- package/dist/language/flows/flow-cross-step.d.ts +7 -1
- package/dist/language/flows/flow-cross-step.js +9 -0
- package/dist/language/flows/flow-expect-grammar.js +15 -10
- package/dist/language/flows/flow-intent.js +6 -1
- package/dist/language/flows/flow-journey.d.ts +8 -0
- package/dist/language/flows/flow-journey.js +13 -0
- package/dist/language/flows/flow-lease.d.ts +27 -0
- package/dist/language/flows/flow-lease.js +59 -0
- package/dist/language/flows/flow-replay-run.d.ts +1 -87
- package/dist/language/flows/flow-replay-run.js +111 -310
- package/dist/language/flows/flow-replay.js +21 -19
- package/dist/language/flows/flow-replayable.d.ts +38 -0
- package/dist/language/flows/flow-replayable.js +179 -0
- package/dist/language/flows/flow-start-path.d.ts +108 -0
- package/dist/language/flows/flow-start-path.js +313 -0
- package/dist/language/flows/flow-step-runners.d.ts +23 -2
- package/dist/language/flows/flow-step-runners.js +191 -32
- package/dist/language/flows/flow-store-for-session.d.ts +8 -1
- package/dist/language/flows/flow-store-for-session.js +6 -0
- package/dist/language/flows/flow-tools.d.ts +2 -23
- package/dist/language/flows/flow-tools.js +63 -113
- package/dist/language/flows/flows.d.ts +4 -6
- package/dist/language/flows/flows.js +90 -15
- package/dist/language/flows/heal-run.d.ts +10 -4
- package/dist/language/flows/heal-run.js +26 -9
- package/dist/language/flows/recording/flake.d.ts +3 -27
- package/dist/language/flows/recording/flake.js +1 -1
- package/dist/language/flows/recording/recording-backtrack.js +1 -4
- package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
- package/dist/language/flows/recording/tape/recordings.js +9 -3
- package/dist/language/flows/replay.d.ts +25 -5
- package/dist/language/flows/replay.js +83 -16
- package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
- package/dist/language/flows/suite/coverage.d.ts +9 -0
- package/dist/language/flows/suite/coverage.js +12 -1
- package/dist/language/flows/suite-selection.d.ts +25 -0
- package/dist/language/flows/suite-selection.js +41 -9
- package/dist/machine/git-tracks.d.ts +6 -0
- package/dist/machine/git-tracks.js +36 -0
- package/dist/memory/cloud/background-sync.d.ts +25 -0
- package/dist/memory/cloud/background-sync.js +79 -0
- package/dist/memory/cloud/cloud-config.d.ts +12 -1
- package/dist/memory/cloud/cloud-config.js +39 -13
- package/dist/memory/cloud/cloud-sync.d.ts +3 -24
- package/dist/memory/cloud/cloud-sync.js +5 -2
- package/dist/memory/cloud/harness-config.d.ts +0 -7
- package/dist/memory/cloud/memory-scope.d.ts +19 -0
- package/dist/memory/cloud/memory-scope.js +48 -0
- package/dist/memory/cloud/sync-answer.d.ts +43 -0
- package/dist/memory/cloud/sync-answer.js +42 -0
- package/dist/memory/cloud/sync-cycle.d.ts +40 -10
- package/dist/memory/cloud/sync-cycle.js +97 -144
- package/dist/memory/cloud/sync-daemon.d.ts +50 -3
- package/dist/memory/cloud/sync-daemon.js +473 -83
- package/dist/memory/cloud/sync-describe.d.ts +28 -0
- package/dist/memory/cloud/sync-describe.js +92 -0
- package/dist/memory/cloud/sync-disk.d.ts +9 -1
- package/dist/memory/cloud/sync-disk.js +137 -33
- package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
- package/dist/memory/cloud/sync-flow-versions.js +42 -0
- package/dist/memory/impact/impact-store.js +32 -15
- package/dist/memory/intent/intent-shard.d.ts +41 -266
- package/dist/memory/intent/intent-tools.js +20 -61
- package/dist/memory/intent/record-request.d.ts +27 -0
- package/dist/memory/intent/record-request.js +88 -0
- package/dist/memory/intent/settled-words.js +9 -1
- package/dist/memory/journal/drive-flow.d.ts +3 -0
- package/dist/memory/journal/drive-flow.js +11 -41
- package/dist/memory/journal/envelope-store.js +1 -1
- package/dist/memory/journal/envelope.d.ts +6 -154
- package/dist/memory/journal/episode-log.d.ts +107 -0
- package/dist/memory/journal/episode-log.js +302 -0
- package/dist/memory/journal/journal-recorder.d.ts +7 -0
- package/dist/memory/journal/journal-recorder.js +22 -9
- package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
- package/dist/memory/journal/on-disk/ambient-file.js +1 -1
- package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
- package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
- package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
- package/dist/memory/journal/self-observation.js +3 -1
- package/dist/memory/journal/session-end.js +23 -9
- package/dist/memory/journal/session-journal.js +39 -20
- package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
- package/dist/memory/project/artifact-root-resolver.js +68 -23
- package/dist/memory/project/artifact-root.d.ts +17 -3
- package/dist/memory/project/artifact-root.js +47 -9
- package/dist/memory/project/fs/fs-port.d.ts +5 -0
- package/dist/memory/project/fs/fs-port.js +13 -0
- package/dist/memory/project/learned-routes.d.ts +3 -4
- package/dist/memory/project/learned-routes.js +3 -11
- package/dist/memory/project/link-directory.js +5 -2
- package/dist/memory/project/root-claims.d.ts +3 -1
- package/dist/memory/project/root-claims.js +41 -7
- package/dist/memory/project/session-root.d.ts +1 -1
- package/dist/memory/project/session-root.js +1 -15
- package/dist/memory/project/sync-status.js +5 -6
- package/dist/memory/recall/memory-tools.js +2 -2
- package/dist/memory/recall/platform-memory.d.ts +3 -1
- package/dist/memory/recall/platform-memory.js +9 -1
- package/dist/memory/recall/project-memory.js +15 -19
- package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
- package/dist/portal/bridge/auth-failure-reason.js +19 -0
- package/dist/portal/bridge/bridge.d.ts +19 -4
- package/dist/portal/bridge/bridge.js +150 -177
- package/dist/portal/bridge/harness-request.d.ts +15 -0
- package/dist/portal/bridge/harness-request.js +19 -0
- package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
- package/dist/portal/bridge/origin/origin-follow.js +110 -0
- package/dist/portal/bridge/pairing-token.d.ts +6 -0
- package/dist/portal/bridge/pairing-token.js +47 -16
- package/dist/portal/bridge/protocol-skew.d.ts +27 -2
- package/dist/portal/bridge/protocol-skew.js +66 -2
- package/dist/portal/bridge/session-nonces.d.ts +46 -0
- package/dist/portal/bridge/session-nonces.js +72 -0
- package/dist/portal/input/viewport-tools.d.ts +31 -0
- package/dist/portal/input/viewport-tools.js +106 -15
- package/dist/portal/pool/bounded-close.d.ts +23 -0
- package/dist/portal/pool/bounded-close.js +38 -0
- package/dist/portal/pool/browser-pool.d.ts +44 -39
- package/dist/portal/pool/browser-pool.js +247 -95
- package/dist/portal/pool/context-permissions.d.ts +9 -1
- package/dist/portal/pool/context-permissions.js +26 -0
- package/dist/portal/pool/lease-emulation.d.ts +37 -0
- package/dist/portal/pool/lease-emulation.js +29 -0
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +74 -7
- package/dist/portal/pool/pool-contract.d.ts +23 -1
- package/dist/portal/pool/pool-lease.d.ts +128 -0
- package/dist/portal/pool/pool-lease.js +49 -0
- package/dist/portal/pool/zero-install.d.ts +8 -1
- package/dist/portal/pool/zero-install.js +24 -2
- package/dist/portal/production/production-activation.d.ts +136 -0
- package/dist/portal/production/production-activation.js +173 -0
- package/dist/portal/production/production-drive.d.ts +52 -0
- package/dist/portal/production/production-drive.js +301 -0
- package/dist/portal/production/production-hello.d.ts +23 -0
- package/dist/portal/production/production-hello.js +23 -0
- package/dist/portal/realm/web-realm.js +42 -15
- package/dist/portal/session/control-envelope.d.ts +1 -1
- package/dist/portal/session/dev-server/served-document.d.ts +0 -5
- package/dist/portal/session/dev-server/served-document.js +6 -8
- package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
- package/dist/portal/session/first-run-wiring.d.ts +3 -36
- package/dist/portal/session/first-run-wiring.js +10 -103
- package/dist/portal/session/live-control-tools.js +61 -19
- package/dist/portal/session/no-session-next-action.d.ts +11 -0
- package/dist/portal/session/no-session-next-action.js +40 -15
- package/dist/portal/session/no-session-watch.d.ts +7 -0
- package/dist/portal/session/no-session-watch.js +67 -23
- package/dist/portal/session/output-budget.d.ts +10 -0
- package/dist/portal/session/output-budget.js +16 -0
- package/dist/portal/session/presence/session-lease.d.ts +2 -0
- package/dist/portal/session/presence/session-lease.js +8 -0
- package/dist/portal/session/recorded-gaps.d.ts +15 -11
- package/dist/portal/session/recorded-gaps.js +39 -18
- package/dist/portal/session/serving-directory.d.ts +24 -2
- package/dist/portal/session/serving-directory.js +93 -5
- package/dist/portal/session/session-info.d.ts +26 -0
- package/dist/portal/session/session-info.js +20 -0
- package/dist/portal/session/session-manager.d.ts +35 -3
- package/dist/portal/session/session-manager.js +69 -14
- package/dist/portal/session/session-successor.js +1 -9
- package/dist/portal/session/session-tools.js +22 -4
- package/dist/portal/session/session.d.ts +10 -10
- package/dist/portal/session/session.js +37 -29
- package/dist/portal/session/zero-install-first-call.d.ts +7 -2
- package/dist/portal/session/zero-install-first-call.js +43 -20
- package/dist/start-wiring.d.ts +2 -2
- package/dist/start-wiring.js +17 -3
- package/dist/status-payload.d.ts +11 -1
- package/dist/status-payload.js +7 -1
- package/dist/surface/agent-presence-grace.d.ts +11 -0
- package/dist/surface/agent-presence-grace.js +34 -0
- package/dist/surface/http-server.d.ts +12 -1
- package/dist/surface/http-server.js +64 -15
- package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
- package/dist/surface/mcp/faults/mcp-outage.js +19 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
- package/dist/surface/mcp/mcp-proxy.js +194 -267
- package/dist/surface/mcp/mcp.d.ts +20 -3
- package/dist/surface/mcp/mcp.js +88 -25
- package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
- package/dist/surface/mcp/proxy/drive-calls.js +114 -5
- package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
- package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
- package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
- package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
- package/dist/surface/mcp/server-instructions.js +35 -16
- package/dist/surface/mcp/shared-params.d.ts +8 -0
- package/dist/surface/mcp/shared-params.js +15 -1
- package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
- package/dist/surface/mcp/sse-frame-parser.js +18 -0
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +13 -0
- package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
- package/dist/surface/mcp/tool-catalog-cache.js +14 -4
- package/dist/surface/tools/account-tool.d.ts +4 -3
- package/dist/surface/tools/account-tool.js +20 -31
- package/dist/surface/tools/act/act-danger.d.ts +2 -0
- package/dist/surface/tools/act/act-danger.js +41 -14
- package/dist/surface/tools/act/act-observation.d.ts +11 -0
- package/dist/surface/tools/act/act-observation.js +33 -0
- package/dist/surface/tools/act/act-preflight.js +10 -3
- package/dist/surface/tools/act/act-sequence-retry.js +2 -1
- package/dist/surface/tools/act/act-target.js +19 -5
- package/dist/surface/tools/act/durable.js +1 -1
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
- package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
- package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
- package/dist/surface/tools/act/unsettled-find.js +71 -0
- package/dist/surface/tools/act-sequence-tool.js +53 -24
- package/dist/surface/tools/act-tools.d.ts +2 -3
- package/dist/surface/tools/act-tools.js +49 -47
- package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
- package/dist/surface/tools/agent/for-the-agent.js +41 -3
- package/dist/surface/tools/assert/assert-grade.js +8 -3
- package/dist/surface/tools/assert/assert-verdict.js +4 -2
- package/dist/surface/tools/browser-tools.js +7 -4
- package/dist/surface/tools/chat-drives.js +50 -25
- package/dist/surface/tools/coverage-tools.js +1 -1
- package/dist/surface/tools/dynamic-tools.d.ts +8 -0
- package/dist/surface/tools/dynamic-tools.js +89 -34
- package/dist/surface/tools/empty-session-list.d.ts +18 -25
- package/dist/surface/tools/empty-session-list.js +67 -38
- package/dist/surface/tools/error-recovery.d.ts +17 -7
- package/dist/surface/tools/error-recovery.js +53 -20
- package/dist/surface/tools/explore-tools.d.ts +10 -0
- package/dist/surface/tools/explore-tools.js +72 -19
- package/dist/surface/tools/feedback-tools.js +23 -2
- package/dist/surface/tools/gap-novelty.d.ts +6 -0
- package/dist/surface/tools/gap-novelty.js +9 -0
- package/dist/surface/tools/gaps/capability-absences.js +4 -3
- package/dist/surface/tools/harness-explore.d.ts +1 -1
- package/dist/surface/tools/harness-explore.js +6 -4
- package/dist/surface/tools/harness-gate.d.ts +43 -21
- package/dist/surface/tools/harness-gate.js +55 -81
- package/dist/surface/tools/harness-script.d.ts +2 -0
- package/dist/surface/tools/harness-script.js +11 -6
- package/dist/surface/tools/harness-toolset.js +3 -4
- package/dist/surface/tools/invoke-tool.d.ts +0 -8
- package/dist/surface/tools/invoke-tool.js +164 -178
- package/dist/surface/tools/lease-hint.d.ts +9 -0
- package/dist/surface/tools/lease-hint.js +22 -3
- package/dist/surface/tools/lease-permissions.d.ts +1 -1
- package/dist/surface/tools/lease-readiness.d.ts +55 -0
- package/dist/surface/tools/lease-readiness.js +150 -2
- package/dist/surface/tools/lease-tools.d.ts +3 -75
- package/dist/surface/tools/lease-tools.js +124 -188
- package/dist/surface/tools/map-tools.d.ts +20 -0
- package/dist/surface/tools/map-tools.js +145 -0
- package/dist/surface/tools/merge-tools.js +11 -7
- package/dist/surface/tools/next-step.js +6 -3
- package/dist/surface/tools/observe-tools.js +46 -35
- package/dist/surface/tools/platform-moment.d.ts +3 -12
- package/dist/surface/tools/platform-moment.js +12 -24
- package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
- package/dist/surface/tools/read/complete-snapshot.js +13 -2
- package/dist/surface/tools/read/query-paginate.js +6 -0
- package/dist/surface/tools/read/query-shape.d.ts +9 -0
- package/dist/surface/tools/read/query-shape.js +15 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
- package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
- package/dist/surface/tools/read-tools.js +5 -5
- package/dist/surface/tools/real-input-attempt.d.ts +11 -0
- package/dist/surface/tools/real-input-attempt.js +206 -38
- package/dist/surface/tools/reconcile-tools.js +21 -8
- package/dist/surface/tools/reticle-result.d.ts +3 -0
- package/dist/surface/tools/reticle-result.js +8 -1
- package/dist/surface/tools/run-report.d.ts +22 -0
- package/dist/surface/tools/run-report.js +141 -0
- package/dist/surface/tools/session-ports.d.ts +57 -0
- package/dist/surface/tools/session-ports.js +102 -0
- package/dist/surface/tools/tool-kit.d.ts +58 -4
- package/dist/surface/tools/tool-kit.js +140 -6
- package/dist/surface/tools/tool-surface.d.ts +2 -0
- package/dist/surface/tools/tool-surface.js +45 -0
- package/dist/surface/tools/tools.js +49 -87
- package/dist/telemetry/automation-hint.d.ts +5 -0
- package/dist/telemetry/automation-hint.js +7 -0
- package/dist/telemetry/cli-telemetry.d.ts +22 -0
- package/dist/telemetry/cli-telemetry.js +80 -11
- package/dist/telemetry/daemon-telemetry.d.ts +3 -1
- package/dist/telemetry/daemon-telemetry.js +9 -2
- package/dist/telemetry/feedback-cli.d.ts +1 -1
- package/dist/telemetry/feedback-cli.js +8 -3
- package/dist/telemetry/feedback.d.ts +1 -1
- package/dist/telemetry/feedback.js +51 -4
- package/dist/telemetry/harness-run.d.ts +3 -3
- package/dist/telemetry/harness-run.js +18 -7
- package/dist/telemetry/hud-events.d.ts +1 -1
- package/dist/telemetry/hud-metrics.d.ts +6 -3
- package/dist/telemetry/hud-metrics.js +20 -8
- package/dist/telemetry/install-source.js +1 -1
- package/dist/telemetry/mcp-connection.d.ts +1 -1
- package/dist/telemetry/mcp-connection.js +21 -2
- package/dist/telemetry/onboarding-firsts.d.ts +6 -1
- package/dist/telemetry/onboarding-firsts.js +41 -1
- package/dist/telemetry/proxy-telemetry.d.ts +42 -0
- package/dist/telemetry/proxy-telemetry.js +70 -1
- package/dist/telemetry/session-metrics.d.ts +1 -3
- package/dist/telemetry/session-metrics.js +16 -12
- package/dist/telemetry/telemetry.d.ts +9 -1
- package/dist/telemetry/telemetry.js +16 -1
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +7 -1
- package/dist/wire-journal.js +12 -2
- package/docs/README.md +4 -2
- package/docs/actions.mdx +7 -6
- package/docs/adapters.md +2 -1
- package/docs/agent-cheatsheet.md +19 -5
- package/docs/architecture.md +13 -10
- package/docs/autodrive.md +6 -5
- package/docs/benchmarks.md +2 -2
- package/docs/capabilities.mdx +1 -1
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +6 -6
- package/docs/cli/doctor.mdx +3 -1
- package/docs/cli/feedback.mdx +11 -7
- package/docs/cli/gate.mdx +1 -1
- package/docs/cli/help.mdx +1 -1
- package/docs/cli/init.mdx +20 -16
- package/docs/cli/mcp.mdx +5 -2
- package/docs/cli/open.mdx +5 -2
- package/docs/cli/report.mdx +1 -1
- package/docs/cli/restart.mdx +1 -1
- package/docs/cli/rollback.mdx +4 -4
- package/docs/cli/serve.mdx +7 -5
- package/docs/cli/setup.mdx +1 -1
- package/docs/cli/status.mdx +6 -2
- package/docs/cli/stop.mdx +3 -3
- package/docs/cli/telemetry.mdx +5 -1
- package/docs/cli/try.mdx +8 -8
- package/docs/cli/update.mdx +8 -5
- package/docs/cli/verify.mdx +12 -5
- package/docs/cli/version.mdx +1 -1
- package/docs/cli.mdx +10 -6
- package/docs/debugging.md +1 -1
- package/docs/deploy-checks.md +8 -6
- package/docs/desktop.mdx +14 -18
- package/docs/enterprise.md +6 -6
- package/docs/environment.mdx +5 -3
- package/docs/faq.mdx +9 -6
- package/docs/first-drive.md +19 -9
- package/docs/flows.md +3 -4
- package/docs/for-agents.md +1 -1
- package/docs/frameworks.mdx +34 -11
- package/docs/getting-started.md +46 -29
- package/docs/http-transport.md +2 -2
- package/docs/human-control.md +8 -8
- package/docs/index.mdx +2 -2
- package/docs/install-agentic.mdx +18 -19
- package/docs/install-manual.mdx +8 -4
- package/docs/integration-patterns.md +5 -5
- package/docs/multi-agent-testing.md +7 -5
- package/docs/packages/browser.mdx +34 -2
- package/docs/packages/core.mdx +2 -1
- package/docs/packages/electron.mdx +15 -3
- package/docs/packages/eslint-plugin.mdx +1 -1
- package/docs/packages/next.mdx +17 -5
- package/docs/packages/react.mdx +8 -1
- package/docs/packages/server.mdx +3 -3
- package/docs/packages/tauri.mdx +3 -3
- package/docs/packages/vite-plugin.mdx +1 -1
- package/docs/packages.mdx +19 -6
- package/docs/platform-integration.md +12 -4
- package/docs/predicates.mdx +18 -7
- package/docs/production-mode.md +108 -0
- package/docs/prompt-capture.md +99 -0
- package/docs/quickstart.mdx +14 -12
- package/docs/recipes.mdx +9 -8
- package/docs/required-checks.md +3 -2
- package/docs/skill-file.mdx +4 -3
- package/docs/skill-setup.md +2 -2
- package/docs/skill.md +62 -70
- package/docs/state-files.md +1 -0
- package/docs/state-management.mdx +11 -9
- package/docs/system-map.md +14 -13
- package/docs/telemetry.md +32 -24
- package/docs/testing.md +9 -5
- package/docs/tools/act-and-wait.mdx +17 -13
- package/docs/tools/act-sequence.mdx +40 -66
- package/docs/tools/act.mdx +7 -5
- package/docs/tools/assert.mdx +1 -1
- package/docs/tools/look.mdx +1 -1
- package/docs/tools/navigate.mdx +1 -1
- package/docs/tools/network.mdx +13 -11
- package/docs/tools/overview.mdx +3 -3
- package/docs/tools/query.mdx +3 -3
- package/docs/tools/session-and-feedback.mdx +9 -6
- package/docs/tools/sessions.mdx +7 -0
- package/docs/tools/snapshot.mdx +9 -7
- package/docs/tools/tools-and-run.mdx +11 -10
- package/docs/tools/verify.mdx +1 -1
- package/docs/troubleshooting.mdx +21 -9
- package/docs/usage.md +58 -43
- package/docs/use-cases.mdx +2 -2
- package/docs/vs-chrome-devtools-mcp.mdx +5 -5
- package/docs/vs-playwright-mcp.mdx +5 -4
- package/docs/what-is-recorded.md +12 -7
- package/docs/what-is-reticle.mdx +2 -2
- package/docs/why-reticle.mdx +1 -1
- package/package.json +9 -12
- package/dist/command/dev/stale-issue-guard.d.ts +0 -34
- package/dist/command/dev/stale-issue-guard.js +0 -69
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* finally established (see `replayLines`), so the daemon still gets its handshake in order.
|
|
16
16
|
*/
|
|
17
17
|
import { SERVER_VERSION } from '../../../command/version/identity/server-version.js';
|
|
18
|
-
import { MCP_SERVER_NAME } from '@reticlehq/core';
|
|
18
|
+
import { MCP_SERVER_NAME, WRITING_RULE_SHORT } from '@reticlehq/core';
|
|
19
19
|
/** The version we answer with if the client proposed none. */
|
|
20
20
|
const FALLBACK_PROTOCOL_VERSION = '2024-11-05';
|
|
21
21
|
/**
|
|
@@ -28,7 +28,8 @@ const FALLBACK_PROTOCOL_VERSION = '2024-11-05';
|
|
|
28
28
|
* connected, initialized and toolless until a human notices.
|
|
29
29
|
*/
|
|
30
30
|
export const TOOLS_CHANGED_NOTIFICATION = 'notifications/tools/list_changed';
|
|
31
|
-
|
|
31
|
+
/** A line as a JSON-RPC object, or null when it is not JSON or not an object. */
|
|
32
|
+
export function parseLine(line) {
|
|
32
33
|
try {
|
|
33
34
|
const parsed = JSON.parse(line);
|
|
34
35
|
return 'object' === typeof parsed && parsed !== null ? parsed : null;
|
|
@@ -103,6 +104,8 @@ export function toolsChangedNotification(catalogWasLocal) {
|
|
|
103
104
|
return null;
|
|
104
105
|
return JSON.stringify({ jsonrpc: '2.0', method: TOOLS_CHANGED_NOTIFICATION });
|
|
105
106
|
}
|
|
107
|
+
/** Says that the degraded text is shorter than the healthy one. */
|
|
108
|
+
const DEGRADED_OMITTED = 'This text omits the replay and argument notes.';
|
|
106
109
|
/**
|
|
107
110
|
* What a locally-answered handshake must say about itself.
|
|
108
111
|
*
|
|
@@ -122,17 +125,23 @@ export function toolsChangedNotification(catalogWasLocal) {
|
|
|
122
125
|
* on the initialize result, which SUCCEEDED, and every host we target puts it in front of the model.
|
|
123
126
|
* A tool description cannot reach an agent that was handed no tools.
|
|
124
127
|
*
|
|
125
|
-
* The healthy block is kept underneath
|
|
126
|
-
*
|
|
128
|
+
* The healthy block is kept underneath: an agent that IS about to get a working surface (the common
|
|
129
|
+
* case — the first call wakes a daemon) still needs to know how to drive it. Only its part up to the
|
|
130
|
+
* writing rule is kept. Claude Code shows about the first 4,096 characters, and the notice plus the
|
|
131
|
+
* whole block came to about 4,600, so the client cut the writing rule. The text says what it left
|
|
132
|
+
* out, so the cut is not silent.
|
|
127
133
|
*/
|
|
128
134
|
export function degradedInstructions(healthy, port, reason) {
|
|
129
|
-
|
|
135
|
+
const ruleAt = healthy.indexOf(WRITING_RULE_SHORT);
|
|
136
|
+
const kept = -1 === ruleAt ? healthy : healthy.slice(0, ruleAt + WRITING_RULE_SHORT.length);
|
|
137
|
+
const omitted = kept.length < healthy.length ? `\n\n${DEGRADED_OMITTED}` : '';
|
|
138
|
+
return `DEGRADED SURFACE. READ THIS BEFORE ANY reticle_* CALL. No Reticle daemon answered on port ${String(port)} (${reason}). The Reticle MCP proxy answered this handshake, not the daemon. A tool list you got is from a cache or is empty: it proves nothing.
|
|
130
139
|
|
|
131
|
-
Reticle IS installed: this process is Reticle. Do NOT report it as missing
|
|
140
|
+
Reticle IS installed: this process is Reticle. Do NOT report it as missing or not installed. The daemon is not reachable yet.
|
|
132
141
|
|
|
133
|
-
Your next reticle_* call starts a daemon
|
|
142
|
+
Your next reticle_* call starts a daemon. Then it works, or it fails with the reason. If you have NO reticle_* tools, tell the user that, and tell them to run \`npx @reticlehq/server doctor\` in a terminal. It shows what holds port ${String(port)} and if a daemon can start.
|
|
134
143
|
|
|
135
|
-
${
|
|
144
|
+
${kept}${omitted}`;
|
|
136
145
|
}
|
|
137
146
|
/**
|
|
138
147
|
* The largest single JSON-RPC line the proxy will accumulate from a client.
|
|
@@ -190,3 +199,62 @@ export function drainLines(buffer, chunk, maxLineBytes = MAX_STDIN_LINE_BYTES, d
|
|
|
190
199
|
discarding: restOversized,
|
|
191
200
|
};
|
|
192
201
|
}
|
|
202
|
+
/** JSON-RPC id the proxy uses for its own replayed `initialize` — never one the client could send. */
|
|
203
|
+
export const RECONNECT_INITIALIZE_ID = '__reticle_proxy_reinit';
|
|
204
|
+
const INITIALIZE_METHOD = 'initialize';
|
|
205
|
+
const INITIALIZED_METHOD = 'notifications/initialized';
|
|
206
|
+
/**
|
|
207
|
+
* Makes a reconnect invisible to the client.
|
|
208
|
+
*
|
|
209
|
+
* The daemon builds a FRESH `McpServer` per SSE connection, so a reconnected session has never seen
|
|
210
|
+
* the client's `initialize` — every subsequent `tools/call` would hit an uninitialized server. The
|
|
211
|
+
* proxy therefore remembers the handshake the client sent once and replays it into each new session.
|
|
212
|
+
* The replay is re-issued under a reserved id so the daemon's response to it can be dropped rather
|
|
213
|
+
* than reaching the client's stdout, where a duplicate JSON-RPC id would be a protocol violation.
|
|
214
|
+
*/
|
|
215
|
+
export class HandshakeReplay {
|
|
216
|
+
#initialize = null;
|
|
217
|
+
#initialized = null;
|
|
218
|
+
#pendingReplayId = null;
|
|
219
|
+
/** Record one outbound client line. Cheap enough to call for every stdin message. */
|
|
220
|
+
observeOutbound(line) {
|
|
221
|
+
const msg = parseLine(line);
|
|
222
|
+
if (null === msg) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
// The first initialize is the session's identity; a client re-issuing one does not change it.
|
|
226
|
+
if (msg.method === INITIALIZE_METHOD && null === this.#initialize) {
|
|
227
|
+
this.#initialize = line;
|
|
228
|
+
}
|
|
229
|
+
else if (msg.method === INITIALIZED_METHOD) {
|
|
230
|
+
this.#initialized = line;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/** Lines to POST into a freshly-established session, before any queued client traffic. */
|
|
234
|
+
replayLines() {
|
|
235
|
+
if (null === this.#initialize) {
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
const msg = parseLine(this.#initialize);
|
|
239
|
+
if (null === msg) {
|
|
240
|
+
return [];
|
|
241
|
+
}
|
|
242
|
+
this.#pendingReplayId = RECONNECT_INITIALIZE_ID;
|
|
243
|
+
const reinit = { ...msg, id: RECONNECT_INITIALIZE_ID };
|
|
244
|
+
return null === this.#initialized
|
|
245
|
+
? [JSON.stringify(reinit)]
|
|
246
|
+
: [JSON.stringify(reinit), this.#initialized];
|
|
247
|
+
}
|
|
248
|
+
/** True when this inbound daemon line is the echo of our replayed handshake and must not be forwarded. */
|
|
249
|
+
shouldSuppressInbound(line) {
|
|
250
|
+
if (null === this.#pendingReplayId) {
|
|
251
|
+
return false;
|
|
252
|
+
}
|
|
253
|
+
const msg = parseLine(line);
|
|
254
|
+
if (null === msg || msg.id !== this.#pendingReplayId) {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
this.#pendingReplayId = null; // one response per replay — anything later is not ours to swallow
|
|
258
|
+
return true;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReticleTool, WRITING_RULE_SHORT } from '@reticlehq/core';
|
|
2
2
|
import { SHARED_PARAM_GUIDANCE } from './shared-params.js';
|
|
3
|
+
import { wiringConsent } from '../tools/empty-session-list.js';
|
|
3
4
|
import { defaultAdvertisedNames } from '../tools/tool-surface.js';
|
|
4
5
|
import { surfaceVocabulary, listOf } from './surface-vocabulary.js';
|
|
5
6
|
/**
|
|
@@ -35,8 +36,8 @@ import { surfaceVocabulary, listOf } from './surface-vocabulary.js';
|
|
|
35
36
|
* `reticle gate` is FOLDED INTO the done sentence rather than given a paragraph, and that is the
|
|
36
37
|
* budget rule working rather than a stylistic choice.
|
|
37
38
|
*
|
|
38
|
-
* The instruction block has a hard
|
|
39
|
-
*
|
|
39
|
+
* The instruction block has a hard cap: about what a client shows of it (see the test). It cannot be
|
|
40
|
+
* raised, so a new sentence must cut an older one. There
|
|
40
41
|
* is no measurement for `gate`: it is built, it has anti-reward-hacking, and it appeared in no
|
|
41
42
|
* surface an agent reads, which is an argument and not a number. Cutting a measured sentence to
|
|
42
43
|
* make room for an unmeasured one would be strictly worse. So it costs about a hundred characters
|
|
@@ -44,9 +45,9 @@ import { surfaceVocabulary, listOf } from './surface-vocabulary.js';
|
|
|
44
45
|
*/
|
|
45
46
|
const verdictDiscipline = (v) => `Reticle verifies a running web app from the inside: go (${v.navigate}), look (${listOf(v.look, v.find)}), act and prove in one hop (${v.actAndWait}), observe (${listOf(v.observe, v.state, v.network, v.console)}), assert (${v.assert}). Verify a user-facing change against the real app before you call it done — \`npx @reticlehq/server gate --since <ref>\` fails unless a passing artifact covers every flow your edits affect — and never weaken a check to make it pass.
|
|
46
47
|
|
|
47
|
-
Only ${v.act.length > 0 ? `${v.actAndWait}, ${v.assert} and ${v.act}{steps}` : `${v.actAndWait} and ${v.assert}`} produce a verdict. Everything else proves nothing
|
|
48
|
+
Only ${v.act.length > 0 ? `${v.actAndWait}, ${v.assert} and ${v.act}{steps}` : `${v.actAndWait} and ${v.assert}`} produce a verdict. Everything else proves nothing. Prefer ${v.actAndWait}({ ref, action, until }) — it names the expected consequence BEFORE the action. Only verified:"yes" is a pass; "unknown" and "no-fault" (nothing declared) are not proved, never failed. When a verdict catches what reading the code missed, say Reticle found it. Do a result's \`next\`.
|
|
48
49
|
|
|
49
|
-
Done is the journey's END proved, not its first step: drive each step your change touches and give the last an \`until\` naming the end state (\`durable: true\` if it must persist). A "yes" on it over a clean capture IS the answer — stop.${v.act.length > 0 ? ` Several steps? ONE ${v.act}{ steps: [{ target, action, expect }] } drives them all and stops at the first expect that fails
|
|
50
|
+
Done is the journey's END proved, not its first step: drive each step your change touches and give the last an \`until\` naming the end state (\`durable: true\` if it must persist). A "yes" on it over a clean capture IS the answer — stop.${v.act.length > 0 ? ` Several steps? ONE ${v.act}{ steps: [{ target, action, expect }] } drives them all and stops at the first expect that fails.` : ''}
|
|
50
51
|
|
|
51
52
|
DIAGNOSING a bug? Read the source first — Reticle proves what the app DOES, not why. Drive to CONFIRM a fix, not to find one.`;
|
|
52
53
|
/**
|
|
@@ -77,7 +78,7 @@ const replayFirst = (v) => {
|
|
|
77
78
|
if (0 === v.replayChange.length)
|
|
78
79
|
return '';
|
|
79
80
|
const ask = v.affected.length > 0 ? `${v.affected} names the saved flows covering your edits; ` : '';
|
|
80
|
-
return `Changed code? Replay before you drive. ${ask}${v.replayChange} replays them for one verified + because
|
|
81
|
+
return `Changed code? Replay before you drive. ${ask}${v.replayChange} replays them for one verified + because. "yes": proved, stop. "no": names the step that broke. "unknown": NO saved flow covers it, so nothing was proved — drive it, and never report it as passing. What you drive by hand is saved as a flow automatically.${driveOnce(v)}`;
|
|
81
82
|
};
|
|
82
83
|
/**
|
|
83
84
|
* A drive outlives a client's timeout, so its call answers with a run id instead of waiting for the
|
|
@@ -85,7 +86,7 @@ const replayFirst = (v) => {
|
|
|
85
86
|
*/
|
|
86
87
|
const driveOnce = (v) => 0 === v.explore.length
|
|
87
88
|
? ''
|
|
88
|
-
: ` Drivers: you, or the Harness (${v.explore}; opt-in
|
|
89
|
+
: ` Drivers: you, or the Harness (${v.explore}; opt-in, no setup score needed): poll its runId; never start two.`;
|
|
89
90
|
/**
|
|
90
91
|
* The first move, for a project no app has ever connected to.
|
|
91
92
|
*
|
|
@@ -100,12 +101,27 @@ const driveOnce = (v) => 0 === v.explore.length
|
|
|
100
101
|
// The lead is a snapshot, not a present fact: these instructions are sent ONCE, at the handshake, and
|
|
101
102
|
// the app can connect a minute later. Stated as fact, it kept agents running setup while the session
|
|
102
103
|
// list showed the app connected (#1362).
|
|
103
|
-
const firstMoveFor = (v, appHere) => `FIRST: when this session started, no app had connected to Reticle in this project
|
|
104
|
+
const firstMoveFor = (v, appHere) => `FIRST: when this session started, no app had connected to Reticle in this project, so \`init\` has not wired it.${verifyNowFor(v)}
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
To wire it for good: ${wiringConsent()} ${v.sessions} changes no file. A session on this project's app listed there is the proof that it is wired.${appHere ? TELL_THE_USER : ''}`;
|
|
107
|
+
/**
|
|
108
|
+
* A verdict before any wiring. The lead used to say that until the app was wired "no other tool can
|
|
109
|
+
* tell you anything about this app", which is false: the lease reads any running page with
|
|
110
|
+
* Reticle's own reader. Measured with `claude -p` on a fresh Vite app with the MCP registered and no
|
|
111
|
+
* `init`: the agent made no Reticle call and wrote, ran and deleted a Playwright script instead.
|
|
112
|
+
*/
|
|
113
|
+
// A real agent given no URL source started a second dev server beside the user's own.
|
|
114
|
+
const urlFrom = (v) => '' === v.sessions
|
|
115
|
+
? ''
|
|
116
|
+
: ` Get <URL> from next_step.lease in ${v.sessions}. Do not start a second dev server.`;
|
|
117
|
+
function verifyNowFor(v) {
|
|
118
|
+
if ('' === v.zeroInstall)
|
|
119
|
+
return '';
|
|
120
|
+
return ` To check a change now, with no file changed: \`${v.zeroInstall}\` opens it in Reticle's own browser. Use it instead of writing a browser script.${urlFrom(v)}`;
|
|
121
|
+
}
|
|
122
|
+
const UNWIRED_LEAD_END = 'is the proof that it is wired.';
|
|
107
123
|
// An agent never asked to verify anything never reads "fix that first"; this makes it raise wiring.
|
|
108
|
-
const TELL_THE_USER = ' If none is listed, this directory holds a web app that is not wired: in your first reply, even if their request is unrelated, tell the user in one line and
|
|
124
|
+
const TELL_THE_USER = ' If none is listed, this directory holds a web app that is not wired: in your first reply, even if their request is unrelated, tell the user in one line and ask the consent question above.';
|
|
109
125
|
/** The nudge set for the AGENT's directory: a shared daemon briefs from where IT started. */
|
|
110
126
|
export function localizeInstructions(instructions, appHere) {
|
|
111
127
|
const without = instructions.replace(TELL_THE_USER, '');
|
|
@@ -133,13 +149,13 @@ export function localizeInstructions(instructions, appHere) {
|
|
|
133
149
|
*/
|
|
134
150
|
const reachFor = (v) => {
|
|
135
151
|
const lines = [
|
|
136
|
-
`${v.observe} is the evidence channel: everything the page did since a cursor, in one read. Take it BEFORE you call a build broken
|
|
152
|
+
`${v.observe} is the evidence channel: everything the page did since a cursor, in one read. Take it BEFORE you call a build broken. ${v.settle} settles a page that is changing without you; ${v.inspect} maps an element to its source file:line, which turns a finding into an edit${v.yield.length > 0 ? `; ${v.yield} hands the tab back to the human` : ''}.`,
|
|
137
153
|
];
|
|
138
154
|
// Said ONLY when both halves are advertised. A catalogue with no way to invoke what it lists sends
|
|
139
155
|
// the agent at a tool it cannot call and then off the product entirely — see
|
|
140
156
|
// surface-vocabulary.ts. Where there is no cold tail, there is nothing to say about reaching it.
|
|
141
157
|
if (v.coldTail.length > 0) {
|
|
142
|
-
lines.push(`${v.coldTail} Two to know early: ${ReticleTool.RUN}({ tool: "${ReticleTool.CONTEXT}", args: {} }) returns what this run already established,
|
|
158
|
+
lines.push(`${v.coldTail} Two to know early: ${ReticleTool.RUN}({ tool: "${ReticleTool.CONTEXT}", args: {} }) returns what this run already established, and ${ReticleTool.RUN}({ tool: "${ReticleTool.INTENT}", args: { action: "declare", request: "<user's words, verbatim>" } }), once per request, declares what the work is MEANT to do.`);
|
|
143
159
|
// Measured: in 8 real agent runs asked to test an app, none read what Reticle already held
|
|
144
160
|
// first, and none could tell its user the credits or the Harness state.
|
|
145
161
|
lines.push(`Before testing, read what Reticle knows: ${ReticleTool.RUN}({ tool: "${ReticleTool.MEMORY}", args: {} })${v.yield.length > 0 ? ` and ${ReticleTool.SESSION} {action:"account"} (plan, credits, Harness)` : ''}.`);
|
|
@@ -147,7 +163,7 @@ const reachFor = (v) => {
|
|
|
147
163
|
return lines.join('\n\n');
|
|
148
164
|
};
|
|
149
165
|
/** The feedback ask. Constant: an agent that cannot get set up is the report we most need. */
|
|
150
|
-
const feedbackAsk = (v) => `Feedback is first-class
|
|
166
|
+
const feedbackAsk = (v) => `Feedback is first-class: once per session, when Reticle broke, lied, missed something, cost too many calls, or the install, wiring or setup gave you trouble, send \`${v.feedback}\` and carry on. Tools unreachable? \`npx @reticlehq/server feedback --agent --kind <kind> "what happened"\`. A bug in the app under test belongs in your answer to the user.`;
|
|
151
167
|
/** The instructions this daemon should advertise, given what it knows about the project. */
|
|
152
168
|
/**
|
|
153
169
|
* Instructions are sent ONCE at initialize; the tool surface is re-sent every turn, and costs an
|
|
@@ -179,9 +195,12 @@ export function buildServerInstructions(state) {
|
|
|
179
195
|
* into a dead end.
|
|
180
196
|
*/
|
|
181
197
|
const replay = replayFirst(v);
|
|
198
|
+
// The writing rule sits beside the feedback ask, the text it is most about, and not at the end:
|
|
199
|
+
// a client that cuts the block cuts the end first.
|
|
200
|
+
const feedback = `${feedbackAsk(v)}\n\n${WRITING_RULE_SHORT}`;
|
|
182
201
|
const base = state.previouslyConnected
|
|
183
|
-
? `${verdictDiscipline(v)}\n\n${reachFor(v)}\n\n${
|
|
184
|
-
: `${firstMove}\n\n${verdictDiscipline(v)}\n\n${
|
|
202
|
+
? `${verdictDiscipline(v)}\n\n${reachFor(v)}\n\n${feedback}`
|
|
203
|
+
: `${firstMove}\n\n${verdictDiscipline(v)}\n\n${feedback}`;
|
|
185
204
|
const withReplay = replay.length > 0 ? `${base}\n\n${replay}` : base;
|
|
186
|
-
return `${withReplay}\n\n${SHARED_PARAM_GUIDANCE}
|
|
205
|
+
return `${withReplay}\n\n${SHARED_PARAM_GUIDANCE}`;
|
|
187
206
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
1
2
|
/**
|
|
2
3
|
* Parameters that mean the same thing on every tool, documented ONCE instead of every turn.
|
|
3
4
|
*
|
|
@@ -23,5 +24,12 @@
|
|
|
23
24
|
export declare const SHARED_PARAM_SHORT: Readonly<Record<string, string>>;
|
|
24
25
|
/** The full text, sent once at initialize. Everything trimmed above is restated here. */
|
|
25
26
|
export declare const SHARED_PARAM_GUIDANCE: string;
|
|
27
|
+
/**
|
|
28
|
+
* The short form for one parameter, or undefined when it keeps its own text.
|
|
29
|
+
*
|
|
30
|
+
* `since` is a cursor (a number) on every tool but `reticle_verify`, where it is a git ref. That one
|
|
31
|
+
* keeps its own description, so the cursor text never reaches a parameter that takes a ref.
|
|
32
|
+
*/
|
|
33
|
+
export declare function sharedParamShort(name: string, schema: z.ZodTypeAny): string | undefined;
|
|
26
34
|
/** Is this a parameter whose guidance now lives in the instructions block? */
|
|
27
35
|
export declare function isSharedParam(name: string): boolean;
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
/** The short form left in the per-turn schema. Must still make sense with no instructions at all. */
|
|
23
23
|
export const SHARED_PARAM_SHORT = {
|
|
24
24
|
sessionId: 'Target a specific tab. Omit unless you mean one — see instructions.',
|
|
25
|
-
since: 'Cursor from a prior act
|
|
25
|
+
since: 'Cursor (a number) from a prior act or observe result.',
|
|
26
26
|
limit: 'Cap descriptors to the first N.',
|
|
27
27
|
};
|
|
28
28
|
/** The full text, sent once at initialize. Everything trimmed above is restated here. */
|
|
@@ -30,6 +30,20 @@ export const SHARED_PARAM_GUIDANCE = 'Arguments that mean the same thing on ever
|
|
|
30
30
|
'tab; Reticle scopes to your project, prefers the active one, and refuses rather than guesses when ' +
|
|
31
31
|
'ambiguous. `since` — a cursor from a prior act/observe, bounding an observation to what came ' +
|
|
32
32
|
'after it, or a git ref when verifying a change. `limit` — caps returned descriptors.';
|
|
33
|
+
/** A value only a string-typed `since` accepts. */
|
|
34
|
+
const GIT_REF_PROBE = 'main';
|
|
35
|
+
/**
|
|
36
|
+
* The short form for one parameter, or undefined when it keeps its own text.
|
|
37
|
+
*
|
|
38
|
+
* `since` is a cursor (a number) on every tool but `reticle_verify`, where it is a git ref. That one
|
|
39
|
+
* keeps its own description, so the cursor text never reaches a parameter that takes a ref.
|
|
40
|
+
*/
|
|
41
|
+
export function sharedParamShort(name, schema) {
|
|
42
|
+
if ('since' === name && schema.safeParse(GIT_REF_PROBE).success) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return SHARED_PARAM_SHORT[name];
|
|
46
|
+
}
|
|
33
47
|
/** Is this a parameter whose guidance now lives in the instructions block? */
|
|
34
48
|
export function isSharedParam(name) {
|
|
35
49
|
return Object.hasOwn(SHARED_PARAM_SHORT, name);
|
|
@@ -17,3 +17,14 @@ export declare class SseFrameParser {
|
|
|
17
17
|
#private;
|
|
18
18
|
push(chunk: string): SseFrame[];
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Turn an `endpoint` frame's data into a POST target, or null when there is nothing usable in it.
|
|
22
|
+
*
|
|
23
|
+
* An empty (or whitespace) data field is the shape a malformed daemon response takes, and it used to
|
|
24
|
+
* be accepted: `postUrl` became `''`, which is not `null`, so the proxy considered itself CONNECTED
|
|
25
|
+
* and posted every subsequent message to the empty string. Each one failed, the queue never armed
|
|
26
|
+
* its deadline because nothing was ever queued, and the agent held a session that could not carry a
|
|
27
|
+
* single call. Refusing the frame keeps the proxy in its disconnected path, which already knows how
|
|
28
|
+
* to reconnect and how to answer what it cannot send.
|
|
29
|
+
*/
|
|
30
|
+
export declare function buildSessionUrl(rawData: string, port: number): string | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { LOOPBACK_HOST } from '@reticlehq/core';
|
|
1
2
|
/**
|
|
2
3
|
* Incremental SSE frame parser for the MCP front door.
|
|
3
4
|
*
|
|
@@ -39,3 +40,20 @@ export class SseFrameParser {
|
|
|
39
40
|
return frames;
|
|
40
41
|
}
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Turn an `endpoint` frame's data into a POST target, or null when there is nothing usable in it.
|
|
45
|
+
*
|
|
46
|
+
* An empty (or whitespace) data field is the shape a malformed daemon response takes, and it used to
|
|
47
|
+
* be accepted: `postUrl` became `''`, which is not `null`, so the proxy considered itself CONNECTED
|
|
48
|
+
* and posted every subsequent message to the empty string. Each one failed, the queue never armed
|
|
49
|
+
* its deadline because nothing was ever queued, and the agent held a session that could not carry a
|
|
50
|
+
* single call. Refusing the frame keeps the proxy in its disconnected path, which already knows how
|
|
51
|
+
* to reconnect and how to answer what it cannot send.
|
|
52
|
+
*/
|
|
53
|
+
export function buildSessionUrl(rawData, port) {
|
|
54
|
+
const trimmed = rawData.trim();
|
|
55
|
+
if ('' === trimmed) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return trimmed.startsWith('/') ? `http://${LOOPBACK_HOST}:${port}${trimmed}` : trimmed;
|
|
59
|
+
}
|
|
@@ -43,6 +43,8 @@ export interface SurfaceVocabulary {
|
|
|
43
43
|
heal: string;
|
|
44
44
|
/** Start or poll a Harness drive, or empty when the surface cannot reach it. */
|
|
45
45
|
explore: string;
|
|
46
|
+
/** Open the running app with Reticle's own reader and no file changed, or empty. */
|
|
47
|
+
zeroInstall: string;
|
|
46
48
|
}
|
|
47
49
|
/** Drop the empty slots, so a sentence never reads "look (), find ()". */
|
|
48
50
|
export declare function listOf(...calls: readonly string[]): string;
|
|
@@ -9,6 +9,18 @@ function callOf(advertised, direct, parent, action) {
|
|
|
9
9
|
// slot costs a capability the agent has to discover; a wrong name costs the whole product.
|
|
10
10
|
return '';
|
|
11
11
|
}
|
|
12
|
+
// The URL is the one the session list names. A bare "<the running app's URL>" sent a real agent to
|
|
13
|
+
// start a second dev server on a port it chose, beside the user's own.
|
|
14
|
+
const ZERO_INSTALL_ARGS = `{ action: "acquire", url: "<URL>" }`;
|
|
15
|
+
/** The zero-install lease, direct where it is advertised, through `reticle_run` where that is. */
|
|
16
|
+
function zeroInstallCall(advertised) {
|
|
17
|
+
if (advertised.has(ReticleTool.LEASE))
|
|
18
|
+
return `${ReticleTool.LEASE} ${ZERO_INSTALL_ARGS}`;
|
|
19
|
+
if (advertised.has(ReticleTool.RUN)) {
|
|
20
|
+
return `${ReticleTool.RUN}({ tool: "${ReticleTool.LEASE}", args: ${ZERO_INSTALL_ARGS} })`;
|
|
21
|
+
}
|
|
22
|
+
return '';
|
|
23
|
+
}
|
|
12
24
|
/** Drop the empty slots, so a sentence never reads "look (), find ()". */
|
|
13
25
|
export function listOf(...calls) {
|
|
14
26
|
return calls.filter((call) => call.length > 0).join(' / ');
|
|
@@ -53,5 +65,6 @@ export function surfaceVocabulary(advertisedNames) {
|
|
|
53
65
|
replayAll: call(ReticleTool.FLOW_REPLAY, ReticleTool.VERIFY, 'flows'),
|
|
54
66
|
heal: advertised.has(ReticleTool.FLOW_HEAL) ? ReticleTool.FLOW_HEAL : '',
|
|
55
67
|
explore: call(ReticleTool.VERIFY_EXPLORE, ReticleTool.VERIFY, 'explore'),
|
|
68
|
+
zeroInstall: zeroInstallCall(advertised),
|
|
56
69
|
};
|
|
57
70
|
}
|
|
@@ -35,6 +35,8 @@ export declare class ToolCatalogCache {
|
|
|
35
35
|
#private;
|
|
36
36
|
/** Watch a line coming BACK from the daemon; remember it if it is a tool catalog. */
|
|
37
37
|
observe(line: string): void;
|
|
38
|
+
/** Hold a list that did not come from the daemon: the static catalog, while the daemon starts. */
|
|
39
|
+
remember(tools: unknown[]): void;
|
|
38
40
|
has(): boolean;
|
|
39
41
|
/**
|
|
40
42
|
* A response to `request` from the cached catalog, or null when this is not a tools/list request or
|
|
@@ -53,8 +53,15 @@ export class ToolCatalogCache {
|
|
|
53
53
|
observe(line) {
|
|
54
54
|
const msg = parse(line);
|
|
55
55
|
const tools = msg?.result?.tools;
|
|
56
|
-
if (Array.isArray(tools) && tools.length > 0)
|
|
56
|
+
if (Array.isArray(tools) && tools.length > 0) {
|
|
57
57
|
this.#tools = tools;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Hold a list that did not come from the daemon: the static catalog, while the daemon starts. */
|
|
61
|
+
remember(tools) {
|
|
62
|
+
if (tools.length > 0) {
|
|
63
|
+
this.#tools = tools;
|
|
64
|
+
}
|
|
58
65
|
}
|
|
59
66
|
has() {
|
|
60
67
|
return this.#tools !== undefined;
|
|
@@ -65,13 +72,16 @@ export class ToolCatalogCache {
|
|
|
65
72
|
* id is not an answer, it is noise the client will never match.
|
|
66
73
|
*/
|
|
67
74
|
answer(request) {
|
|
68
|
-
if (this.#tools === undefined)
|
|
75
|
+
if (this.#tools === undefined) {
|
|
69
76
|
return null;
|
|
77
|
+
}
|
|
70
78
|
const msg = parse(request);
|
|
71
|
-
if (msg?.method !== LIST_METHOD)
|
|
79
|
+
if (msg?.method !== LIST_METHOD) {
|
|
72
80
|
return null;
|
|
73
|
-
|
|
81
|
+
}
|
|
82
|
+
if (msg.id === undefined || null === msg.id) {
|
|
74
83
|
return null;
|
|
84
|
+
}
|
|
75
85
|
return JSON.stringify({ jsonrpc: '2.0', id: msg.id, result: { tools: this.#tools } });
|
|
76
86
|
}
|
|
77
87
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import type { ToolDef } from './tool-kit.js';
|
|
2
2
|
/** What the agent is told to do next, in plain words: one step, the first one that applies. */
|
|
3
3
|
export declare const ACCOUNT_NEXT: {
|
|
4
|
-
readonly SIGN_IN: "The user is not signed in to Reticle. Ask them to run `reticle connect` in the app folder: it signs them in and links this project.
|
|
4
|
+
readonly SIGN_IN: "The user is not signed in to Reticle. Ask them to run `reticle connect` in the app folder: it signs them in and links this project.";
|
|
5
5
|
readonly LINK: "This project does not report to the dashboard yet. Ask the user to press \"Link this project\" on the Harness page of the HUD, or to run `reticle connect` in the app folder.";
|
|
6
|
-
readonly
|
|
6
|
+
readonly unreachable: (url: string | undefined) => string;
|
|
7
7
|
readonly NO_CREDITS: (said: string) => string;
|
|
8
|
-
readonly locked: (percent: number, missing: string) => string;
|
|
9
8
|
readonly OFF: "Reticle Harness is off for this project. The user can switch it on in the HUD (the Harness row at the foot of the Agent Log) or on the dashboard.";
|
|
10
9
|
readonly NO_PROVIDER: "The platform has no model provider set, so Reticle Harness cannot run now. Tell the user; it is not on their side.";
|
|
11
10
|
readonly ready: (typical: number | undefined, max: number | undefined) => string;
|
|
@@ -16,6 +15,8 @@ export interface AccountInput {
|
|
|
16
15
|
dashboardUrl?: string;
|
|
17
16
|
/** The platform's `/v1/model/config` answer; undefined when unlinked, null when it did not answer. */
|
|
18
17
|
platform: Record<string, unknown> | null | undefined;
|
|
18
|
+
/** Where the linked cloud is, said when it does not answer. */
|
|
19
|
+
cloudUrl?: string;
|
|
19
20
|
}
|
|
20
21
|
/** The facts and the next step. Pure: the tool's I/O is in `readAccount`. */
|
|
21
22
|
export declare function accountFacts(input: AccountInput): Record<string, unknown>;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Where the user stands with Reticle, for the coding agent: signed in or not, whether this project
|
|
3
|
-
* reports to the dashboard, the plan and credits left, whether Reticle Harness is on
|
|
3
|
+
* reports to the dashboard, the plan and credits left, whether Reticle Harness is on,
|
|
4
4
|
* what a Harness run costs, and the one thing to do next.
|
|
5
5
|
*
|
|
6
6
|
* In 16 real Claude Code and Codex runs, no agent could answer "how many credits do I have" or "can
|
|
7
7
|
* the Harness run" from a tool: those facts lived only in the HUD and the dashboard. This reads the
|
|
8
8
|
* same sources they do (the HUD's snapshot for the account, the platform's model config for the
|
|
9
|
-
* plan
|
|
9
|
+
* plan and credits), so the agent and the HUD cannot disagree. No setup score gates the Harness.
|
|
10
10
|
*/
|
|
11
11
|
import { z } from 'zod';
|
|
12
|
-
import { ReticleTool, asRecord, asString } from '@reticlehq/core';
|
|
12
|
+
import { CONNECT_COMMAND, ReticleTool, asRecord, asString } from '@reticlehq/core';
|
|
13
13
|
import { creditsUsageText } from '@reticlehq/core/hud';
|
|
14
14
|
import { impactSnapshot } from '../../memory/impact/impact-recorder.js';
|
|
15
15
|
import { readDashboardUrl } from '../../memory/project/sync-status.js';
|
|
@@ -17,16 +17,13 @@ import { sessionRoot } from '../../memory/project/session-root.js';
|
|
|
17
17
|
import { platformHeaders } from '../../features/harness/platform/server-driver.js';
|
|
18
18
|
const CONFIG_PATH = '/v1/model/config';
|
|
19
19
|
const CONFIG_TIMEOUT_MS = 3_000;
|
|
20
|
-
const UNLOCK_PERCENT = 80;
|
|
21
20
|
/** What the agent is told to do next, in plain words: one step, the first one that applies. */
|
|
22
21
|
export const ACCOUNT_NEXT = {
|
|
23
|
-
SIGN_IN:
|
|
24
|
-
LINK:
|
|
25
|
-
|
|
22
|
+
SIGN_IN: `The user is not signed in to Reticle. Ask them to run \`${CONNECT_COMMAND}\` in the app folder: it signs them in and links this project.`,
|
|
23
|
+
LINK: `This project does not report to the dashboard yet. Ask the user to press "Link this project" on the Harness page of the HUD, or to run \`${CONNECT_COMMAND}\` in the app folder.`,
|
|
24
|
+
unreachable: (url) => `Reticle Cloud${url === undefined ? '' : ` at ${url}`} did not answer, so credits and the Harness are not known now. ` +
|
|
25
|
+
'The project is still linked: ask the user to check the connection, then read the account again. Local checks still work.',
|
|
26
26
|
NO_CREDITS: (said) => `${said} Reticle Harness cannot run until the user gets more credits on the dashboard's Plan and usage page.`,
|
|
27
|
-
locked: (percent, missing) =>
|
|
28
|
-
// The platform's own sentence already names the score and the gaps: said once, not twice.
|
|
29
|
-
`${0 < missing.length ? missing : `Setup score ${String(percent)}%: Reticle Harness needs ${String(UNLOCK_PERCENT)}%.`} Offer to close these gaps, then drive one flow to raise the score.`,
|
|
30
27
|
OFF: 'Reticle Harness is off for this project. The user can switch it on in the HUD (the Harness row at the foot of the Agent Log) or on the dashboard.',
|
|
31
28
|
NO_PROVIDER: 'The platform has no model provider set, so Reticle Harness cannot run now. Tell the user; it is not on their side.',
|
|
32
29
|
ready: (typical, max) => 'Reticle Harness is on and ready: reticle_verify { action: "explore", persona: "<the journey, with the text the page must show at the end in quotes>" }' +
|
|
@@ -49,7 +46,7 @@ export function accountFacts(input) {
|
|
|
49
46
|
if (input.platform === undefined)
|
|
50
47
|
return { ...base, next: ACCOUNT_NEXT.LINK };
|
|
51
48
|
if (null === input.platform)
|
|
52
|
-
return { ...base, next: ACCOUNT_NEXT.
|
|
49
|
+
return { ...base, next: ACCOUNT_NEXT.unreachable(input.cloudUrl) };
|
|
53
50
|
const p = input.platform;
|
|
54
51
|
const rawCredits = asRecord(p['credits']);
|
|
55
52
|
const used = num(rawCredits['used']);
|
|
@@ -74,18 +71,10 @@ export function accountFacts(input) {
|
|
|
74
71
|
const runCost = asRecord(p['harnessRunCredits']);
|
|
75
72
|
const typical = num(runCost['typical']);
|
|
76
73
|
const max = num(runCost['max']);
|
|
77
|
-
const lock = asRecord(p['harnessLock']);
|
|
78
|
-
const score = num(p['coverageScore']);
|
|
79
|
-
const percent = score === undefined ? undefined : Math.floor(score * 100 + 1e-9);
|
|
80
|
-
const unlocked = true === p['harnessUnlocked'];
|
|
81
74
|
const provider = str(p['provider']);
|
|
82
75
|
const providerReady = provider === undefined ? true : asRecord(p['available'])[provider] !== false;
|
|
83
76
|
const harness = {
|
|
84
77
|
on: true === p['harnessEnabled'],
|
|
85
|
-
unlocked,
|
|
86
|
-
...(percent === undefined ? {} : { setupScore: percent }),
|
|
87
|
-
...(str(lock['reason']) === undefined ? {} : { missing: str(lock['reason']) }),
|
|
88
|
-
...(str(lock['prompt']) === undefined ? {} : { setupPrompt: str(lock['prompt']) }),
|
|
89
78
|
...(typical === undefined
|
|
90
79
|
? {}
|
|
91
80
|
: { runCredits: { typical, ...(max === undefined ? {} : { max }) } }),
|
|
@@ -98,19 +87,15 @@ export function accountFacts(input) {
|
|
|
98
87
|
};
|
|
99
88
|
const next = credits !== undefined && 0 === credits.left
|
|
100
89
|
? ACCOUNT_NEXT.NO_CREDITS(credits.said)
|
|
101
|
-
: !
|
|
102
|
-
? ACCOUNT_NEXT.
|
|
103
|
-
: !
|
|
104
|
-
? ACCOUNT_NEXT.
|
|
105
|
-
:
|
|
106
|
-
? ACCOUNT_NEXT.OFF
|
|
107
|
-
: ACCOUNT_NEXT.ready(typical, max);
|
|
90
|
+
: !providerReady
|
|
91
|
+
? ACCOUNT_NEXT.NO_PROVIDER
|
|
92
|
+
: !harness.on
|
|
93
|
+
? ACCOUNT_NEXT.OFF
|
|
94
|
+
: ACCOUNT_NEXT.ready(typical, max);
|
|
108
95
|
return { ...facts, next };
|
|
109
96
|
}
|
|
110
97
|
/** The platform's model config with this project's linked key; undefined unlinked, null on no answer. */
|
|
111
|
-
async function platformConfig(
|
|
112
|
-
// The project's own link, not the environment: an agent asks about the project it is in.
|
|
113
|
-
const platform = (await deps.linkedCloud?.()) ?? null;
|
|
98
|
+
async function platformConfig(platform) {
|
|
114
99
|
if (null === platform)
|
|
115
100
|
return undefined;
|
|
116
101
|
try {
|
|
@@ -138,17 +123,21 @@ async function readAccount(deps, sessionId) {
|
|
|
138
123
|
const snapshot = impactSnapshot(root);
|
|
139
124
|
const account = snapshot?.account;
|
|
140
125
|
const dashboardUrl = root === undefined ? undefined : readDashboardUrl(root);
|
|
126
|
+
// The tab's own project's link, as the Harness reads it: the daemon's own folder may be unlinked
|
|
127
|
+
// (or another project) while the tab's is linked, and the answer was "press Link this project".
|
|
128
|
+
const platform = (await deps.linkedCloud?.(root).catch(() => null)) ?? null;
|
|
141
129
|
return accountFacts({
|
|
142
130
|
signedIn: true === account?.signedIn,
|
|
143
131
|
...(account?.org === undefined ? {} : { workspace: account.org }),
|
|
144
132
|
...(dashboardUrl === undefined ? {} : { dashboardUrl }),
|
|
145
|
-
platform: await platformConfig(
|
|
133
|
+
platform: await platformConfig(platform),
|
|
134
|
+
...(null === platform ? {} : { cloudUrl: platform.url }),
|
|
146
135
|
});
|
|
147
136
|
}
|
|
148
137
|
export const ACCOUNT_TOOLS = [
|
|
149
138
|
{
|
|
150
139
|
name: ReticleTool.ACCOUNT,
|
|
151
|
-
description: 'Where the user stands with Reticle: signed in or not, whether this project reports to the dashboard, the plan and credits left, whether Reticle Harness is on
|
|
140
|
+
description: 'Where the user stands with Reticle: signed in or not, whether this project reports to the dashboard, the plan and credits left, whether Reticle Harness is on, what a Harness run costs, and the one thing to do next. Read it before you tell the user anything about credits, the plan or the Harness.',
|
|
152
141
|
inputSchema: {
|
|
153
142
|
sessionId: z.string().optional().describe('Target a specific tab. Omit unless you mean one.'),
|
|
154
143
|
},
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { ActionType } from '@reticlehq/core';
|
|
2
|
+
/** A Harness call goes to a payment provider's origin only when its journey asked to pay. */
|
|
3
|
+
export declare function assertNotPaymentNavigation(url: string): void;
|
|
2
4
|
export declare function assertNotDestructive(action: ActionType, innerArgs: Record<string, unknown>, inspected: unknown): void;
|
|
3
5
|
/**
|
|
4
6
|
* A drag is judged on BOTH ends. Dropping a harmless row onto "Delete" is destructive, and the
|