@reticlehq/server 3.4.0 → 3.6.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 +16 -8
- package/dist/chromium-launch-options.d.ts +3 -1
- package/dist/chromium-launch-options.js +2 -1
- package/dist/command/cli/adhoc-verdict.d.ts +1 -0
- package/dist/command/cli/adhoc-verdict.js +6 -3
- 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/cloud-session.d.ts +4 -4
- package/dist/command/cli/auth/device-flow.d.ts +2 -2
- package/dist/command/cli/cli-flow-commands.js +4 -8
- package/dist/command/cli/cli-parse.d.ts +1 -1
- package/dist/command/cli/cli-parse.js +13 -11
- package/dist/command/cli/cli-verify.d.ts +1 -1
- package/dist/command/cli/cli-verify.js +35 -25
- package/dist/command/cli/cloud-cli.js +110 -12
- package/dist/command/cli/cloud-login.d.ts +9 -1
- package/dist/command/cli/cloud-login.js +43 -8
- package/dist/command/cli/demo/demo-page.js +11 -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/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/lifecycle/daemon-lifecycle.js +4 -1
- package/dist/command/cli/ports/port-holder.d.ts +10 -0
- package/dist/command/cli/ports/port-holder.js +24 -0
- package/dist/command/cli/setup-mcp-cli.js +15 -5
- package/dist/command/cli/tutorial.d.ts +2 -2
- package/dist/command/cli/tutorial.js +6 -9
- package/dist/command/cli.d.ts +6 -0
- package/dist/command/cli.js +45 -23
- 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-resolve.d.ts +14 -0
- package/dist/command/daemon/daemon-resolve.js +33 -2
- package/dist/command/setup/agent-writer.d.ts +1 -1
- package/dist/command/setup/agent-writer.js +3 -2
- 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-wait.d.ts +10 -0
- package/dist/command/setup/bringup/dev-server-wait.js +20 -1
- package/dist/command/setup/init/init-port.d.ts +4 -0
- package/dist/command/setup/init/init-port.js +10 -0
- package/dist/command/setup/init/init-runtime.d.ts +10 -0
- package/dist/command/setup/init/init-runtime.js +71 -9
- package/dist/command/setup/node-effects.js +8 -2
- package/dist/command/setup/remaining-steps.js +2 -1
- package/dist/command/setup/run-setup.d.ts +7 -0
- package/dist/command/setup/run-setup.js +38 -25
- package/dist/command/setup/setup-command.d.ts +2 -1
- package/dist/command/setup/setup-command.js +2 -0
- package/dist/command/setup/setup-mcp.d.ts +2 -0
- package/dist/command/setup/setup-mcp.js +14 -5
- package/dist/command/version/peer-announce.d.ts +6 -2
- package/dist/command/version/peer-announce.js +8 -6
- package/dist/command/version/version-nudge.d.ts +17 -3
- package/dist/command/version/version-nudge.js +25 -4
- package/dist/command/version/version-skew.js +11 -2
- package/dist/features/crawl/crawl-tools.js +4 -0
- package/dist/features/crawl/crawl.d.ts +6 -0
- package/dist/features/crawl/crawl.js +9 -1
- package/dist/features/exhaust/ledger.d.ts +7 -0
- 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 +27 -1
- package/dist/features/harness/drive-report.js +162 -11
- package/dist/features/harness/drivers.d.ts +10 -14
- package/dist/features/harness/drivers.js +10 -14
- package/dist/features/harness/fill-values.d.ts +3 -69
- package/dist/features/harness/fill-values.js +3 -133
- package/dist/features/harness/goals.d.ts +21 -0
- package/dist/features/harness/goals.js +77 -0
- package/dist/features/harness/harness.d.ts +21 -0
- package/dist/features/harness/harness.js +69 -2
- 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 +94 -0
- package/dist/features/harness/platform/local-apps.js +204 -0
- package/dist/features/harness/platform/remote-drive.d.ts +180 -0
- package/dist/features/harness/platform/remote-drive.js +365 -0
- package/dist/features/harness/platform/script.d.ts +48 -0
- package/dist/features/harness/platform/script.js +128 -0
- package/dist/features/harness/platform/server-driver.d.ts +41 -0
- package/dist/features/harness/platform/server-driver.js +179 -0
- package/dist/features/harness/platform-config.d.ts +7 -0
- package/dist/features/harness/platform-config.js +14 -2
- 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 +41 -0
- package/dist/features/harness/script/script-run.js +299 -0
- package/dist/features/license/license.d.ts +2 -2
- package/dist/features/visual/visual-tools.d.ts +10 -1
- package/dist/features/visual/visual-tools.js +40 -3
- package/dist/hooks/driven-by.d.ts +4 -0
- package/dist/hooks/driven-by.js +16 -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 +1 -0
- package/dist/index.js +91 -89
- package/dist/judgement/capsule/capsule-store.d.ts +4 -4
- package/dist/judgement/runs/artifact/build-verification-run.js +6 -0
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
- package/dist/judgement/runs/artifact/replay-mapping.js +16 -6
- package/dist/judgement/runs/artifact/run-store.d.ts +1 -1
- package/dist/judgement/runs/artifact/run-store.js +26 -1
- package/dist/judgement/runs/drive-run.d.ts +22 -0
- package/dist/judgement/runs/drive-run.js +99 -1
- package/dist/judgement/runs/repair-prompt.js +1 -1
- package/dist/judgement/runs/reticle-runner.js +8 -1
- package/dist/judgement/runs/verification-sync.d.ts +3 -2
- package/dist/judgement/runs/verification-sync.js +4 -3
- 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 +34 -0
- package/dist/language/flows/flow-anchor.d.ts +54 -8
- package/dist/language/flows/flow-anchor.js +88 -3
- 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-learning.js +8 -11
- 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 +101 -94
- package/dist/language/flows/flow-replay.d.ts +23 -1
- package/dist/language/flows/flow-replay.js +92 -19
- package/dist/language/flows/flow-scope.js +5 -1
- package/dist/language/flows/flow-step-runners.d.ts +20 -2
- package/dist/language/flows/flow-step-runners.js +236 -42
- package/dist/language/flows/flow-store-for-session.d.ts +2 -2
- package/dist/language/flows/flow-store-for-session.js +2 -2
- package/dist/language/flows/flow-tools.js +58 -34
- package/dist/language/flows/flows.js +5 -2
- package/dist/language/flows/heal-run.js +6 -4
- package/dist/language/flows/recording/flake.d.ts +2 -2
- package/dist/language/flows/recording/tape/recordings.d.ts +30 -4
- package/dist/language/flows/recording/tape/recordings.js +40 -8
- 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 +27 -9
- 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.js +8 -4
- package/dist/launch-chromium.d.ts +27 -5
- package/dist/launch-chromium.js +38 -8
- package/dist/memory/cloud/cloud-config.d.ts +12 -0
- package/dist/memory/cloud/cloud-config.js +15 -0
- package/dist/memory/cloud/cloud-sync.d.ts +17 -14
- package/dist/memory/cloud/cloud-sync.js +12 -1
- package/dist/memory/cloud/harness-config.d.ts +26 -1
- package/dist/memory/cloud/harness-config.js +99 -4
- 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 +144 -0
- package/dist/memory/cloud/memory-scope.js +205 -0
- package/dist/memory/cloud/sync-cycle.d.ts +21 -3
- package/dist/memory/cloud/sync-cycle.js +45 -5
- package/dist/memory/cloud/sync-daemon.js +7 -5
- package/dist/memory/cloud/sync-disk.d.ts +1 -1
- package/dist/memory/cloud/sync-disk.js +5 -8
- package/dist/memory/impact/account-watch.d.ts +19 -0
- package/dist/memory/impact/account-watch.js +34 -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 +16 -0
- package/dist/memory/impact/impact-store.js +142 -26
- package/dist/memory/intent/intent-shard.d.ts +2 -2
- package/dist/memory/intent/intent-tools.js +88 -5
- package/dist/memory/journal/envelope.d.ts +16 -16
- package/dist/memory/journal/journal-query.d.ts +14 -0
- package/dist/memory/journal/journal-query.js +15 -0
- package/dist/memory/journal/journal-recorder.js +7 -1
- package/dist/memory/journal/on-disk/retention.d.ts +3 -0
- package/dist/memory/journal/on-disk/retention.js +5 -0
- package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
- package/dist/memory/journal/on-disk/workspace-tiers.js +7 -4
- package/dist/memory/journal/session-end.js +6 -4
- package/dist/memory/project/artifact-root-resolver.d.ts +36 -1
- package/dist/memory/project/artifact-root-resolver.js +134 -26
- package/dist/memory/project/artifact-root.d.ts +42 -5
- package/dist/memory/project/artifact-root.js +87 -8
- package/dist/memory/project/dir/reticle-dir.d.ts +4 -2
- package/dist/memory/project/dir/reticle-dir.js +3 -1
- package/dist/memory/project/project-tools.js +22 -3
- package/dist/memory/project/session-root.d.ts +24 -1
- package/dist/memory/project/session-root.js +41 -5
- package/dist/memory/project/sync-status.d.ts +39 -0
- package/dist/memory/project/sync-status.js +90 -0
- package/dist/memory/recall/memory-tools.js +2 -0
- package/dist/memory/recall/project-memory.d.ts +19 -0
- package/dist/memory/recall/project-memory.js +45 -6
- package/dist/portal/bridge/bridge.d.ts +7 -4
- package/dist/portal/bridge/bridge.js +25 -3
- package/dist/portal/bridge/pairing-token.d.ts +9 -0
- package/dist/portal/bridge/pairing-token.js +17 -0
- package/dist/portal/input/real-input.d.ts +81 -10
- package/dist/portal/input/real-input.js +207 -22
- package/dist/portal/input/viewport-tools.js +19 -9
- package/dist/portal/pool/browser-pool.d.ts +22 -9
- package/dist/portal/pool/browser-pool.js +70 -35
- package/dist/portal/pool/playwright-launcher.d.ts +13 -0
- package/dist/portal/pool/playwright-launcher.js +17 -1
- package/dist/portal/pool/pool-contract.d.ts +7 -4
- package/dist/portal/session/command-payload.d.ts +8 -0
- package/dist/portal/session/command-payload.js +19 -0
- package/dist/portal/session/dev-server/dev-command.d.ts +12 -0
- package/dist/portal/session/dev-server/dev-command.js +61 -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/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/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 +28 -3
- package/dist/portal/session/no-session-diagnosis.d.ts +7 -0
- package/dist/portal/session/no-session-diagnosis.js +15 -0
- package/dist/portal/session/no-session-next-action.d.ts +11 -0
- package/dist/portal/session/no-session-next-action.js +31 -5
- package/dist/portal/session/no-session-watch.d.ts +14 -1
- package/dist/portal/session/no-session-watch.js +63 -10
- package/dist/portal/session/presence/session-mirror.js +3 -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 +7 -0
- package/dist/portal/session/session-health.js +6 -0
- package/dist/portal/session/session-info.d.ts +8 -1
- package/dist/portal/session/session-info.js +6 -0
- package/dist/portal/session/session-manager.d.ts +21 -0
- package/dist/portal/session/session-manager.js +44 -8
- package/dist/portal/session/session-reaper.js +4 -1
- package/dist/portal/session/session-successor.d.ts +5 -0
- package/dist/portal/session/session-tools.js +26 -3
- package/dist/portal/session/session.d.ts +12 -10
- package/dist/portal/session/session.js +30 -31
- package/dist/start-options.d.ts +6 -0
- package/dist/status-payload.d.ts +10 -0
- package/dist/status-payload.js +23 -0
- package/dist/surface/http-server.d.ts +1 -1
- package/dist/surface/http-server.js +15 -4
- package/dist/surface/mcp/mcp-proxy.d.ts +5 -0
- package/dist/surface/mcp/mcp-proxy.js +36 -5
- package/dist/surface/mcp/mcp.d.ts +11 -6
- package/dist/surface/mcp/mcp.js +28 -14
- package/dist/surface/mcp/proxy/proxy-log.js +3 -5
- package/dist/surface/mcp/server-instructions.d.ts +4 -2
- package/dist/surface/mcp/server-instructions.js +14 -4
- package/dist/surface/mcp/shared-params.js +2 -2
- 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/settle-in-flight.js +25 -3
- package/dist/surface/tools/act-sequence-tool.js +2 -2
- package/dist/surface/tools/act-tools.js +25 -9
- package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
- package/dist/surface/tools/assert/assert-verdict.js +17 -2
- package/dist/surface/tools/browser-tools.js +8 -1
- package/dist/surface/tools/chat-drives.d.ts +26 -0
- package/dist/surface/tools/chat-drives.js +165 -0
- package/dist/surface/tools/dynamic-tools.js +29 -2
- package/dist/surface/tools/empty-session-list.d.ts +41 -0
- package/dist/surface/tools/empty-session-list.js +80 -0
- package/dist/surface/tools/error-recovery.d.ts +6 -0
- package/dist/surface/tools/error-recovery.js +38 -6
- package/dist/surface/tools/explore-tools.d.ts +10 -1
- package/dist/surface/tools/explore-tools.js +82 -13
- package/dist/surface/tools/feedback-tools.js +14 -0
- package/dist/surface/tools/harness-explore.d.ts +96 -14
- package/dist/surface/tools/harness-explore.js +227 -202
- package/dist/surface/tools/harness-plan.d.ts +12 -0
- package/dist/surface/tools/harness-plan.js +31 -0
- package/dist/surface/tools/harness-script.d.ts +8 -0
- package/dist/surface/tools/harness-script.js +342 -0
- package/dist/surface/tools/harness-toolset.d.ts +14 -1
- package/dist/surface/tools/harness-toolset.js +77 -6
- package/dist/surface/tools/invoke-tool.js +64 -9
- package/dist/surface/tools/lease-seed.d.ts +29 -0
- package/dist/surface/tools/lease-seed.js +123 -0
- package/dist/surface/tools/lease-tools.d.ts +3 -23
- package/dist/surface/tools/lease-tools.js +30 -131
- package/dist/surface/tools/live-call-text.js +2 -2
- package/dist/surface/tools/next-step.d.ts +19 -0
- package/dist/surface/tools/next-step.js +159 -0
- package/dist/surface/tools/observe-tools.js +2 -4
- package/dist/surface/tools/platform-moment.d.ts +12 -0
- package/dist/surface/tools/platform-moment.js +168 -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 +8 -2
- package/dist/surface/tools/real-input-attempt.js +96 -13
- package/dist/surface/tools/tool-kit.d.ts +25 -1
- package/dist/surface/tools/tool-kit.js +4 -6
- package/dist/surface/tools/tools.js +20 -48
- package/dist/telemetry/argument-shape.js +1 -1
- package/dist/telemetry/hud-metrics.d.ts +2 -0
- package/dist/telemetry/hud-metrics.js +17 -0
- package/dist/telemetry/onboarding-firsts.d.ts +2 -2
- package/dist/telemetry/onboarding-firsts.js +2 -2
- package/dist/telemetry/telemetry.d.ts +12 -0
- package/dist/telemetry/telemetry.js +43 -14
- package/dist/telemetry/verification-of.js +1 -0
- package/dist/wire-journal.js +4 -1
- package/docs/README.md +1 -1
- package/docs/actions.mdx +1 -2
- package/docs/agent-cheatsheet.md +1 -1
- package/docs/autodrive.md +29 -25
- package/docs/cli/cloud.mdx +6 -4
- package/docs/cli/doctor.mdx +6 -0
- package/docs/cli/drive.mdx +8 -2
- package/docs/cli/init.mdx +11 -13
- package/docs/cli/status.mdx +5 -1
- package/docs/cli/version.mdx +3 -3
- package/docs/cli.mdx +14 -8
- package/docs/desktop.mdx +5 -1
- package/docs/environment.mdx +3 -7
- package/docs/getting-started.md +14 -2
- package/docs/human-control.md +1 -2
- package/docs/index.mdx +4 -3
- package/docs/install-agentic.mdx +1 -1
- package/docs/install-manual.mdx +2 -2
- package/docs/packages/next.mdx +3 -0
- package/docs/packages/tauri.mdx +2 -2
- package/docs/packages/vite-plugin.mdx +24 -1
- package/docs/packages.mdx +1 -1
- package/docs/quickstart.mdx +23 -11
- package/docs/telemetry.md +1 -1
- package/docs/tools/act.mdx +1 -1
- package/docs/tools/session-and-feedback.mdx +9 -9
- package/docs/usage.md +5 -3
- package/docs/what-is-recorded.md +13 -3
- package/docs/what-is-reticle.mdx +3 -1
- package/package.json +8 -12
- 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 -46
- package/dist/features/harness/openai-driver.js +0 -194
- package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
- package/dist/memory/project/dir/fill-value-store.js +0 -88
- package/docs/local-registry.md +0 -143
|
@@ -9,12 +9,16 @@ import { HudPanel, HudView } from '@reticlehq/core';
|
|
|
9
9
|
*/
|
|
10
10
|
/** How many steps of the journey one window keeps. A journey longer than this is cut, and says so. */
|
|
11
11
|
export const HUD_JOURNEY_MAX = 60;
|
|
12
|
+
/** Distinct slide ids counted per window; past this a broken notices file is not a dashboard. */
|
|
13
|
+
const MAX_SLIDE_IDS = 20;
|
|
14
|
+
const SLIDE_ID = /^[a-z0-9-]{1,56}$/;
|
|
12
15
|
export class HudMetrics {
|
|
13
16
|
#now;
|
|
14
17
|
#controls = new Map();
|
|
15
18
|
#viewMs = new Map();
|
|
16
19
|
#panelMs = new Map();
|
|
17
20
|
#journey = [];
|
|
21
|
+
#slides = new Map();
|
|
18
22
|
#cut = false;
|
|
19
23
|
/** Did anything happen this window. A HUD merely sitting open is not worth a flush of its own. */
|
|
20
24
|
#changed = false;
|
|
@@ -27,6 +31,8 @@ export class HudMetrics {
|
|
|
27
31
|
// A control the HUD never rendered is dropped here, the one place HUD use is counted, so free
|
|
28
32
|
// text cannot ride in on the id.
|
|
29
33
|
const control = use.control !== undefined && isHudControl(use.control) ? use.control : undefined;
|
|
34
|
+
if (use.slide !== undefined)
|
|
35
|
+
this.#countSlide(use.slide);
|
|
30
36
|
if (control === undefined && use.view === undefined && use.panel === undefined)
|
|
31
37
|
return;
|
|
32
38
|
this.#changed = true;
|
|
@@ -47,6 +53,15 @@ export class HudMetrics {
|
|
|
47
53
|
this.#step(`panel:${use.panel}`);
|
|
48
54
|
}
|
|
49
55
|
}
|
|
56
|
+
#countSlide(slide) {
|
|
57
|
+
// A slide id is Reticle's own (`notice-<id>` for the remote ones): lowercase words and dashes.
|
|
58
|
+
if (!SLIDE_ID.test(slide))
|
|
59
|
+
return;
|
|
60
|
+
if (!this.#slides.has(slide) && this.#slides.size >= MAX_SLIDE_IDS)
|
|
61
|
+
return;
|
|
62
|
+
this.#slides.set(slide, (this.#slides.get(slide) ?? 0) + 1);
|
|
63
|
+
this.#changed = true;
|
|
64
|
+
}
|
|
50
65
|
get empty() {
|
|
51
66
|
return !this.#changed;
|
|
52
67
|
}
|
|
@@ -60,12 +75,14 @@ export class HudMetrics {
|
|
|
60
75
|
...(panelMs.size > 0 ? { hudPanelMs: Object.fromEntries(panelMs) } : {}),
|
|
61
76
|
...(this.#journey.length > 0 ? { hudJourney: [...this.#journey] } : {}),
|
|
62
77
|
...(this.#cut ? { hudJourneyCut: true } : {}),
|
|
78
|
+
...(this.#slides.size > 0 ? { hudSlides: Object.fromEntries(this.#slides) } : {}),
|
|
63
79
|
};
|
|
64
80
|
}
|
|
65
81
|
/** Start the next window. The current view and panel carry over, timed from now. */
|
|
66
82
|
reset() {
|
|
67
83
|
const at = this.#now();
|
|
68
84
|
this.#controls.clear();
|
|
85
|
+
this.#slides.clear();
|
|
69
86
|
this.#viewMs.clear();
|
|
70
87
|
this.#panelMs.clear();
|
|
71
88
|
this.#journey.length = 0;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/** A
|
|
1
|
+
/** A successful page read. The dispatcher calls this after excluding refusals and pauses. */
|
|
2
2
|
export declare function noteOnboardingFirst(toolName: string): void;
|
|
3
3
|
/**
|
|
4
4
|
* The first ACTION of this run, and the fact that this install has been driven at all.
|
|
5
5
|
*
|
|
6
|
-
* Called
|
|
6
|
+
* Called after the dispatcher observes a dispatched action, rather than on an attempted call.
|
|
7
7
|
* The name test was `toolName === ReticleTool.ACT`, on the worry that `act_and_wait` would report
|
|
8
8
|
* one call as two different firsts — and the worry was backwards: this server's instructions tell
|
|
9
9
|
* every agent to PREFER `act_and_wait`, so the step measured the tool we ask agents not to use and
|
|
@@ -15,7 +15,7 @@ import { reportOnboardingStep } from './onboarding-funnel.js';
|
|
|
15
15
|
* drives in another has still only crossed each of these once.
|
|
16
16
|
*/
|
|
17
17
|
const seen = { look: false, act: false, verdict: false, driven: false };
|
|
18
|
-
/** A
|
|
18
|
+
/** A successful page read. The dispatcher calls this after excluding refusals and pauses. */
|
|
19
19
|
export function noteOnboardingFirst(toolName) {
|
|
20
20
|
if (!seen.look && LOOK_TOOLS.has(toolName)) {
|
|
21
21
|
seen.look = true;
|
|
@@ -29,7 +29,7 @@ export function noteOnboardingFirst(toolName) {
|
|
|
29
29
|
/**
|
|
30
30
|
* The first ACTION of this run, and the fact that this install has been driven at all.
|
|
31
31
|
*
|
|
32
|
-
* Called
|
|
32
|
+
* Called after the dispatcher observes a dispatched action, rather than on an attempted call.
|
|
33
33
|
* The name test was `toolName === ReticleTool.ACT`, on the worry that `act_and_wait` would report
|
|
34
34
|
* one call as two different firsts — and the worry was backwards: this server's instructions tell
|
|
35
35
|
* every agent to PREFER `act_and_wait`, so the step measured the tool we ask agents not to use and
|
|
@@ -10,6 +10,18 @@ import { TelemetryEventKind, ProjectIdSource, type Crash, type Feedback, type Id
|
|
|
10
10
|
* analytics side learns a customer list only when we deliberately upload one.
|
|
11
11
|
*/
|
|
12
12
|
export declare const POSTHOG_GROUP_ORGANIZATION = "organization";
|
|
13
|
+
/**
|
|
14
|
+
* Read (or mint-and-persist) the anonymous machine id. `firstRun` is true the run that created it.
|
|
15
|
+
*
|
|
16
|
+
* Read first and create exclusively (`wx`), rather than asking `existsSync` and then writing: two
|
|
17
|
+
* processes starting together used to both see no file, both mint, and the second write replaced
|
|
18
|
+
* the first id, so one machine reported as two first runs. The loser of the exclusive create now
|
|
19
|
+
* reads the winner's id instead.
|
|
20
|
+
*/
|
|
21
|
+
export declare const resolveIdentity: (file?: string) => {
|
|
22
|
+
anonymousId: string;
|
|
23
|
+
firstRun: boolean;
|
|
24
|
+
};
|
|
13
25
|
/**
|
|
14
26
|
* One-way project fingerprint: distinct-count of this = "projects Reticle is used in", reveals nothing.
|
|
15
27
|
*
|
|
@@ -19,6 +19,7 @@ import { appendFileSync, readFileSync, writeFileSync, mkdirSync, existsSync, rmS
|
|
|
19
19
|
import { homedir, platform } from 'node:os';
|
|
20
20
|
import { dirname, join } from 'node:path';
|
|
21
21
|
import { TelemetryEventKind, TELEMETRY_EVENT_VERSION, ProjectIdSource, isSessionScoped, } from '@reticlehq/core/telemetry';
|
|
22
|
+
import { ReticleEnv } from '@reticlehq/core';
|
|
22
23
|
import { SERVER_VERSION } from '../command/version/identity/server-version.js';
|
|
23
24
|
const RETICLE_DIR = join(homedir(), '.reticle');
|
|
24
25
|
const ID_FILE = join(RETICLE_DIR, 'telemetry-id');
|
|
@@ -100,8 +101,8 @@ import { licenseFacts } from './license-activation.js';
|
|
|
100
101
|
import { gitFacts } from './git-facts.js';
|
|
101
102
|
import { currentAutomationHint } from './automation-hint.js';
|
|
102
103
|
const Env = {
|
|
103
|
-
DISABLE:
|
|
104
|
-
DO_NOT_TRACK:
|
|
104
|
+
DISABLE: ReticleEnv.TELEMETRY, // "0" / "false" / "off" → disabled
|
|
105
|
+
DO_NOT_TRACK: ReticleEnv.DO_NOT_TRACK, // the cross-tool opt-out convention (any truthy value)
|
|
105
106
|
URL: 'RETICLE_TELEMETRY_URL', // override the PostHog host (EU cloud / self-hosted)
|
|
106
107
|
FILE: 'RETICLE_TELEMETRY_FILE', // record to a local JSONL file and send NOTHING — see the sink note
|
|
107
108
|
KEY: 'RETICLE_TELEMETRY_KEY', // override the PostHog project key
|
|
@@ -140,17 +141,45 @@ const isDisabled = (env, cwd = process.cwd()) => {
|
|
|
140
141
|
* file, and a test run. This lifts one implicit guard for one user-initiated event kind.
|
|
141
142
|
*/
|
|
142
143
|
const onlyBlockedBySourceCheckout = (env, cwd) => isDisabled(env, cwd) && !isDisabled(env, '/');
|
|
143
|
-
/**
|
|
144
|
-
const
|
|
144
|
+
/** Node's code for "the file is already there" — what an exclusive create answers when it lost. */
|
|
145
|
+
const EEXIST = 'EEXIST';
|
|
146
|
+
const isAlreadyThere = (error) => 'object' === typeof error && null !== error && EEXIST === error.code;
|
|
147
|
+
const readIdFile = (file) => {
|
|
145
148
|
try {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
149
|
+
const id = readFileSync(file, 'utf8').trim();
|
|
150
|
+
return id.length > 0 ? id : undefined;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
/**
|
|
157
|
+
* Read (or mint-and-persist) the anonymous machine id. `firstRun` is true the run that created it.
|
|
158
|
+
*
|
|
159
|
+
* Read first and create exclusively (`wx`), rather than asking `existsSync` and then writing: two
|
|
160
|
+
* processes starting together used to both see no file, both mint, and the second write replaced
|
|
161
|
+
* the first id, so one machine reported as two first runs. The loser of the exclusive create now
|
|
162
|
+
* reads the winner's id instead.
|
|
163
|
+
*/
|
|
164
|
+
export const resolveIdentity = (file = ID_FILE) => {
|
|
165
|
+
try {
|
|
166
|
+
const existing = readIdFile(file);
|
|
167
|
+
if (existing !== undefined)
|
|
168
|
+
return { anonymousId: existing, firstRun: false };
|
|
151
169
|
const id = randomUUID();
|
|
152
|
-
mkdirSync(
|
|
153
|
-
|
|
170
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
171
|
+
try {
|
|
172
|
+
writeFileSync(file, id, { encoding: 'utf8', flag: 'wx' });
|
|
173
|
+
}
|
|
174
|
+
catch (error) {
|
|
175
|
+
if (!isAlreadyThere(error))
|
|
176
|
+
throw error;
|
|
177
|
+
const raced = readIdFile(file);
|
|
178
|
+
if (raced !== undefined)
|
|
179
|
+
return { anonymousId: raced, firstRun: false };
|
|
180
|
+
// An empty file left by a crash: replace it, as the old code did.
|
|
181
|
+
writeFileSync(file, id, 'utf8');
|
|
182
|
+
}
|
|
154
183
|
return { anonymousId: id, firstRun: true };
|
|
155
184
|
}
|
|
156
185
|
catch {
|
|
@@ -209,10 +238,10 @@ const packageRoot = (cwd) => {
|
|
|
209
238
|
/** Print the opt-out notice exactly once per machine (honest disclosure, the OSS-trust bar). */
|
|
210
239
|
const showNoticeOnce = () => {
|
|
211
240
|
try {
|
|
212
|
-
if (existsSync(NOTICE_FILE))
|
|
213
|
-
return;
|
|
214
241
|
mkdirSync(RETICLE_DIR, { recursive: true });
|
|
215
|
-
|
|
242
|
+
// Exclusive create IS the "once": it throws when the file is already there, so the check and
|
|
243
|
+
// the write cannot be split by a second process printing the notice too.
|
|
244
|
+
writeFileSync(NOTICE_FILE, '1', { encoding: 'utf8', flag: 'wx' });
|
|
216
245
|
process.stderr.write('reticle: anonymous usage telemetry helps improve reticle — no code, no PII, ' +
|
|
217
246
|
`and your app's data never leaves your machine (${POLICY_URL}). ` +
|
|
218
247
|
'Opt out any time: reticle telemetry disable\n');
|
|
@@ -70,6 +70,7 @@ const REPLAY_VERDICTS = new Map([
|
|
|
70
70
|
[ReplayStatus.OK, { verified: Verified.YES, passed: true }],
|
|
71
71
|
[ReplayStatus.DRIFT, { verified: Verified.NO, passed: false }],
|
|
72
72
|
[ReplayStatus.ERROR, { verified: Verified.UNKNOWN, passed: false }],
|
|
73
|
+
[ReplayStatus.UNVERIFIABLE, { verified: Verified.UNKNOWN, passed: false }],
|
|
73
74
|
]);
|
|
74
75
|
function replayVerdict(toolName, status) {
|
|
75
76
|
if (ReticleTool.FLOW_REPLAY !== toolName || 'string' !== typeof status)
|
package/dist/wire-journal.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* the 1000-line backstop is what asked for the split.
|
|
9
9
|
*/
|
|
10
10
|
import { artifactRootResolver } from './memory/project/artifact-root-resolver.js';
|
|
11
|
+
import { servingDirectoryOf } from './portal/session/serving-directory.js';
|
|
11
12
|
import { originOf } from './portal/session/session-manager.js';
|
|
12
13
|
import { Bridge } from './portal/bridge/bridge.js';
|
|
13
14
|
import { FlowStore } from './language/flows/flows.js';
|
|
@@ -35,7 +36,9 @@ export function attachJournal(bridge, deps) {
|
|
|
35
36
|
const ambientStore = new AmbientStore(deps.fs, deps.reticleRoot);
|
|
36
37
|
// Built once, not per session: the resolver walks config discovery and the user-level registry,
|
|
37
38
|
// and neither changes between two tabs connecting a second apart.
|
|
38
|
-
const resolveArtifactRoot = artifactRootResolver(deps.reticleRoot
|
|
39
|
+
const resolveArtifactRoot = artifactRootResolver(deps.reticleRoot, {
|
|
40
|
+
servingDirectory: servingDirectoryOf,
|
|
41
|
+
});
|
|
39
42
|
bridge.attachSessionCreate((session) => {
|
|
40
43
|
// Stamp the project's own `.reticle` before ANY counter fires for this session. Without it every
|
|
41
44
|
// verdict is recorded against wherever the daemon was started, which is how one app's evidence
|
package/docs/README.md
CHANGED
|
@@ -76,7 +76,7 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
|
|
|
76
76
|
| [vs-screenshots.mdx](vs-screenshots.mdx) | why a better vision model does not fix a non-visual bug |
|
|
77
77
|
| [what-is-recorded.md](what-is-recorded.md) | what Reticle keeps, what is redacted, and what it takes for any of it to leave your machine |
|
|
78
78
|
| [telemetry.md](telemetry.md) | what is collected, and how to turn it off |
|
|
79
|
-
| [local-registry.md](local-registry.md) | installing an unpublished build |
|
|
79
|
+
| [local-registry.md](https://github.com/reticlehq/reticle/blob/main/docs/local-registry.md) | installing an unpublished build |
|
|
80
80
|
| [license-activation.mdx](license-activation.mdx) | you have a key: where to set it, how to confirm it, what to do when it fails |
|
|
81
81
|
| [enterprise.md](enterprise.md) | the licensed surface |
|
|
82
82
|
|
package/docs/actions.mdx
CHANGED
|
@@ -5,7 +5,7 @@ description: Every action reticle_act and reticle_act_and_wait can perform, with
|
|
|
5
5
|
icon: hand-pointer
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
Every action Reticle can perform takes the same shape: a `ref` from [`reticle_look { action: "page" }`](/tools/snapshot) or [`reticle_look { action: "find" }`](/tools/query), an `action` name, and an optional `args` object. The same
|
|
8
|
+
Every action Reticle can perform takes the same shape: a `ref` from [`reticle_look { action: "page" }`](/tools/snapshot) or [`reticle_look { action: "find" }`](/tools/query), an `action` name, and an optional `args` object. The same actions are available on [`reticle_act`](/tools/act), which proves nothing, and on [`reticle_act_and_wait`](/tools/act-and-wait), which returns a verdict.
|
|
9
9
|
|
|
10
10
|
```json
|
|
11
11
|
{ "ref": "e104", "action": "fill", "args": { "value": "reticle" } }
|
|
@@ -26,7 +26,6 @@ Every action Reticle can perform takes the same shape: a `ref` from [`reticle_lo
|
|
|
26
26
|
| `scrollIntoView` | none | |
|
|
27
27
|
| `upload` | `{ content?, name?, type?, path? }` | Sets a file on `<input type="file">`. Inline bytes default to `"reticle test file"` / `"file.txt"` / `"text/plain"`. `path` reads a file from disk, scoped to the project root plus any opt-in directories listed in `.reticle.json` as `"uploadRoots": ["~/Downloads", "/Volumes/fixtures"]`. A refusal names every allowed root. |
|
|
28
28
|
| `drag` | `{ toRef }` | Pointer-based drag (dnd-kit, react-beautiful-dnd) plus HTML5 DnD. `target` is an alias |
|
|
29
|
-
| `webmcp` | `{ tool, params }` | Calls a `navigator.modelContext` tool, if the site exposes one |
|
|
30
29
|
|
|
31
30
|
### Arguments that are not actions
|
|
32
31
|
|
package/docs/agent-cheatsheet.md
CHANGED
|
@@ -135,7 +135,7 @@ Not on this surface at all, but one hop away: `reticle_run { tool, args }` calls
|
|
|
135
135
|
| --- | --- | --- |
|
|
136
136
|
| **flows** | `reticle_flow_save*` / `reticle_flow_replay` / `reticle_verify { action: "heal" }` | Replayable **golden journeys**, anchored to testids/signals; drift is legible and self-heals. |
|
|
137
137
|
| **baselines** | `reticle_baseline {action:"save"}` / `reticle_baseline {action:"diff"}` | Structural **"before" snapshots**; `reticle_baseline {action:"diff"}` flags regressions against them. |
|
|
138
|
-
| **project.json** | `reticle_project` | Cross-run **run-history**: "did it behave like last run?" read via `reticle_project`. |
|
|
138
|
+
| **project.json** | `reticle_project` | Cross-run **run-history**: "did it behave like last run?" read via `reticle_project`. Its `cloud.sync` says where this project's runs stand with the platform (on it, waiting, refused, last push); `push: true` syncs before answering. |
|
|
139
139
|
|
|
140
140
|
> `reticle_project` / `project.json` are the **run-history layer**. flows answer "does the journey still work?"; baselines answer "did the structure change?"; project.json answers "is this run consistent with prior runs?".
|
|
141
141
|
|
package/docs/autodrive.md
CHANGED
|
@@ -6,7 +6,7 @@ icon: steering-wheel
|
|
|
6
6
|
|
|
7
7
|
Driving an app is the expensive part of verifying one. Every snapshot, every act result and every observation lands in your agent's context and is re-read on every turn after, and none of it is kept: the next run starts from nothing and pays again.
|
|
8
8
|
|
|
9
|
-
`reticle_verify { action: "explore" }`
|
|
9
|
+
`reticle_verify { action: "explore" }` hands the driving to the Reticle Harness. It decides on the Reticle platform, and the daemon on your machine executes each step through the same tool surface your agent uses, records what it drove as saved flows, and hands back a few lines. It needs a linked project (`reticle connect`).
|
|
10
10
|
|
|
11
11
|
```jsonc
|
|
12
12
|
reticle_verify {
|
|
@@ -32,51 +32,55 @@ So the drive is a one-off: pay for it once, and the journeys it recorded become
|
|
|
32
32
|
|
|
33
33
|
A drive reads `.reticle` first: every saved flow with the consequence that must still hold, and every signal and testid your app declares that no flow has ever asserted. It builds a plan from that before it opens its eyes on a page.
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
With no persona, anything already recorded is **replayed**, deterministically, with no model call at all, and only the gaps are driven (see the plan below). With a persona, it drives that journey and replays nothing else: the saved flows have nothing to do with the journey you named. So a second run over the same app is mostly free, and the model budget is spent on the part nobody has proved yet rather than on rediscovering what is already on disk. A replay that goes red is reported as a regression; one that DRIFTS is reported separately, because the app moved under the recording and that needs re-anchoring rather than a code change.
|
|
36
36
|
|
|
37
37
|
Every journey a drive walks is saved, whatever happens to the drive, including one that broke, ran out of budget, or whose model simply stopped asking for tools.
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## The platform plans the drive
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
With a platform credential (`reticle connect`, or `RETICLE_API_KEY`), the platform plans every drive. With a persona or without one, it proposes the people worth being, orders the saved flows, finds where they branch, and writes into each journey the product rules that apply to it, read from your project's own intents. The rules tell the Harness what the journey is for and where it ends (a journey that names Settings is not finished before Settings). They are not checked as assertions: a rule like "the row shows refunded" is guidance, and the checks are the consequences each step declares. Your machine sends what the project knows, with each saved step as a short hash and never the values it typed. It runs the plan it gets back and reports what happened. The plan is checked before it runs, and a plan that fails the checks is dropped. Every decision while it drives is the platform's too: your machine executes each step it is handed and reports what happened.
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
| --- | --- |
|
|
45
|
-
| `RETICLE_API_KEY` | `jev`, against the platform's own proxy, using the key `reticle link` already wrote. No model API key of your own, and the cheap path: it answers typed questions about the page rather than generating tool calls as text. |
|
|
46
|
-
| `ANTHROPIC_API_KEY` | `anthropic`, which generates its calls as text. |
|
|
47
|
-
| `OPENAI_API_KEY` | `openai`, the same, on OpenAI. |
|
|
48
|
-
| `JEV_API_KEY` | `jev`, against TypeSafe directly, for anyone who holds their own key. |
|
|
43
|
+
## With no persona, it writes a plan first
|
|
49
44
|
|
|
50
|
-
|
|
45
|
+
Called with no `persona`, explore writes the whole drive down before it starts, as a drive plan:
|
|
51
46
|
|
|
52
|
-
|
|
47
|
+
- **Journeys.** Each saved flow worth replaying, plus one open journey for each persona the platform proposes, for the request the user declared (`reticle_intent { action: "declare" }`), and for each intent nobody has proved. Replays need no model; only open journeys reach one.
|
|
48
|
+
- **Order.** A flow that `needs` another runs after it. An open journey runs after the flow everything else needs, usually sign-in.
|
|
49
|
+
- **Lanes.** Each journey nothing else needs gets a lane holding what it needs, in order. Lanes run side by side, each in its own leased browser context, four at a time. A journey that needs one from another lane waits for it, and is blocked if that journey failed. A prerequisite that commits something (a payment, an email) runs in one lane only, and the others wait on it rather than commit it twice.
|
|
50
|
+
- **Branches.** Flows that start with the same steps become one journey. The shared steps are driven once and marked as a checkpoint, then each flow continues from that point. Every flow after the first replays back to the checkpoint first, so none of them starts from the page the previous one left.
|
|
53
51
|
|
|
54
|
-
|
|
52
|
+
The plan appears at the top of the HUD's Agent Log: one row per lane, a card per journey, the running journey opened to its steps, and each card marked as it passes, fails or is blocked. The tool's answer carries one line per journey.
|
|
53
|
+
|
|
54
|
+
Two `reticle_flow_replay` arguments make the branches possible, and you can use them directly. `to` stops before a step. `at` continues at a step on the page as it is, without driving the steps before it. A part-way replay checks the steps it drove and records nothing about the flow as a whole.
|
|
55
|
+
|
|
56
|
+
## What it needs
|
|
57
|
+
|
|
58
|
+
**A project on the Reticle platform.** Every plan includes the Harness: Free comes with monthly Harness credits, one per decision the Harness makes. Run `reticle connect` once in your app's folder. The Harness runs on the platform: planning, personas, and every choice of what to press next. A model key of your own does not drive it, and a machine with no platform link gets the refusal and the way to fix it.
|
|
55
59
|
|
|
56
60
|
| Variable | What it does |
|
|
57
61
|
| --- | --- |
|
|
58
|
-
| `
|
|
59
|
-
| `RETICLE_HARNESS_MAX_STEPS` | Ceiling on
|
|
60
|
-
| `
|
|
61
|
-
|
|
62
|
-
## Two models, and what each one is for
|
|
62
|
+
| `RETICLE_API_KEY` | The key `reticle connect` (or `reticle link`) wrote. The daemon uses it to ask the platform to drive. |
|
|
63
|
+
| `RETICLE_HARNESS_MAX_STEPS` | Ceiling on steps in one drive. Bounds cost, not value. |
|
|
64
|
+
| `RETICLE_SECRET_<FIELD>` | The value for a secret field, such as `RETICLE_SECRET_AUTH_PASSWORD` for a field named `auth-password`. Only the field's NAME goes to the platform. The value is typed in on your machine and never sent. |
|
|
63
65
|
|
|
64
|
-
The
|
|
66
|
+
**What you see.** The HUD's Agent Log marks the moment the Harness takes over ("Reticle Harness is driving") and gives its steps their own colour, so you can tell its work from your agent's. Each Harness drive is recorded as its own run, named for its journey and credited to the Harness, beside your agent's run. Any "double-quoted text" in a persona must be on the page when the journey ends, and is checked.
|
|
65
67
|
|
|
66
|
-
|
|
68
|
+
## How it decides
|
|
67
69
|
|
|
68
|
-
|
|
70
|
+
The platform drives with Jev, a System One model that answers typed questions and cannot write. Every choice is a selection from candidates read off the page: which element, which tool, what consequence to claim. Three rules sit around those choices, because each one was a drive that stopped short or claimed nothing:
|
|
69
71
|
|
|
70
|
-
|
|
72
|
+
- A journey that names a page it has not reached ("then turn on automatic refunds in Settings") is not finished. The Harness goes there instead of stopping.
|
|
73
|
+
- A dialog whose destructive action already ran is closed rather than treated as the end of the journey.
|
|
74
|
+
- A control the destructive-action gate refused is a write, so the Harness always claims a request or a signal for it. A save the server rejects then fails visibly instead of passing as nothing to prove.
|
|
71
75
|
|
|
72
76
|
## Turning it off, and who pays for it
|
|
73
77
|
|
|
74
78
|
A project linked to a Reticle workspace reads two things from it before a drive starts, and honours both:
|
|
75
79
|
|
|
76
|
-
- **The switch.** Autonomous driving can be turned off per project
|
|
77
|
-
- **
|
|
80
|
+
- **The switch.** Autonomous driving can be turned off per project, from the HUD's Reticle Harness switch or the dashboard (Settings → Verification model). A drive then refuses and says where to turn it back on. Switched off while a platform drive is running, the drive stops at its next turn with `stopReason: "stopped"`, keeps what it drove, and says so in the Agent Log. Everything else is unaffected, including the tools your own agent drives with.
|
|
81
|
+
- **Credits.** Every workspace gets Harness credits each 30 days: Free 500, Pro 4,800 a seat, Enterprise as agreed. One credit is one decision the Harness makes. The HUD shows how many are left; once they are spent a drive is refused with that number and the way to get more.
|
|
78
82
|
|
|
79
|
-
|
|
83
|
+
A daemon that cannot reach the platform at all drives normally: an unreachable settings endpoint is not a reason to lose a feature you were never told to stop using.
|
|
80
84
|
|
|
81
85
|
## What it will not do
|
|
82
86
|
|
package/docs/cli/cloud.mdx
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: reticle cloud commands
|
|
3
|
-
description:
|
|
3
|
+
description: Connect a project in one command, then read runs and regressions from Reticle Cloud.
|
|
4
4
|
icon: cloud
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
From your app directory, `reticle connect --project "My App"` wires the app, opens browser sign-in approval if needed, links the named cloud project, and syncs the local history already on this machine. Run the [installer](/quickstart) once on the machine first. The commands below remain available when you need to sign in or link separately.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx @reticlehq/server
|
|
10
|
+
npx @reticlehq/server connect --project "My App"
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Use `--url https://your-cloud-origin` for a self-hosted cloud. `connect` checks a saved sign-in against that exact host before reuse; if it has expired, the browser approval opens again. It mints or reuses a project-scoped key, so there is no key to paste. A newly wired app may have no run to sync yet: ask your agent to verify one flow and the linked daemon will sync the result. Run `reticle whoami` to check the binding and `reticle push` to send anything still pending.
|
|
14
|
+
|
|
15
|
+
The other cloud commands are thin clients over the `/v1` API. Their logic is server-side.
|
|
14
16
|
|
|
15
17
|
## Where credentials live
|
|
16
18
|
|
package/docs/cli/doctor.mdx
CHANGED
|
@@ -74,6 +74,12 @@ All three captures below are real, taken by pointing `PLAYWRIGHT_BROWSERS_PATH`
|
|
|
74
74
|
|
|
75
75
|
**`✓ using the installed Google Chrome`** (or Microsoft Edge) means the pinned build is absent and Reticle drives the browser you already have instead, through Playwright's channel. Nothing to do: the line also names the command that adds Playwright's own build, if you want it.
|
|
76
76
|
|
|
77
|
+
**`✓ using <path> (RETICLE_CHROMIUM_PATH)`** means you named the browser with [`RETICLE_CHROMIUM_PATH`](/environment), so the bundled revision is not checked at all. If the path does not exist, is not a file (a directory, say), or is not executable, the line says which instead, and offers no install command, because installing would not fix a wrong path:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
chromium ✗ RETICLE_CHROMIUM_PATH points at /opt/nope/chrome, which does not exist; fix the path, or unset it to use Playwright's own Chromium
|
|
81
|
+
```
|
|
82
|
+
|
|
77
83
|
When neither is there, Reticle does not refuse. The first command that needs a browser (a lease, `verify`, a drive) runs the bundled Playwright's own pinned install for you, announced on stderr so `reticle mcp`'s stdout stays clean. The two `✗` lines below are what you see when that has not happened yet, or failed.
|
|
78
84
|
|
|
79
85
|
**`✗ wrong revision`** means builds are installed and none of them is the wanted one. One pinned download away. The line names the revision Playwright wants, then every revision the root actually holds, then the exact command:
|
package/docs/cli/drive.mdx
CHANGED
|
@@ -53,10 +53,16 @@ A daemon on `:4400` is the normal state the moment any agent connects, and `driv
|
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
55
|
$ npx @reticlehq/server drive http://localhost:5173
|
|
56
|
-
{"event":"reticle_drive_attached","port":4400,"url":"http://localhost:5173","sessionId":"lease-9f2b…","ready":true}
|
|
56
|
+
{"event":"reticle_drive_attached","port":4400,"url":"http://localhost:5173","sessionId":"lease-9f2b…","ready":true,"projectId":"web","title":"Web"}
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
-
A plain-text line follows it naming the same session, how long it survives untouched (any tool call against it resets that), and, if the page never dialled the bridge, why.
|
|
59
|
+
A plain-text line follows it naming the same session, the app it belongs to (the `projectId` and title the page reported), how long it survives untouched (any tool call against it resets that), and, if the page never dialled the bridge, why.
|
|
60
|
+
|
|
61
|
+
In a monorepo the port you meant for one app can be held by another. When the current directory's `.reticle.json` names a different project from the one the page reported, the line ends with a warning saying so, and the JSON carries both as `projectId` and `expectedProjectId`. Real capture, with app `admin` on the port, `drive` run from app `web`, and the sentence break shown as `...`:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
attached to the Reticle daemon on :4497 ... it is driving http://localhost:5177/?__reticle_project=admin (project "admin", "Admin console") as session lease-74bf5522-8eee-4ea2-b66d-4c056c7dad3a, which every Reticle tool can address. It is released after 300s untouched; any tool call against it resets that. Warning: this directory's .reticle.json is project "web", but the page at http://localhost:5177/?__reticle_project=admin is project "admin", so another app is probably serving that port. Check which dev server is on it before trusting anything this session reports.
|
|
65
|
+
```
|
|
60
66
|
|
|
61
67
|
That session lives in the daemon, so the tools your agent already has open can address it by id. You do **not** need `reticle stop` first, and should not use it: the MCP proxy respawns a daemon as soon as the next tool call arrives, which is a race a manual `stop` loses.
|
|
62
68
|
|
package/docs/cli/init.mdx
CHANGED
|
@@ -74,21 +74,19 @@ With `--no-mcp`, the whole MCP and rules group collapses into one skipped line:
|
|
|
74
74
|
--no-mcp ... also skips the agent rule files (CLAUDE.md / AGENTS.md / .cursor) and the /reticle command
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
Run from a workspace root with several apps, it refuses to guess,
|
|
77
|
+
Run from a workspace root with several apps, it refuses to guess, prints a command for each one, and exits `1`:
|
|
78
78
|
|
|
79
79
|
```
|
|
80
|
-
Several apps found in this workspace. Re-run `reticle init`
|
|
81
|
-
adapters/build/next
|
|
82
|
-
adapters/build/vite
|
|
83
|
-
apps/atlas
|
|
84
|
-
apps/bench-app
|
|
85
|
-
apps/electron-smoke
|
|
86
|
-
apps/large-dom-bench
|
|
87
|
-
apps/next-smoke
|
|
88
|
-
apps/tauri-smoke
|
|
89
|
-
apps/vibe-builder-demo
|
|
90
|
-
|
|
91
|
-
Or name one without changing directory: reticle init --app apps/next-smoke
|
|
80
|
+
Several apps found in this workspace. Re-run `reticle init` for the one you want:
|
|
81
|
+
reticle init --app adapters/build/next
|
|
82
|
+
reticle init --app adapters/build/vite
|
|
83
|
+
reticle init --app apps/atlas
|
|
84
|
+
reticle init --app apps/bench-app
|
|
85
|
+
reticle init --app apps/electron-smoke
|
|
86
|
+
reticle init --app apps/large-dom-bench
|
|
87
|
+
reticle init --app apps/next-smoke
|
|
88
|
+
reticle init --app apps/tauri-smoke
|
|
89
|
+
reticle init --app apps/vibe-builder-demo
|
|
92
90
|
```
|
|
93
91
|
|
|
94
92
|
Given `--app`, it says which directory it moved to before printing the plan:
|
package/docs/cli/status.mdx
CHANGED
|
@@ -45,7 +45,11 @@ A session's parenthesised notes are the ones that explain an answer you would ot
|
|
|
45
45
|
|
|
46
46
|
### `--json`
|
|
47
47
|
|
|
48
|
-
The same facts as one
|
|
48
|
+
The same facts as one JSON line on stdout, so a caller can pipe it to a parser:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx @reticlehq/server status --json | jq '.running, .sessionCount'
|
|
52
|
+
```
|
|
49
53
|
|
|
50
54
|
```json
|
|
51
55
|
{
|
package/docs/cli/version.mdx
CHANGED
|
@@ -16,10 +16,10 @@ All three are the same command. No flags.
|
|
|
16
16
|
|
|
17
17
|
## What it prints
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
The version, and nothing else, on stdout, so `V=$(reticle version)` works:
|
|
20
20
|
|
|
21
|
-
```
|
|
22
|
-
|
|
21
|
+
```text
|
|
22
|
+
3.6.0
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## Exit codes
|
package/docs/cli.mdx
CHANGED
|
@@ -13,13 +13,9 @@ npx @reticlehq/server <command>
|
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
<Warning>
|
|
16
|
-
|
|
17
|
-
`
|
|
18
|
-
|
|
19
|
-
unrelated author, so putting `npx` in front of it downloads and runs their code instead of ours.
|
|
20
|
-
Once
|
|
21
|
-
`@reticlehq/server` is a dependency of your project, `reticle <command>` works from an npm script
|
|
22
|
-
or with the bin on your PATH.
|
|
16
|
+
If you used the installer, run `reticle <command>`: it put that bin on your PATH. Otherwise use
|
|
17
|
+
`npx @reticlehq/server <command>`. Do not put `npx` before the bare `reticle` bin name: the npm
|
|
18
|
+
package with that name belongs to an unrelated author.
|
|
23
19
|
</Warning>
|
|
24
20
|
|
|
25
21
|
<Note>
|
|
@@ -30,9 +26,19 @@ npx @reticlehq/server <command>
|
|
|
30
26
|
|
|
31
27
|
## Setup and diagnosis
|
|
32
28
|
|
|
29
|
+
### `reticle connect`
|
|
30
|
+
|
|
31
|
+
From an app directory, one command wires an unwired app, proves a browser session, signs in through browser approval if needed, links the chosen cloud project, and syncs existing local history. A saved sign-in is reused only after the intended cloud host accepts it. Run `reticle init` instead for local-only verification.
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx @reticlehq/server connect --project "My App"
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For a self-hosted cloud, add `--url <cloud origin>`. If the app was already wired, `connect` keeps its local setup and refreshes the cloud link. A fresh app has no run to send until you verify a flow with your agent.
|
|
38
|
+
|
|
33
39
|
### `reticle init`
|
|
34
40
|
|
|
35
|
-
Wires Reticle into the project in the current directory, then boots the app and proves a session connected. It exits non-zero if nothing connected, and prints what is left to do. It does not drive: proving a flow is the FIRST RUN, `reticle verify <url> --explore --persona "<who does what>"`.
|
|
41
|
+
Wires Reticle into the project in the current directory, then boots the app and proves a session connected. It exits non-zero if nothing connected, and prints what is left to do. It does not drive: proving a flow is the FIRST RUN, which your agent drives with `reticle_act_and_wait` and an `until` on its last step, or, with a linked project, `reticle verify <url> --explore --persona "<who does what>"`.
|
|
36
42
|
|
|
37
43
|
```
|
|
38
44
|
reticle init [--env KEY=VALUE]... [--app <dir>] [--license <key>]
|
package/docs/desktop.mdx
CHANGED
|
@@ -210,13 +210,15 @@ installReticleCapture(win);
|
|
|
210
210
|
|
|
211
211
|
That is all: no CDP flag, no extra packages, and it works on a packaged `file://` renderer. `reticle_screenshot` and `reticle_visual_diff` then work on your app.
|
|
212
212
|
|
|
213
|
+
In a multi-window app, name each window: `installReticleCapture(win, { label: 'settings' })`. The session list then shows `window: "settings"`. Electron windows have no name of their own, and two of them often share a url.
|
|
214
|
+
|
|
213
215
|
Alternatively, since an Electron renderer _is_ Chromium, `--remote-debugging-port=9222` plus `RETICLE_CDP_URL=http://127.0.0.1:9222` also works and additionally enables `fullPage` (the main-process route captures the window as composited, so it cannot scroll-stitch).
|
|
214
216
|
|
|
215
217
|
**Tauri: one Rust command.** The crate is versioned independently of the npm packages:
|
|
216
218
|
|
|
217
219
|
```toml
|
|
218
220
|
[dependencies]
|
|
219
|
-
reticle-tauri = "3.
|
|
221
|
+
reticle-tauri = "3.6"
|
|
220
222
|
```
|
|
221
223
|
|
|
222
224
|
```rust
|
|
@@ -344,6 +346,8 @@ Playwright MCP is faster. It is also structurally unable to see an IPC failure,
|
|
|
344
346
|
|
|
345
347
|
**`reticle open` says there is nothing to open.** That is correct for a desktop app. There is no URL, and there is no `reticle drive` for desktop either. Both launch a browser, which is not what you are testing.
|
|
346
348
|
|
|
349
|
+
**Several windows, and the wrong one gets driven.** Every window that loads the SDK is its own session, and `reticle_session { action: "list" }` names each (`window: "main"`: Tauri's label, or the `label` you gave `installReticleCapture` on Electron) with whether it is `hidden`. A page served as an error (a dev server's 404 for a static page, say) carries `documentStatus` and is never auto-selected ahead of a working one. To drive a specific window, pass its `sessionId`. To get rid of a stray hidden window for good, call `reticle_session { action: "end", sessionId, disconnect: true }`. It stays detached across its own reloads until the daemon restarts.
|
|
350
|
+
|
|
347
351
|
**A screenshot came back partly blank.** The window is occluded or minimized, so it is only partially composited. Bring it forward and capture again.
|
|
348
352
|
|
|
349
353
|
**`{ ok: false, reason: 'full-page-unsupported' }`.** You asked for `fullPage: true` on a platform that cannot render offscreen. Only Tauri on Linux (WebKitGTK) can. Capture the viewport instead, or scroll and capture in sections.
|
package/docs/environment.mdx
CHANGED
|
@@ -33,6 +33,7 @@ Reticle works with none of these set. Each one changes a single behaviour, and m
|
|
|
33
33
|
| Variable | Read by | What it does |
|
|
34
34
|
| --- | --- | --- |
|
|
35
35
|
| `RETICLE_CDP_URL` | daemon | Attach to a browser that is already running, over CDP, instead of launching one. |
|
|
36
|
+
| `RETICLE_CHROMIUM_PATH` | daemon, `drive`, `verify`, `doctor` | The Chromium executable to launch, for a machine where Playwright's own build is missing and cannot be installed and there is no Chrome or Edge in the usual place. When set, nothing else is tried: no Playwright build, no Chrome or Edge, no install. A path that does not exist, is not a file, or is not executable is refused with a message naming it and saying which. `doctor` reports on this path instead of the bundled build. |
|
|
36
37
|
| `RETICLE_MAX_CONTEXTS` | daemon | The most leased headless browser contexts the pool runs at once. |
|
|
37
38
|
| `RETICLE_MAX_MESSAGES_PER_SECOND` | daemon | Events per second a page may send before the bridge starts sampling them. It never disconnects. Raise it for a legitimately busy app, such as a streaming dashboard. |
|
|
38
39
|
|
|
@@ -62,13 +63,8 @@ Reticle works with none of these set. Each one changes a single behaviour, and m
|
|
|
62
63
|
| `RETICLE_CLOUD_KEY` | CLI, daemon | The key's earlier name. Still honoured. |
|
|
63
64
|
| `RETICLE_CLOUD_URL`, `RETICLE_URL` | CLI, daemon | The platform host. `RETICLE_CLOUD_URL` wins when both are set. |
|
|
64
65
|
| `RETICLE_SYNC_INTERVAL_MS` | `reticle sync --watch` | How often the watching sync runs. Every 60 seconds by default. |
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
67
|
-
| `RETICLE_HARNESS_BASE_URL` | autonomous drive | A proxy or gateway in front of the model API. |
|
|
68
|
-
| `RETICLE_HARNESS_MAX_STEPS` | autonomous drive | A hard ceiling on model turns in one drive. It bounds cost. |
|
|
69
|
-
| `RETICLE_HARNESS_DRIVER` | autonomous drive | Which model drives: `anthropic` (the default) or `jev`. |
|
|
70
|
-
| `JEV_API_KEY`, `RETICLE_HARNESS_JEV_URL` | autonomous drive | A direct key and base URL for the `jev` driver. The usual path is `RETICLE_API_KEY` through the platform. |
|
|
71
|
-
| `OPENAI_API_KEY`, `RETICLE_HARNESS_OPENAI_MODEL` | autonomous drive | A direct key and model for the OpenAI driver. |
|
|
66
|
+
| `RETICLE_HARNESS_MAX_STEPS` | autonomous drive | A hard ceiling on steps in one drive. It bounds cost. The drive itself runs on the platform and needs a linked project; every plan, Free included, has monthly Harness credits. |
|
|
67
|
+
| `RETICLE_SECRET_<FIELD>` | autonomous drive, replay | The value of a secret field, typed in on this machine. Only the field's name goes to the platform. |
|
|
72
68
|
|
|
73
69
|
## Licensing
|
|
74
70
|
|