@reticlehq/server 3.6.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/SKILL.md +122 -123
- 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 +18 -2
- package/dist/command/cli/adhoc-verdict.js +70 -6
- 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/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 +28 -105
- 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 +34 -4
- package/dist/command/cli/cli-verify.js +81 -12
- package/dist/command/cli/cloud-cli.d.ts +13 -0
- package/dist/command/cli/cloud-cli.js +145 -333
- 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 +15 -1
- package/dist/command/cli/cloud-login.js +67 -13
- 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/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/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 +11 -2
- 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.js +1 -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 +29 -8
- 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 -178
- 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 +14 -0
- package/dist/command/cli.js +103 -83
- package/dist/command/daemon/daemon-resilience.js +4 -4
- package/dist/command/daemon/daemon-resolve.d.ts +9 -1
- package/dist/command/daemon/daemon-resolve.js +49 -10
- 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/dev-server-log-cap.js +2 -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 +10 -1
- package/dist/command/setup/init/init-port.js +22 -2
- package/dist/command/setup/init/init-runtime.d.ts +12 -2
- package/dist/command/setup/init/init-runtime.js +96 -37
- package/dist/command/setup/node-effects.d.ts +2 -0
- package/dist/command/setup/node-effects.js +36 -8
- 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 +1 -1
- package/dist/command/setup/run-setup.d.ts +29 -9
- package/dist/command/setup/run-setup.js +34 -28
- package/dist/command/setup/setup-command.d.ts +23 -0
- package/dist/command/setup/setup-command.js +57 -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 +38 -2
- package/dist/features/crawl/crawl.js +14 -1
- package/dist/features/exhaust/ledger.d.ts +14 -14
- package/dist/features/harness/drive-report.d.ts +39 -5
- package/dist/features/harness/drive-report.js +271 -54
- 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 +1 -1
- package/dist/features/harness/drivers.js +1 -1
- 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/goals.d.ts +68 -7
- package/dist/features/harness/goals.js +289 -36
- package/dist/features/harness/harness.d.ts +30 -1
- package/dist/features/harness/harness.js +141 -7
- package/dist/features/harness/platform/local-apps.d.ts +36 -3
- package/dist/features/harness/platform/local-apps.js +81 -5
- 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 +8 -2
- package/dist/features/harness/platform/remote-drive.js +22 -9
- package/dist/features/harness/platform/script.d.ts +57 -11
- package/dist/features/harness/platform/script.js +144 -12
- package/dist/features/harness/platform/server-driver.d.ts +17 -4
- package/dist/features/harness/platform/server-driver.js +29 -26
- package/dist/features/harness/platform-config.d.ts +38 -5
- package/dist/features/harness/platform-config.js +93 -8
- package/dist/features/harness/route-guess.d.ts +13 -0
- package/dist/features/harness/route-guess.js +49 -0
- package/dist/features/harness/script/script-run.d.ts +30 -1
- package/dist/features/harness/script/script-run.js +355 -48
- 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.js +22 -14
- 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 +21 -2
- package/dist/hooks/driven-by.js +42 -2
- package/dist/hooks/hook-bus.d.ts +4 -0
- package/dist/hooks/hook-bus.js +18 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +26 -183
- 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 +20 -4
- 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.js +25 -9
- package/dist/judgement/runs/artifact/run-store.d.ts +13 -1
- package/dist/judgement/runs/artifact/run-store.js +175 -8
- 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 +53 -5
- package/dist/judgement/runs/drive-run.js +234 -20
- package/dist/judgement/runs/resume.d.ts +44 -0
- package/dist/judgement/runs/resume.js +137 -0
- package/dist/judgement/runs/reticle-runner.js +5 -2
- 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 +2 -0
- package/dist/judgement/runs/verification-sync.js +36 -15
- package/dist/language/flows/decision.js +2 -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 +7 -2
- package/dist/language/flows/flow-anchor.js +10 -3
- 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 +37 -3
- package/dist/language/flows/flow-replay-run.js +16 -18
- package/dist/language/flows/flow-replay-types.d.ts +1 -1
- package/dist/language/flows/flow-replay.d.ts +18 -1
- package/dist/language/flows/flow-replay.js +22 -7
- package/dist/language/flows/flow-result.d.ts +22 -1
- package/dist/language/flows/flow-result.js +47 -2
- package/dist/language/flows/flow-step-runners.d.ts +2 -0
- package/dist/language/flows/flow-step-runners.js +12 -6
- package/dist/language/flows/flow-store-for-session.js +5 -1
- package/dist/language/flows/flow-tools.d.ts +10 -0
- package/dist/language/flows/flow-tools.js +61 -62
- package/dist/language/flows/flows.d.ts +16 -1
- package/dist/language/flows/flows.js +69 -10
- package/dist/language/flows/narrow-write.d.ts +7 -0
- package/dist/language/flows/narrow-write.js +36 -1
- package/dist/language/flows/recording/recording-backtrack.js +14 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +29 -1
- package/dist/language/flows/recording/tape/recordings.js +60 -10
- package/dist/language/flows/replay.js +29 -6
- package/dist/language/flows/single-replay.d.ts +7 -0
- package/dist/language/flows/single-replay.js +26 -0
- package/dist/language/flows/verify-change-tools.d.ts +1 -0
- package/dist/language/flows/verify-change-tools.js +200 -193
- package/dist/memory/cloud/cloud-config.d.ts +10 -1
- package/dist/memory/cloud/cloud-config.js +19 -5
- package/dist/memory/cloud/cloud-sync.js +3 -3
- package/dist/memory/cloud/harness-config.d.ts +49 -0
- package/dist/memory/cloud/harness-config.js +16 -20
- package/dist/memory/cloud/memory-scope.d.ts +17 -0
- package/dist/memory/cloud/memory-scope.js +22 -0
- package/dist/memory/cloud/sync-cycle.d.ts +32 -4
- package/dist/memory/cloud/sync-cycle.js +113 -12
- package/dist/memory/cloud/sync-daemon.d.ts +11 -0
- package/dist/memory/cloud/sync-daemon.js +114 -4
- package/dist/memory/cloud/sync-disk.js +26 -2
- 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 +16 -1
- package/dist/memory/impact/account-watch.js +26 -1
- package/dist/memory/impact/impact-store.d.ts +1 -4
- package/dist/memory/impact/impact-store.js +32 -42
- 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 +12 -0
- package/dist/memory/intent/intent-store.d.ts +1 -0
- package/dist/memory/intent/intent-tools.js +42 -2
- 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/journal-recorder.js +46 -3
- package/dist/memory/journal/on-disk/retention.d.ts +5 -0
- package/dist/memory/journal/on-disk/retention.js +27 -2
- package/dist/memory/journal/on-disk/workspace-tiers.js +2 -0
- package/dist/memory/journal/session-end.d.ts +15 -1
- package/dist/memory/journal/session-end.js +38 -7
- package/dist/memory/project/artifact-root-resolver.js +33 -5
- package/dist/memory/project/artifact-root.d.ts +4 -3
- package/dist/memory/project/artifact-root.js +2 -2
- package/dist/memory/project/dir/reticle-dir.d.ts +14 -0
- package/dist/memory/project/dir/reticle-dir.js +23 -2
- package/dist/memory/project/link-directory.d.ts +15 -0
- package/dist/memory/project/link-directory.js +44 -0
- 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 +2 -0
- package/dist/memory/project/session-root.js +9 -1
- package/dist/memory/project/sync-status.d.ts +46 -0
- package/dist/memory/project/sync-status.js +135 -1
- package/dist/memory/recall/memory-tools.js +46 -3
- 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.js +36 -8
- package/dist/portal/bridge/bridge.d.ts +9 -5
- package/dist/portal/bridge/bridge.js +66 -23
- package/dist/portal/bridge/harness-request.d.ts +23 -0
- package/dist/portal/bridge/harness-request.js +27 -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 +2 -0
- package/dist/portal/input/real-input.js +13 -10
- package/dist/portal/pool/browser-pool.d.ts +48 -0
- package/dist/portal/pool/browser-pool.js +120 -2
- 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 +27 -5
- package/dist/portal/pool/playwright-launcher.js +59 -14
- package/dist/portal/pool/pool-contract.d.ts +21 -1
- 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.js +6 -1
- 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 +9 -0
- package/dist/portal/session/dev-server/dev-command.js +27 -1
- 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/human/live-control.d.ts +9 -2
- package/dist/portal/session/human/live-control.js +12 -3
- package/dist/portal/session/live-control-tools.js +82 -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 +1 -1
- package/dist/portal/session/no-session-diagnosis.js +31 -9
- package/dist/portal/session/no-session-next-action.d.ts +20 -0
- package/dist/portal/session/no-session-next-action.js +134 -61
- package/dist/portal/session/no-session-watch.js +179 -22
- package/dist/portal/session/presence/session-lease.js +1 -1
- package/dist/portal/session/recorded-gaps.d.ts +97 -0
- package/dist/portal/session/recorded-gaps.js +251 -0
- package/dist/portal/session/session-health.d.ts +11 -0
- package/dist/portal/session/session-health.js +3 -1
- package/dist/portal/session/session-info.js +2 -1
- package/dist/portal/session/session-manager.d.ts +18 -0
- package/dist/portal/session/session-manager.js +54 -3
- package/dist/portal/session/session-successor.d.ts +8 -0
- package/dist/portal/session/session-successor.js +1 -1
- package/dist/portal/session/session.d.ts +15 -28
- package/dist/portal/session/session.js +60 -61
- 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 +7 -1
- package/dist/start-wiring.d.ts +63 -0
- package/dist/start-wiring.js +169 -0
- package/dist/status-payload.d.ts +13 -1
- package/dist/status-payload.js +13 -1
- package/dist/surface/http-server.js +7 -1
- 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 +4 -0
- package/dist/surface/mcp/mcp-proxy.js +29 -8
- package/dist/surface/mcp/mcp.d.ts +23 -0
- package/dist/surface/mcp/mcp.js +34 -4
- 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.js +22 -14
- package/dist/surface/mcp/shared-params.js +1 -1
- 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/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-sequence-tool.js +136 -27
- package/dist/surface/tools/act-tools.d.ts +0 -9
- package/dist/surface/tools/act-tools.js +48 -34
- 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.js +25 -15
- package/dist/surface/tools/browser-tools.js +43 -1
- package/dist/surface/tools/chat-drives.d.ts +75 -0
- package/dist/surface/tools/chat-drives.js +265 -21
- 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 +10 -0
- package/dist/surface/tools/empty-session-list.js +45 -5
- package/dist/surface/tools/error-recovery.d.ts +8 -0
- package/dist/surface/tools/error-recovery.js +69 -5
- package/dist/surface/tools/explore-tools.d.ts +23 -2
- package/dist/surface/tools/explore-tools.js +377 -74
- package/dist/surface/tools/feedback-tools.d.ts +2 -3
- package/dist/surface/tools/feedback-tools.js +4 -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 +52 -73
- package/dist/surface/tools/harness-explore.js +177 -146
- 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 +5 -0
- package/dist/surface/tools/harness-plan.js +7 -0
- package/dist/surface/tools/harness-script.d.ts +22 -0
- package/dist/surface/tools/harness-script.js +256 -38
- 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 +8 -0
- package/dist/surface/tools/harness-toolset.js +27 -4
- 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 +220 -93
- 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 +20 -0
- package/dist/surface/tools/lease-seed.js +45 -1
- package/dist/surface/tools/lease-tools.d.ts +10 -1
- package/dist/surface/tools/lease-tools.js +119 -69
- package/dist/surface/tools/live-call-text.js +2 -2
- 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 +11 -1
- package/dist/surface/tools/next-step.js +73 -18
- package/dist/surface/tools/observe-tools.js +43 -5
- package/dist/surface/tools/platform-moment.d.ts +60 -0
- package/dist/surface/tools/platform-moment.js +132 -4
- package/dist/surface/tools/read-tools.js +65 -14
- 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 +68 -2
- package/dist/surface/tools/tool-kit.js +73 -1
- package/dist/surface/tools/tools.js +25 -13
- 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 +27 -6
- package/dist/telemetry/hud-metrics.js +99 -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 +26 -2
- package/dist/telemetry/telemetry.js +102 -21
- package/dist/telemetry/verification-of.d.ts +3 -1
- package/dist/telemetry/verification-of.js +12 -4
- package/dist/wire-journal.d.ts +2 -2
- package/dist/wire-journal.js +16 -5
- package/docs/README.md +2 -2
- package/docs/actions.mdx +6 -3
- package/docs/adapters.md +1 -1
- package/docs/agent-cheatsheet.md +24 -27
- package/docs/architecture.md +5 -5
- package/docs/autodrive.md +13 -12
- 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 +8 -3
- package/docs/cli/drive.mdx +12 -12
- 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 +32 -15
- 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 +13 -4
- 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 +3 -2
- package/docs/cli.mdx +110 -41
- package/docs/debugging.md +3 -3
- package/docs/deploy-checks.md +1 -1
- package/docs/desktop.mdx +5 -3
- package/docs/enterprise.md +11 -10
- package/docs/environment.mdx +5 -2
- 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 +66 -64
- package/docs/human-control.md +15 -14
- package/docs/index.mdx +15 -43
- package/docs/install-agentic.mdx +22 -37
- package/docs/install-manual.mdx +22 -12
- 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 +8 -8
- package/docs/packages/test.mdx +4 -10
- package/docs/packages/vite-plugin.mdx +11 -4
- package/docs/packages.mdx +11 -15
- package/docs/platform-integration.md +6 -5
- package/docs/predicates.mdx +40 -24
- package/docs/quickstart.mdx +58 -29
- 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 +22 -24
- 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 +13 -4
- 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 +51 -45
- 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 +7 -5
- package/docs/what-is-reticle.mdx +2 -2
- package/docs/why-reticle.mdx +1 -1
- package/package.json +6 -5
- package/dist/command/cli/demo/demo-page.d.ts +0 -78
- package/dist/command/cli/demo/demo-page.js +0 -249
- package/dist/command/cli/demo/demo-run.d.ts +0 -38
- package/dist/command/cli/demo/demo-run.js +0 -138
- 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/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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type LinkCapability, type LinkNotice } from '@reticlehq/core';
|
|
1
|
+
import { type CoverageCapability, type LinkAppGap, type LinkDevServer, type LinkHelloFailure, type LinkUnsyncedRoot, type LinkCapability, type LinkNotice } from '@reticlehq/core';
|
|
2
2
|
import { type DriveCandidate } from './remote-drive.js';
|
|
3
3
|
/** How often apps are reported. The platform counts an app live for two and a half of these. */
|
|
4
4
|
export declare const LOCAL_APPS_REPORT_MS = 10000;
|
|
@@ -18,6 +18,14 @@ export interface AppTab extends DriveCandidate {
|
|
|
18
18
|
projectId?: string;
|
|
19
19
|
adapters: string[];
|
|
20
20
|
runtime?: string;
|
|
21
|
+
/** The SDK the page announced. The dashboard compares it with `reticleVersion` per app. */
|
|
22
|
+
sdkVersion?: string;
|
|
23
|
+
/** The page's HELLO channels, plus the coverage markers (`source`, `testid`) it earned. */
|
|
24
|
+
channels?: string[];
|
|
25
|
+
/** Instrumentation gaps this tab's verdicts recorded, newest first. */
|
|
26
|
+
gaps?: LinkAppGap[];
|
|
27
|
+
/** Coverage capabilities that do not apply to this app. */
|
|
28
|
+
notApplicable?: CoverageCapability[];
|
|
21
29
|
}
|
|
22
30
|
export interface ReportedApp {
|
|
23
31
|
key: string;
|
|
@@ -25,7 +33,20 @@ export interface ReportedApp {
|
|
|
25
33
|
url: string;
|
|
26
34
|
title?: string;
|
|
27
35
|
stack: string[];
|
|
36
|
+
sdkVersion?: string;
|
|
37
|
+
channels?: string[];
|
|
38
|
+
gaps?: LinkAppGap[];
|
|
39
|
+
adapters?: string[];
|
|
40
|
+
notApplicable?: CoverageCapability[];
|
|
28
41
|
}
|
|
42
|
+
/** What a report carries beside its apps. Every field additive; see `LinkReportKey`. */
|
|
43
|
+
export interface ReportExtras {
|
|
44
|
+
devServers?: LinkDevServer[];
|
|
45
|
+
helloFailure?: LinkHelloFailure;
|
|
46
|
+
unsynced?: LinkUnsyncedRoot[];
|
|
47
|
+
}
|
|
48
|
+
/** `path` under `home` as `~/...`, so no home directory leaves the machine in a report. */
|
|
49
|
+
export declare function homeRelative(path: string, home: string): string;
|
|
29
50
|
/** This machine: a stable id that is not its home path, and the name a person knows it by. */
|
|
30
51
|
export declare const machineOf: (hostname: string, home: string) => Machine;
|
|
31
52
|
/**
|
|
@@ -42,6 +63,8 @@ export declare const NOT_AN_APP_ADDRESS = "Reticle only opens a web address on t
|
|
|
42
63
|
export declare function mayOpen(url: string, openUrls: readonly string[]): boolean;
|
|
43
64
|
/** A project id as a name: the SDK stamps `<package>-<8 hex>`, and the hash means nothing to a person. */
|
|
44
65
|
export declare const nameFromProjectId: (projectId: string) => string;
|
|
66
|
+
/** The address as the app knows it: the params Reticle put on it to adopt a tab are not the app's. */
|
|
67
|
+
export declare const withoutMarks: (raw: string) => string;
|
|
45
68
|
/**
|
|
46
69
|
* The apps to report, grouped by the platform credential each one's project is linked with. The
|
|
47
70
|
* linked credential is reported even with no app open: it is how the chat knows the machine is there
|
|
@@ -65,10 +88,15 @@ export interface AppReportDeps {
|
|
|
65
88
|
platform: Platform;
|
|
66
89
|
apps: ReportedApp[];
|
|
67
90
|
}[]>;
|
|
68
|
-
/**
|
|
69
|
-
|
|
91
|
+
/**
|
|
92
|
+
* Open an app so it connects: one somebody asked to bring back, named by its app key so the tab
|
|
93
|
+
* writes into that app's own `.reticle`. A throw is logged, never fatal.
|
|
94
|
+
*/
|
|
95
|
+
open: (url: string, appKey?: string) => Promise<void>;
|
|
70
96
|
/** A drive is waiting for the project this credential is for. */
|
|
71
97
|
drivePending: (platform: Platform) => void;
|
|
98
|
+
/** Dev servers, the last refused hello and unsent runs: read once per report. */
|
|
99
|
+
extras?: () => Promise<ReportExtras>;
|
|
72
100
|
/**
|
|
73
101
|
* Something the platform wants the person told ("update Reticle"), for the project this credential
|
|
74
102
|
* is for. Called once per notice for the daemon's life, however often the platform repeats it.
|
|
@@ -83,6 +111,11 @@ export interface AppReports {
|
|
|
83
111
|
stop: () => void;
|
|
84
112
|
}
|
|
85
113
|
export declare function startAppReports(deps: AppReportDeps): AppReports;
|
|
114
|
+
/**
|
|
115
|
+
* Report now rather than on the next tick: the Harness gate just learned what an app's pages carry,
|
|
116
|
+
* and the platform, which locks a drive on its last report, would otherwise refuse on the old one.
|
|
117
|
+
*/
|
|
118
|
+
export declare const reportAppsNow: () => Promise<void>;
|
|
86
119
|
/**
|
|
87
120
|
* The tab a drive the chat attached to one app uses: a tab of that app and no other, even on the
|
|
88
121
|
* same port. None open: open the app, and wait for it to connect. Null when it never does.
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* waiting, which is how a daemon with nothing open hears about one without polling every few seconds.
|
|
12
12
|
*/
|
|
13
13
|
import { createHash } from 'node:crypto';
|
|
14
|
-
import {
|
|
14
|
+
import { relative, sep } from 'node:path';
|
|
15
|
+
import { LinkReportKey, LinkPath, PLATFORM_LINK_VERSION, RETICLE_URL_PARAM, parseLinkNotices, } from '@reticlehq/core';
|
|
15
16
|
import { pickDriveSession } from './remote-drive.js';
|
|
16
17
|
/** How often apps are reported. The platform counts an app live for two and a half of these. */
|
|
17
18
|
export const LOCAL_APPS_REPORT_MS = 10_000;
|
|
@@ -22,6 +23,15 @@ const APP_OPEN_POLL_MS = 250;
|
|
|
22
23
|
const KEY_LENGTH = 16;
|
|
23
24
|
/** The shell a plain browser tab reports: not worth a word on a card that says what it is built with. */
|
|
24
25
|
const WEB_RUNTIME = 'web';
|
|
26
|
+
/** `path` under `home` as `~/...`, so no home directory leaves the machine in a report. */
|
|
27
|
+
export function homeRelative(path, home) {
|
|
28
|
+
const inside = relative(home, path);
|
|
29
|
+
if (0 === inside.length)
|
|
30
|
+
return '~';
|
|
31
|
+
if (inside.startsWith('..') || inside.startsWith(sep) || /^[a-zA-Z]:/.test(inside))
|
|
32
|
+
return path;
|
|
33
|
+
return `~/${inside.split(sep).join('/')}`;
|
|
34
|
+
}
|
|
25
35
|
const hash = (text) => createHash('sha256').update(text).digest('hex').slice(0, KEY_LENGTH);
|
|
26
36
|
/** This machine: a stable id that is not its home path, and the name a person knows it by. */
|
|
27
37
|
export const machineOf = (hostname, home) => ({
|
|
@@ -65,7 +75,7 @@ export function mayOpen(url, openUrls) {
|
|
|
65
75
|
export const nameFromProjectId = (projectId) => projectId.replace(/-[0-9a-f]{8}$/, '');
|
|
66
76
|
const RETICLE_MARKS = new Set(Object.values(RETICLE_URL_PARAM));
|
|
67
77
|
/** The address as the app knows it: the params Reticle put on it to adopt a tab are not the app's. */
|
|
68
|
-
const withoutMarks = (raw) => {
|
|
78
|
+
export const withoutMarks = (raw) => {
|
|
69
79
|
try {
|
|
70
80
|
const url = new URL(raw);
|
|
71
81
|
for (const mark of [...url.searchParams.keys()])
|
|
@@ -77,6 +87,30 @@ const withoutMarks = (raw) => {
|
|
|
77
87
|
return raw;
|
|
78
88
|
}
|
|
79
89
|
};
|
|
90
|
+
/** Every channel either tab announced, once each; undefined when neither said. */
|
|
91
|
+
function mergedChannels(a, b) {
|
|
92
|
+
return a === undefined && b === undefined
|
|
93
|
+
? undefined
|
|
94
|
+
: [...new Set([...(a ?? []), ...(b ?? [])])];
|
|
95
|
+
}
|
|
96
|
+
/** Every gap either tab recorded, once per kind + missing, the first seen kept. */
|
|
97
|
+
function mergedGaps(a, b) {
|
|
98
|
+
const out = new Map();
|
|
99
|
+
for (const gap of [...(a ?? []), ...(b ?? [])]) {
|
|
100
|
+
const id = `${gap.kind}\u0000${gap.missing}`;
|
|
101
|
+
if (!out.has(id))
|
|
102
|
+
out.set(id, gap);
|
|
103
|
+
}
|
|
104
|
+
return [...out.values()];
|
|
105
|
+
}
|
|
106
|
+
/** `app` carrying the merged channels and gaps, omitting each when there is nothing to say. */
|
|
107
|
+
function withSeen(app, channels, gaps) {
|
|
108
|
+
return {
|
|
109
|
+
...app,
|
|
110
|
+
...(channels === undefined ? {} : { [LinkReportKey.CHANNELS]: channels }),
|
|
111
|
+
...(0 === gaps.length ? {} : { [LinkReportKey.GAPS]: gaps }),
|
|
112
|
+
};
|
|
113
|
+
}
|
|
80
114
|
/**
|
|
81
115
|
* The apps to report, grouped by the platform credential each one's project is linked with. The
|
|
82
116
|
* linked credential is reported even with no app open: it is how the chat knows the machine is there
|
|
@@ -100,8 +134,18 @@ export async function appsByPlatform(tabs, linked, machineId, describe) {
|
|
|
100
134
|
continue;
|
|
101
135
|
const key = appKeyOf(machineId, about.dir, tab.projectId);
|
|
102
136
|
const apps = group(about.platform).apps;
|
|
103
|
-
|
|
137
|
+
// Of two tabs of one app, the one that has seen the most speaks for it (a tie keeps the earlier,
|
|
138
|
+
// so a visible one still speaks over a hidden one). What they have SEEN is merged, so the setup
|
|
139
|
+
// score does not depend on which tab happened to report: a fresh tab opened beside a driven one
|
|
140
|
+
// once dropped it and locked the Harness.
|
|
141
|
+
const held = apps.get(key);
|
|
142
|
+
const channels = mergedChannels(held?.[LinkReportKey.CHANNELS], tab.channels);
|
|
143
|
+
const gaps = mergedGaps(held?.[LinkReportKey.GAPS], tab.gaps);
|
|
144
|
+
if (held !== undefined &&
|
|
145
|
+
(tab.channels?.length ?? 0) <= (held[LinkReportKey.CHANNELS]?.length ?? 0)) {
|
|
146
|
+
apps.set(key, withSeen(held, channels, gaps));
|
|
104
147
|
continue;
|
|
148
|
+
}
|
|
105
149
|
const stack = [
|
|
106
150
|
...new Set([...tab.adapters, ...(tab.runtime === undefined ? [] : [tab.runtime])]),
|
|
107
151
|
].filter((part) => WEB_RUNTIME !== part);
|
|
@@ -111,6 +155,12 @@ export async function appsByPlatform(tabs, linked, machineId, describe) {
|
|
|
111
155
|
url: withoutMarks(tab.url),
|
|
112
156
|
...(tab.title === undefined ? {} : { title: tab.title }),
|
|
113
157
|
stack,
|
|
158
|
+
...(tab.sdkVersion === undefined ? {} : { sdkVersion: tab.sdkVersion }),
|
|
159
|
+
...(0 === tab.adapters.length ? {} : { [LinkReportKey.ADAPTERS]: tab.adapters }),
|
|
160
|
+
...(tab.notApplicable === undefined
|
|
161
|
+
? {}
|
|
162
|
+
: { [LinkReportKey.NOT_APPLICABLE]: tab.notApplicable }),
|
|
163
|
+
...withSeen({}, channels, gaps),
|
|
114
164
|
});
|
|
115
165
|
}
|
|
116
166
|
return [...groups.values()].map(({ platform, apps }) => ({ platform, apps: [...apps.values()] }));
|
|
@@ -125,6 +175,7 @@ export function startAppReports(deps) {
|
|
|
125
175
|
return;
|
|
126
176
|
busy = true;
|
|
127
177
|
try {
|
|
178
|
+
const extras = (await deps.extras?.().catch(() => undefined)) ?? {};
|
|
128
179
|
for (const { platform, apps } of await deps.apps()) {
|
|
129
180
|
try {
|
|
130
181
|
const res = await doFetch(`${platform.url}${LinkPath.APPS}`, {
|
|
@@ -139,6 +190,15 @@ export function startAppReports(deps) {
|
|
|
139
190
|
protocol: PLATFORM_LINK_VERSION,
|
|
140
191
|
capabilities: deps.capabilities,
|
|
141
192
|
apps,
|
|
193
|
+
...(extras.devServers === undefined
|
|
194
|
+
? {}
|
|
195
|
+
: { [LinkReportKey.DEV_SERVERS]: extras.devServers }),
|
|
196
|
+
...(extras.helloFailure === undefined
|
|
197
|
+
? {}
|
|
198
|
+
: { [LinkReportKey.HELLO_FAILURE]: extras.helloFailure }),
|
|
199
|
+
...(extras.unsynced === undefined
|
|
200
|
+
? {}
|
|
201
|
+
: { [LinkReportKey.UNSYNCED]: extras.unsynced }),
|
|
142
202
|
}),
|
|
143
203
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
144
204
|
});
|
|
@@ -159,7 +219,7 @@ export function startAppReports(deps) {
|
|
|
159
219
|
continue;
|
|
160
220
|
open.add(key);
|
|
161
221
|
deps.log?.(`reticle: opening ${url}, asked for from the platform chat`);
|
|
162
|
-
await deps.open(url).catch((error) => {
|
|
222
|
+
await deps.open(url, key).catch((error) => {
|
|
163
223
|
deps.log?.(`reticle: could not open ${url}: ${String(error)}`);
|
|
164
224
|
});
|
|
165
225
|
}
|
|
@@ -180,8 +240,24 @@ export function startAppReports(deps) {
|
|
|
180
240
|
};
|
|
181
241
|
const timer = setInterval(() => void tick(), deps.intervalMs ?? LOCAL_APPS_REPORT_MS);
|
|
182
242
|
timer.unref();
|
|
183
|
-
|
|
243
|
+
const reports = {
|
|
244
|
+
tick,
|
|
245
|
+
stop: () => {
|
|
246
|
+
clearInterval(timer);
|
|
247
|
+
if (running === reports)
|
|
248
|
+
running = undefined;
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
running = reports;
|
|
252
|
+
return reports;
|
|
184
253
|
}
|
|
254
|
+
/** The daemon's running reports. ponytail: one per daemon, the last one started. */
|
|
255
|
+
let running;
|
|
256
|
+
/**
|
|
257
|
+
* Report now rather than on the next tick: the Harness gate just learned what an app's pages carry,
|
|
258
|
+
* and the platform, which locks a drive on its last report, would otherwise refuse on the old one.
|
|
259
|
+
*/
|
|
260
|
+
export const reportAppsNow = () => running?.tick() ?? Promise.resolve();
|
|
185
261
|
/**
|
|
186
262
|
* The tab a drive the chat attached to one app uses: a tab of that app and no other, even on the
|
|
187
263
|
* same port. None open: open the app, and wait for it to connect. Null when it never does.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The credentials a persona names, taken out of it before it leaves this machine.
|
|
3
|
+
*
|
|
4
|
+
* A persona that said "sign in as ana@acme.test, password: hunter2" was driven with the platform's
|
|
5
|
+
* default address and a 401, so every journey behind a login failed; and the persona travelled
|
|
6
|
+
* verbatim, so the password was stored in the synced run. The values become secret fields this
|
|
7
|
+
* machine fills (the platform types a placeholder for a field it knows only by name, see
|
|
8
|
+
* `server-driver.ts`), the password is redacted from the text, and the persona's own values win over
|
|
9
|
+
* a `RETICLE_SECRET_*` set in the environment, which wins over the platform's default.
|
|
10
|
+
*/
|
|
11
|
+
/** What stands in for a password in the text that is sent and stored. */
|
|
12
|
+
export declare const REDACTED_SECRET = "[redacted]";
|
|
13
|
+
export interface PersonaCredentials {
|
|
14
|
+
/** The persona with its password redacted: what may be sent to the platform and stored. */
|
|
15
|
+
persona: string;
|
|
16
|
+
/** Secret-field variables the drive fills from, persona values only. */
|
|
17
|
+
secrets: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
/** Take the email and password a persona names out of it. */
|
|
20
|
+
export declare function personaCredentials(persona: string): PersonaCredentials;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The credentials a persona names, taken out of it before it leaves this machine.
|
|
3
|
+
*
|
|
4
|
+
* A persona that said "sign in as ana@acme.test, password: hunter2" was driven with the platform's
|
|
5
|
+
* default address and a 401, so every journey behind a login failed; and the persona travelled
|
|
6
|
+
* verbatim, so the password was stored in the synced run. The values become secret fields this
|
|
7
|
+
* machine fills (the platform types a placeholder for a field it knows only by name, see
|
|
8
|
+
* `server-driver.ts`), the password is redacted from the text, and the persona's own values win over
|
|
9
|
+
* a `RETICLE_SECRET_*` set in the environment, which wins over the platform's default.
|
|
10
|
+
*/
|
|
11
|
+
/** The prefix a secret field's variable carries; the server driver reads the same. */
|
|
12
|
+
const SECRET_ENV_PREFIX = 'RETICLE_SECRET_';
|
|
13
|
+
/**
|
|
14
|
+
* The field names an email is offered under, as the platform derives them from a label.
|
|
15
|
+
* ponytail: the common sign-in labels only; a form labelled otherwise gets the platform's default.
|
|
16
|
+
*/
|
|
17
|
+
const EMAIL_FIELDS = ['EMAIL', 'EMAIL_ADDRESS', 'WORK_EMAIL', 'YOUR_EMAIL'];
|
|
18
|
+
const PASSWORD_FIELDS = [
|
|
19
|
+
'PASSWORD',
|
|
20
|
+
'CURRENT_PASSWORD',
|
|
21
|
+
'NEW_PASSWORD',
|
|
22
|
+
'CREATE_A_PASSWORD',
|
|
23
|
+
'CHOOSE_A_PASSWORD',
|
|
24
|
+
'CONFIRM_PASSWORD',
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* The person a persona is, when it opens with their name: "Nina Patel, who …". A sign-up form asks
|
|
28
|
+
* for it, and the Harness typed "reticle harness" into First name. Only a leading name followed by a
|
|
29
|
+
* comma counts; "an admin who …" names nobody and fills nothing.
|
|
30
|
+
*/
|
|
31
|
+
const NAME = /^\s*(\p{Lu}\p{Ll}+)(?:\s+(\p{Lu}\p{Ll}+))?\s*,/u;
|
|
32
|
+
/** What stands in for a password in the text that is sent and stored. */
|
|
33
|
+
export const REDACTED_SECRET = '[redacted]';
|
|
34
|
+
const EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/;
|
|
35
|
+
/**
|
|
36
|
+
* "password: x", "password is x", "password = x", a quoted value right after the word, or an
|
|
37
|
+
* unquoted one with a digit in it ("password Nina-pass-12345!"): a word with no digit after
|
|
38
|
+
* "password" is prose ("reset the password from the menu"), never a value.
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* An unquoted value stops at a closing bracket, and a sentence's full stop is not part of it:
|
|
42
|
+
* "(password: x!)" typed "x!)" and every sign-in was refused.
|
|
43
|
+
*/
|
|
44
|
+
const PASSWORD = /\bpass(?:word|code)\b(?:\s*(?::|=|\bis\b)\s*(?:"([^"\n]+)"|“([^”\n]+)”|([^\s"“,;()]+?)(?=\.?(?:\s|$|[,;)])))|\s+(?:"([^"\n]+)"|“([^”\n]+)”)|\s+([^\s"“,;()]*\d[^\s"“,;()]*?)(?=\.?(?:\s|$|[,;)])))/i;
|
|
45
|
+
/** Take the email and password a persona names out of it. */
|
|
46
|
+
export function personaCredentials(persona) {
|
|
47
|
+
const secrets = {};
|
|
48
|
+
const name = NAME.exec(persona);
|
|
49
|
+
if (name?.[1] !== undefined) {
|
|
50
|
+
const full = name[2] === undefined ? name[1] : `${name[1]} ${name[2]}`;
|
|
51
|
+
secrets[`${SECRET_ENV_PREFIX}FIRST_NAME`] = name[1];
|
|
52
|
+
secrets[`${SECRET_ENV_PREFIX}FULL_NAME`] = full;
|
|
53
|
+
secrets[`${SECRET_ENV_PREFIX}NAME`] = full;
|
|
54
|
+
if (name[2] !== undefined)
|
|
55
|
+
secrets[`${SECRET_ENV_PREFIX}LAST_NAME`] = name[2];
|
|
56
|
+
}
|
|
57
|
+
const email = EMAIL.exec(persona)?.[0];
|
|
58
|
+
if (email !== undefined)
|
|
59
|
+
for (const field of EMAIL_FIELDS)
|
|
60
|
+
secrets[`${SECRET_ENV_PREFIX}${field}`] = email;
|
|
61
|
+
const match = PASSWORD.exec(persona);
|
|
62
|
+
const password = match?.slice(1).find((group) => group !== undefined);
|
|
63
|
+
if (null === match || password === undefined)
|
|
64
|
+
return { persona, secrets };
|
|
65
|
+
for (const field of PASSWORD_FIELDS)
|
|
66
|
+
secrets[`${SECRET_ENV_PREFIX}${field}`] = password;
|
|
67
|
+
const redacted = match[0].replace(password, REDACTED_SECRET);
|
|
68
|
+
return { persona: persona.replace(match[0], redacted), secrets };
|
|
69
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two platform calls a drive needs outside its own turns: the grant that pays for a drive, and
|
|
3
|
+
* the run the platform kept once the local record is gone.
|
|
4
|
+
*
|
|
5
|
+
* Both answer with a value and never throw: an unreachable platform is a sentence to show, not a
|
|
6
|
+
* crash in the CLI or in the HUD's button handler.
|
|
7
|
+
*/
|
|
8
|
+
/** What the grant is for: `reticle try`'s one drive, or a drive started from the HUD or an agent. */
|
|
9
|
+
export declare const FreeDriveKind: {
|
|
10
|
+
readonly TRY: "try";
|
|
11
|
+
readonly EXPLORE: "explore";
|
|
12
|
+
};
|
|
13
|
+
export type FreeDriveKind = (typeof FreeDriveKind)[keyof typeof FreeDriveKind];
|
|
14
|
+
/** One HTTP request, narrowed so a test answers it without a network. */
|
|
15
|
+
export type PlatformFetch = (url: string, init: {
|
|
16
|
+
method: string;
|
|
17
|
+
headers: Record<string, string>;
|
|
18
|
+
body?: string;
|
|
19
|
+
}) => Promise<{
|
|
20
|
+
status: number;
|
|
21
|
+
text(): Promise<string>;
|
|
22
|
+
}>;
|
|
23
|
+
/** The drive the platform granted, or why it would not. */
|
|
24
|
+
export type FreeDrive = {
|
|
25
|
+
granted: true;
|
|
26
|
+
driveId: string;
|
|
27
|
+
} | {
|
|
28
|
+
granted: false;
|
|
29
|
+
needsCard: boolean;
|
|
30
|
+
message: string;
|
|
31
|
+
hint?: string;
|
|
32
|
+
};
|
|
33
|
+
interface Platform {
|
|
34
|
+
url: string;
|
|
35
|
+
apiKey: string;
|
|
36
|
+
}
|
|
37
|
+
/** The dashboard page where a trial starts, at the origin of whatever link the platform gave. */
|
|
38
|
+
export declare function planUrl(dashboard: string): string;
|
|
39
|
+
/** Ask the platform for a drive it will pay for. Every failure is an answer, never a throw. */
|
|
40
|
+
export declare function requestFreeDrive(platform: Platform, kind: FreeDriveKind, doFetch?: PlatformFetch): Promise<FreeDrive>;
|
|
41
|
+
/**
|
|
42
|
+
* A synced run as the explore poll answers it, in the poll's own fields.
|
|
43
|
+
*
|
|
44
|
+
* The platform serves the run file under `run` with the authoritative verdict (a review overturn
|
|
45
|
+
* wins) beside it — the dashboard's shape. The poll's agent needs the outcome and where it came from,
|
|
46
|
+
* not the whole file; `reticle runs <id>` prints the full answer for anyone who wants it.
|
|
47
|
+
*/
|
|
48
|
+
export declare function platformRunAnswer(runId: string, body: Record<string, unknown>): {
|
|
49
|
+
status: string;
|
|
50
|
+
runId: string;
|
|
51
|
+
summary: string;
|
|
52
|
+
};
|
|
53
|
+
/** Said when the platform has no such run: it may simply not have synced yet. */
|
|
54
|
+
export declare const msgRunNotOnPlatform: (runId: string) => string;
|
|
55
|
+
/** The platform's answer for one run (`{ run, verdict, grade, projectName, … }`), or why not. */
|
|
56
|
+
export declare function fetchPlatformRun(platform: Platform, runId: string, doFetch?: PlatformFetch): Promise<{
|
|
57
|
+
run: Record<string, unknown>;
|
|
58
|
+
} | {
|
|
59
|
+
error: string;
|
|
60
|
+
}>;
|
|
61
|
+
export {};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two platform calls a drive needs outside its own turns: the grant that pays for a drive, and
|
|
3
|
+
* the run the platform kept once the local record is gone.
|
|
4
|
+
*
|
|
5
|
+
* Both answer with a value and never throw: an unreachable platform is a sentence to show, not a
|
|
6
|
+
* crash in the CLI or in the HUD's button handler.
|
|
7
|
+
*/
|
|
8
|
+
const FREE_DRIVE_PATH = '/v1/harness/free-drive';
|
|
9
|
+
const RUNS_PATH = '/v1/runs';
|
|
10
|
+
const NEEDS_CARD = 'needs_card';
|
|
11
|
+
const HTTP_PAYMENT_REQUIRED = 402;
|
|
12
|
+
const HTTP_NOT_FOUND = 404;
|
|
13
|
+
/** Where a workspace starts its trial: the dashboard's billing settings, at its origin. */
|
|
14
|
+
const PLAN_PATH = '/settings?group=billing';
|
|
15
|
+
/** What the grant is for: `reticle try`'s one drive, or a drive started from the HUD or an agent. */
|
|
16
|
+
export const FreeDriveKind = { TRY: 'try', EXPLORE: 'explore' };
|
|
17
|
+
const defaultFetch = (url, init) => fetch(url, init);
|
|
18
|
+
const base = (platform) => platform.url.replace(/\/+$/, '');
|
|
19
|
+
const headers = (platform) => ({
|
|
20
|
+
'content-type': 'application/json',
|
|
21
|
+
authorization: `Bearer ${platform.apiKey}`,
|
|
22
|
+
});
|
|
23
|
+
function record(text) {
|
|
24
|
+
try {
|
|
25
|
+
const parsed = JSON.parse(text);
|
|
26
|
+
return 'object' === typeof parsed && null !== parsed ? parsed : {};
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return {};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
const str = (value) => ('string' === typeof value ? value : undefined);
|
|
33
|
+
/** The dashboard page where a trial starts, at the origin of whatever link the platform gave. */
|
|
34
|
+
export function planUrl(dashboard) {
|
|
35
|
+
try {
|
|
36
|
+
return `${new URL(dashboard).origin}${PLAN_PATH}`;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return `${dashboard.replace(/\/+$/, '')}${PLAN_PATH}`;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/** Ask the platform for a drive it will pay for. Every failure is an answer, never a throw. */
|
|
43
|
+
export async function requestFreeDrive(platform, kind, doFetch = defaultFetch) {
|
|
44
|
+
try {
|
|
45
|
+
const res = await doFetch(`${base(platform)}${FREE_DRIVE_PATH}`, {
|
|
46
|
+
method: 'POST',
|
|
47
|
+
headers: headers(platform),
|
|
48
|
+
body: JSON.stringify({ kind }),
|
|
49
|
+
});
|
|
50
|
+
const body = record(await res.text());
|
|
51
|
+
const driveId = str(body['driveId']);
|
|
52
|
+
if (true === body['granted'] && driveId !== undefined)
|
|
53
|
+
return { granted: true, driveId };
|
|
54
|
+
const message = str(body['message']) ??
|
|
55
|
+
`The Reticle platform did not grant a drive (it answered ${String(res.status)}).`;
|
|
56
|
+
const hint = str(body['hint']);
|
|
57
|
+
return {
|
|
58
|
+
granted: false,
|
|
59
|
+
needsCard: HTTP_PAYMENT_REQUIRED === res.status || NEEDS_CARD === body['error'],
|
|
60
|
+
message,
|
|
61
|
+
...(hint === undefined ? {} : { hint }),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
return {
|
|
66
|
+
granted: false,
|
|
67
|
+
needsCard: false,
|
|
68
|
+
message: `Could not reach the Reticle platform: ${error instanceof Error ? error.message : String(error)}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
const DRIVE_DONE = 'done';
|
|
73
|
+
const msgFromDashboard = (verdict, checks) => `From the dashboard (the drive itself is no longer on this machine): ${verdict === undefined ? 'no verdict recorded' : `verdict ${verdict}`}, ${String(checks)} check${1 === checks ? '' : 's'}.`;
|
|
74
|
+
/**
|
|
75
|
+
* A synced run as the explore poll answers it, in the poll's own fields.
|
|
76
|
+
*
|
|
77
|
+
* The platform serves the run file under `run` with the authoritative verdict (a review overturn
|
|
78
|
+
* wins) beside it — the dashboard's shape. The poll's agent needs the outcome and where it came from,
|
|
79
|
+
* not the whole file; `reticle runs <id>` prints the full answer for anyone who wants it.
|
|
80
|
+
*/
|
|
81
|
+
export function platformRunAnswer(runId, body) {
|
|
82
|
+
const run = body['run'];
|
|
83
|
+
const checks = 'object' === typeof run &&
|
|
84
|
+
null !== run &&
|
|
85
|
+
Array.isArray(run['checks'])
|
|
86
|
+
? run['checks'].length
|
|
87
|
+
: 0;
|
|
88
|
+
return { status: DRIVE_DONE, runId, summary: msgFromDashboard(str(body['verdict']), checks) };
|
|
89
|
+
}
|
|
90
|
+
/** Said when the platform has no such run: it may simply not have synced yet. */
|
|
91
|
+
export const msgRunNotOnPlatform = (runId) => `Run ${runId} is not on the Reticle platform: not synced yet, or not found.`;
|
|
92
|
+
/** The platform's answer for one run (`{ run, verdict, grade, projectName, … }`), or why not. */
|
|
93
|
+
export async function fetchPlatformRun(platform, runId, doFetch = defaultFetch) {
|
|
94
|
+
try {
|
|
95
|
+
const res = await doFetch(`${base(platform)}${RUNS_PATH}/${encodeURIComponent(runId)}`, {
|
|
96
|
+
method: 'GET',
|
|
97
|
+
headers: headers(platform),
|
|
98
|
+
});
|
|
99
|
+
if (HTTP_NOT_FOUND === res.status)
|
|
100
|
+
return { error: msgRunNotOnPlatform(runId) };
|
|
101
|
+
const body = record(await res.text());
|
|
102
|
+
if (200 > res.status || 300 <= res.status)
|
|
103
|
+
return {
|
|
104
|
+
error: str(body['message']) ??
|
|
105
|
+
`The Reticle platform answered ${String(res.status)} for ${runId}.`,
|
|
106
|
+
};
|
|
107
|
+
return { run: body };
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
return {
|
|
111
|
+
error: `Could not reach the Reticle platform: ${error instanceof Error ? error.message : String(error)}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every sentence the Harness refuses with, and the platform's refusal codes they answer.
|
|
3
|
+
*
|
|
4
|
+
* The recogniser that tells an agent "this is a deliberate refusal, here is the way out" rather than
|
|
5
|
+
* "this may be a defect in Reticle" used to match the PLATFORM's wording by regular expression. The
|
|
6
|
+
* platform reworded its lock ("Harness is locked. Setup score: …") and every locked Harness came back
|
|
7
|
+
* inviting a bug report. A refusal now carries the platform's CODE, the code picks a lead sentence
|
|
8
|
+
* owned here, and the recogniser matches these constants — never another repository's prose.
|
|
9
|
+
*/
|
|
10
|
+
/** The codes the platform's refusals carry (`{ error: { code, message } }`, or a flat `error`). */
|
|
11
|
+
export declare const PlatformRefusalCode: {
|
|
12
|
+
readonly HARNESS_OFF: "harness_off";
|
|
13
|
+
readonly HARNESS_LOCKED: "harness_locked";
|
|
14
|
+
readonly NEEDS_CARD: "needs_card";
|
|
15
|
+
};
|
|
16
|
+
/** The lead sentence each code's refusal opens with: what the agent reads, and what is recognised. */
|
|
17
|
+
export declare const RefusalLead: {
|
|
18
|
+
readonly harness_locked: "Reticle Harness is locked for this project.";
|
|
19
|
+
readonly harness_off: "The Reticle Harness is off for this project.";
|
|
20
|
+
readonly needs_card: "Reticle Harness credits are used up for this workspace.";
|
|
21
|
+
};
|
|
22
|
+
/** A platform refusal, read from its response body. Two shapes: nested `{ error: { code, message } }` and flat `{ error, message }`. */
|
|
23
|
+
export declare function readRefusal(text: string): {
|
|
24
|
+
code?: string;
|
|
25
|
+
message?: string;
|
|
26
|
+
};
|
|
27
|
+
/** The sentence a refusal is told in: the code's own lead, then the platform's words. */
|
|
28
|
+
export declare function refusalSentence(refusal: {
|
|
29
|
+
code?: string;
|
|
30
|
+
message?: string;
|
|
31
|
+
}, status: number): string;
|
|
32
|
+
/**
|
|
33
|
+
* What a person said about autonomous driving on the platform, honoured here.
|
|
34
|
+
*
|
|
35
|
+
* The switch existed, persisted and round-tripped, and the daemon read it and threw it away — so
|
|
36
|
+
* turning the harness OFF changed a value in a database and nothing else. A control that does not
|
|
37
|
+
* control anything is worse than no control: somebody turns it off, watches Reticle drive their app
|
|
38
|
+
* anyway, and now correctly distrusts every other switch in the product.
|
|
39
|
+
*
|
|
40
|
+
* Absent means OFF. The Harness is opt-in: a new project starts with it off, and an answer that does
|
|
41
|
+
* not say it is on is not a yes to spend credits on.
|
|
42
|
+
*/
|
|
43
|
+
export declare const MSG_HARNESS_DISABLED: string;
|
|
44
|
+
/**
|
|
45
|
+
* The other reason a drive can be refused, and it is NOT the same reason.
|
|
46
|
+
*
|
|
47
|
+
* A drive through the platform spends Reticle's model budget, bounded by the workspace's Harness
|
|
48
|
+
* credits. The platform answers this only when something other than the switch stops it.
|
|
49
|
+
*/
|
|
50
|
+
export declare const MSG_HARNESS_UNCLAIMED: string;
|
|
51
|
+
/** The platform could not be asked, and the drive would spend Reticle's budget without its yes. */
|
|
52
|
+
export declare const MSG_HARNESS_UNCONFIRMED: string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every sentence the Harness refuses with, and the platform's refusal codes they answer.
|
|
3
|
+
*
|
|
4
|
+
* The recogniser that tells an agent "this is a deliberate refusal, here is the way out" rather than
|
|
5
|
+
* "this may be a defect in Reticle" used to match the PLATFORM's wording by regular expression. The
|
|
6
|
+
* platform reworded its lock ("Harness is locked. Setup score: …") and every locked Harness came back
|
|
7
|
+
* inviting a bug report. A refusal now carries the platform's CODE, the code picks a lead sentence
|
|
8
|
+
* owned here, and the recogniser matches these constants — never another repository's prose.
|
|
9
|
+
*/
|
|
10
|
+
/** The codes the platform's refusals carry (`{ error: { code, message } }`, or a flat `error`). */
|
|
11
|
+
export const PlatformRefusalCode = {
|
|
12
|
+
HARNESS_OFF: 'harness_off',
|
|
13
|
+
HARNESS_LOCKED: 'harness_locked',
|
|
14
|
+
NEEDS_CARD: 'needs_card',
|
|
15
|
+
};
|
|
16
|
+
/** The lead sentence each code's refusal opens with: what the agent reads, and what is recognised. */
|
|
17
|
+
export const RefusalLead = {
|
|
18
|
+
[PlatformRefusalCode.HARNESS_LOCKED]: 'Reticle Harness is locked for this project.',
|
|
19
|
+
[PlatformRefusalCode.HARNESS_OFF]: 'The Reticle Harness is off for this project.',
|
|
20
|
+
[PlatformRefusalCode.NEEDS_CARD]: 'Reticle Harness credits are used up for this workspace.',
|
|
21
|
+
};
|
|
22
|
+
/** A platform refusal, read from its response body. Two shapes: nested `{ error: { code, message } }` and flat `{ error, message }`. */
|
|
23
|
+
export function readRefusal(text) {
|
|
24
|
+
try {
|
|
25
|
+
const body = JSON.parse(text);
|
|
26
|
+
const nested = 'object' === typeof body.error && null !== body.error
|
|
27
|
+
? body.error
|
|
28
|
+
: {};
|
|
29
|
+
const code = 'string' === typeof body.error ? body.error : nested.code;
|
|
30
|
+
const message = 'string' === typeof nested.message ? nested.message : body.message;
|
|
31
|
+
return {
|
|
32
|
+
...('string' === typeof code ? { code } : {}),
|
|
33
|
+
...('string' === typeof message ? { message } : {}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const leadOf = (code) => Object.entries(RefusalLead).find(([known]) => known === code)?.[1];
|
|
41
|
+
/** The sentence a refusal is told in: the code's own lead, then the platform's words. */
|
|
42
|
+
export function refusalSentence(refusal, status) {
|
|
43
|
+
const message = refusal.message ?? `the platform answered ${String(status)}`;
|
|
44
|
+
const lead = leadOf(refusal.code);
|
|
45
|
+
return lead === undefined || message.startsWith(lead) ? message : `${lead} ${message}`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* What a person said about autonomous driving on the platform, honoured here.
|
|
49
|
+
*
|
|
50
|
+
* The switch existed, persisted and round-tripped, and the daemon read it and threw it away — so
|
|
51
|
+
* turning the harness OFF changed a value in a database and nothing else. A control that does not
|
|
52
|
+
* control anything is worse than no control: somebody turns it off, watches Reticle drive their app
|
|
53
|
+
* anyway, and now correctly distrusts every other switch in the product.
|
|
54
|
+
*
|
|
55
|
+
* Absent means OFF. The Harness is opt-in: a new project starts with it off, and an answer that does
|
|
56
|
+
* not say it is on is not a yes to spend credits on.
|
|
57
|
+
*/
|
|
58
|
+
export const MSG_HARNESS_DISABLED = "The Reticle Harness is off for this project. The user can switch it on in the HUD's Settings " +
|
|
59
|
+
'or the Reticle dashboard (Settings → Projects → Reticle Harness on <project>); until then, drive the app yourself ' +
|
|
60
|
+
'through the MCP tools.';
|
|
61
|
+
/**
|
|
62
|
+
* The other reason a drive can be refused, and it is NOT the same reason.
|
|
63
|
+
*
|
|
64
|
+
* A drive through the platform spends Reticle's model budget, bounded by the workspace's Harness
|
|
65
|
+
* credits. The platform answers this only when something other than the switch stops it.
|
|
66
|
+
*/
|
|
67
|
+
export const MSG_HARNESS_UNCLAIMED = 'The Reticle platform says this workspace cannot drive the Harness right now, usually because its ' +
|
|
68
|
+
'credits are spent: see Settings → Plan in the Reticle dashboard.';
|
|
69
|
+
/** The platform could not be asked, and the drive would spend Reticle's budget without its yes. */
|
|
70
|
+
export const MSG_HARNESS_UNCONFIRMED = 'Could not confirm Harness access with the Reticle platform, so the drive did not start. Try ' +
|
|
71
|
+
'again in a moment.';
|
|
@@ -109,7 +109,7 @@ export interface RemoteDriveDeps {
|
|
|
109
109
|
/** How a session ask waits before it is sent again. */
|
|
110
110
|
sleep?: (ms: number) => Promise<void>;
|
|
111
111
|
/** Drive the app toward `goal`, in `sessionId`. A throw is reported as a failed drive, in its own words. */
|
|
112
|
-
drive: (goal: string, sessionId: string | undefined) => Promise<RemoteDriveOutcome>;
|
|
112
|
+
drive: (goal: string, sessionId: string | undefined, spec?: DriveSpec) => Promise<RemoteDriveOutcome>;
|
|
113
113
|
/**
|
|
114
114
|
* What the driven tab shows now, as a JPEG, or undefined when it cannot be captured (a tab this
|
|
115
115
|
* daemon did not launch). Absent: the drive runs with no picture, and the chat shows its steps.
|
|
@@ -146,7 +146,13 @@ export declare const NO_OWN_TAB = "No tab of this project is connected to Reticl
|
|
|
146
146
|
* daemon serves every project on the machine but polls with ONE credential, so without this a
|
|
147
147
|
* request made in project A drove project B's tab and sent pictures of it to A's chat.
|
|
148
148
|
*/
|
|
149
|
-
export declare function pickOwnDriveSession(tabs: readonly DriveCandidate[], goal: string, apiKey: string, keyOf: (sessionId: string) => Promise<string | undefined
|
|
149
|
+
export declare function pickOwnDriveSession(tabs: readonly DriveCandidate[], goal: string, apiKey: string, keyOf: (sessionId: string) => Promise<string | undefined>,
|
|
150
|
+
/**
|
|
151
|
+
* Open the project's app when none of its tabs is connected, and the session it opened. A
|
|
152
|
+
* dashboard Re-verify with the dev server up and no tab open was answered "Open this project's
|
|
153
|
+
* app, then ask again" by a daemon that knew the app's address.
|
|
154
|
+
*/
|
|
155
|
+
reopen?: () => Promise<string | undefined>): Promise<string | null>;
|
|
150
156
|
export interface DriveCandidate {
|
|
151
157
|
sessionId: string;
|
|
152
158
|
url: string;
|