@reticlehq/server 3.5.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/SKILL.md +123 -116
- package/dist/chromium-launch-options.d.ts +3 -1
- package/dist/chromium-launch-options.js +2 -1
- package/dist/command/cli/adhoc-suite.d.ts +14 -0
- package/dist/command/cli/adhoc-suite.js +42 -7
- package/dist/command/cli/adhoc-verdict.d.ts +19 -2
- package/dist/command/cli/adhoc-verdict.js +76 -9
- package/dist/command/cli/answers/gate-exit.d.ts +23 -0
- package/dist/command/cli/answers/gate-exit.js +45 -0
- package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
- package/dist/command/cli/answers/gate-hook-message.js +3 -1
- package/dist/command/cli/answers/open-note.d.ts +2 -0
- package/dist/command/cli/answers/open-note.js +22 -0
- package/dist/command/cli/auth/device-flow.d.ts +13 -2
- package/dist/command/cli/auth/device-flow.js +17 -0
- package/dist/command/cli/cli-doctor.js +14 -0
- package/dist/command/cli/cli-flow-commands.d.ts +0 -11
- package/dist/command/cli/cli-flow-commands.js +31 -112
- package/dist/command/cli/cli-kill.js +3 -2
- package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
- package/dist/command/cli/cli-parse-grammar.js +75 -0
- package/dist/command/cli/cli-parse-verify.d.ts +2 -0
- package/dist/command/cli/cli-parse-verify.js +18 -0
- package/dist/command/cli/cli-parse.d.ts +19 -28
- package/dist/command/cli/cli-parse.js +82 -182
- package/dist/command/cli/cli-update-commands.d.ts +1 -1
- package/dist/command/cli/cli-update-commands.js +61 -9
- package/dist/command/cli/cli-usage.d.ts +33 -0
- package/dist/command/cli/cli-usage.js +287 -0
- package/dist/command/cli/cli-verify.d.ts +35 -5
- package/dist/command/cli/cli-verify.js +114 -35
- package/dist/command/cli/cloud-cli.d.ts +13 -0
- package/dist/command/cli/cloud-cli.js +192 -341
- package/dist/command/cli/cloud-kit.d.ts +12 -0
- package/dist/command/cli/cloud-kit.js +41 -2
- package/dist/command/cli/cloud-link.d.ts +57 -0
- package/dist/command/cli/cloud-link.js +308 -0
- package/dist/command/cli/cloud-login.d.ts +22 -0
- package/dist/command/cli/cloud-login.js +96 -8
- package/dist/command/cli/context-command.d.ts +1 -0
- package/dist/command/cli/context-command.js +33 -0
- package/dist/command/cli/daemon-start-options.d.ts +3 -0
- package/dist/command/cli/daemon-start-options.js +24 -3
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +46 -0
- package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
- package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
- package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
- package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
- package/dist/command/cli/doctor/doctor-project-line.js +5 -4
- package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
- package/dist/command/cli/doctor/doctor-rows.js +6 -0
- package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
- package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
- package/dist/command/cli/drive/drive-attach.d.ts +27 -2
- package/dist/command/cli/drive/drive-attach.js +71 -4
- package/dist/command/cli/drive/drive-command.d.ts +2 -1
- package/dist/command/cli/drive/drive-command.js +13 -7
- package/dist/command/cli/known-regression.d.ts +13 -0
- package/dist/command/cli/known-regression.js +34 -0
- package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
- package/dist/command/cli/launch/sdk-version-match.js +25 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +15 -3
- package/dist/command/cli/mcp-command.d.ts +6 -0
- package/dist/command/cli/mcp-command.js +13 -5
- package/dist/command/cli/ports/port-holder.d.ts +10 -0
- package/dist/command/cli/ports/port-holder.js +25 -1
- package/dist/command/cli/project-name.d.ts +29 -1
- package/dist/command/cli/project-name.js +107 -2
- package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
- package/dist/command/cli/setup-mcp-cli.js +35 -12
- package/dist/command/cli/status/status-lines.d.ts +1 -0
- package/dist/command/cli/status/status-lines.js +47 -2
- package/dist/command/cli/status/workspace-links.d.ts +10 -0
- package/dist/command/cli/status/workspace-links.js +29 -0
- package/dist/command/cli/try-command.d.ts +96 -0
- package/dist/command/cli/try-command.js +362 -0
- package/dist/command/cli/tutorial.d.ts +0 -100
- package/dist/command/cli/tutorial.js +0 -181
- package/dist/command/cli/verify-results.d.ts +19 -0
- package/dist/command/cli/verify-results.js +29 -0
- package/dist/command/cli-onboarding.d.ts +0 -11
- package/dist/command/cli-onboarding.js +0 -15
- package/dist/command/cli.d.ts +20 -0
- package/dist/command/cli.js +130 -104
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
- package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
- package/dist/command/daemon/daemon-resilience.js +4 -4
- package/dist/command/daemon/daemon-resolve.d.ts +23 -1
- package/dist/command/daemon/daemon-resolve.js +79 -9
- package/dist/command/setup/agent-writer.d.ts +1 -1
- package/dist/command/setup/agent-writer.js +3 -2
- package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
- package/dist/command/setup/bringup/bridge-port.js +13 -3
- package/dist/command/setup/bringup/connect-lease.d.ts +1 -0
- package/dist/command/setup/bringup/connect-lease.js +1 -0
- package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
- package/dist/command/setup/bringup/dev-server-wait.d.ts +8 -0
- package/dist/command/setup/bringup/dev-server-wait.js +19 -0
- package/dist/command/setup/bringup/ensure-daemon.js +9 -2
- package/dist/command/setup/init/agent-restart.d.ts +23 -0
- package/dist/command/setup/init/agent-restart.js +28 -0
- package/dist/command/setup/init/init-port.d.ts +14 -1
- package/dist/command/setup/init/init-port.js +32 -2
- package/dist/command/setup/init/init-runtime.d.ts +22 -2
- package/dist/command/setup/init/init-runtime.js +114 -38
- package/dist/command/setup/node-effects.d.ts +2 -0
- package/dist/command/setup/node-effects.js +38 -9
- package/dist/command/setup/probe/existing-app.d.ts +12 -0
- package/dist/command/setup/probe/existing-app.js +14 -0
- package/dist/command/setup/remaining-steps.js +2 -1
- package/dist/command/setup/run-setup.d.ts +34 -9
- package/dist/command/setup/run-setup.js +65 -51
- package/dist/command/setup/setup-command.d.ts +25 -1
- package/dist/command/setup/setup-command.js +59 -4
- package/dist/command/setup/setup-mcp.js +25 -2
- package/dist/command/setup/tauri-signing.d.ts +19 -0
- package/dist/command/setup/tauri-signing.js +79 -0
- package/dist/command/setup/terminal/listeners.d.ts +10 -1
- package/dist/command/setup/terminal/listeners.js +37 -6
- package/dist/command/update/update-nudge.d.ts +9 -0
- package/dist/command/update/update-nudge.js +1 -1
- package/dist/command/update/updater.js +11 -15
- package/dist/command/version/version-nudge.js +3 -0
- package/dist/command/version/version-skew.d.ts +20 -1
- package/dist/command/version/version-skew.js +49 -4
- package/dist/features/crawl/crawl-tools.js +4 -0
- package/dist/features/crawl/crawl.d.ts +6 -0
- package/dist/features/crawl/crawl.js +23 -2
- package/dist/features/exhaust/ledger.d.ts +21 -14
- package/dist/features/exhaust/ledger.js +35 -9
- package/dist/features/harness/app-findings.d.ts +2 -0
- package/dist/features/harness/app-findings.js +52 -0
- package/dist/features/harness/drive-report.d.ts +61 -1
- package/dist/features/harness/drive-report.js +394 -26
- package/dist/features/harness/drive-runs.d.ts +120 -0
- package/dist/features/harness/drive-runs.js +289 -0
- package/dist/features/harness/drivers.d.ts +10 -14
- package/dist/features/harness/drivers.js +10 -14
- package/dist/features/harness/explore/console-pages.d.ts +15 -0
- package/dist/features/harness/explore/console-pages.js +146 -0
- package/dist/features/harness/explore/disparity.d.ts +19 -0
- package/dist/features/harness/explore/disparity.js +71 -0
- package/dist/features/harness/explore/fake-app.d.ts +16 -0
- package/dist/features/harness/explore/fake-app.js +49 -0
- package/dist/features/harness/explore/goal-search.d.ts +26 -0
- package/dist/features/harness/explore/goal-search.js +144 -0
- package/dist/features/harness/explore/page-tree.d.ts +49 -0
- package/dist/features/harness/explore/page-tree.js +148 -0
- package/dist/features/harness/explore/site-map.d.ts +34 -0
- package/dist/features/harness/explore/site-map.js +150 -0
- package/dist/features/harness/fill-values.d.ts +3 -73
- package/dist/features/harness/fill-values.js +3 -169
- package/dist/features/harness/goals.d.ts +82 -0
- package/dist/features/harness/goals.js +330 -0
- package/dist/features/harness/harness.d.ts +51 -1
- package/dist/features/harness/harness.js +207 -6
- package/dist/features/harness/platform/drive-target.d.ts +30 -0
- package/dist/features/harness/platform/drive-target.js +81 -0
- package/dist/features/harness/platform/local-apps.d.ts +127 -0
- package/dist/features/harness/platform/local-apps.js +280 -0
- package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
- package/dist/features/harness/platform/persona-credentials.js +69 -0
- package/dist/features/harness/platform/platform-drives.d.ts +61 -0
- package/dist/features/harness/platform/platform-drives.js +114 -0
- package/dist/features/harness/platform/refusal.d.ts +52 -0
- package/dist/features/harness/platform/refusal.js +71 -0
- package/dist/features/harness/platform/remote-drive.d.ts +186 -0
- package/dist/features/harness/platform/remote-drive.js +378 -0
- package/dist/features/harness/platform/script.d.ts +94 -0
- package/dist/features/harness/platform/script.js +260 -0
- package/dist/features/harness/platform/server-driver.d.ts +54 -0
- package/dist/features/harness/platform/server-driver.js +182 -0
- package/dist/features/harness/platform-config.d.ts +41 -1
- package/dist/features/harness/platform-config.js +106 -9
- package/dist/features/harness/route-guess.d.ts +13 -0
- package/dist/features/harness/route-guess.js +49 -0
- package/dist/features/harness/script/app-controls.d.ts +5 -0
- package/dist/features/harness/script/app-controls.js +40 -0
- package/dist/features/harness/script/lane-ids.d.ts +14 -0
- package/dist/features/harness/script/lane-ids.js +16 -0
- package/dist/features/harness/script/script-run.d.ts +70 -0
- package/dist/features/harness/script/script-run.js +606 -0
- package/dist/features/license/license.d.ts +2 -2
- package/dist/features/visual/step-shots.d.ts +31 -0
- package/dist/features/visual/step-shots.js +231 -0
- package/dist/features/visual/visual-tools.d.ts +10 -1
- package/dist/features/visual/visual-tools.js +62 -17
- package/dist/hooks/client-directory.d.ts +18 -0
- package/dist/hooks/client-directory.js +57 -0
- package/dist/hooks/coding-agents.d.ts +34 -0
- package/dist/hooks/coding-agents.js +117 -0
- package/dist/hooks/driven-by.d.ts +23 -0
- package/dist/hooks/driven-by.js +56 -0
- package/dist/hooks/hook-bus.d.ts +4 -0
- package/dist/hooks/hook-bus.js +18 -0
- package/dist/hooks/hook-commands.js +15 -4
- package/dist/hooks/tool-log.d.ts +9 -0
- package/dist/hooks/tool-log.js +29 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +80 -243
- package/dist/judgement/capsule/capsule-store.d.ts +2 -2
- package/dist/judgement/capsule/causal-summary.d.ts +15 -1
- package/dist/judgement/capsule/causal-summary.js +33 -0
- package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
- package/dist/judgement/runs/artifact/build-verification-run.js +25 -3
- package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
- package/dist/judgement/runs/artifact/gap-summary.js +12 -3
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +37 -11
- package/dist/judgement/runs/artifact/run-store.d.ts +14 -2
- package/dist/judgement/runs/artifact/run-store.js +195 -3
- package/dist/judgement/runs/context-tools.js +59 -1
- package/dist/judgement/runs/default-run-id.d.ts +3 -0
- package/dist/judgement/runs/default-run-id.js +16 -0
- package/dist/judgement/runs/drive-run.d.ts +71 -1
- package/dist/judgement/runs/drive-run.js +317 -5
- package/dist/judgement/runs/repair-prompt.js +1 -1
- package/dist/judgement/runs/resume.d.ts +44 -0
- package/dist/judgement/runs/resume.js +137 -0
- package/dist/judgement/runs/reticle-runner.js +13 -3
- package/dist/judgement/runs/runner-port.d.ts +5 -1
- package/dist/judgement/runs/runner-port.js +8 -2
- package/dist/judgement/runs/verification-sync.d.ts +5 -2
- package/dist/judgement/runs/verification-sync.js +40 -18
- package/dist/language/flows/change/gate.d.ts +10 -0
- package/dist/language/flows/change/gate.js +22 -0
- package/dist/language/flows/decision.js +36 -1
- package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
- package/dist/language/flows/fields/flow-secret-field.js +25 -2
- package/dist/language/flows/flow-anchor.d.ts +61 -10
- package/dist/language/flows/flow-anchor.js +98 -6
- package/dist/language/flows/flow-cross-step.d.ts +15 -0
- package/dist/language/flows/flow-cross-step.js +21 -0
- package/dist/language/flows/flow-intent.d.ts +1 -0
- package/dist/language/flows/flow-journey.d.ts +6 -0
- package/dist/language/flows/flow-journey.js +20 -0
- package/dist/language/flows/flow-learning.d.ts +4 -0
- package/dist/language/flows/flow-learning.js +45 -14
- package/dist/language/flows/flow-mutate-tools.js +5 -3
- package/dist/language/flows/flow-replay-run.d.ts +23 -9
- package/dist/language/flows/flow-replay-run.js +115 -110
- package/dist/language/flows/flow-replay-types.d.ts +1 -1
- package/dist/language/flows/flow-replay.d.ts +40 -1
- package/dist/language/flows/flow-replay.js +110 -22
- package/dist/language/flows/flow-result.d.ts +22 -1
- package/dist/language/flows/flow-result.js +47 -2
- package/dist/language/flows/flow-scope.js +5 -1
- package/dist/language/flows/flow-step-runners.d.ts +22 -2
- package/dist/language/flows/flow-step-runners.js +247 -47
- package/dist/language/flows/flow-store-for-session.d.ts +2 -2
- package/dist/language/flows/flow-store-for-session.js +7 -3
- package/dist/language/flows/flow-tools.d.ts +10 -0
- package/dist/language/flows/flow-tools.js +112 -89
- package/dist/language/flows/flows.d.ts +16 -1
- package/dist/language/flows/flows.js +74 -12
- package/dist/language/flows/heal-run.js +6 -4
- package/dist/language/flows/narrow-write.d.ts +7 -0
- package/dist/language/flows/narrow-write.js +36 -1
- package/dist/language/flows/recording/flake.d.ts +2 -2
- package/dist/language/flows/recording/recording-backtrack.js +14 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +58 -4
- package/dist/language/flows/recording/tape/recordings.js +95 -13
- package/dist/language/flows/replay-from-hud.d.ts +20 -0
- package/dist/language/flows/replay-from-hud.js +51 -0
- package/dist/language/flows/replay.d.ts +9 -5
- package/dist/language/flows/replay.js +56 -15
- package/dist/language/flows/single-replay.d.ts +7 -0
- package/dist/language/flows/single-replay.js +26 -0
- package/dist/language/flows/suite/suite-flakes.js +2 -0
- package/dist/language/flows/suite-selection.d.ts +2 -15
- package/dist/language/flows/suite-selection.js +4 -3
- package/dist/language/flows/verify-change-tools.d.ts +1 -0
- package/dist/language/flows/verify-change-tools.js +202 -191
- package/dist/launch-chromium.d.ts +27 -5
- package/dist/launch-chromium.js +38 -8
- package/dist/memory/cloud/cloud-config.d.ts +22 -1
- package/dist/memory/cloud/cloud-config.js +34 -5
- package/dist/memory/cloud/cloud-sync.d.ts +17 -14
- package/dist/memory/cloud/cloud-sync.js +15 -4
- package/dist/memory/cloud/harness-config.d.ts +75 -1
- package/dist/memory/cloud/harness-config.js +115 -24
- package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
- package/dist/memory/cloud/hud-notices-source.js +128 -0
- package/dist/memory/cloud/memory-scope.d.ts +161 -0
- package/dist/memory/cloud/memory-scope.js +227 -0
- package/dist/memory/cloud/sync-cycle.d.ts +44 -7
- package/dist/memory/cloud/sync-cycle.js +129 -15
- package/dist/memory/cloud/sync-daemon.d.ts +11 -0
- package/dist/memory/cloud/sync-daemon.js +121 -9
- package/dist/memory/cloud/sync-disk.d.ts +1 -1
- package/dist/memory/cloud/sync-disk.js +31 -10
- package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
- package/dist/memory/cloud/sync-screenshots.js +105 -0
- package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
- package/dist/memory/cloud/unsynced-roots.js +166 -0
- package/dist/memory/impact/account-watch.d.ts +34 -0
- package/dist/memory/impact/account-watch.js +59 -0
- package/dist/memory/impact/impact-recorder.d.ts +8 -0
- package/dist/memory/impact/impact-recorder.js +12 -2
- package/dist/memory/impact/impact-store.d.ts +17 -4
- package/dist/memory/impact/impact-store.js +169 -63
- package/dist/memory/intent/inline-intent.d.ts +1 -0
- package/dist/memory/intent/intent-shard-store.js +16 -4
- package/dist/memory/intent/intent-shard.d.ts +14 -2
- package/dist/memory/intent/intent-store.d.ts +1 -0
- package/dist/memory/intent/intent-tools.js +122 -4
- package/dist/memory/intent/open-intents.d.ts +6 -0
- package/dist/memory/intent/open-intents.js +10 -1
- package/dist/memory/intent/settled-words.d.ts +24 -0
- package/dist/memory/intent/settled-words.js +130 -0
- package/dist/memory/journal/drive-flow.d.ts +16 -0
- package/dist/memory/journal/drive-flow.js +34 -2
- package/dist/memory/journal/drive-run-flush.d.ts +2 -0
- package/dist/memory/journal/drive-run-flush.js +20 -5
- package/dist/memory/journal/envelope.d.ts +8 -8
- package/dist/memory/journal/journal-recorder.js +52 -3
- package/dist/memory/journal/on-disk/retention.d.ts +8 -0
- package/dist/memory/journal/on-disk/retention.js +32 -2
- package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
- package/dist/memory/journal/on-disk/workspace-tiers.js +9 -4
- package/dist/memory/journal/session-end.d.ts +15 -1
- package/dist/memory/journal/session-end.js +42 -9
- package/dist/memory/project/artifact-root-resolver.d.ts +26 -1
- package/dist/memory/project/artifact-root-resolver.js +125 -16
- package/dist/memory/project/artifact-root.d.ts +46 -8
- package/dist/memory/project/artifact-root.js +89 -10
- package/dist/memory/project/dir/reticle-dir.d.ts +18 -2
- package/dist/memory/project/dir/reticle-dir.js +26 -3
- package/dist/memory/project/link-directory.d.ts +15 -0
- package/dist/memory/project/link-directory.js +44 -0
- package/dist/memory/project/project-tools.js +22 -3
- package/dist/memory/project/root-claims.d.ts +6 -0
- package/dist/memory/project/root-claims.js +39 -0
- package/dist/memory/project/session-root.d.ts +26 -1
- package/dist/memory/project/session-root.js +49 -5
- package/dist/memory/project/sync-status.d.ts +85 -0
- package/dist/memory/project/sync-status.js +224 -0
- package/dist/memory/recall/memory-tools.js +47 -2
- package/dist/memory/recall/platform-memory.d.ts +34 -0
- package/dist/memory/recall/platform-memory.js +139 -0
- package/dist/memory/recall/project-memory.d.ts +19 -0
- package/dist/memory/recall/project-memory.js +80 -13
- package/dist/portal/bridge/bridge.d.ts +9 -3
- package/dist/portal/bridge/bridge.js +82 -22
- package/dist/portal/bridge/harness-request.d.ts +23 -0
- package/dist/portal/bridge/harness-request.js +27 -0
- package/dist/portal/bridge/pairing-token.d.ts +9 -0
- package/dist/portal/bridge/pairing-token.js +17 -0
- package/dist/portal/bridge/wrong-path.d.ts +17 -0
- package/dist/portal/bridge/wrong-path.js +35 -0
- package/dist/portal/input/network-mock-tools.js +11 -2
- package/dist/portal/input/real-input.d.ts +83 -10
- package/dist/portal/input/real-input.js +218 -30
- package/dist/portal/input/viewport-tools.js +3 -3
- package/dist/portal/pool/browser-pool.d.ts +70 -9
- package/dist/portal/pool/browser-pool.js +190 -37
- package/dist/portal/pool/context-permissions.d.ts +33 -0
- package/dist/portal/pool/context-permissions.js +33 -0
- package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
- package/dist/portal/pool/lease-marker-stamp.js +49 -0
- package/dist/portal/pool/playwright-launcher.d.ts +35 -0
- package/dist/portal/pool/playwright-launcher.js +64 -3
- package/dist/portal/pool/pool-contract.d.ts +28 -5
- package/dist/portal/session/agent-link.d.ts +8 -0
- package/dist/portal/session/agent-link.js +17 -0
- package/dist/portal/session/command-payload.d.ts +8 -0
- package/dist/portal/session/command-payload.js +24 -0
- package/dist/portal/session/daemon-answers.d.ts +3 -3
- package/dist/portal/session/daemon-answers.js +4 -2
- package/dist/portal/session/dev-server/dev-command.d.ts +21 -0
- package/dist/portal/session/dev-server/dev-command.js +87 -12
- package/dist/portal/session/facts/departure-note.d.ts +22 -0
- package/dist/portal/session/facts/departure-note.js +47 -0
- package/dist/portal/session/facts/observed-state.d.ts +16 -18
- package/dist/portal/session/facts/observed-state.js +46 -3
- package/dist/portal/session/facts/session-replaced.d.ts +5 -0
- package/dist/portal/session/facts/session-replaced.js +5 -0
- package/dist/portal/session/first-run-wiring.d.ts +42 -0
- package/dist/portal/session/first-run-wiring.js +132 -0
- package/dist/portal/session/human/live-control.d.ts +9 -2
- package/dist/portal/session/human/live-control.js +12 -3
- package/dist/portal/session/human/notes-ledger.d.ts +20 -0
- package/dist/portal/session/human/notes-ledger.js +55 -0
- package/dist/portal/session/human/review-store.d.ts +12 -0
- package/dist/portal/session/human/review-store.js +18 -10
- package/dist/portal/session/live-control-tools.d.ts +0 -13
- package/dist/portal/session/live-control-tools.js +107 -13
- package/dist/portal/session/narration-args.d.ts +5 -0
- package/dist/portal/session/narration-args.js +17 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +8 -1
- package/dist/portal/session/no-session-diagnosis.js +46 -9
- package/dist/portal/session/no-session-next-action.d.ts +31 -0
- package/dist/portal/session/no-session-next-action.js +159 -60
- package/dist/portal/session/no-session-watch.d.ts +14 -1
- package/dist/portal/session/no-session-watch.js +227 -17
- package/dist/portal/session/presence/session-lease.js +1 -1
- package/dist/portal/session/presence/session-mirror.js +3 -0
- package/dist/portal/session/recorded-gaps.d.ts +97 -0
- package/dist/portal/session/recorded-gaps.js +251 -0
- package/dist/portal/session/serving-directory.d.ts +27 -0
- package/dist/portal/session/serving-directory.js +45 -0
- package/dist/portal/session/session-health.d.ts +18 -0
- package/dist/portal/session/session-health.js +9 -1
- package/dist/portal/session/session-info.d.ts +8 -1
- package/dist/portal/session/session-info.js +8 -1
- package/dist/portal/session/session-manager.d.ts +39 -0
- package/dist/portal/session/session-manager.js +98 -11
- package/dist/portal/session/session-reaper.js +4 -1
- package/dist/portal/session/session-successor.d.ts +13 -0
- package/dist/portal/session/session-successor.js +1 -1
- package/dist/portal/session/session-tools.js +26 -3
- package/dist/portal/session/session.d.ts +22 -30
- package/dist/portal/session/session.js +81 -79
- package/dist/portal/session/timing/command-timeout.js +25 -1
- package/dist/portal/session/timing/wall-clock.d.ts +1 -1
- package/dist/portal/session/timing/wall-clock.js +1 -1
- package/dist/portal/session/zero-install-first-call.d.ts +31 -0
- package/dist/portal/session/zero-install-first-call.js +88 -0
- package/dist/start-options.d.ts +12 -0
- package/dist/start-wiring.d.ts +63 -0
- package/dist/start-wiring.js +169 -0
- package/dist/status-payload.d.ts +23 -1
- package/dist/status-payload.js +36 -1
- package/dist/surface/http-server.js +18 -2
- package/dist/surface/mcp/attach-memory.d.ts +1 -0
- package/dist/surface/mcp/attach-memory.js +12 -1
- package/dist/surface/mcp/mcp-proxy.d.ts +9 -0
- package/dist/surface/mcp/mcp-proxy.js +65 -13
- package/dist/surface/mcp/mcp.d.ts +34 -6
- package/dist/surface/mcp/mcp.js +61 -17
- package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
- package/dist/surface/mcp/proxy/drive-calls.js +27 -0
- package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
- package/dist/surface/mcp/server-instructions.d.ts +4 -2
- package/dist/surface/mcp/server-instructions.js +32 -14
- package/dist/surface/mcp/shared-params.js +2 -2
- package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
- package/dist/surface/mcp/surface-vocabulary.js +1 -0
- package/dist/surface/tools/account-tool.d.ts +22 -0
- package/dist/surface/tools/account-tool.js +157 -0
- package/dist/surface/tools/act/act-danger.d.ts +11 -0
- package/dist/surface/tools/act/act-danger.js +38 -1
- package/dist/surface/tools/act/act-observation.d.ts +33 -0
- package/dist/surface/tools/act/act-observation.js +57 -0
- package/dist/surface/tools/act/act-preflight.js +25 -2
- package/dist/surface/tools/act/act-target.js +8 -3
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +8 -0
- package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
- package/dist/surface/tools/act/resolve-target.d.ts +1 -1
- package/dist/surface/tools/act/resolve-target.js +18 -3
- package/dist/surface/tools/act/screen-request.d.ts +34 -0
- package/dist/surface/tools/act/screen-request.js +113 -0
- package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
- package/dist/surface/tools/act/sequence-grade.js +13 -2
- package/dist/surface/tools/act/settle-in-flight.js +25 -3
- package/dist/surface/tools/act-sequence-tool.js +138 -29
- package/dist/surface/tools/act-tools.d.ts +0 -9
- package/dist/surface/tools/act-tools.js +71 -41
- package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
- package/dist/surface/tools/agent/app-notes-learning.js +80 -0
- package/dist/surface/tools/agent/app-notes.d.ts +4 -0
- package/dist/surface/tools/agent/app-notes.js +48 -0
- package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
- package/dist/surface/tools/agent/build-staleness.js +62 -0
- package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
- package/dist/surface/tools/agent/compact-envelope.js +374 -0
- package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
- package/dist/surface/tools/agent/for-the-agent.js +44 -0
- package/dist/surface/tools/agent/notices.d.ts +50 -0
- package/dist/surface/tools/agent/notices.js +152 -0
- package/dist/surface/tools/agent/reteach.d.ts +11 -0
- package/dist/surface/tools/agent/reteach.js +50 -0
- package/dist/surface/tools/args/alias-args.d.ts +5 -0
- package/dist/surface/tools/args/alias-args.js +10 -0
- package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
- package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
- package/dist/surface/tools/assert/assert-source.d.ts +15 -0
- package/dist/surface/tools/assert/assert-source.js +40 -0
- package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +42 -17
- package/dist/surface/tools/browser-tools.js +51 -2
- package/dist/surface/tools/chat-drives.d.ts +101 -0
- package/dist/surface/tools/chat-drives.js +409 -0
- package/dist/surface/tools/coverage-tools.d.ts +2 -10
- package/dist/surface/tools/coverage-tools.js +2 -53
- package/dist/surface/tools/dynamic-tools.js +29 -1
- package/dist/surface/tools/empty-session-list.d.ts +51 -0
- package/dist/surface/tools/empty-session-list.js +120 -0
- package/dist/surface/tools/error-recovery.d.ts +14 -0
- package/dist/surface/tools/error-recovery.js +105 -8
- package/dist/surface/tools/explore-tools.d.ts +31 -1
- package/dist/surface/tools/explore-tools.js +438 -66
- package/dist/surface/tools/feedback-tools.d.ts +2 -3
- package/dist/surface/tools/feedback-tools.js +18 -3
- package/dist/surface/tools/gap-novelty.d.ts +3 -1
- package/dist/surface/tools/gap-novelty.js +8 -1
- package/dist/surface/tools/harness-explore.d.ts +118 -57
- package/dist/surface/tools/harness-explore.js +344 -292
- package/dist/surface/tools/harness-gate.d.ts +88 -0
- package/dist/surface/tools/harness-gate.js +235 -0
- package/dist/surface/tools/harness-hunt.d.ts +43 -0
- package/dist/surface/tools/harness-hunt.js +215 -0
- package/dist/surface/tools/harness-plan.d.ts +17 -0
- package/dist/surface/tools/harness-plan.js +38 -0
- package/dist/surface/tools/harness-script.d.ts +30 -0
- package/dist/surface/tools/harness-script.js +560 -0
- package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
- package/dist/surface/tools/harness-tab-guard.js +27 -0
- package/dist/surface/tools/harness-toolset.d.ts +22 -1
- package/dist/surface/tools/harness-toolset.js +101 -7
- package/dist/surface/tools/human-notes.d.ts +16 -0
- package/dist/surface/tools/human-notes.js +27 -0
- package/dist/surface/tools/invoke-tool.d.ts +5 -2
- package/dist/surface/tools/invoke-tool.js +263 -85
- package/dist/surface/tools/lease-hint.js +26 -5
- package/dist/surface/tools/lease-permissions.d.ts +33 -0
- package/dist/surface/tools/lease-permissions.js +73 -0
- package/dist/surface/tools/lease-readiness.d.ts +38 -0
- package/dist/surface/tools/lease-readiness.js +57 -0
- package/dist/surface/tools/lease-seed.d.ts +49 -0
- package/dist/surface/tools/lease-seed.js +167 -0
- package/dist/surface/tools/lease-tools.d.ts +13 -24
- package/dist/surface/tools/lease-tools.js +146 -197
- package/dist/surface/tools/live-call-text.js +4 -4
- package/dist/surface/tools/merge-tools.js +42 -2
- package/dist/surface/tools/merged-name-redirect.js +4 -0
- package/dist/surface/tools/next-step.d.ts +29 -0
- package/dist/surface/tools/next-step.js +214 -0
- package/dist/surface/tools/observe-tools.js +45 -9
- package/dist/surface/tools/platform-moment.d.ts +72 -0
- package/dist/surface/tools/platform-moment.js +296 -0
- package/dist/surface/tools/query-hint-schema.d.ts +7 -0
- package/dist/surface/tools/query-hint-schema.js +10 -0
- package/dist/surface/tools/read-tools.js +71 -14
- package/dist/surface/tools/real-input-attempt.js +96 -13
- package/dist/surface/tools/reticle-result.d.ts +120 -0
- package/dist/surface/tools/reticle-result.js +364 -0
- package/dist/surface/tools/tool-kit.d.ts +83 -3
- package/dist/surface/tools/tool-kit.js +77 -7
- package/dist/surface/tools/tools.js +43 -59
- package/dist/telemetry/account-envelope.d.ts +7 -0
- package/dist/telemetry/account-envelope.js +61 -0
- package/dist/telemetry/agent-client.d.ts +15 -0
- package/dist/telemetry/agent-client.js +57 -0
- package/dist/telemetry/app-instrumented.js +9 -2
- package/dist/telemetry/argument-shape.d.ts +7 -0
- package/dist/telemetry/argument-shape.js +86 -1
- package/dist/telemetry/automation-hint.d.ts +2 -3
- package/dist/telemetry/automation-hint.js +33 -8
- package/dist/telemetry/cli-telemetry.js +7 -2
- package/dist/telemetry/daemon-telemetry.js +3 -0
- package/dist/telemetry/error-fingerprint.d.ts +10 -1
- package/dist/telemetry/error-fingerprint.js +61 -5
- package/dist/telemetry/feedback-cli.d.ts +0 -13
- package/dist/telemetry/feedback-cli.js +0 -77
- package/dist/telemetry/feedback.d.ts +13 -0
- package/dist/telemetry/feedback.js +183 -17
- package/dist/telemetry/harness-run.d.ts +18 -0
- package/dist/telemetry/harness-run.js +80 -0
- package/dist/telemetry/hud-events.d.ts +16 -0
- package/dist/telemetry/hud-events.js +27 -0
- package/dist/telemetry/hud-metrics.d.ts +29 -6
- package/dist/telemetry/hud-metrics.js +116 -25
- package/dist/telemetry/init-telemetry.js +2 -2
- package/dist/telemetry/install-source.d.ts +13 -25
- package/dist/telemetry/install-source.js +44 -3
- package/dist/telemetry/mcp-connection.d.ts +0 -14
- package/dist/telemetry/mcp-connection.js +5 -1
- package/dist/telemetry/onboarding-firsts.d.ts +32 -0
- package/dist/telemetry/onboarding-firsts.js +81 -6
- package/dist/telemetry/platform-linked.d.ts +5 -0
- package/dist/telemetry/platform-linked.js +32 -0
- package/dist/telemetry/project-profile.js +5 -3
- package/dist/telemetry/proxy-telemetry.js +4 -1
- package/dist/telemetry/session-metrics.d.ts +15 -4
- package/dist/telemetry/session-metrics.js +88 -52
- package/dist/telemetry/telemetry.d.ts +38 -2
- package/dist/telemetry/telemetry.js +144 -34
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +13 -4
- package/dist/wire-journal.d.ts +2 -2
- package/dist/wire-journal.js +20 -6
- package/docs/README.md +3 -3
- package/docs/actions.mdx +6 -3
- package/docs/adapters.md +1 -1
- package/docs/agent-cheatsheet.md +25 -28
- package/docs/architecture.md +5 -5
- package/docs/autodrive.md +33 -28
- package/docs/benchmarks.md +5 -5
- package/docs/best-practices.mdx +27 -9
- package/docs/capabilities.mdx +14 -16
- package/docs/cli/affected.mdx +1 -1
- package/docs/cli/cloud.mdx +54 -75
- package/docs/cli/doctor.mdx +14 -3
- package/docs/cli/drive.mdx +20 -14
- package/docs/cli/feedback.mdx +3 -3
- package/docs/cli/gate.mdx +7 -2
- package/docs/cli/help.mdx +50 -55
- package/docs/cli/init.mdx +43 -28
- package/docs/cli/license.mdx +12 -8
- package/docs/cli/mcp.mdx +4 -4
- package/docs/cli/open.mdx +3 -3
- package/docs/cli/report.mdx +4 -2
- package/docs/cli/restart.mdx +2 -2
- package/docs/cli/rollback.mdx +14 -8
- package/docs/cli/serve.mdx +4 -4
- package/docs/cli/setup.mdx +23 -0
- package/docs/cli/status.mdx +18 -5
- package/docs/cli/stop.mdx +67 -8
- package/docs/cli/try.mdx +62 -0
- package/docs/cli/update.mdx +4 -3
- package/docs/cli/verify.mdx +17 -6
- package/docs/cli/version.mdx +5 -4
- package/docs/cli.mdx +111 -42
- package/docs/debugging.md +3 -3
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +9 -3
- package/docs/enterprise.md +11 -10
- package/docs/environment.mdx +7 -8
- package/docs/faq.mdx +3 -3
- package/docs/first-drive.md +5 -4
- package/docs/flows.md +35 -27
- package/docs/for-agents.md +4 -5
- package/docs/frameworks.mdx +32 -21
- package/docs/getting-started.md +65 -61
- package/docs/human-control.md +16 -16
- package/docs/index.mdx +15 -42
- package/docs/install-agentic.mdx +22 -37
- package/docs/install-manual.mdx +23 -13
- package/docs/instrumentation.mdx +5 -3
- package/docs/integration-patterns.md +7 -7
- package/docs/license-activation.mdx +1 -1
- package/docs/multi-agent-testing.md +24 -6
- package/docs/packages/babel-plugin.mdx +4 -2
- package/docs/packages/browser.mdx +16 -10
- package/docs/packages/core.mdx +12 -5
- package/docs/packages/electron.mdx +3 -2
- package/docs/packages/engine.mdx +1 -1
- package/docs/packages/eslint-plugin.mdx +18 -12
- package/docs/packages/next.mdx +8 -7
- package/docs/packages/open-verification.mdx +1 -1
- package/docs/packages/server.mdx +5 -5
- package/docs/packages/tauri.mdx +9 -9
- package/docs/packages/test.mdx +4 -10
- package/docs/packages/vite-plugin.mdx +32 -4
- package/docs/packages.mdx +11 -15
- package/docs/platform-integration.md +6 -5
- package/docs/predicates.mdx +40 -24
- package/docs/quickstart.mdx +69 -30
- package/docs/required-checks.md +8 -7
- package/docs/reticle-manual.md +15 -5
- package/docs/skill-file.mdx +17 -79
- package/docs/skill-setup.md +9 -9
- package/docs/skill.md +200 -0
- package/docs/system-map.md +7 -7
- package/docs/telemetry.md +23 -25
- package/docs/testing.md +4 -4
- package/docs/token-efficiency.md +12 -12
- package/docs/tools/act-and-wait.mdx +9 -2
- package/docs/tools/act-sequence.mdx +6 -7
- package/docs/tools/act.mdx +2 -2
- package/docs/tools/assert.mdx +18 -17
- package/docs/tools/console.mdx +9 -9
- package/docs/tools/inspect.mdx +16 -7
- package/docs/tools/look.mdx +24 -0
- package/docs/tools/navigate.mdx +5 -3
- package/docs/tools/network.mdx +2 -2
- package/docs/tools/observe.mdx +6 -6
- package/docs/tools/overview.mdx +34 -33
- package/docs/tools/query.mdx +5 -5
- package/docs/tools/session-and-feedback.mdx +22 -13
- package/docs/tools/sessions.mdx +8 -8
- package/docs/tools/snapshot.mdx +6 -5
- package/docs/tools/state.mdx +9 -9
- package/docs/tools/tools-and-run.mdx +26 -24
- package/docs/tools/verify.mdx +28 -0
- package/docs/tools/wait-for.mdx +8 -4
- package/docs/troubleshooting.mdx +21 -6
- package/docs/usage.md +55 -46
- package/docs/use-cases.mdx +3 -3
- package/docs/vs-chrome-devtools-mcp.mdx +9 -6
- package/docs/vs-playwright-mcp.mdx +3 -1
- package/docs/what-is-recorded.md +17 -5
- package/docs/what-is-reticle.mdx +5 -3
- package/docs/why-reticle.mdx +1 -1
- package/package.json +9 -12
- package/dist/command/cli/demo/demo-page.d.ts +0 -78
- package/dist/command/cli/demo/demo-page.js +0 -241
- package/dist/command/cli/demo/demo-run.d.ts +0 -38
- package/dist/command/cli/demo/demo-run.js +0 -138
- package/dist/features/harness/driver.d.ts +0 -50
- package/dist/features/harness/driver.js +0 -236
- package/dist/features/harness/jev-driver.d.ts +0 -188
- package/dist/features/harness/jev-driver.js +0 -678
- package/dist/features/harness/openai-driver.d.ts +0 -58
- package/dist/features/harness/openai-driver.js +0 -206
- package/dist/judgement/hunt/hunt-report.d.ts +0 -49
- package/dist/judgement/hunt/hunt-report.js +0 -84
- package/dist/language/flows/buddy-status.d.ts +0 -25
- package/dist/language/flows/buddy-status.js +0 -32
- package/dist/language/flows/change/watch-batcher.d.ts +0 -18
- package/dist/language/flows/change/watch-batcher.js +0 -19
- package/dist/memory/cloud/harness-offer.d.ts +0 -44
- package/dist/memory/cloud/harness-offer.js +0 -145
- package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
- package/dist/memory/project/dir/fill-value-store.js +0 -88
- package/dist/surface/tools/feature-capture.d.ts +0 -151
- package/dist/surface/tools/feature-capture.js +0 -235
- package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
- package/dist/surface/tools/tool-hit-rate.js +0 -90
- package/dist/telemetry/harness-drive.d.ts +0 -4
- package/dist/telemetry/harness-drive.js +0 -35
- package/dist/telemetry/identify.d.ts +0 -22
- package/dist/telemetry/identify.js +0 -73
- package/docs/cli/capsules.mdx +0 -70
- package/docs/cli/hunt.mdx +0 -73
- package/docs/cli/identify.mdx +0 -76
- package/docs/cli/kill.mdx +0 -91
- package/docs/cli/watch.mdx +0 -62
- package/docs/local-registry.md +0 -143
|
@@ -26,6 +26,11 @@ interface SyncPolicy {
|
|
|
26
26
|
* the bug happen again, and a defect nobody else can reproduce is a defect nobody else can fix.
|
|
27
27
|
*/
|
|
28
28
|
capsules: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Push each run's step screenshots after the run. Follows `runs` when the link does not say:
|
|
31
|
+
* a project that keeps its runs local has not agreed to send pictures of its pages either.
|
|
32
|
+
*/
|
|
33
|
+
screenshots: boolean;
|
|
29
34
|
}
|
|
30
35
|
/** Where a verification actually executes. Reserved for the hosted-runner path; default local. */
|
|
31
36
|
export declare const VerifyMode: {
|
|
@@ -40,8 +45,12 @@ export interface ProjectCloud {
|
|
|
40
45
|
verify: VerifyMode;
|
|
41
46
|
/** The cloud project id this project is linked to (for display/logging); null when env-fallback. */
|
|
42
47
|
projectId: string | null;
|
|
48
|
+
/** The link as one key, cloud + workspace + project (`credentialSlot`); absent when env-fallback. */
|
|
49
|
+
link?: string;
|
|
43
50
|
/** Why `config` is null, in words a person can act on. Absent when attached. */
|
|
44
51
|
reason?: string;
|
|
52
|
+
/** Attached, but not with the key the caller exported: said, never silent. */
|
|
53
|
+
note?: string;
|
|
45
54
|
}
|
|
46
55
|
/** Look up the API key for a cloud project id in the user credentials map. */
|
|
47
56
|
/**
|
|
@@ -77,7 +86,19 @@ export declare function resolveProjectCloud(fs: FileSystemPort, reticleRoot: str
|
|
|
77
86
|
* three lines somewhere they belong. The harness reads it so a machine that has run `reticle link`
|
|
78
87
|
* needs no exported key — see `withLinkedCredential`.
|
|
79
88
|
*/
|
|
80
|
-
export declare const linkedCloudPort: (fs: FileSystemPort, reticleRoot: string, homeDir: string, env: NodeJS.ProcessEnv) => () => Promise<CloudConfig | null>;
|
|
89
|
+
export declare const linkedCloudPort: (fs: FileSystemPort, reticleRoot: string, homeDir: string, env: NodeJS.ProcessEnv) => (root?: string) => Promise<CloudConfig | null>;
|
|
90
|
+
/**
|
|
91
|
+
* The API key a tab's own project resolves to, so a credential is only ever used for its own tabs.
|
|
92
|
+
* A tab whose project cannot be resolved has no key.
|
|
93
|
+
*/
|
|
94
|
+
export declare const sessionApiKeyPort: (fs: FileSystemPort, homeDir: string, env: NodeJS.ProcessEnv, rootOf: (id: string) => string) => (sessionId: string) => Promise<string | undefined>;
|
|
95
|
+
/** The platform and key a tab's own project resolves to, or undefined when it is not linked. */
|
|
96
|
+
export declare const sessionCloudPort: (fs: FileSystemPort, homeDir: string, env: NodeJS.ProcessEnv, rootOf: (id: string) => string) => (sessionId: string) => Promise<CloudConfig | undefined>;
|
|
97
|
+
/**
|
|
98
|
+
* The credential for pushing RUNS, or null when this project opted out with `sync.runs: false`.
|
|
99
|
+
* `reticle verify` used the port above and pushed its run and progress regardless of the opt-out.
|
|
100
|
+
*/
|
|
101
|
+
export declare const linkedRunsCloudPort: (fs: FileSystemPort, reticleRoot: string, homeDir: string, env: NodeJS.ProcessEnv) => () => Promise<CloudConfig | null>;
|
|
81
102
|
/**
|
|
82
103
|
* The environment with this project's resolved credential written into it, for the readers that
|
|
83
104
|
* take an env record (the panel's model config and harness switch). Handed `process.env` alone,
|
|
@@ -17,7 +17,13 @@ import { resolveCloudConfig } from './cloud-sync.js';
|
|
|
17
17
|
export const CLOUD_LINK_FILE = ReticleDir.CLOUD_LINK_FILE;
|
|
18
18
|
/** `~/.reticle/credentials.json` — the user's per-cloud-project API keys (the only secret). */
|
|
19
19
|
export const CREDENTIALS_FILE = 'credentials.json';
|
|
20
|
-
const DEFAULT_SYNC_POLICY = {
|
|
20
|
+
const DEFAULT_SYNC_POLICY = {
|
|
21
|
+
runs: true,
|
|
22
|
+
memory: true,
|
|
23
|
+
flows: true,
|
|
24
|
+
capsules: true,
|
|
25
|
+
screenshots: true,
|
|
26
|
+
};
|
|
21
27
|
/** Where a verification actually executes. Reserved for the hosted-runner path; default local. */
|
|
22
28
|
export const VerifyMode = { LOCAL: 'local', SERVER: 'server' };
|
|
23
29
|
const asBool = (v, fallback) => ('boolean' === typeof v ? v : fallback);
|
|
@@ -51,6 +57,7 @@ function parseLink(raw) {
|
|
|
51
57
|
memory: asBool(sync.memory, DEFAULT_SYNC_POLICY.memory),
|
|
52
58
|
flows: asBool(sync.flows, DEFAULT_SYNC_POLICY.flows),
|
|
53
59
|
capsules: asBool(sync.capsules, DEFAULT_SYNC_POLICY.capsules),
|
|
60
|
+
screenshots: asBool(sync.screenshots, asBool(sync.runs, DEFAULT_SYNC_POLICY.screenshots)),
|
|
54
61
|
},
|
|
55
62
|
verify: o.verify === VerifyMode.SERVER ? VerifyMode.SERVER : VerifyMode.LOCAL,
|
|
56
63
|
};
|
|
@@ -135,7 +142,7 @@ export async function resolveProjectCloud(fs, reticleRoot, homeDir, env) {
|
|
|
135
142
|
verify: VerifyMode.LOCAL,
|
|
136
143
|
projectId: null,
|
|
137
144
|
...(null === config
|
|
138
|
-
? { reason: 'cloud not attached here: run `reticle
|
|
145
|
+
? { reason: 'cloud not attached here: run `reticle connect`, or set RETICLE_API_KEY' }
|
|
139
146
|
: {}),
|
|
140
147
|
};
|
|
141
148
|
}
|
|
@@ -144,6 +151,7 @@ export async function resolveProjectCloud(fs, reticleRoot, homeDir, env) {
|
|
|
144
151
|
memory: link.sync.memory ?? DEFAULT_SYNC_POLICY.memory,
|
|
145
152
|
flows: link.sync.flows ?? DEFAULT_SYNC_POLICY.flows,
|
|
146
153
|
capsules: link.sync.capsules ?? DEFAULT_SYNC_POLICY.capsules,
|
|
154
|
+
screenshots: link.sync.screenshots ?? DEFAULT_SYNC_POLICY.screenshots,
|
|
147
155
|
};
|
|
148
156
|
const stored = credentialFor(await readJson(fs, join(homeDir, ReticleDir.ROOT, CREDENTIALS_FILE)), link.projectId, link.url, link.orgId);
|
|
149
157
|
/*
|
|
@@ -161,16 +169,22 @@ export async function resolveProjectCloud(fs, reticleRoot, homeDir, env) {
|
|
|
161
169
|
? undefined
|
|
162
170
|
: fromEnv !== null
|
|
163
171
|
? `this repo is linked to ${linkedUrl}, and RETICLE_API_KEY is set for ${fromEnv.url}: ` +
|
|
164
|
-
`set RETICLE_CLOUD_URL=${linkedUrl} to use that key here, or run \`reticle
|
|
172
|
+
`set RETICLE_CLOUD_URL=${linkedUrl} to use that key here, or run \`reticle connect\` for it`
|
|
165
173
|
: `this repo is linked to ${linkedUrl}, and this machine has no key for it: run ` +
|
|
166
|
-
'`reticle
|
|
174
|
+
'`reticle connect`, or set RETICLE_API_KEY' +
|
|
167
175
|
(DEFAULT_PLATFORM_URL === linkedUrl ? '' : ` with RETICLE_CLOUD_URL=${linkedUrl}`);
|
|
176
|
+
const note = stored !== null && fromEnv !== null && fromEnv.apiKey !== stored
|
|
177
|
+
? `RETICLE_API_KEY is set, but this repo uses the key \`reticle connect\` stored for it: ` +
|
|
178
|
+
'a stored key wins over the environment, so the exported key was not used'
|
|
179
|
+
: undefined;
|
|
168
180
|
return {
|
|
169
181
|
config,
|
|
170
182
|
policy,
|
|
171
183
|
verify: link.verify,
|
|
172
184
|
projectId: link.projectId,
|
|
185
|
+
link: credentialSlot(link.url, link.projectId, link.orgId),
|
|
173
186
|
...(reason === undefined ? {} : { reason }),
|
|
187
|
+
...(note === undefined ? {} : { note }),
|
|
174
188
|
};
|
|
175
189
|
}
|
|
176
190
|
/**
|
|
@@ -181,7 +195,22 @@ export async function resolveProjectCloud(fs, reticleRoot, homeDir, env) {
|
|
|
181
195
|
* three lines somewhere they belong. The harness reads it so a machine that has run `reticle link`
|
|
182
196
|
* needs no exported key — see `withLinkedCredential`.
|
|
183
197
|
*/
|
|
184
|
-
export const linkedCloudPort = (fs, reticleRoot, homeDir, env) => async () => (await resolveProjectCloud(fs, reticleRoot, homeDir, env)).config;
|
|
198
|
+
export const linkedCloudPort = (fs, reticleRoot, homeDir, env) => async (root) => (await resolveProjectCloud(fs, root ?? reticleRoot, homeDir, env)).config;
|
|
199
|
+
/**
|
|
200
|
+
* The API key a tab's own project resolves to, so a credential is only ever used for its own tabs.
|
|
201
|
+
* A tab whose project cannot be resolved has no key.
|
|
202
|
+
*/
|
|
203
|
+
export const sessionApiKeyPort = (fs, homeDir, env, rootOf) => async (sessionId) => (await sessionCloudPort(fs, homeDir, env, rootOf)(sessionId))?.apiKey;
|
|
204
|
+
/** The platform and key a tab's own project resolves to, or undefined when it is not linked. */
|
|
205
|
+
export const sessionCloudPort = (fs, homeDir, env, rootOf) => async (sessionId) => (await resolveProjectCloud(fs, rootOf(sessionId), homeDir, env)).config ?? undefined;
|
|
206
|
+
/**
|
|
207
|
+
* The credential for pushing RUNS, or null when this project opted out with `sync.runs: false`.
|
|
208
|
+
* `reticle verify` used the port above and pushed its run and progress regardless of the opt-out.
|
|
209
|
+
*/
|
|
210
|
+
export const linkedRunsCloudPort = (fs, reticleRoot, homeDir, env) => async () => {
|
|
211
|
+
const cloud = await resolveProjectCloud(fs, reticleRoot, homeDir, env);
|
|
212
|
+
return cloud.policy.runs ? cloud.config : null;
|
|
213
|
+
};
|
|
185
214
|
/**
|
|
186
215
|
* The environment with this project's resolved credential written into it, for the readers that
|
|
187
216
|
* take an env record (the panel's model config and harness switch). Handed `process.env` alone,
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Optional cloud sync for saved flows. "Logged in" here means the two cloud env vars are set (written by
|
|
3
|
-
* `reticle login` later; settable by hand today): the hosted URL and an API key from the Reticle
|
|
4
|
-
* dashboard. When present, a freshly-saved flow is pushed to `POST /v1/flows` so the team's regression
|
|
5
|
-
* suite lives in the cloud — surviving refactors and runnable in CI. When absent, sync is a no-op and
|
|
6
|
-
* everything stays 100% local (the "no phone-home" default: nothing leaves the machine unless you opt in).
|
|
7
|
-
*
|
|
8
|
-
* Sync is best-effort: a network failure NEVER fails the local save. The flow is already on disk; the
|
|
9
|
-
* cloud copy is an enhancement, so a push error is logged and swallowed.
|
|
10
|
-
*/
|
|
11
1
|
import { z } from 'zod';
|
|
12
2
|
import { type FlowFile, type ReticleVerificationRun, type RunRecord, type VerifyProgressEvent } from '@reticlehq/core';
|
|
13
3
|
/**
|
|
@@ -40,6 +30,19 @@ export declare function cloudFetch(url: string, init: {
|
|
|
40
30
|
headers: Record<string, string>;
|
|
41
31
|
body?: string;
|
|
42
32
|
}, timeoutMs?: number): Promise<Response>;
|
|
33
|
+
/**
|
|
34
|
+
* One sync request, status and body, under the same timeout every cloud call has. The sync daemon
|
|
35
|
+
* and `reticle sync` each called a bare `fetch`: one accepted-but-silent connection left the daemon's
|
|
36
|
+
* cycle running forever, and the dashboard stopped updating with nothing logged.
|
|
37
|
+
*/
|
|
38
|
+
export declare function syncRequest(url: string, init: {
|
|
39
|
+
method: string;
|
|
40
|
+
headers: Record<string, string>;
|
|
41
|
+
body?: string;
|
|
42
|
+
}, timeoutMs?: number): Promise<{
|
|
43
|
+
status: number;
|
|
44
|
+
text: string;
|
|
45
|
+
}>;
|
|
43
46
|
export declare const SyncOutcome: {
|
|
44
47
|
readonly SYNCED: "synced";
|
|
45
48
|
readonly SKIPPED: "skipped";
|
|
@@ -123,20 +126,20 @@ declare const ServerVerificationSchema: z.ZodObject<{
|
|
|
123
126
|
}>, "many">;
|
|
124
127
|
summary: z.ZodString;
|
|
125
128
|
}, "strip", z.ZodTypeAny, {
|
|
126
|
-
verificationId: string;
|
|
127
|
-
verdict: string | null;
|
|
128
129
|
flows: {
|
|
129
130
|
status: string;
|
|
130
131
|
name: string;
|
|
131
132
|
}[];
|
|
132
|
-
summary: string;
|
|
133
|
-
}, {
|
|
134
133
|
verificationId: string;
|
|
135
134
|
verdict: string | null;
|
|
135
|
+
summary: string;
|
|
136
|
+
}, {
|
|
136
137
|
flows: {
|
|
137
138
|
status: string;
|
|
138
139
|
name: string;
|
|
139
140
|
}[];
|
|
141
|
+
verificationId: string;
|
|
142
|
+
verdict: string | null;
|
|
140
143
|
summary: string;
|
|
141
144
|
}>;
|
|
142
145
|
export type ServerVerification = z.infer<typeof ServerVerificationSchema>;
|
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
* Sync is best-effort: a network failure NEVER fails the local save. The flow is already on disk; the
|
|
9
9
|
* cloud copy is an enhancement, so a push error is logged and swallowed.
|
|
10
10
|
*/
|
|
11
|
+
import { shareableRun } from '@reticlehq/core/artifacts';
|
|
11
12
|
import { z } from 'zod';
|
|
12
|
-
import { VERIFY_PROGRESS_MAX_EVENTS, platformCredentialFrom, } from '@reticlehq/core';
|
|
13
|
+
import { VERIFY_PROGRESS_MAX_EVENTS, platformCredentialFrom, flowJsonReplacer, } from '@reticlehq/core';
|
|
13
14
|
/**
|
|
14
15
|
* Env var names — the presence of BOTH is what "logged in" means for cloud sync.
|
|
15
16
|
*
|
|
@@ -60,7 +61,7 @@ const TIMEOUT_ERROR_NAMES = new Set(['TimeoutError', 'AbortError']);
|
|
|
60
61
|
const UNSENDABLE_HEADER_CHAR = /[^ -ÿ]/;
|
|
61
62
|
/** Which knob holds the credential behind a header, so the error can name the thing to go and edit. */
|
|
62
63
|
const CREDENTIAL_SOURCE = {
|
|
63
|
-
authorization: `${CloudEnv.KEY} (or the session from \`reticle
|
|
64
|
+
authorization: `${CloudEnv.KEY} (or the session from \`reticle connect\`)`,
|
|
64
65
|
};
|
|
65
66
|
/**
|
|
66
67
|
* Refuse a request whose headers cannot be encoded, before it is sent.
|
|
@@ -97,6 +98,15 @@ export async function cloudFetch(url, init, timeoutMs = CLOUD_FETCH_TIMEOUT_MS)
|
|
|
97
98
|
throw err;
|
|
98
99
|
}
|
|
99
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* One sync request, status and body, under the same timeout every cloud call has. The sync daemon
|
|
103
|
+
* and `reticle sync` each called a bare `fetch`: one accepted-but-silent connection left the daemon's
|
|
104
|
+
* cycle running forever, and the dashboard stopped updating with nothing logged.
|
|
105
|
+
*/
|
|
106
|
+
export async function syncRequest(url, init, timeoutMs = CLOUD_FETCH_TIMEOUT_MS) {
|
|
107
|
+
const res = await cloudFetch(url, init, timeoutMs);
|
|
108
|
+
return { status: res.status, text: await res.text() };
|
|
109
|
+
}
|
|
100
110
|
export const SyncOutcome = {
|
|
101
111
|
SYNCED: 'synced',
|
|
102
112
|
SKIPPED: 'skipped',
|
|
@@ -116,7 +126,7 @@ export async function syncFlowToCloud(flow, config, projectId, fetchImpl) {
|
|
|
116
126
|
'content-type': 'application/json',
|
|
117
127
|
authorization: `Bearer ${config.apiKey}`,
|
|
118
128
|
},
|
|
119
|
-
body: JSON.stringify(projectId === undefined ? { flow } : { flow, projectId }),
|
|
129
|
+
body: JSON.stringify(projectId === undefined ? { flow } : { flow, projectId }, flowJsonReplacer),
|
|
120
130
|
});
|
|
121
131
|
return res.ok
|
|
122
132
|
? { outcome: SyncOutcome.SYNCED, status: res.status }
|
|
@@ -143,7 +153,8 @@ export async function syncRunToCloud(run, config, fetchImpl) {
|
|
|
143
153
|
'content-type': 'application/json',
|
|
144
154
|
authorization: `Bearer ${config.apiKey}`,
|
|
145
155
|
},
|
|
146
|
-
|
|
156
|
+
// The prompt context leaves the machine only when the project opted in.
|
|
157
|
+
body: JSON.stringify(shareableRun(run)),
|
|
147
158
|
});
|
|
148
159
|
return res.ok
|
|
149
160
|
? { outcome: SyncOutcome.SYNCED, status: res.status }
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The harness switch, cached for a HUD that reads it inline.
|
|
3
|
+
*
|
|
4
|
+
* `fetchPlatformConfig` already asks the platform and parses the answer; this adds the one thing the
|
|
5
|
+
* impact snapshot needs and the drive path does not — a SYNCHRONOUS read. The snapshot is rebuilt
|
|
6
|
+
* dozens of times a session, the answer changes about as often as somebody opens a settings page,
|
|
7
|
+
* and a panel that awaited the network on every repaint would be a panel that stutters.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately its own cache rather than a shared abstraction with the notices source:
|
|
10
|
+
* two callers with the same caching problem is not yet a pattern, and the day one of them needs a
|
|
11
|
+
* different staleness rule the shared version becomes the awkward one.
|
|
12
|
+
*
|
|
13
|
+
* Every failure answers `undefined`, which the HUD must read as "we have not heard" and render as NO
|
|
14
|
+
* control — never as "off". Showing a switch that cannot be honoured is worse than showing none.
|
|
15
|
+
*
|
|
16
|
+
* The loader arrives as a PORT rather than an import. Reading the platform lives in
|
|
17
|
+
* `features/harness`, and a cloud-memory file reaching into a feature is the reach the directory
|
|
18
|
+
* guard refuses — correctly, and for the same reason it refused the tool surface reaching the other
|
|
19
|
+
* way. Whoever wires the daemon owns both sides and can hand one to the other.
|
|
20
|
+
*/
|
|
21
|
+
import type { CreditKind } from '@reticlehq/core';
|
|
1
22
|
/** Narrowed to what this file stores: the caller's own type is richer and irrelevant here. */
|
|
2
23
|
export interface HarnessConfigView {
|
|
3
24
|
provider: string;
|
|
@@ -5,8 +26,61 @@ export interface HarnessConfigView {
|
|
|
5
26
|
harnessEntitled: boolean;
|
|
6
27
|
/** Whether the platform holds a key for `provider`. Entitlement is not readiness — see the offer. */
|
|
7
28
|
providerReady: boolean;
|
|
29
|
+
credits?: {
|
|
30
|
+
used: number;
|
|
31
|
+
limit: number;
|
|
32
|
+
kind?: CreditKind | undefined;
|
|
33
|
+
endsAt?: number;
|
|
34
|
+
};
|
|
35
|
+
/** The platform's coverage gate, when it sent one: the HUD prefers it to the local score. */
|
|
36
|
+
gate?: {
|
|
37
|
+
unlocked: boolean;
|
|
38
|
+
percent?: number;
|
|
39
|
+
reason?: string;
|
|
40
|
+
prompt?: string;
|
|
41
|
+
};
|
|
42
|
+
plan?: {
|
|
43
|
+
kind: CreditKind;
|
|
44
|
+
daysLeft?: number;
|
|
45
|
+
seats?: number;
|
|
46
|
+
};
|
|
47
|
+
harnessRuns?: number;
|
|
48
|
+
memoryEntries?: number;
|
|
8
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* The answer as the HUD is pushed it: the grant's end date becomes whole days left, counted on the
|
|
52
|
+
* daemon's clock (the HUD has none worth trusting for this). No end date, no days. Pure.
|
|
53
|
+
*/
|
|
54
|
+
export declare function configForHud(config: HarnessConfigView, now: number): Omit<HarnessConfigView, 'credits'> & {
|
|
55
|
+
credits?: {
|
|
56
|
+
used: number;
|
|
57
|
+
limit: number;
|
|
58
|
+
kind?: CreditKind | undefined;
|
|
59
|
+
daysLeft?: number;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
9
62
|
export interface ConfigSource {
|
|
10
63
|
read(): HarnessConfigView | undefined;
|
|
11
64
|
}
|
|
12
|
-
export
|
|
65
|
+
export interface MutableConfigSource extends ConfigSource {
|
|
66
|
+
applyWrite(enabled: boolean): void;
|
|
67
|
+
recheck(): void;
|
|
68
|
+
subscribe(listener: () => void): () => void;
|
|
69
|
+
/** Re-read in the background, telling listeners only when the answer changed. */
|
|
70
|
+
poll(): void;
|
|
71
|
+
}
|
|
72
|
+
export declare function harnessConfigSource(load: () => Promise<HarnessConfigView | undefined>, now?: () => number): MutableConfigSource;
|
|
73
|
+
export type ConfigsByRoot = (root: string) => MutableConfigSource;
|
|
74
|
+
/**
|
|
75
|
+
* One live config source per project root, created on first ask; `onChange` hears every update.
|
|
76
|
+
*
|
|
77
|
+
* The platform read arrives as `load`, so this cache never reaches for the harness feature that
|
|
78
|
+
* performs it: the daemon, which owns both, joins them. It sat inline in `start` and `startDaemon`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function harnessConfigsByRoot(load: (root: string) => Promise<HarnessConfigView | undefined>, onChange?: (root: string) => void): ConfigsByRoot;
|
|
81
|
+
/**
|
|
82
|
+
* The HUD's harness switch, written to the platform with this project's credential. Nothing is
|
|
83
|
+
* awaited: an accepted write updates the cache at once, and a refused or failed one re-reads the
|
|
84
|
+
* platform so the switch springs back to the truth rather than staying where the user left it.
|
|
85
|
+
*/
|
|
86
|
+
export declare function applyHarnessSwitch(configs: ConfigsByRoot, root: string, enabled: boolean, envFor: () => Promise<Record<string, string | undefined>>): void;
|
|
@@ -1,48 +1,69 @@
|
|
|
1
|
-
|
|
2
|
-
* The harness switch, cached for a HUD that reads it inline.
|
|
3
|
-
*
|
|
4
|
-
* `fetchPlatformConfig` already asks the platform and parses the answer; this adds the one thing the
|
|
5
|
-
* impact snapshot needs and the drive path does not — a SYNCHRONOUS read. The snapshot is rebuilt
|
|
6
|
-
* dozens of times a session, the answer changes about as often as somebody opens a settings page,
|
|
7
|
-
* and a panel that awaited the network on every repaint would be a panel that stutters.
|
|
8
|
-
*
|
|
9
|
-
* Deliberately the same shape as `harnessOfferSource` next door rather than a shared abstraction:
|
|
10
|
-
* two callers with the same caching problem is not yet a pattern, and the day one of them needs a
|
|
11
|
-
* different staleness rule the shared version becomes the awkward one.
|
|
12
|
-
*
|
|
13
|
-
* Every failure answers `undefined`, which the HUD must read as "we have not heard" and render as NO
|
|
14
|
-
* control — never as "off". Showing a switch that cannot be honoured is worse than showing none.
|
|
15
|
-
*
|
|
16
|
-
* The loader arrives as a PORT rather than an import. Reading the platform lives in
|
|
17
|
-
* `features/harness`, and a cloud-memory file reaching into a feature is the reach the directory
|
|
18
|
-
* guard refuses — correctly, and for the same reason it refused the tool surface reaching the other
|
|
19
|
-
* way. Whoever wires the daemon owns both sides and can hand one to the other.
|
|
20
|
-
*/
|
|
1
|
+
import { writeHarnessSwitch } from './harness-switch.js';
|
|
21
2
|
/** How long a cached answer is trusted. A person who just changed it expects the panel to notice. */
|
|
22
3
|
const FRESH_MS = 30 * 1_000;
|
|
4
|
+
const DAY_MS = 24 * 60 * 60 * 1_000;
|
|
5
|
+
/**
|
|
6
|
+
* The answer as the HUD is pushed it: the grant's end date becomes whole days left, counted on the
|
|
7
|
+
* daemon's clock (the HUD has none worth trusting for this). No end date, no days. Pure.
|
|
8
|
+
*/
|
|
9
|
+
export function configForHud(config, now) {
|
|
10
|
+
if (config.credits === undefined)
|
|
11
|
+
return config;
|
|
12
|
+
const { endsAt, ...credits } = config.credits;
|
|
13
|
+
return {
|
|
14
|
+
...config,
|
|
15
|
+
credits: endsAt === undefined
|
|
16
|
+
? credits
|
|
17
|
+
: { ...credits, daysLeft: Math.max(0, Math.ceil((endsAt - now) / DAY_MS)) },
|
|
18
|
+
};
|
|
19
|
+
}
|
|
23
20
|
export function harnessConfigSource(load, now = () => Date.now()) {
|
|
24
21
|
let cached;
|
|
25
22
|
// `undefined` rather than 0: "never asked" is a different state from "asked at the epoch", and
|
|
26
23
|
// conflating them made a source with an injected clock never take its first read.
|
|
27
24
|
let fetchedAt;
|
|
28
25
|
let inFlight = false;
|
|
26
|
+
let queuedRefresh = false;
|
|
27
|
+
let revision = 0;
|
|
28
|
+
/** Set for a background poll, so an unchanged answer does not repaint every HUD. */
|
|
29
|
+
let quiet = false;
|
|
30
|
+
const listeners = new Set();
|
|
31
|
+
const notify = () => {
|
|
32
|
+
for (const listener of listeners)
|
|
33
|
+
listener();
|
|
34
|
+
};
|
|
29
35
|
const refresh = () => {
|
|
30
36
|
if (inFlight)
|
|
31
37
|
return;
|
|
32
38
|
inFlight = true;
|
|
39
|
+
const startedAtRevision = revision;
|
|
33
40
|
void load()
|
|
34
41
|
.then((cfg) => {
|
|
35
42
|
// A failed read keeps the LAST good answer rather than blanking the control mid-session:
|
|
36
43
|
// one dropped request is not evidence that somebody changed their mind.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
44
|
+
const before = JSON.stringify(cached);
|
|
45
|
+
if (startedAtRevision === revision) {
|
|
46
|
+
if (cfg !== undefined)
|
|
47
|
+
cached = cfg;
|
|
48
|
+
fetchedAt = now();
|
|
49
|
+
}
|
|
50
|
+
// A poll that learned nothing new repaints nothing; anything else is said at once.
|
|
51
|
+
if (!quiet || before !== JSON.stringify(cached))
|
|
52
|
+
notify();
|
|
53
|
+
quiet = false;
|
|
40
54
|
})
|
|
41
55
|
.catch(() => {
|
|
42
|
-
|
|
56
|
+
if (startedAtRevision === revision)
|
|
57
|
+
fetchedAt = now();
|
|
58
|
+
quiet = false;
|
|
59
|
+
notify();
|
|
43
60
|
})
|
|
44
61
|
.finally(() => {
|
|
45
62
|
inFlight = false;
|
|
63
|
+
if (queuedRefresh) {
|
|
64
|
+
queuedRefresh = false;
|
|
65
|
+
refresh();
|
|
66
|
+
}
|
|
46
67
|
});
|
|
47
68
|
};
|
|
48
69
|
// Asked at construction, not first read: the daemon pushes a snapshot the instant a session
|
|
@@ -54,5 +75,75 @@ export function harnessConfigSource(load, now = () => Date.now()) {
|
|
|
54
75
|
refresh();
|
|
55
76
|
return cached;
|
|
56
77
|
},
|
|
78
|
+
applyWrite(enabled) {
|
|
79
|
+
revision += 1;
|
|
80
|
+
if (cached !== undefined)
|
|
81
|
+
cached = { ...cached, harnessEnabled: enabled };
|
|
82
|
+
fetchedAt = now();
|
|
83
|
+
notify();
|
|
84
|
+
if (cached === undefined) {
|
|
85
|
+
if (inFlight)
|
|
86
|
+
queuedRefresh = true;
|
|
87
|
+
else
|
|
88
|
+
refresh();
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
recheck() {
|
|
92
|
+
notify(); // Roll back an optimistic HUD switch immediately, even if the GET is slow.
|
|
93
|
+
if (inFlight)
|
|
94
|
+
queuedRefresh = true;
|
|
95
|
+
else
|
|
96
|
+
refresh();
|
|
97
|
+
},
|
|
98
|
+
subscribe(listener) {
|
|
99
|
+
listeners.add(listener);
|
|
100
|
+
return () => listeners.delete(listener);
|
|
101
|
+
},
|
|
102
|
+
poll() {
|
|
103
|
+
if (inFlight)
|
|
104
|
+
return;
|
|
105
|
+
quiet = true;
|
|
106
|
+
refresh();
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* One live config source per project root, created on first ask; `onChange` hears every update.
|
|
112
|
+
*
|
|
113
|
+
* The platform read arrives as `load`, so this cache never reaches for the harness feature that
|
|
114
|
+
* performs it: the daemon, which owns both, joins them. It sat inline in `start` and `startDaemon`.
|
|
115
|
+
*/
|
|
116
|
+
export function harnessConfigsByRoot(load, onChange) {
|
|
117
|
+
const sources = new Map();
|
|
118
|
+
return (root) => {
|
|
119
|
+
let source = sources.get(root);
|
|
120
|
+
if (source === undefined) {
|
|
121
|
+
source = harnessConfigSource(() => load(root));
|
|
122
|
+
if (onChange !== undefined) {
|
|
123
|
+
source.subscribe(() => onChange(root));
|
|
124
|
+
// The switch can be flipped anywhere: the console, another tab, the API. A HUD that only
|
|
125
|
+
// learned of it on its next tool call showed Harness ON over a drive that had stopped.
|
|
126
|
+
const live = source;
|
|
127
|
+
setInterval(() => live.poll(), FRESH_MS).unref();
|
|
128
|
+
}
|
|
129
|
+
sources.set(root, source);
|
|
130
|
+
}
|
|
131
|
+
return source;
|
|
57
132
|
};
|
|
58
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* The HUD's harness switch, written to the platform with this project's credential. Nothing is
|
|
136
|
+
* awaited: an accepted write updates the cache at once, and a refused or failed one re-reads the
|
|
137
|
+
* platform so the switch springs back to the truth rather than staying where the user left it.
|
|
138
|
+
*/
|
|
139
|
+
export function applyHarnessSwitch(configs, root, enabled, envFor) {
|
|
140
|
+
void envFor()
|
|
141
|
+
.then((env) => writeHarnessSwitch(env, enabled))
|
|
142
|
+
.then((saved) => {
|
|
143
|
+
if (saved)
|
|
144
|
+
configs(root).applyWrite(enabled);
|
|
145
|
+
else
|
|
146
|
+
configs(root).recheck();
|
|
147
|
+
})
|
|
148
|
+
.catch(() => configs(root).recheck());
|
|
149
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type HudNoticeEntry } from '@reticlehq/core/hud';
|
|
2
|
+
/**
|
|
3
|
+
* The largest body the daemon will read or keep. The real file is a few hundred bytes; anything near
|
|
4
|
+
* this is not a notices file, and the cache on disk must not grow with whatever the network sends.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MAX_NOTICES_BODY_BYTES: number;
|
|
7
|
+
export type NoticesLoad = (url: string, etag: string | undefined) => Promise<{
|
|
8
|
+
status: number;
|
|
9
|
+
etag?: string | undefined;
|
|
10
|
+
body?: string | undefined;
|
|
11
|
+
}>;
|
|
12
|
+
export interface NoticesSource {
|
|
13
|
+
/** The entries this daemon knows, unfiltered. Never throws, never waits. */
|
|
14
|
+
read(): HudNoticeEntry[];
|
|
15
|
+
}
|
|
16
|
+
export declare function hudNoticesSource(opts: {
|
|
17
|
+
cacheFile: string;
|
|
18
|
+
now?: () => number;
|
|
19
|
+
load?: NoticesLoad;
|
|
20
|
+
url?: string;
|
|
21
|
+
}): NoticesSource;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The HUD rail's notices, as the daemon keeps them.
|
|
3
|
+
*
|
|
4
|
+
* Read synchronously (the snapshot is rebuilt many times a session), served from a disk cache that
|
|
5
|
+
* survives restarts, and revalidated in the background with the stored ETag, so an unchanged file
|
|
6
|
+
* costs a 304 and no body. A failed or garbled refresh keeps the last good copy: the rail is
|
|
7
|
+
* marketing, and nothing about it may block or break a session. See core `hud-notices.ts`.
|
|
8
|
+
*/
|
|
9
|
+
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
10
|
+
import { dirname } from 'node:path';
|
|
11
|
+
import { ReticleEnv } from '@reticlehq/core';
|
|
12
|
+
import { HUD_NOTICES_URL, NOTICES_FILE_VERSION, parseHudNotices, } from '@reticlehq/core/hud';
|
|
13
|
+
/** How long a copy is trusted before it is revalidated. Notices change over days, not minutes. */
|
|
14
|
+
const FRESH_MS = 6 * 60 * 60 * 1_000;
|
|
15
|
+
const TIMEOUT_MS = 5_000;
|
|
16
|
+
/**
|
|
17
|
+
* The largest body the daemon will read or keep. The real file is a few hundred bytes; anything near
|
|
18
|
+
* this is not a notices file, and the cache on disk must not grow with whatever the network sends.
|
|
19
|
+
*/
|
|
20
|
+
export const MAX_NOTICES_BODY_BYTES = 64 * 1_024;
|
|
21
|
+
/** Overrides the notices URL: self-hosting, staging, tests. */
|
|
22
|
+
const NOTICES_URL_ENV = 'RETICLE_HUD_NOTICES_URL';
|
|
23
|
+
/**
|
|
24
|
+
* The same opt-outs telemetry honours. The notices file carries nothing about anybody, but it is a
|
|
25
|
+
* request to reticle.sh, and somebody who switched Reticle's outbound calls off asked for none.
|
|
26
|
+
*/
|
|
27
|
+
function outboundOff(env) {
|
|
28
|
+
const telemetry = (env[ReticleEnv.TELEMETRY] ?? '').toLowerCase();
|
|
29
|
+
const dnt = env[ReticleEnv.DO_NOT_TRACK];
|
|
30
|
+
return (['0', 'false', 'off'].includes(telemetry) ||
|
|
31
|
+
('string' === typeof dnt && dnt !== '' && dnt !== '0'));
|
|
32
|
+
}
|
|
33
|
+
const defaultLoad = async (url, etag) => {
|
|
34
|
+
const res = await fetch(url, {
|
|
35
|
+
headers: etag === undefined ? {} : { 'if-none-match': etag },
|
|
36
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
status: res.status,
|
|
40
|
+
etag: res.headers.get('etag') ?? undefined,
|
|
41
|
+
body: 304 === res.status ? undefined : await res.text(),
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
function readCache(path) {
|
|
45
|
+
try {
|
|
46
|
+
const raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
47
|
+
if ('object' !== typeof raw || null === raw)
|
|
48
|
+
return undefined;
|
|
49
|
+
const record = raw;
|
|
50
|
+
const fetchedAt = record['fetchedAt'];
|
|
51
|
+
const etag = record['etag'];
|
|
52
|
+
return {
|
|
53
|
+
fetchedAt: 'number' === typeof fetchedAt ? fetchedAt : 0,
|
|
54
|
+
...('string' === typeof etag ? { etag } : {}),
|
|
55
|
+
file: record['file'],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function writeCache(path, cached) {
|
|
63
|
+
try {
|
|
64
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
65
|
+
writeFileSync(path, JSON.stringify(cached));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
/* a cache that cannot be written is a fetch next time, not an error */
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export function hudNoticesSource(opts) {
|
|
72
|
+
const now = opts.now ?? (() => Date.now());
|
|
73
|
+
const load = opts.load ?? defaultLoad;
|
|
74
|
+
const url = opts.url ?? process.env[NOTICES_URL_ENV] ?? HUD_NOTICES_URL;
|
|
75
|
+
let cached = readCache(opts.cacheFile);
|
|
76
|
+
let entries = cached === undefined ? [] : parseHudNotices(cached.file);
|
|
77
|
+
let inFlight = false;
|
|
78
|
+
let askedAt;
|
|
79
|
+
const refresh = () => {
|
|
80
|
+
inFlight = true;
|
|
81
|
+
askedAt = now();
|
|
82
|
+
void load(url, cached?.etag)
|
|
83
|
+
.then((answer) => {
|
|
84
|
+
if (304 === answer.status && cached !== undefined) {
|
|
85
|
+
cached = { ...cached, fetchedAt: now() };
|
|
86
|
+
writeCache(opts.cacheFile, cached);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
if (200 !== answer.status || answer.body === undefined)
|
|
90
|
+
return;
|
|
91
|
+
if (MAX_NOTICES_BODY_BYTES < Buffer.byteLength(answer.body))
|
|
92
|
+
return;
|
|
93
|
+
let file;
|
|
94
|
+
try {
|
|
95
|
+
file = JSON.parse(answer.body);
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// An unreadable file keeps the last good notices rather than emptying the rail.
|
|
101
|
+
const parsed = parseHudNotices(file);
|
|
102
|
+
if (0 === parsed.length && 0 < entries.length)
|
|
103
|
+
return;
|
|
104
|
+
entries = parsed;
|
|
105
|
+
// The cache holds what VALIDATED, rebuilt from the schema's output, never the body itself:
|
|
106
|
+
// unknown fields and rejected entries in a network answer do not reach the disk.
|
|
107
|
+
cached = {
|
|
108
|
+
etag: answer.etag,
|
|
109
|
+
fetchedAt: now(),
|
|
110
|
+
file: { version: NOTICES_FILE_VERSION, notices: parsed },
|
|
111
|
+
};
|
|
112
|
+
writeCache(opts.cacheFile, cached);
|
|
113
|
+
})
|
|
114
|
+
.catch(() => undefined)
|
|
115
|
+
.finally(() => {
|
|
116
|
+
inFlight = false;
|
|
117
|
+
});
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
read() {
|
|
121
|
+
const last = Math.max(cached?.fetchedAt ?? 0, askedAt ?? Number.NEGATIVE_INFINITY);
|
|
122
|
+
const stale = cached === undefined && askedAt === undefined ? true : FRESH_MS <= now() - last;
|
|
123
|
+
if (!inFlight && stale && !outboundOff(process.env))
|
|
124
|
+
refresh();
|
|
125
|
+
return entries;
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|