@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
|
@@ -67,7 +67,17 @@ function reopenableUrl(raw) {
|
|
|
67
67
|
* bin on PATH, so a bare `reticle init` fails with "command not found" exactly where it is handed out.
|
|
68
68
|
*/
|
|
69
69
|
const CLI = 'npx @reticlehq/server';
|
|
70
|
-
const INIT_COMMAND = `${CLI} init`;
|
|
70
|
+
export const INIT_COMMAND = `${CLI} init`;
|
|
71
|
+
/**
|
|
72
|
+
* The consent question for wiring, in one wording for every place that offers `init`: the
|
|
73
|
+
* handshake, the first session call, every next action and the plugin hook. `init` changes the user's files, so the
|
|
74
|
+
* agent asks first. The lease changes nothing, so it needs no question.
|
|
75
|
+
*/
|
|
76
|
+
export function wiringConsent(init = INIT_COMMAND) {
|
|
77
|
+
return ('`init` changes files: it adds a dev-only SDK to package.json and the lockfile, edits the ' +
|
|
78
|
+
'build config and starts the dev server. Ask the user before you wire the app. If they ' +
|
|
79
|
+
`agree, run \`${init}\` in the app's folder. If they decline, do not ask again.`);
|
|
80
|
+
}
|
|
71
81
|
const OPEN_COMMAND = `${CLI} open`;
|
|
72
82
|
const LOCALHOST = 'http://localhost';
|
|
73
83
|
/**
|
|
@@ -77,13 +87,26 @@ const LOCALHOST = 'http://localhost';
|
|
|
77
87
|
const ZERO_INSTALL_SEES = 'the lease supplies the SDK itself: DOM, network, console and routes, but no component state ' +
|
|
78
88
|
'or source file:line until the app is wired';
|
|
79
89
|
/** The zero-install call, with the URL only when it can be named without guessing. */
|
|
80
|
-
function zeroInstallLease(url) {
|
|
81
|
-
|
|
90
|
+
export function zeroInstallLease(url) {
|
|
91
|
+
// Through reticle_run: reticle_lease is not on the default surface, and reticle_run is on every one (#1547).
|
|
92
|
+
return `reticle_run { tool: "reticle_lease", args: { action: "acquire", url: "${url ?? "<the app's URL>"}" } }`;
|
|
82
93
|
}
|
|
83
94
|
/** Nothing here says this project was ever wired: no config, no recorded connection, no session. */
|
|
84
95
|
function neverWired(facts) {
|
|
85
96
|
return !facts.initialized && true !== facts.previouslyConnected && !facts.everConnected;
|
|
86
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* The start advice's first claim when no port is this project's. A scan that heard a page it could
|
|
100
|
+
* not tie to this project says so, because "nothing is listening" is then false.
|
|
101
|
+
*/
|
|
102
|
+
function notThisProject(others) {
|
|
103
|
+
if (others === undefined || 0 === others.length) {
|
|
104
|
+
return 'nothing is listening on the ports Reticle scans, so the app is probably not running — ';
|
|
105
|
+
}
|
|
106
|
+
const named = others.map((port) => `:${String(port)}`).join(', ');
|
|
107
|
+
return (`${named} serves a page, but its process does not run in this project's folder, so this app ` +
|
|
108
|
+
`is probably not running — if one of them IS this app, open it instead of starting a second one, `);
|
|
109
|
+
}
|
|
87
110
|
export function nextActionFor(facts) {
|
|
88
111
|
// FIRST, above every other cause, because it is the only one supported by positive evidence about
|
|
89
112
|
// a daemon rather than by an absence. This project's own connection record names a live daemon
|
|
@@ -149,7 +172,8 @@ export function nextActionFor(facts) {
|
|
|
149
172
|
(departedTo === undefined || '' === departedTo
|
|
150
173
|
? 'the tab was closed, reloaded, or the lease aged out. '
|
|
151
174
|
: `the page navigated away to ${redactUrl(departedTo)}. `) +
|
|
152
|
-
'Reopen the app, or take one you own with
|
|
175
|
+
'Reopen the app, or take one you own with ' +
|
|
176
|
+
'reticle_run { tool: "reticle_lease", args: { action: "acquire", url } }.' +
|
|
153
177
|
bound,
|
|
154
178
|
};
|
|
155
179
|
}
|
|
@@ -163,8 +187,8 @@ export function nextActionFor(facts) {
|
|
|
163
187
|
const projectIds = configsElsewhere.flatMap((config) => config.projectId === undefined ? [] : [config.projectId]);
|
|
164
188
|
const leaseAlternative = 0 === projectIds.length
|
|
165
189
|
? ''
|
|
166
|
-
: ' Alternatively, acquire the app URL explicitly with reticle_lease ' +
|
|
167
|
-
'{action:"acquire", url, projectId} using the matching projectId above.';
|
|
190
|
+
: ' Alternatively, acquire the app URL explicitly with reticle_run { tool: "reticle_lease", ' +
|
|
191
|
+
'args: { action: "acquire", url, projectId } } using the matching projectId above.';
|
|
168
192
|
return {
|
|
169
193
|
action: NoSessionAction.OPEN_APP,
|
|
170
194
|
reason: `a \`.reticle.json\` was found outside this daemon's directory: ${named}. This is a ` +
|
|
@@ -215,8 +239,8 @@ export function nextActionFor(facts) {
|
|
|
215
239
|
'This daemon was started outside the project (an IDE that registers the MCP server ' +
|
|
216
240
|
'globally starts it in `/` or your home directory), so it has no `.reticle.json` to match ' +
|
|
217
241
|
'the page against. Do NOT run `reticle init`: the config it would write is already correct ' +
|
|
218
|
-
'somewhere else. Take a context you own instead with
|
|
219
|
-
"projectId}, or restart the daemon from the app's own directory.
|
|
242
|
+
'somewhere else. Take a context you own instead with reticle_run { tool: "reticle_lease", ' +
|
|
243
|
+
'args: { action: "acquire", url, projectId } }, or restart the daemon from the app\'s own directory.',
|
|
220
244
|
};
|
|
221
245
|
}
|
|
222
246
|
if (0 === facts.listening.length || departedPortIsGone) {
|
|
@@ -229,7 +253,7 @@ export function nextActionFor(facts) {
|
|
|
229
253
|
: ` The session that was on ${redactUrl(stopped.url)} is gone and nothing listens there now.`;
|
|
230
254
|
const notRunning = departedPortIsGone
|
|
231
255
|
? "nothing answers on the port this project's app was last on, so the app is probably not running — "
|
|
232
|
-
:
|
|
256
|
+
: notThisProject(facts.otherListeners);
|
|
233
257
|
if (dev === undefined) {
|
|
234
258
|
if (facts.exists !== undefined && !facts.exists('package.json')) {
|
|
235
259
|
const ecosystem = detectNonJsEcosystem(facts.exists);
|
|
@@ -279,12 +303,12 @@ export function nextActionFor(facts) {
|
|
|
279
303
|
(undefined === dev.script ? 'launcher' : `\`${dev.script}\` script`) +
|
|
280
304
|
(dev.directory === undefined ? '' : `, in \`${dev.directory}\``) +
|
|
281
305
|
` — run it in the ` +
|
|
282
|
-
'background, tell the human it is running, then call
|
|
306
|
+
'background, tell the human it is running, then call reticle_session { action: "list" } again.' +
|
|
283
307
|
stoppedNote +
|
|
284
308
|
(neverWired(facts)
|
|
285
309
|
? ` Once it is up, ${zeroInstallLease(dev.port === undefined ? undefined : `${LOCALHOST}:${String(dev.port)}`)} ` +
|
|
286
310
|
`gets a verdict with nothing installed (${ZERO_INSTALL_SEES}); ` +
|
|
287
|
-
|
|
311
|
+
`To wire it for good: ${wiringConsent(facts.init ?? INIT_COMMAND)} Then restart the dev server and reload.`
|
|
288
312
|
: ''),
|
|
289
313
|
};
|
|
290
314
|
}
|
|
@@ -301,9 +325,9 @@ export function nextActionFor(facts) {
|
|
|
301
325
|
reason: `something is listening (${ports}) but no \`.reticle.json\` was found, so the app may ` +
|
|
302
326
|
'carry no Reticle SDK. For a verdict NOW with nothing installed: ' +
|
|
303
327
|
`${zeroInstallLease(target === undefined ? undefined : `${LOCALHOST}:${String(target)}`)} — ` +
|
|
304
|
-
`${ZERO_INSTALL_SEES}. To wire it for good
|
|
305
|
-
"
|
|
306
|
-
'the page.',
|
|
328
|
+
`${ZERO_INSTALL_SEES}. To wire it for good: ${wiringConsent(facts.init ?? INIT_COMMAND)} ` +
|
|
329
|
+
"The app's folder is not always where this daemon stands. Then restart the dev server and " +
|
|
330
|
+
'reload the page.',
|
|
307
331
|
};
|
|
308
332
|
}
|
|
309
333
|
if (only === undefined) {
|
|
@@ -343,7 +367,8 @@ export function nextActionFor(facts) {
|
|
|
343
367
|
/** The same action as one sentence, for the prose message the human reads. */
|
|
344
368
|
export function renderNextAction(next) {
|
|
345
369
|
const command = next.command;
|
|
346
|
-
|
|
370
|
+
// `init` changes the user's files, so its line repeats the consent in the reason, not an order.
|
|
371
|
+
return command === undefined || NoSessionAction.RUN_INIT === next.action
|
|
347
372
|
? `NEXT ACTION: ${next.reason}`
|
|
348
373
|
: `NEXT ACTION: run \`${command}\` — ${next.reason}`;
|
|
349
374
|
}
|
|
@@ -67,6 +67,13 @@ interface NoSessionWatchOptions {
|
|
|
67
67
|
* somebody else's app. Injected for tests; production reads the registry scoped by projectId/root.
|
|
68
68
|
*/
|
|
69
69
|
ownDevServerPorts?: () => readonly number[];
|
|
70
|
+
/**
|
|
71
|
+
* The folder the process listening on `port` runs in, or undefined when it cannot be read.
|
|
72
|
+
*
|
|
73
|
+
* An unwired project announces no port, so this is the one fact that ties a running dev server
|
|
74
|
+
* to it. Injected for tests; a test that injects `probe` and omits this observes no folder.
|
|
75
|
+
*/
|
|
76
|
+
listenerDirectory?: (port: number) => string | undefined;
|
|
70
77
|
/**
|
|
71
78
|
* What the route the last session was on answers right now, as an HTTP status, or undefined
|
|
72
79
|
* when there is no answer to report.
|
|
@@ -30,6 +30,8 @@ import { findOccupiedSiblings } from '../../command/cli/ports/sibling-ports.js';
|
|
|
30
30
|
import { isAuthRefusalReason } from '../bridge/auth-failure-reason.js';
|
|
31
31
|
import { devServersForProject } from '@reticlehq/core';
|
|
32
32
|
import { readDevServers } from '../../command/daemon/dev-servers.js';
|
|
33
|
+
import { servingDirectoryOf } from './serving-directory.js';
|
|
34
|
+
import { within } from './zero-install-first-call.js';
|
|
33
35
|
/** Slow enough to be free, fast enough that a dev server started 15s ago is already reflected. */
|
|
34
36
|
const REFRESH_MS = 15_000;
|
|
35
37
|
/** The URL an auto-attach opens. `localhost` for the same reason the probe uses it: both stacks. */
|
|
@@ -69,6 +71,12 @@ export function startNoSessionWatch(options) {
|
|
|
69
71
|
* `options.probe` returns only the serving set, so this stays empty for injected probes.
|
|
70
72
|
*/
|
|
71
73
|
let slowListeners = [];
|
|
74
|
+
/** The folder each listening port's process runs in, read on the scan's cadence, not when asked. */
|
|
75
|
+
let listenerDirs = new Map();
|
|
76
|
+
const listenerDirectory = options.listenerDirectory ??
|
|
77
|
+
(options.probe === undefined
|
|
78
|
+
? (port) => servingDirectoryOf(`${LOCALHOST}:${String(port)}`)
|
|
79
|
+
: () => undefined);
|
|
72
80
|
let siblingListeners = [];
|
|
73
81
|
/**
|
|
74
82
|
* What the last-known route answered, cached beside the port scan for the same reason the scan
|
|
@@ -97,8 +105,9 @@ export function startNoSessionWatch(options) {
|
|
|
97
105
|
*/
|
|
98
106
|
const projectScopeFacts = () => {
|
|
99
107
|
const initialized = isWired();
|
|
100
|
-
if (initialized)
|
|
108
|
+
if (initialized) {
|
|
101
109
|
return { initialized };
|
|
110
|
+
}
|
|
102
111
|
const discovery = discoverProjectConfigs(directory);
|
|
103
112
|
const elsewhere = discovery.found.filter((config) => config.directory !== directory);
|
|
104
113
|
if (elsewhere.length > 0) {
|
|
@@ -192,21 +201,25 @@ export function startNoSessionWatch(options) {
|
|
|
192
201
|
*/
|
|
193
202
|
const scanPorts = () => {
|
|
194
203
|
const ports = new Set(DEV_SERVER_PORTS);
|
|
195
|
-
for (const port of ownDevServerPorts())
|
|
204
|
+
for (const port of ownDevServerPorts()) {
|
|
196
205
|
ports.add(port);
|
|
206
|
+
}
|
|
197
207
|
const pinned = detectDevCommandInProject(directory)?.port;
|
|
198
|
-
if (pinned !== undefined)
|
|
208
|
+
if (pinned !== undefined) {
|
|
199
209
|
ports.add(pinned);
|
|
210
|
+
}
|
|
200
211
|
const known = options.sessions.lastKnown?.();
|
|
201
212
|
const knownPort = known === undefined ? undefined : portOfUrl(known.url);
|
|
202
|
-
if (knownPort !== undefined)
|
|
213
|
+
if (knownPort !== undefined) {
|
|
203
214
|
ports.add(knownPort);
|
|
215
|
+
}
|
|
204
216
|
// Every departed project, not only the newest. B can still be serving on :3005 after A leaves
|
|
205
217
|
// on :5173, and a scan that never asked :3005 would report B's app as stopped.
|
|
206
218
|
for (const url of options.sessions.tombstoneUrls?.() ?? []) {
|
|
207
219
|
const port = portOfUrl(url);
|
|
208
|
-
if (port !== undefined)
|
|
220
|
+
if (port !== undefined) {
|
|
209
221
|
ports.add(port);
|
|
222
|
+
}
|
|
210
223
|
}
|
|
211
224
|
return [...ports];
|
|
212
225
|
};
|
|
@@ -216,8 +229,9 @@ export function startNoSessionWatch(options) {
|
|
|
216
229
|
* browser is worse than the sentence the diagnosis already writes about the ports it saw.
|
|
217
230
|
*/
|
|
218
231
|
const attributable = (port) => {
|
|
219
|
-
if (ownDevServerPorts().includes(port))
|
|
232
|
+
if (ownDevServerPorts().includes(port)) {
|
|
220
233
|
return true;
|
|
234
|
+
}
|
|
221
235
|
const known = options.sessions.lastKnown?.();
|
|
222
236
|
const projectId = readProjectId(directory);
|
|
223
237
|
if (known === undefined || projectId === undefined || known.projectId !== projectId) {
|
|
@@ -232,17 +246,22 @@ export function startNoSessionWatch(options) {
|
|
|
232
246
|
};
|
|
233
247
|
const autoAttach = async (ports) => {
|
|
234
248
|
const attach = options.attach;
|
|
235
|
-
if (attach === undefined)
|
|
249
|
+
if (attach === undefined) {
|
|
236
250
|
return;
|
|
237
|
-
|
|
251
|
+
}
|
|
252
|
+
if (1 !== ports.length) {
|
|
238
253
|
return;
|
|
254
|
+
}
|
|
239
255
|
const [only] = ports;
|
|
240
|
-
if (only === undefined || attempted.has(only))
|
|
256
|
+
if (only === undefined || attempted.has(only)) {
|
|
241
257
|
return;
|
|
242
|
-
|
|
258
|
+
}
|
|
259
|
+
if (!isWired()) {
|
|
243
260
|
return;
|
|
244
|
-
|
|
261
|
+
}
|
|
262
|
+
if (!attributable(only)) {
|
|
245
263
|
return;
|
|
264
|
+
}
|
|
246
265
|
attempted.add(only);
|
|
247
266
|
try {
|
|
248
267
|
await attach(`${LOCALHOST}:${String(only)}`);
|
|
@@ -254,10 +273,12 @@ export function startNoSessionWatch(options) {
|
|
|
254
273
|
const refresh = () => {
|
|
255
274
|
// Nothing to diagnose while a session is live, and no reason to scan. What the last scan saw
|
|
256
275
|
// predates this session, so it is no observation of where the session goes on to depart from.
|
|
257
|
-
if (options.sessions.count() > 0)
|
|
276
|
+
if (options.sessions.count() > 0) {
|
|
258
277
|
probed = new Set();
|
|
259
|
-
|
|
278
|
+
}
|
|
279
|
+
if (running || options.sessions.count() > 0) {
|
|
260
280
|
return;
|
|
281
|
+
}
|
|
261
282
|
running = true;
|
|
262
283
|
const candidates = scanPorts();
|
|
263
284
|
void (options.probe === undefined
|
|
@@ -269,6 +290,10 @@ export function startNoSessionWatch(options) {
|
|
|
269
290
|
.then(async (ports) => {
|
|
270
291
|
probed = new Set(candidates);
|
|
271
292
|
listening = ports;
|
|
293
|
+
listenerDirs = new Map(ports.flatMap((port) => {
|
|
294
|
+
const dir = listenerDirectory(port);
|
|
295
|
+
return dir === undefined ? [] : [[port, dir]];
|
|
296
|
+
}));
|
|
272
297
|
siblingListeners =
|
|
273
298
|
options.occupiedSiblings !== undefined
|
|
274
299
|
? await options.occupiedSiblings()
|
|
@@ -280,8 +305,9 @@ export function startNoSessionWatch(options) {
|
|
|
280
305
|
const known = options.sessions.lastKnown?.();
|
|
281
306
|
if (known !== undefined && lastKnownStatus?.url !== known.url) {
|
|
282
307
|
const status = await routeStatus(known.url);
|
|
283
|
-
if (status !== undefined)
|
|
308
|
+
if (status !== undefined) {
|
|
284
309
|
lastKnownStatus = { url: known.url, status };
|
|
310
|
+
}
|
|
285
311
|
}
|
|
286
312
|
await autoAttach(ports);
|
|
287
313
|
})
|
|
@@ -324,10 +350,12 @@ export function startNoSessionWatch(options) {
|
|
|
324
350
|
*/
|
|
325
351
|
const currentHelloRefusal = () => {
|
|
326
352
|
const closure = options.sessions.lastClosure?.();
|
|
327
|
-
if (closure?.page === undefined || isAuthRefusalReason(closure.reason))
|
|
353
|
+
if (closure?.page === undefined || isAuthRefusalReason(closure.reason)) {
|
|
328
354
|
return undefined;
|
|
329
|
-
|
|
355
|
+
}
|
|
356
|
+
if (true === options.sessions.connectedSinceLastClosure?.()) {
|
|
330
357
|
return undefined;
|
|
358
|
+
}
|
|
331
359
|
return { reason: closure.reason, ...closure.page };
|
|
332
360
|
};
|
|
333
361
|
/**
|
|
@@ -354,15 +382,25 @@ export function startNoSessionWatch(options) {
|
|
|
354
382
|
const ownPorts = new Set(devServersForProject(readDevServers(stateDir), { projectId, root: dir }).map((entry) => entry.port));
|
|
355
383
|
if (known !== undefined) {
|
|
356
384
|
const port = portOfUrl(known.url);
|
|
357
|
-
if (port !== undefined)
|
|
385
|
+
if (port !== undefined) {
|
|
358
386
|
ownPorts.add(port);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
// A process that runs in this folder is this project's dev server, announced or not. An unwired
|
|
390
|
+
// project announces nothing, and without this its running app read as absent.
|
|
391
|
+
for (const port of listening) {
|
|
392
|
+
if (within(listenerDirs.get(port), dir)) {
|
|
393
|
+
ownPorts.add(port);
|
|
394
|
+
}
|
|
359
395
|
}
|
|
360
396
|
const heard = listening.filter((port) => ownPorts.has(port));
|
|
397
|
+
const others = listening.filter((port) => !ownPorts.has(port));
|
|
361
398
|
// Not in the last scan means we have not looked, not that the server stopped. Treating the
|
|
362
399
|
// gap as "down" is what tells a still-running app to start a second one.
|
|
363
400
|
for (const port of ownPorts) {
|
|
364
|
-
if (!probed.has(port) && !heard.includes(port))
|
|
401
|
+
if (!probed.has(port) && !heard.includes(port)) {
|
|
365
402
|
heard.push(port);
|
|
403
|
+
}
|
|
366
404
|
}
|
|
367
405
|
const slow = slowListeners.filter((port) => ownPorts.has(port));
|
|
368
406
|
const closure = options.sessions.lastClosure?.();
|
|
@@ -433,6 +471,7 @@ export function startNoSessionWatch(options) {
|
|
|
433
471
|
...(helloRefused === undefined ? {} : { helloRefused: helloRefused.reason }),
|
|
434
472
|
...(split === undefined ? {} : { splitBrain: split }),
|
|
435
473
|
listening: heard,
|
|
474
|
+
...(0 === others.length ? {} : { otherListeners: others }),
|
|
436
475
|
slowListeners: slow,
|
|
437
476
|
...(known === undefined
|
|
438
477
|
? {}
|
|
@@ -451,8 +490,9 @@ export function startNoSessionWatch(options) {
|
|
|
451
490
|
*/
|
|
452
491
|
const callerAnswer = () => {
|
|
453
492
|
const caller = callingClientDirectory();
|
|
454
|
-
if (caller === undefined)
|
|
493
|
+
if (caller === undefined) {
|
|
455
494
|
return undefined;
|
|
495
|
+
}
|
|
456
496
|
return diagnosisFor(caller);
|
|
457
497
|
};
|
|
458
498
|
/**
|
|
@@ -489,8 +529,9 @@ export function startNoSessionWatch(options) {
|
|
|
489
529
|
// command and the sentence beside it name the same page.
|
|
490
530
|
...(() => {
|
|
491
531
|
const known = options.sessions.lastKnown?.();
|
|
492
|
-
if (known === undefined)
|
|
532
|
+
if (known === undefined) {
|
|
493
533
|
return {};
|
|
534
|
+
}
|
|
494
535
|
return {
|
|
495
536
|
lastKnownUrl: known.url,
|
|
496
537
|
...(known.departedTo === undefined ? {} : { departedTo: known.departedTo }),
|
|
@@ -512,8 +553,9 @@ export function startNoSessionWatch(options) {
|
|
|
512
553
|
// calls a moment apart can genuinely disagree (#615).
|
|
513
554
|
const explain = () => {
|
|
514
555
|
const caller = callerAnswer();
|
|
515
|
-
if (caller !== undefined)
|
|
556
|
+
if (caller !== undefined) {
|
|
516
557
|
return explainNoSession(caller.facts);
|
|
558
|
+
}
|
|
517
559
|
const scope = projectScopeFacts();
|
|
518
560
|
return explainNoSession({
|
|
519
561
|
everConnected: options.sessions.everConnected(),
|
|
@@ -563,8 +605,9 @@ export function startNoSessionWatch(options) {
|
|
|
563
605
|
// has none to name.
|
|
564
606
|
...(() => {
|
|
565
607
|
const known = options.sessions.lastKnown?.();
|
|
566
|
-
if (undefined === known)
|
|
608
|
+
if (undefined === known) {
|
|
567
609
|
return {};
|
|
610
|
+
}
|
|
568
611
|
// The status rides only when it was fetched for THIS url. A departure since the fetch
|
|
569
612
|
// means the cached answer is about a route nobody is asking about.
|
|
570
613
|
const status = lastKnownStatus !== undefined && lastKnownStatus.url === known.url
|
|
@@ -635,8 +678,9 @@ export function wireSessionScope(sessions, activeProjectId, port,
|
|
|
635
678
|
wasReapedLease,
|
|
636
679
|
/** Opens a URL in a Reticle-owned browser (the pool). Omitted ⇒ auto-attach is off. */
|
|
637
680
|
attach) {
|
|
638
|
-
if (activeProjectId !== undefined)
|
|
681
|
+
if (activeProjectId !== undefined) {
|
|
639
682
|
sessions.setDefaultScope({ projectId: activeProjectId });
|
|
683
|
+
}
|
|
640
684
|
return startNoSessionWatch({
|
|
641
685
|
sessions,
|
|
642
686
|
port,
|
|
@@ -79,4 +79,14 @@ export declare function sizeCost(payload: unknown): SizeCost;
|
|
|
79
79
|
* Non-object results (e.g. a thrown-error envelope) pass through unchanged.
|
|
80
80
|
*/
|
|
81
81
|
export declare function withSizeCost<T>(result: T): T;
|
|
82
|
+
/**
|
|
83
|
+
* Drop `sessionId` from an event in a response the caller scoped to ONE session.
|
|
84
|
+
*
|
|
85
|
+
* The caller passed that id in the request, so echoing it on every event is the request quoted back
|
|
86
|
+
* once per row. Measured on a live app it was 25% of a four-event `reticle_observe` payload, and it
|
|
87
|
+
* grows linearly with the timeline — a fifty-event window spends ~2.5KB restating a fact the caller
|
|
88
|
+
* supplied. The id stays on the wire between SDK and bridge, where events from different sessions
|
|
89
|
+
* really do interleave; it is only redundant at this boundary.
|
|
90
|
+
*/
|
|
91
|
+
export declare function withoutConstantSessionId(event: unknown): unknown;
|
|
82
92
|
export {};
|
|
@@ -106,3 +106,19 @@ export function withSizeCost(result) {
|
|
|
106
106
|
return result;
|
|
107
107
|
return { ...result, cost: sizeCost(result) };
|
|
108
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Drop `sessionId` from an event in a response the caller scoped to ONE session.
|
|
111
|
+
*
|
|
112
|
+
* The caller passed that id in the request, so echoing it on every event is the request quoted back
|
|
113
|
+
* once per row. Measured on a live app it was 25% of a four-event `reticle_observe` payload, and it
|
|
114
|
+
* grows linearly with the timeline — a fifty-event window spends ~2.5KB restating a fact the caller
|
|
115
|
+
* supplied. The id stays on the wire between SDK and bridge, where events from different sessions
|
|
116
|
+
* really do interleave; it is only redundant at this boundary.
|
|
117
|
+
*/
|
|
118
|
+
export function withoutConstantSessionId(event) {
|
|
119
|
+
if (typeof event !== 'object' || null === event) {
|
|
120
|
+
return event;
|
|
121
|
+
}
|
|
122
|
+
const { sessionId: _sessionId, ...rest } = event;
|
|
123
|
+
return rest;
|
|
124
|
+
}
|
|
@@ -12,3 +12,5 @@ export interface SessionLease {
|
|
|
12
12
|
IMPORTANT: string;
|
|
13
13
|
}
|
|
14
14
|
export declare function buildSessionLease(sessionId: string, openedAt: number): SessionLease;
|
|
15
|
+
/** The age warning spliced onto session-bound results after SESSION_LEASE.WARN_AFTER_MS, else undefined. */
|
|
16
|
+
export declare function sessionAgeWarning(sessionId: string, ageMs: number): string | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SESSION_LEASE } from '@reticlehq/core';
|
|
1
2
|
/**
|
|
2
3
|
* Kept SHORT on purpose, and this is the reason to read before editing it.
|
|
3
4
|
*
|
|
@@ -12,3 +13,10 @@ const SESSION_LEASE_NOTICE = 'When you stop driving, call reticle_session {actio
|
|
|
12
13
|
export function buildSessionLease(sessionId, openedAt) {
|
|
13
14
|
return { sessionId, opened_at: openedAt, IMPORTANT: SESSION_LEASE_NOTICE };
|
|
14
15
|
}
|
|
16
|
+
/** The age warning spliced onto session-bound results after SESSION_LEASE.WARN_AFTER_MS, else undefined. */
|
|
17
|
+
export function sessionAgeWarning(sessionId, ageMs) {
|
|
18
|
+
if (ageMs < SESSION_LEASE.WARN_AFTER_MS)
|
|
19
|
+
return undefined;
|
|
20
|
+
const minutes = Math.floor(ageMs / 60_000);
|
|
21
|
+
return `Session ${sessionId} has been open for ${String(minutes)} minutes. If your task is complete, call reticle_session{action:"end"} now.`;
|
|
22
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { InboxMessage } from './human/live-control.js';
|
|
2
|
-
import { type Coverage, CoverageCapability, type ImpactSnapshot } from '@reticlehq/core';
|
|
2
|
+
import { type Coverage, CoverageCapability, type ImpactSnapshot, ENGINE_BLIND_SPOTS_FIELD, type EngineBlindSpot, type Predicate } from '@reticlehq/core';
|
|
3
3
|
export interface RecordedGap {
|
|
4
4
|
kind: string;
|
|
5
5
|
missing: string;
|
|
@@ -46,6 +46,16 @@ export interface ProbedTab extends NotedTab {
|
|
|
46
46
|
* True when a page showed something not known before.
|
|
47
47
|
*/
|
|
48
48
|
export declare function probeMarkers(tabs: readonly ProbedTab[]): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* The `engineBlindSpots` field for a verdict result: what this engine could not observe in the
|
|
51
|
+
* session so far. Notes this verdict's own comparison first, so a `compare` clears the arithmetic
|
|
52
|
+
* spot on the result that ran it. `claims`: the inline intent, then the run's declared intents.
|
|
53
|
+
*/
|
|
54
|
+
export declare function engineBlindSpotsField(sessionId: string, predicate: Predicate | undefined, intent: unknown, declared: readonly {
|
|
55
|
+
statement: string;
|
|
56
|
+
}[]): {
|
|
57
|
+
[ENGINE_BLIND_SPOTS_FIELD]: EngineBlindSpot[];
|
|
58
|
+
};
|
|
49
59
|
/** What this session's verdicts recorded, newest first. */
|
|
50
60
|
export declare function recordedGaps(sessionId: string): readonly RecordedGap[];
|
|
51
61
|
/** Forget a session that ended. What its app has shown is kept: it is still that app's. */
|
|
@@ -72,22 +82,16 @@ export declare function announcedChannels(tab: InstrumentedTab): string[];
|
|
|
72
82
|
* The platform reads the same list from the local-apps report, so both sides move together.
|
|
73
83
|
*/
|
|
74
84
|
export declare function notApplicableOf(tab: NotedTab): CoverageCapability[];
|
|
75
|
-
/** Whether the Harness may drive this tab's app (see core's `instrumentation-coverage.ts`), as pushed. */
|
|
76
|
-
export interface TabHarnessGate {
|
|
77
|
-
percent: number;
|
|
78
|
-
unlocked: boolean;
|
|
79
|
-
reason?: string;
|
|
80
|
-
}
|
|
81
85
|
/**
|
|
82
|
-
* This tab's coverage and its
|
|
83
|
-
*
|
|
84
|
-
*
|
|
86
|
+
* This tab's coverage and its setup score (see core's `instrumentation-coverage.ts`), with the
|
|
87
|
+
* coding-agent prompt when its verdicts recorded any gap. The score is information: it never gates
|
|
88
|
+
* the Harness.
|
|
85
89
|
*/
|
|
86
90
|
export declare function instrumentationOf(tab: InstrumentedTab,
|
|
87
91
|
/** The app's other tabs: what any of them has seen or recorded counts, as on the platform. */
|
|
88
92
|
siblings?: readonly InstrumentedTab[]): Coverage & {
|
|
89
93
|
prompt?: string;
|
|
90
|
-
|
|
94
|
+
setupScore: number;
|
|
91
95
|
};
|
|
92
96
|
/**
|
|
93
97
|
* The impact snapshot a tab is pushed, carrying that tab's own coverage, running drive and agent
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { withRunningDrive } from '../../features/harness/drive-runs.js';
|
|
10
10
|
import { agentLinkOf } from './agent-link.js';
|
|
11
|
-
import { CoverageMarker, InstrumentationGapKind, LINK_APP_GAPS_MAX, ReticleCommand, agentPromptFor, coverageOf,
|
|
11
|
+
import { CoverageMarker, InstrumentationGapKind, LINK_APP_GAPS_MAX, ReticleCommand, agentPromptFor, coverageOf, coveragePercent, CoverageCapability, ENGINE_BLIND_SPOTS_FIELD, computesComparison, engineBlindSpots, } from '@reticlehq/core';
|
|
12
12
|
const bySession = new Map();
|
|
13
13
|
const text = (value) => 'string' === typeof value && 0 < value.length ? value : undefined;
|
|
14
14
|
/** Remember gaps a verdict on this session just reported. Malformed entries are skipped. */
|
|
@@ -90,6 +90,13 @@ export function noteActedElement(tab, result) {
|
|
|
90
90
|
return;
|
|
91
91
|
const acted = result;
|
|
92
92
|
noteTestidSeen(tab, text(acted['testid']));
|
|
93
|
+
// An action that ran with a canvas on screen: its pixels go unobserved for this run.
|
|
94
|
+
const effect = acted['effect'];
|
|
95
|
+
const canvases = 'object' === typeof effect && null !== effect
|
|
96
|
+
? effect['canvases']
|
|
97
|
+
: undefined;
|
|
98
|
+
if ('number' === typeof canvases && 0 < canvases)
|
|
99
|
+
canvasSeen.add(tab.id);
|
|
93
100
|
const source = acted['source'];
|
|
94
101
|
if ('object' === typeof source && null !== source) {
|
|
95
102
|
const file = text(source['file']);
|
|
@@ -146,6 +153,29 @@ export async function probeMarkers(tabs) {
|
|
|
146
153
|
}));
|
|
147
154
|
return before < sourceSeen.size + testidSeen.size;
|
|
148
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Sessions where an action ran with a canvas on screen, and sessions where a verdict ran a computed
|
|
158
|
+
* comparison. Facts about a RUN, so a reload (a new HELLO under the same id) does not clear them.
|
|
159
|
+
*/
|
|
160
|
+
const canvasSeen = new Set();
|
|
161
|
+
const comparedSeen = new Set();
|
|
162
|
+
/**
|
|
163
|
+
* The `engineBlindSpots` field for a verdict result: what this engine could not observe in the
|
|
164
|
+
* session so far. Notes this verdict's own comparison first, so a `compare` clears the arithmetic
|
|
165
|
+
* spot on the result that ran it. `claims`: the inline intent, then the run's declared intents.
|
|
166
|
+
*/
|
|
167
|
+
export function engineBlindSpotsField(sessionId, predicate, intent, declared) {
|
|
168
|
+
if (computesComparison(predicate))
|
|
169
|
+
comparedSeen.add(sessionId);
|
|
170
|
+
const claims = [text(intent), ...declared.map((each) => each.statement)];
|
|
171
|
+
return {
|
|
172
|
+
[ENGINE_BLIND_SPOTS_FIELD]: engineBlindSpots({
|
|
173
|
+
canvasSeen: canvasSeen.has(sessionId),
|
|
174
|
+
compared: comparedSeen.has(sessionId),
|
|
175
|
+
claims,
|
|
176
|
+
}),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
149
179
|
/** What this session's verdicts recorded, newest first. */
|
|
150
180
|
export function recordedGaps(sessionId) {
|
|
151
181
|
return bySession.get(sessionId) ?? [];
|
|
@@ -162,6 +192,8 @@ export function forgetAllRecordedGaps() {
|
|
|
162
192
|
sourceSeen.clear();
|
|
163
193
|
testidSeen.clear();
|
|
164
194
|
sourceNotApplicable.clear();
|
|
195
|
+
canvasSeen.clear();
|
|
196
|
+
comparedSeen.clear();
|
|
165
197
|
}
|
|
166
198
|
/**
|
|
167
199
|
* The tab's HELLO channels, plus the `source` marker when an act or verdict mapped a control to
|
|
@@ -204,9 +236,9 @@ export function notApplicableOf(tab) {
|
|
|
204
236
|
: [];
|
|
205
237
|
}
|
|
206
238
|
/**
|
|
207
|
-
* This tab's coverage and its
|
|
208
|
-
*
|
|
209
|
-
*
|
|
239
|
+
* This tab's coverage and its setup score (see core's `instrumentation-coverage.ts`), with the
|
|
240
|
+
* coding-agent prompt when its verdicts recorded any gap. The score is information: it never gates
|
|
241
|
+
* the Harness.
|
|
210
242
|
*/
|
|
211
243
|
export function instrumentationOf(tab,
|
|
212
244
|
/** The app's other tabs: what any of them has seen or recorded counts, as on the platform. */
|
|
@@ -220,21 +252,10 @@ siblings = []) {
|
|
|
220
252
|
const url = tab.url ?? '';
|
|
221
253
|
const appName = appNameOf(url);
|
|
222
254
|
const notApplicable = notApplicableOf(tab);
|
|
223
|
-
const
|
|
224
|
-
const harnessGate = {
|
|
225
|
-
percent: gate.percent,
|
|
226
|
-
unlocked: gate.unlocked,
|
|
227
|
-
...(gate.reason === undefined ? {} : { reason: gate.reason }),
|
|
228
|
-
};
|
|
229
|
-
if (!gate.unlocked)
|
|
230
|
-
return {
|
|
231
|
-
...coverage,
|
|
232
|
-
harnessGate,
|
|
233
|
-
prompt: harnessUnlockPrompt({ coverage, gaps, appName, url, notApplicable }),
|
|
234
|
-
};
|
|
255
|
+
const setupScore = coveragePercent(coverage, notApplicable);
|
|
235
256
|
return 0 === gaps.length
|
|
236
|
-
? { ...coverage,
|
|
237
|
-
: { ...coverage,
|
|
257
|
+
? { ...coverage, setupScore }
|
|
258
|
+
: { ...coverage, setupScore, prompt: agentPromptFor({ gaps, appName, url }) };
|
|
238
259
|
}
|
|
239
260
|
/**
|
|
240
261
|
* The impact snapshot a tab is pushed, carrying that tab's own coverage, running drive and agent
|
|
@@ -8,13 +8,24 @@
|
|
|
8
8
|
* which `memory/project` has no business knowing. The resolver takes the answer as an injected
|
|
9
9
|
* function; the composition roots pass this one.
|
|
10
10
|
*/
|
|
11
|
-
import { type DevServerEntry } from '@reticlehq/core';
|
|
11
|
+
import { type Checkout, type DevServerEntry } from '@reticlehq/core';
|
|
12
|
+
import { type CheckoutSource } from './session-manager.js';
|
|
12
13
|
/** Where `servingDirectoryOf` gets its two observations. Injected so a test needs no processes. */
|
|
13
14
|
export interface ServingDirectoryIo {
|
|
14
15
|
/** Live dev servers that announced themselves (the Vite plugin writes `devserver-<port>.json`). */
|
|
15
16
|
devServers: () => readonly DevServerEntry[];
|
|
16
17
|
/** The working directory of whatever listens on `port`, or null when it cannot be read. */
|
|
17
18
|
listenerCwd: (port: number) => string | null;
|
|
19
|
+
/** A running dev proxy that serves names under `.localhost`, or undefined when there is none. */
|
|
20
|
+
devProxy?: () => DevProxy | undefined;
|
|
21
|
+
}
|
|
22
|
+
/** A dev proxy: the ports it listens on, and the dev server port behind each name it serves. */
|
|
23
|
+
export interface DevProxy {
|
|
24
|
+
ports: readonly number[];
|
|
25
|
+
routes: readonly {
|
|
26
|
+
hostname: string;
|
|
27
|
+
port: number;
|
|
28
|
+
}[];
|
|
18
29
|
}
|
|
19
30
|
/**
|
|
20
31
|
* The directory of the dev server that served `origin`, or undefined when it cannot be observed.
|
|
@@ -22,6 +33,17 @@ export interface ServingDirectoryIo {
|
|
|
22
33
|
* Two observations, exact one first. A dev server whose plugin announced this port names its own
|
|
23
34
|
* root and works on every platform. Otherwise the process listening on the port is asked for its
|
|
24
35
|
* working directory, which covers frameworks with no announcing plugin (Next.js) wherever `lsof`
|
|
25
|
-
* runs.
|
|
36
|
+
* runs. Behind a dev proxy, the proxy's route table first names the dev server's own port. Loopback
|
|
37
|
+
* only: a remote page's port says nothing about any process on this machine.
|
|
26
38
|
*/
|
|
27
39
|
export declare function servingDirectoryOf(origin: string, io?: ServingDirectoryIo): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* The live answers for a worktree-scoped resolve: the calling agent's checkout (from the directory
|
|
42
|
+
* its MCP proxy runs in) and each tab's checkout (from the dev server that served it).
|
|
43
|
+
*
|
|
44
|
+
* A tab is placed once for each connection. A page that a different dev server serves has reloaded,
|
|
45
|
+
* and a reload is a new connection. A cache by origin and time named a port that moved to another
|
|
46
|
+
* worktree after the old one for its whole lifetime.
|
|
47
|
+
* ponytail: a lookup that failed stays failed for that connection; the tab then counts as unknown.
|
|
48
|
+
*/
|
|
49
|
+
export declare function liveCheckoutSource(placeOrigin?: (origin: string) => Checkout | undefined): CheckoutSource;
|