@reticlehq/server 2.7.0 → 2.9.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 +14 -5
- package/SKILL.md +130 -778
- package/dist/bridge/bridge.d.ts +23 -0
- package/dist/bridge/bridge.js +80 -2
- package/dist/bridge/bridge.test-harness.d.ts +5 -0
- package/dist/bridge/bridge.test-harness.js +6 -4
- package/dist/capsule/causal-summary.d.ts +36 -1
- package/dist/capsule/causal-summary.js +33 -7
- package/dist/capsule/divergence.js +7 -1
- package/dist/cli/chromium-hint.d.ts +33 -5
- package/dist/cli/chromium-hint.js +82 -12
- package/dist/cli/cli-doctor.js +65 -34
- package/dist/cli/cli-flow-commands.js +8 -8
- package/dist/cli/cli-kill.d.ts +58 -0
- package/dist/cli/cli-kill.js +162 -0
- package/dist/cli/cli-parse.d.ts +16 -1
- package/dist/cli/cli-parse.js +32 -9
- package/dist/cli/cli-port.d.ts +32 -0
- package/dist/cli/cli-port.js +82 -35
- package/dist/cli/cli-verify.d.ts +21 -0
- package/dist/cli/cli-verify.js +47 -3
- package/dist/cli/config-discovery.d.ts +35 -0
- package/dist/cli/config-discovery.js +163 -0
- package/dist/cli/doctor-daemon-line.js +4 -1
- package/dist/cli/doctor-project-line.d.ts +37 -0
- package/dist/cli/doctor-project-line.js +35 -0
- package/dist/cli/doctor-rows.d.ts +51 -0
- package/dist/cli/doctor-rows.js +54 -0
- package/dist/cli/doctor-sessions-line.d.ts +12 -0
- package/dist/cli/doctor-sessions-line.js +69 -0
- package/dist/cli/drive-attach.d.ts +99 -0
- package/dist/cli/drive-attach.js +203 -0
- package/dist/cli/drive-command.d.ts +13 -0
- package/dist/cli/drive-command.js +103 -0
- package/dist/cli/open-note.d.ts +20 -0
- package/dist/cli/open-note.js +37 -0
- package/dist/cli/port-holder.d.ts +10 -0
- package/dist/cli/port-holder.js +26 -2
- package/dist/cli/status-next-action.d.ts +37 -0
- package/dist/cli/status-next-action.js +61 -0
- package/dist/cli.js +119 -39
- package/dist/crawl/crawl-tools.js +12 -2
- package/dist/crawl/crawl.d.ts +13 -0
- package/dist/crawl/crawl.js +50 -2
- package/dist/events/contradictions.d.ts +46 -0
- package/dist/events/contradictions.js +35 -22
- package/dist/events/declared.d.ts +45 -0
- package/dist/events/declared.js +73 -0
- package/dist/events/echo-mismatch.d.ts +8 -2
- package/dist/events/echo-mismatch.js +33 -5
- package/dist/events/event-filters.d.ts +1 -1
- package/dist/events/event-filters.js +7 -4
- package/dist/events/predicate-eval.d.ts +17 -72
- package/dist/events/predicate-eval.js +117 -236
- package/dist/events/predicate-parse.js +31 -3
- package/dist/events/predicate-route.d.ts +32 -0
- package/dist/events/predicate-route.js +102 -0
- package/dist/events/predicate-schema.d.ts +99 -0
- package/dist/events/predicate-schema.js +309 -0
- package/dist/events/predicate.d.ts +8 -0
- package/dist/events/predicate.js +296 -22
- package/dist/flows/annotate-tools.js +3 -0
- package/dist/flows/annotate.js +18 -4
- package/dist/flows/coverage.d.ts +38 -5
- package/dist/flows/coverage.js +30 -4
- package/dist/flows/decision.d.ts +15 -0
- package/dist/flows/decision.js +1 -1
- package/dist/flows/flow-classify.js +1 -1
- package/dist/flows/flow-replay-run.js +8 -1
- package/dist/flows/flow-tools.js +21 -5
- package/dist/flows/heal-run.js +1 -1
- package/dist/flows/replay.js +3 -0
- package/dist/honesty/accepted-write.d.ts +3 -0
- package/dist/honesty/accepted-write.js +8 -3
- package/dist/honesty/already-true.js +15 -0
- package/dist/honesty/blind-spots.js +10 -2
- package/dist/honesty/honesty.d.ts +11 -0
- package/dist/honesty/honesty.js +1 -0
- package/dist/honesty/uncaptured-bodies.d.ts +4 -2
- package/dist/honesty/uncaptured-bodies.js +9 -2
- package/dist/honesty/unread-outcome.d.ts +8 -0
- package/dist/honesty/unread-outcome.js +36 -9
- package/dist/honesty/unsettled.d.ts +49 -0
- package/dist/honesty/unsettled.js +82 -0
- package/dist/honesty/verified.d.ts +36 -3
- package/dist/honesty/verified.js +54 -11
- package/dist/http-server.d.ts +19 -0
- package/dist/http-server.js +202 -4
- package/dist/impact/impact-recorder.d.ts +23 -0
- package/dist/impact/impact-recorder.js +76 -0
- package/dist/impact/impact-store.d.ts +47 -0
- package/dist/impact/impact-store.js +171 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +47 -10
- package/dist/init/agent-rules.d.ts +36 -0
- package/dist/init/agent-rules.js +132 -22
- package/dist/init/astro-patch.d.ts +2 -1
- package/dist/init/astro-patch.js +38 -6
- package/dist/init/capabilities.d.ts +22 -0
- package/dist/init/capabilities.js +76 -0
- package/dist/init/confirm.d.ts +114 -0
- package/dist/init/confirm.js +165 -0
- package/dist/init/connect-steps.d.ts +2 -0
- package/dist/init/connect-steps.js +50 -0
- package/dist/init/cra.js +3 -2
- package/dist/init/csp-check.d.ts +38 -0
- package/dist/init/csp-check.js +92 -0
- package/dist/init/csp-doctor.d.ts +25 -0
- package/dist/init/csp-doctor.js +49 -0
- package/dist/init/cursor.js +6 -9
- package/dist/init/detect.d.ts +8 -0
- package/dist/init/detect.js +33 -3
- package/dist/init/mcp-clients.d.ts +1 -0
- package/dist/init/mcp-clients.js +51 -7
- package/dist/init/mcp.d.ts +15 -0
- package/dist/init/mcp.js +19 -0
- package/dist/init/non-js-project.js +29 -5
- package/dist/init/plan-framework.d.ts +10 -0
- package/dist/init/plan-framework.js +78 -16
- package/dist/init/plan.d.ts +47 -6
- package/dist/init/plan.js +228 -69
- package/dist/init/run.d.ts +24 -2
- package/dist/init/run.js +157 -45
- package/dist/init/slash-command.d.ts +1 -1
- package/dist/init/slash-command.js +54 -6
- package/dist/init/snippets.d.ts +45 -5
- package/dist/init/snippets.js +194 -42
- package/dist/init/vite-config.js +53 -5
- package/dist/input/network-mock-tools.d.ts +19 -0
- package/dist/input/network-mock-tools.js +37 -5
- package/dist/input/scroll-find.d.ts +6 -0
- package/dist/input/scroll-find.js +17 -2
- package/dist/input/scroll-tools.js +4 -0
- package/dist/journal/attach-journal.d.ts +9 -1
- package/dist/journal/attach-journal.js +13 -2
- package/dist/journal/journal-query.d.ts +13 -0
- package/dist/journal/journal-query.js +28 -3
- package/dist/journal/workspace-gitignore.d.ts +10 -0
- package/dist/journal/workspace-gitignore.js +59 -0
- package/dist/license/license.js +1 -1
- package/dist/mcp/mcp-proxy.d.ts +35 -30
- package/dist/mcp/mcp-proxy.js +306 -104
- package/dist/mcp/mcp.d.ts +10 -1
- package/dist/mcp/mcp.js +70 -34
- package/dist/mcp/proxy-handshake.d.ts +82 -1
- package/dist/mcp/proxy-handshake.js +109 -2
- package/dist/mcp/proxy-lifecycle.d.ts +11 -2
- package/dist/mcp/proxy-lifecycle.js +12 -3
- package/dist/mcp/proxy-log.d.ts +63 -0
- package/dist/mcp/proxy-log.js +132 -0
- package/dist/mcp/server-instructions.d.ts +17 -0
- package/dist/mcp/server-instructions.js +56 -0
- package/dist/mcp/shared-params.d.ts +27 -0
- package/dist/mcp/shared-params.js +36 -0
- package/dist/pool/browser-pool.d.ts +22 -2
- package/dist/pool/browser-pool.js +44 -4
- package/dist/project/learned-routes.d.ts +24 -0
- package/dist/project/learned-routes.js +63 -0
- package/dist/project/project-store.d.ts +6 -0
- package/dist/project/project-store.js +25 -1
- package/dist/project/reticle-dir.d.ts +2 -0
- package/dist/project/reticle-dir.js +1 -0
- package/dist/session/connection-memory.d.ts +59 -0
- package/dist/session/connection-memory.js +108 -0
- package/dist/session/dev-command.d.ts +26 -0
- package/dist/session/dev-command.js +89 -0
- package/dist/session/dev-server-probe.d.ts +68 -0
- package/dist/session/dev-server-probe.js +102 -7
- package/dist/session/last-act.d.ts +26 -0
- package/dist/session/last-act.js +35 -1
- package/dist/session/live-control-tools.js +42 -5
- package/dist/session/no-session-diagnosis.d.ts +67 -2
- package/dist/session/no-session-diagnosis.js +236 -27
- package/dist/session/no-session-next-action.d.ts +46 -0
- package/dist/session/no-session-next-action.js +85 -0
- package/dist/session/no-session-watch.d.ts +40 -1
- package/dist/session/no-session-watch.js +174 -8
- package/dist/session/pending-commands.d.ts +12 -0
- package/dist/session/pending-commands.js +13 -1
- package/dist/session/ref-provenance.d.ts +54 -0
- package/dist/session/ref-provenance.js +61 -0
- package/dist/session/session-lease.js +1 -1
- package/dist/session/session-manager.d.ts +4 -0
- package/dist/session/session-manager.js +35 -5
- package/dist/session/session.d.ts +10 -1
- package/dist/session/session.js +146 -5
- package/dist/telemetry/app-instrumented.d.ts +8 -0
- package/dist/telemetry/app-instrumented.js +10 -0
- package/dist/telemetry/automation-hint.d.ts +17 -0
- package/dist/telemetry/automation-hint.js +71 -0
- package/dist/telemetry/bug-found.d.ts +15 -17
- package/dist/telemetry/bug-found.js +52 -21
- package/dist/telemetry/cli-telemetry.js +7 -1
- package/dist/telemetry/daemon-telemetry.js +24 -0
- package/dist/telemetry/feedback.js +1 -1
- package/dist/telemetry/init-telemetry.js +9 -1
- package/dist/telemetry/install-source.d.ts +56 -0
- package/dist/telemetry/install-source.js +74 -0
- package/dist/telemetry/instrumentation-stall.d.ts +50 -0
- package/dist/telemetry/instrumentation-stall.js +90 -0
- package/dist/telemetry/run-telemetry.js +4 -1
- package/dist/telemetry/session-metrics.d.ts +8 -0
- package/dist/telemetry/session-metrics.js +15 -0
- package/dist/telemetry/telemetry.d.ts +7 -1
- package/dist/telemetry/telemetry.js +26 -2
- package/dist/telemetry/tool-refused.d.ts +19 -0
- package/dist/telemetry/tool-refused.js +55 -0
- package/dist/telemetry/verification-of.js +46 -7
- package/dist/temp-dir.d.ts +27 -0
- package/dist/temp-dir.js +46 -0
- package/dist/tools/act-tools.js +209 -28
- package/dist/tools/assert-grade.d.ts +1 -1
- package/dist/tools/assert-grade.js +27 -5
- package/dist/tools/assert-verdict.js +49 -7
- package/dist/tools/browser-tools.js +10 -0
- package/dist/tools/contract-tools.js +4 -0
- package/dist/tools/dynamic-tools.js +16 -7
- package/dist/tools/error-recovery.d.ts +10 -0
- package/dist/tools/error-recovery.js +73 -9
- package/dist/tools/feedback-invite.js +1 -1
- package/dist/tools/invoke-tool.js +159 -26
- package/dist/tools/lease-hint.d.ts +30 -8
- package/dist/tools/lease-hint.js +65 -14
- package/dist/tools/lease-tools.d.ts +40 -1
- package/dist/tools/lease-tools.js +181 -83
- package/dist/tools/navigate-result.js +1 -1
- package/dist/tools/observe-tools.js +10 -4
- package/dist/tools/observed-nothing.js +1 -1
- package/dist/tools/react-grace.d.ts +52 -0
- package/dist/tools/react-grace.js +90 -0
- package/dist/tools/read-tools.js +67 -5
- package/dist/tools/resolve-target.d.ts +33 -0
- package/dist/tools/resolve-target.js +53 -0
- package/dist/tools/settle-in-flight.d.ts +94 -0
- package/dist/tools/settle-in-flight.js +146 -0
- package/dist/tools/snapshot-delta.d.ts +10 -0
- package/dist/tools/snapshot-delta.js +194 -9
- package/dist/tools/tool-kit.d.ts +8 -0
- package/dist/tools/tool-surface.d.ts +60 -0
- package/dist/tools/tool-surface.js +86 -1
- package/dist/tools/tools.js +61 -8
- package/dist/tools/unadvertised-help.js +9 -6
- package/docs/README.md +55 -11
- package/docs/actions.mdx +120 -0
- package/docs/agent-cheatsheet.md +95 -29
- package/docs/architecture.md +52 -35
- package/docs/benchmarks.md +127 -75
- package/docs/best-practices.mdx +216 -0
- package/docs/capabilities.mdx +534 -0
- package/docs/cli/affected.mdx +53 -0
- package/docs/cli/capsules.mdx +70 -0
- package/docs/cli/cloud.mdx +153 -0
- package/docs/cli/doctor.mdx +109 -0
- package/docs/cli/drive.mdx +74 -0
- package/docs/cli/feedback.mdx +67 -0
- package/docs/cli/gate.mdx +64 -0
- package/docs/cli/help.mdx +94 -0
- package/docs/cli/hunt.mdx +73 -0
- package/docs/cli/identify.mdx +76 -0
- package/docs/cli/init.mdx +121 -0
- package/docs/cli/kill.mdx +91 -0
- package/docs/cli/license.mdx +48 -0
- package/docs/cli/mcp.mdx +61 -0
- package/docs/cli/open.mdx +74 -0
- package/docs/cli/restart.mdx +60 -0
- package/docs/cli/rollback.mdx +35 -0
- package/docs/cli/serve.mdx +69 -0
- package/docs/cli/status.mdx +88 -0
- package/docs/cli/stop.mdx +64 -0
- package/docs/cli/telemetry.mdx +57 -0
- package/docs/cli/update.mdx +52 -0
- package/docs/cli/verify.mdx +76 -0
- package/docs/cli/version.mdx +39 -0
- package/docs/cli/watch.mdx +62 -0
- package/docs/cli.mdx +241 -0
- package/docs/debugging.md +16 -10
- package/docs/deploy-checks.md +45 -12
- package/docs/desktop.mdx +384 -0
- package/docs/docs.json +364 -0
- package/docs/enterprise.md +22 -16
- package/docs/faq.mdx +102 -0
- package/docs/fixtures.md +13 -7
- package/docs/flows.md +29 -23
- package/docs/for-agents.md +71 -0
- package/docs/frameworks.mdx +238 -0
- package/docs/gate-plan.md +48 -42
- package/docs/gates.md +28 -22
- package/docs/getting-started.md +129 -77
- package/docs/human-control.md +24 -18
- package/docs/index.mdx +143 -0
- package/docs/install-agentic.mdx +224 -0
- package/docs/install-manual.mdx +196 -0
- package/docs/instrumentation.mdx +238 -0
- package/docs/integration-patterns.md +41 -35
- package/docs/local-registry.md +19 -13
- package/docs/multi-agent-testing.md +19 -13
- package/docs/packages/babel-plugin.mdx +79 -0
- package/docs/packages/browser.mdx +111 -0
- package/docs/packages/core.mdx +116 -0
- package/docs/packages/electron.mdx +85 -0
- package/docs/packages/eslint-plugin.mdx +86 -0
- package/docs/packages/next.mdx +89 -0
- package/docs/packages/react.mdx +91 -0
- package/docs/packages/server.mdx +98 -0
- package/docs/packages/tauri.mdx +63 -0
- package/docs/packages/test.mdx +119 -0
- package/docs/packages/vite-plugin.mdx +94 -0
- package/docs/packages.mdx +218 -0
- package/docs/platform-integration.md +35 -26
- package/docs/predicates.mdx +248 -0
- package/docs/quickstart.mdx +257 -0
- package/docs/recipes.mdx +282 -0
- package/docs/skill-file.mdx +107 -0
- package/docs/state-management.mdx +199 -0
- package/docs/style.css +14 -0
- package/docs/system-map.md +50 -33
- package/docs/telemetry-contract.md +106 -52
- package/docs/telemetry-events.mdx +475 -0
- package/docs/telemetry.md +63 -55
- package/docs/testing.md +44 -6
- package/docs/token-efficiency.md +37 -27
- package/docs/tools-act-and-wait.mdx +173 -0
- package/docs/tools-act-sequence.mdx +137 -0
- package/docs/tools-act.mdx +95 -0
- package/docs/tools-assert.mdx +129 -0
- package/docs/tools-console.mdx +63 -0
- package/docs/tools-inspect.mdx +88 -0
- package/docs/tools-navigate.mdx +99 -0
- package/docs/tools-network.mdx +119 -0
- package/docs/tools-observe.mdx +145 -0
- package/docs/tools-overview.mdx +160 -0
- package/docs/tools-query.mdx +126 -0
- package/docs/tools-session-and-feedback.mdx +112 -0
- package/docs/tools-sessions.mdx +94 -0
- package/docs/tools-snapshot.mdx +129 -0
- package/docs/tools-state.mdx +104 -0
- package/docs/tools-tools-and-run.mdx +156 -0
- package/docs/tools-wait-for.mdx +85 -0
- package/docs/troubleshooting.mdx +263 -0
- package/docs/usage.md +209 -165
- package/docs/vs-chrome-devtools-mcp.mdx +123 -0
- package/docs/vs-playwright-mcp.mdx +125 -0
- package/docs/vs-screenshots.mdx +137 -0
- package/docs/what-is-reticle.mdx +63 -0
- package/docs/why-reticle.mdx +109 -0
- package/package.json +5 -5
- package/docs/desktop-apps.md +0 -256
- package/docs/matrix/2.5.0/claude-code-machine.json +0 -19
- package/docs/matrix/2.5.0/codex-machine.json +0 -20
- package/docs/matrix/2.5.0/cursor-machine.json +0 -22
- package/docs/matrix/2.5.0/gemini-machine.json +0 -22
- package/docs/matrix/2.5.0/opencode-machine.json +0 -22
- package/docs/matrix/2.5.0/vscode-machine.json +0 -22
- package/docs/matrix/2.5.0/windsurf-machine.json +0 -22
- package/docs/matrix/MATRIX.md +0 -26
- package/docs/matrix/README.md +0 -59
- package/docs/mint.json +0 -61
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '@reticlehq/babel-plugin'
|
|
3
|
+
description: A Babel plugin that stamps data-reticle-source on JSX host elements so Reticle can name the file a node came from.
|
|
4
|
+
icon: file-code
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`@reticlehq/babel-plugin` stamps `data-reticle-source="file:line:col"` onto your JSX at build time, in dev only, so Reticle can name the file a DOM node came from. **You probably do not install this one directly**: [`@reticlehq/vite-plugin`](/packages/vite-plugin) and [`@reticlehq/next`](/packages/next) both pull it in. Reach for it only if you drive Babel yourself.
|
|
8
|
+
|
|
9
|
+
React 19 dropped `_debugSource`, which is what source mapping used to rely on, so without this the tools can tell you the component name but not the file.
|
|
10
|
+
|
|
11
|
+
**Apache 2.0. CommonJS. No runtime dependencies. Peer dependency: `@babel/core ^7`.**
|
|
12
|
+
|
|
13
|
+
## What it stamps
|
|
14
|
+
|
|
15
|
+
```jsx
|
|
16
|
+
// src/components/Login.jsx
|
|
17
|
+
export function Login({ submit }) {
|
|
18
|
+
return <button onClick={submit}>Sign in</button>;
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
becomes, in dev only:
|
|
23
|
+
|
|
24
|
+
```jsx
|
|
25
|
+
export function Login({ submit }) {
|
|
26
|
+
return (
|
|
27
|
+
<button onClick={submit} data-reticle-source="src/components/Login.jsx:2:9">
|
|
28
|
+
Sign in
|
|
29
|
+
</button>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The path is relative to `process.cwd()`, with backslashes normalized to forward slashes. A file with no name stamps `unknown`.
|
|
35
|
+
|
|
36
|
+
## What it skips
|
|
37
|
+
|
|
38
|
+
- Component tags. Only lowercase host elements are stamped, because a component's own JSX gets stamped where it is defined.
|
|
39
|
+
- Elements that already carry the attribute.
|
|
40
|
+
- Nodes with no location information.
|
|
41
|
+
- Anything whose tag name is not a plain `JSXIdentifier`.
|
|
42
|
+
|
|
43
|
+
## Do you install it?
|
|
44
|
+
|
|
45
|
+
Only if you are wiring Babel yourself. [`@reticlehq/vite-plugin`](/packages/vite-plugin) and [`@reticlehq/next`](/packages/next) both pull it in.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm i -D @reticlehq/babel-plugin
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## The export
|
|
52
|
+
|
|
53
|
+
One export, via `export =`. There are no named exports and no `default` interop wrapper, because Babel `require()`s the module and takes the object directly.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
function reticleSourcePlugin({ types }: { types: typeof BabelTypes }): PluginObj<PluginPass>;
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The Babel plugin name is `reticle-source`. Its visitor handles `JSXOpeningElement` only.
|
|
60
|
+
|
|
61
|
+
**It takes no options.** The plugin reads nothing from `state.opts`.
|
|
62
|
+
|
|
63
|
+
## Wiring it by hand
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
// babel.config.cjs
|
|
67
|
+
module.exports = {
|
|
68
|
+
plugins: process.env.NODE_ENV === 'development' ? [require('@reticlehq/babel-plugin')] : [],
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
<Warning>
|
|
73
|
+
Do not write `require('@reticlehq/babel-plugin').default`. With `export =` there is no `.default`,
|
|
74
|
+
and an old README example got this wrong.
|
|
75
|
+
</Warning>
|
|
76
|
+
|
|
77
|
+
## Why an attribute rather than a runtime lookup
|
|
78
|
+
|
|
79
|
+
The stamp survives minification of everything else, costs nothing at runtime, and is readable from the DOM node itself. That is what lets [`reticle_inspect`](/tools-inspect) answer with a file and a line rather than a component name and a shrug.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '@reticlehq/browser'
|
|
3
|
+
description: The Reticle instrumentation SDK that runs inside your page, observing the DOM, network, console, routing and state.
|
|
4
|
+
icon: window
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`@reticlehq/browser` is the Reticle SDK that runs inside your page. It installs the observers, builds semantic snapshots, executes actions, and talks to the bridge. Install it directly only if you are **not** on React or want to call `connect()` yourself, because [`@reticlehq/react`](/packages/react) already re-exports all of it.
|
|
8
|
+
|
|
9
|
+
**Apache 2.0. Depends on `@reticlehq/core` and `@testing-library/dom`.**
|
|
10
|
+
|
|
11
|
+
## Why it exists
|
|
12
|
+
|
|
13
|
+
This is what makes Reticle different from a browser-automation tool. Because it runs _inside_ the app rather than driving it from outside, it can see a state mutation and a fired signal, not just a rendered pixel. It never imports a Node API; that boundary is enforced by the dependency graph.
|
|
14
|
+
|
|
15
|
+
`@testing-library/dom` is why [`reticle_query`](/tools-query) speaks role, label and testid instead of CSS selectors.
|
|
16
|
+
|
|
17
|
+
## When you need it directly
|
|
18
|
+
|
|
19
|
+
Install it yourself when you are not on React, or when you want `connect()` under your own control. React users install [`@reticlehq/react`](/packages/react) instead, which re-exports everything here.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i -D @reticlehq/browser
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
import { reticle } from '@reticlehq/browser';
|
|
27
|
+
if (import.meta.env.DEV) reticle.connect();
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## The `reticle` singleton
|
|
31
|
+
|
|
32
|
+
One instance, memoized on `globalThis` so hot module replacement does not create a second one.
|
|
33
|
+
|
|
34
|
+
| Method | Signature |
|
|
35
|
+
| -------------- | -------------------------------------------------------- |
|
|
36
|
+
| `connect` | `(options?: ReticleConnectOptions) => void` |
|
|
37
|
+
| `connected` | `get connected(): boolean` |
|
|
38
|
+
| `signal` | `(name: string, data?: Record<string, unknown>) => void` |
|
|
39
|
+
| `state` | `(name: string, value: unknown) => void` |
|
|
40
|
+
| `renderCommit` | `(commits: number) => void` |
|
|
41
|
+
| `describe` | `(input: CapabilitiesInput) => void` |
|
|
42
|
+
| `endSession` | `() => void` |
|
|
43
|
+
| `disconnect` | `() => void` |
|
|
44
|
+
|
|
45
|
+
Everything else on the class is private. `Reticle` itself is exported for typing.
|
|
46
|
+
|
|
47
|
+
## `ReticleConnectOptions`
|
|
48
|
+
|
|
49
|
+
Every field is optional.
|
|
50
|
+
|
|
51
|
+
| Option | Type | What it controls |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `url` | `string` | Bridge URL, when you are not on the default port |
|
|
54
|
+
| `session` | `string` | Session id. Defaults to the auto id (`SESSION_AUTO` is re-exported here) |
|
|
55
|
+
| `projectId` | `string` | Project identity stamped on the handshake |
|
|
56
|
+
| `token` | `string` | Pairing token, required for a non-loopback page |
|
|
57
|
+
| `allowNonLocalhost` | `boolean` | Opt in to connecting from a non-localhost origin |
|
|
58
|
+
| `allowInProduction` | `boolean` | Opt in to connecting from a production build. Desktop apps need this |
|
|
59
|
+
| `overlay` | `boolean` | The in-page overlay |
|
|
60
|
+
| `captureNetworkBodies` | `boolean` | Record request and response bodies |
|
|
61
|
+
| `root` | `string` | Repository root, so source paths come back relative |
|
|
62
|
+
| `sdkVersion` | `string` | Reported on the handshake for skew detection |
|
|
63
|
+
| `present` | `boolean` | Presenter mode |
|
|
64
|
+
| `pace` | `number` | Presenter pacing |
|
|
65
|
+
| `narrationDwellMs` | `number` | Presenter narration dwell |
|
|
66
|
+
| `border` | `'session' \| 'busy'` | Which border the overlay draws |
|
|
67
|
+
| `logMax` | `number` | Console buffer cap |
|
|
68
|
+
| `recorder` | `boolean` | Enable flow recording |
|
|
69
|
+
| `annotate` | `boolean` | Enable the human annotation layer |
|
|
70
|
+
| `endedFadeMs` | `number` | Fade after a session ends |
|
|
71
|
+
| `idleEndMs` | `number` | Idle timeout before the session ends itself |
|
|
72
|
+
| `redact` | `RedactionConfig` | Redaction policy, from core |
|
|
73
|
+
|
|
74
|
+
## Capabilities
|
|
75
|
+
|
|
76
|
+
Declaring a capability surface is what lets an agent discover what your app can do without guessing.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { registerCapabilities } from '@reticlehq/browser';
|
|
80
|
+
|
|
81
|
+
registerCapabilities({
|
|
82
|
+
testids: ['login-submit'],
|
|
83
|
+
signals: ['auth:granted'],
|
|
84
|
+
stores: ['session'],
|
|
85
|
+
flows: [{ name: 'login', steps: ['fill email', 'fill password', 'submit'] }],
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Also exported: `getCapabilities()`, `hasCapabilities()`, `setCapabilitiesListener(cb?)`, and the `Capabilities`, `CapabilitiesInput` and `CapabilityFlow` types.
|
|
90
|
+
|
|
91
|
+
## State adapters
|
|
92
|
+
|
|
93
|
+
Register a store and its contents become readable through [`reticle_state`](/tools-state).
|
|
94
|
+
|
|
95
|
+
`registerStore`, `unregisterStore`, `storeNames`, `readStores`, `readStoresWithTruncation`.
|
|
96
|
+
|
|
97
|
+
Ready-made adapters ship for TanStack Query, Jotai, XState, Valtio, MobX, Recoil, Svelte, Pinia, and a plain push store: `tanstackQueryStore`, `jotaiStore`, `xstateStore`, `valtioStore`, `mobxStore`, `recoilStore`, `svelteStore`, `piniaStore`, `pushStore`.
|
|
98
|
+
|
|
99
|
+
## Framework adapters
|
|
100
|
+
|
|
101
|
+
`registerAdapter`, `identifyComponent`, `readComponentState`, `elementHasHoverHandlers`, `adapterNames`, with the `ReticleAdapter`, `ComponentInfo` and `ComponentSource` types. [`@reticlehq/react`](/packages/react) registers the React one.
|
|
102
|
+
|
|
103
|
+
## Lower-level building blocks
|
|
104
|
+
|
|
105
|
+
Exported because the server and the test runner use them, and because an integration may need them: `buildSnapshot`, `matchQuery`, `runQuery`, `executeAction`, `executeSequence`, `describe`, `getRole`, `getAccessibleName`, `getStates`, `isVisible`, `refs`, `RefRegistry`, `setIgnoreSelectors`, `Annotator`, `installAnnotator`, `resolveMarkAnchor`, `inspectChart`, `canvasChartData`.
|
|
106
|
+
|
|
107
|
+
Signal helpers: `createReticleEmitter`, `commitAndSignal`, `registerReticleDomain`.
|
|
108
|
+
|
|
109
|
+
<Card title="Instrumenting an app properly" icon="plug" href="/instrumentation">
|
|
110
|
+
Signals, stores, and what makes evidence strong rather than circumstantial.
|
|
111
|
+
</Card>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '@reticlehq/core'
|
|
3
|
+
description: 'The shared wire contract for Reticle: constants, zod schemas, and the isomorphic kernel every other package imports.'
|
|
4
|
+
icon: cube
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`@reticlehq/core` is the shared wire contract at the bottom of Reticle's dependency graph. Every message that crosses a boundary, browser to bridge, bridge to agent, is defined here as a named constant plus a zod schema. **You almost certainly do not need to install it**: it arrives with whatever Reticle package you did install, and you only reach for it directly if you are building your own integration against the wire format.
|
|
8
|
+
|
|
9
|
+
**Apache 2.0. Depends on `zod` and nothing else.**
|
|
10
|
+
|
|
11
|
+
## Why it exists
|
|
12
|
+
|
|
13
|
+
Without one shared definition the browser and the server drift. One side renames a field, the other keeps reading the old one, and the failure is silent: a verdict that quietly stops carrying its evidence. Core makes that a type error instead.
|
|
14
|
+
|
|
15
|
+
The single dependency is the point. Everything can depend on core without cycles, and nothing core does can drag a filesystem call into the browser bundle.
|
|
16
|
+
|
|
17
|
+
## Do you install it?
|
|
18
|
+
|
|
19
|
+
No. It arrives as a dependency of `@reticlehq/browser`, `@reticlehq/react`, `@reticlehq/server`, `@reticlehq/vite-plugin` or `@reticlehq/electron`. Install it directly only if you are building your own integration against the wire format.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm i @reticlehq/core
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Exports map
|
|
26
|
+
|
|
27
|
+
| Subpath | What it is |
|
|
28
|
+
| --- | --- |
|
|
29
|
+
| `.` | The ESM barrel. Types at `dist/index.d.ts` |
|
|
30
|
+
| `./desktop-contract` | A CommonJS shim, generated at build, for the strings the desktop adapters share |
|
|
31
|
+
| `./schema/*.json` | Generated JSON Schema for the wire types |
|
|
32
|
+
| `./package.json` | The manifest |
|
|
33
|
+
|
|
34
|
+
<Warning>
|
|
35
|
+
There is no `@reticlehq/core/vite` subpath. It was documented in an old README and never existed
|
|
36
|
+
in the exports map. The Vite plugin is [`@reticlehq/vite-plugin`](/packages/vite-plugin).
|
|
37
|
+
</Warning>
|
|
38
|
+
|
|
39
|
+
## What the barrel exports
|
|
40
|
+
|
|
41
|
+
`src/index.ts` is a pure barrel: a stack of `export *` re-exports plus one named export. Grouped by what they are for, and not exhaustive:
|
|
42
|
+
|
|
43
|
+
### Wire constants
|
|
44
|
+
|
|
45
|
+
`RETICLE_DEFAULT_PORT` (`4400`), `RETICLE_WS_PATH` (`/reticle`), `MCP_SSE_PATH`, `MCP_MESSAGE_PATH`, `STATUS_PATH`, `RETICLE_PROTOCOL_VERSION` (`1`), `RETICLE_URL_PARAM`, `LOOPBACK_HOST` (`127.0.0.1`), `TRANSPORT_LIMITS`, `REDACTED_VALUE`, `RING_BUFFER_DEFAULTS`, `DEFAULT_ASSERT_TIMEOUT_MS` (`4000`), `VISUAL_PIXEL_THRESHOLD` (`0.1`), `SCROLL_FIND_DEFAULTS`, `CRAWL_DEFAULTS`.
|
|
46
|
+
|
|
47
|
+
### Environment and directories
|
|
48
|
+
|
|
49
|
+
`ReticleEnv` names every environment variable Reticle reads: `RETICLE_TOKEN`, `RETICLE_HOST`, `RETICLE_ALLOWED_ORIGINS`, `RETICLE_PORT`, `RETICLE_STATE_DIR`, `RETICLE_CDP_URL`, `RETICLE_MAX_CONTEXTS`, `RETICLE_MAX_MESSAGES_PER_SECOND` and the rest. `ReticleDir` names the paths under `.reticle/`.
|
|
50
|
+
|
|
51
|
+
### Enum-like frozen objects
|
|
52
|
+
|
|
53
|
+
`EventType`, `ActionType`, `ElementState`, `QueryBy`, `MessageKind`, `ReticleCommand`, `PhenomenonType`, `SettleReason`, `ComponentStateReason`, `InputMode`, `InputModeReason`, `ActionWarning`, `DriveErrorCode`, `TruncationChannel`, `EventAttribution`, `PerfMetric`, `PresenterMode`, `SnapshotMode`, `VisualReason`, `CONSOLE_LEVELS`, `Verified`.
|
|
54
|
+
|
|
55
|
+
`ComponentStateResult` is an interface, not one of these: it is a type-only export, so importing it as a value fails with `'ComponentStateResult' only refers to a type, but is being used as a value here`.
|
|
56
|
+
|
|
57
|
+
### Zod schemas
|
|
58
|
+
|
|
59
|
+
`ReticleMessageSchema` (a discriminated union on `kind`) and its members `HelloMessageSchema`, `CommandMessageSchema`, `CommandResultSchema`, `EventMessageSchema`, plus `ReticleEventSchema`. Flows are `FlowStepSchema`, `FlowExpectSchema`, `FlowAnchorSchema`, `FlowFileSchema`, `RecordedFlowSchema`. CI runs are `ReticleVerificationRunSchema`, `RunVerdictSchema`, `RunFlowResultSchema`, `RunCheckSchema`, `RunRiskSchema`, `RepairPacketSchema`, `VerificationEvidenceSchema`. Telemetry is `TelemetryEventSchema`, `SessionSummarySchema`, `ProjectProfileSchema`, `FeedbackSchema`, `IdentitySchema`.
|
|
60
|
+
|
|
61
|
+
### Kernel functions
|
|
62
|
+
|
|
63
|
+
Pure, isomorphic, and safe on both sides of the wire:
|
|
64
|
+
|
|
65
|
+
| Function | What it does |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `fingerprintOf` / `CONTRACT_FINGERPRINT` | The contract hash the daemon and the SDK compare on handshake |
|
|
68
|
+
| `bridgeWsUrl` | Build the bridge WebSocket URL |
|
|
69
|
+
| `parseEventPayload`, `isHighValueEvent` | Narrow and rank inbound events |
|
|
70
|
+
| `isConsequenceKind`, `isPresenceKind`, `flowExpectHasConsequence`, `flowExpectIsPresenceOnly` | The consequence versus presence distinction the gate's anti-downgrade check runs on |
|
|
71
|
+
| `selectPath`, `capDepth`, `projectComponentState` | Bounded state projection |
|
|
72
|
+
| `isLoopbackHostname`, `isLocalPage`, `isOpaqueOrigin`, `isDangerousActionText` | The security predicates |
|
|
73
|
+
| `defaultIsSensitiveKey`, `buildRedactionPolicy`, `setActiveRedactionPolicy`, `isSensitiveKey`, `scrubKnownSecrets` | Redaction |
|
|
74
|
+
| `toToon`, `resultToToon`, `isToonable` | The compact result encoding |
|
|
75
|
+
| `projectIdFrom`, `slugifyPackageName` | Project identity |
|
|
76
|
+
| `pickDaemonPort`, `daemonRegistryFileName`, `daemonRegistryPort` | Daemon discovery |
|
|
77
|
+
| `isSessionScoped`, `isSessionState` | Session scoping |
|
|
78
|
+
| `buildUpgradeHint`, `isCloudCapability` | Upgrade hints |
|
|
79
|
+
|
|
80
|
+
## The desktop contract
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import { RETICLE_IPC_GLOBAL, RETICLE_CAPTURE_CHANNEL } from '@reticlehq/core/desktop-contract';
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Six strings shared by the Electron preload and the Tauri crate, in CommonJS because a preload script is required before any ESM transform:
|
|
87
|
+
|
|
88
|
+
| Constant | Value |
|
|
89
|
+
| ------------------------------- | ---------------------------------------------------------- |
|
|
90
|
+
| `RETICLE_IPC_GLOBAL` | `__reticleIpc` |
|
|
91
|
+
| `RETICLE_CAPTURE_CHANNEL` | `__reticle:capture` |
|
|
92
|
+
| `RETICLE_CAPTURE_FILE_PREFIX` | `reticle-capture-` |
|
|
93
|
+
| `RETICLE_TAURI_CAPTURE_COMMAND` | `reticle_capture` |
|
|
94
|
+
| `RETICLE_FULL_PAGE_UNSUPPORTED` | `full-page-unsupported`, for a refused full-page capture |
|
|
95
|
+
| `RETICLE_NOT_COMPOSITED` | `window-not-composited`, for a window that had not painted |
|
|
96
|
+
|
|
97
|
+
<Warning>
|
|
98
|
+
The subpath exports those six constants individually and nothing else. The `DESKTOP_CONTRACT`
|
|
99
|
+
record they are collected into exists on the ESM side only, so importing it here fails with
|
|
100
|
+
`Module '"@reticlehq/core/desktop-contract"' has no exported member 'DESKTOP_CONTRACT'`. Import
|
|
101
|
+
`DESKTOP_CONTRACT` from `@reticlehq/core` instead.
|
|
102
|
+
</Warning>
|
|
103
|
+
|
|
104
|
+
## The JSON schemas
|
|
105
|
+
|
|
106
|
+
Seven files, generated at build from the zod definitions:
|
|
107
|
+
|
|
108
|
+
`reticle-message.json`, `reticle-event.json`, `hello-message.json`, `command-message.json`, `command-result.json`, `event-message.json`, `event-type.json`.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import schema from '@reticlehq/core/schema/reticle-message.json' with { type: 'json' };
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
<Card title="How the pieces fit" icon="sitemap" href="/architecture">
|
|
115
|
+
Where the contract sits between the SDK, the bridge, and the agent.
|
|
116
|
+
</Card>
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '@reticlehq/electron'
|
|
3
|
+
description: The Reticle adapter for Electron, making main-process IPC observable and the window screenshottable.
|
|
4
|
+
icon: display
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`@reticlehq/electron` reaches the two places the renderer-side SDK cannot: the IPC boundary, and `capturePage()`. Install it if your app is Electron and you want main-process IPC observable or the window screenshottable. A web app never needs it.
|
|
8
|
+
|
|
9
|
+
**Apache 2.0. Depends on `@reticlehq/core`. Peer dependency: `electron >= 22`. No build step.**
|
|
10
|
+
|
|
11
|
+
## Why it exists
|
|
12
|
+
|
|
13
|
+
In Electron the interesting failures happen across IPC. The renderer asks the main process for something, the main process quietly fails, and the renderer-side SDK sees nothing at all. That reads as "this app makes no backend calls" rather than "you are blind to them".
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i -D @reticlehq/electron
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Exports map
|
|
20
|
+
|
|
21
|
+
There is no `.` export. Two subpaths only.
|
|
22
|
+
|
|
23
|
+
| Subpath | File | Shape |
|
|
24
|
+
| ----------- | ------------- | --------------------------------- |
|
|
25
|
+
| `./preload` | `preload.cjs` | Side effect only. Exports nothing |
|
|
26
|
+
| `./main` | `main.cjs` | `{ installReticleCapture }` |
|
|
27
|
+
|
|
28
|
+
## The preload
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
// preload.js: this line must be FIRST
|
|
32
|
+
require('@reticlehq/electron/preload');
|
|
33
|
+
|
|
34
|
+
const { contextBridge, ipcRenderer } = require('electron');
|
|
35
|
+
// ... your own bridge setup
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
<Warning>
|
|
39
|
+
It must run before `require('electron')` and before any `contextBridge.exposeInMainWorld` call. It
|
|
40
|
+
patches `ipcRenderer` while those methods are still writable, so ordering is not a style
|
|
41
|
+
preference.
|
|
42
|
+
</Warning>
|
|
43
|
+
|
|
44
|
+
It patches three methods, and each IPC call then surfaces to Reticle as a network record on `ipc://<channel>` with `initiator: 'ipc'`:
|
|
45
|
+
|
|
46
|
+
| Method | Recorded as |
|
|
47
|
+
| ---------------------- | ------------------------------------ |
|
|
48
|
+
| `ipcRenderer.invoke` | Two-way, with its outcome |
|
|
49
|
+
| `ipcRenderer.sendSync` | Two-way, with its outcome |
|
|
50
|
+
| `ipcRenderer.send` | One-way, dispatched, with no outcome |
|
|
51
|
+
|
|
52
|
+
It then exposes `window.__reticleIpc` through the context bridge, with three members used by the SDK rather than by you:
|
|
53
|
+
|
|
54
|
+
| Member | Signature | Notes |
|
|
55
|
+
| --- | --- | --- |
|
|
56
|
+
| `subscribe` | `(callback) => number` | Returns a token, or `-1` if the argument is not a function |
|
|
57
|
+
| `unsubscribe` | `(token) => void` | Real removal |
|
|
58
|
+
| `capture` | `(fullPage) => Promise<string \| null>` | Resolves to a capture file path, `null` when no main handler is installed, and propagates the explicit full-page refusal |
|
|
59
|
+
|
|
60
|
+
## The main process
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
const { installReticleCapture } = require('@reticlehq/electron/main');
|
|
64
|
+
|
|
65
|
+
const win = new BrowserWindow({/* ... */});
|
|
66
|
+
installReticleCapture(win);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`installReticleCapture(win): void` is a no-op on `null` or `undefined`, tracks the window until it closes, and registers the capture handler once for the whole app.
|
|
70
|
+
|
|
71
|
+
The handler calls `webContents.capturePage()`, writes the PNG into a per-process `0700` captures directory as `reticle-capture-<n>.png`, and **returns the file path rather than the bytes**, because the transport has a 64KB cap. It refuses `fullPage: true` explicitly rather than silently returning a viewport shot, and it throws named reasons rather than one blanket silence: `full-page-unsupported` for that refusal, `window-not-composited` when the window had nothing painted yet, `no usable webContents to capture` when the window is gone. The preload re-throws the full-page refusal and turns everything else into `null`.
|
|
72
|
+
|
|
73
|
+
## Renderer wiring
|
|
74
|
+
|
|
75
|
+
The renderer still needs the SDK. A packaged app is a production build, so the connect call has to opt in:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
reticle.connect({ allowInProduction: true });
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Or, with the Vite plugin, `reticle({ desktop: true })`.
|
|
82
|
+
|
|
83
|
+
<Card title="Desktop setup in full" icon="display" href="/desktop">
|
|
84
|
+
Electron and Tauri wiring, and what `reticle doctor` checks for each.
|
|
85
|
+
</Card>
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '@reticlehq/eslint-plugin'
|
|
3
|
+
description: Two lint rules that keep Reticle's signal layer and its comment hygiene self-enforcing.
|
|
4
|
+
icon: shield-check
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`@reticlehq/eslint-plugin` is two ESLint rules that keep Reticle's signal layer self-enforcing. It is entirely optional: nothing in Reticle needs it, and you want it only once your app emits signals and you would like the compiler to notice when a new mutation forgets one.
|
|
8
|
+
|
|
9
|
+
It exists because conventions rot. Someone adds a mutation, forgets the signal, and every verdict for that flow quietly drops a grade. Nothing breaks, the tests still pass, the evidence just gets weaker. A lint rule is the only way a convention survives contact with a deadline.
|
|
10
|
+
|
|
11
|
+
**Apache 2.0. Depends on `@typescript-eslint/utils`. Peer dependency: `eslint >= 9`.**
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm i -D @reticlehq/eslint-plugin
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Exports
|
|
18
|
+
|
|
19
|
+
| Export | What it is |
|
|
20
|
+
| ------------------------- | ------------------------------------------------------------------ |
|
|
21
|
+
| `default` | The plugin object: `{ meta: { name: 'reticle' }, rules, configs }` |
|
|
22
|
+
| `rules` | `{ 'require-signal-on-mutation': ..., 'no-internal-tags': ... }` |
|
|
23
|
+
| `requireSignalOnMutation` | The rule, exported individually |
|
|
24
|
+
| `noInternalTags` | The rule, exported individually |
|
|
25
|
+
|
|
26
|
+
## The rules
|
|
27
|
+
|
|
28
|
+
### `reticle/require-signal-on-mutation`
|
|
29
|
+
|
|
30
|
+
Warns when a store mutation happens without a mapped Reticle signal.
|
|
31
|
+
|
|
32
|
+
**Message id:** `mutationWithoutSignal`. **Text:** `store mutation without a mapped Reticle signal`.
|
|
33
|
+
|
|
34
|
+
**Options** (`options[0]`, no additional properties):
|
|
35
|
+
|
|
36
|
+
| Option | Type | Default |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `mutators` | `string[]` | `[]`. With the default the rule is a no-op, which is deliberate: name your own mutators. Matched by BARE NAME, so `set` also matches `map.set()` and `headers.set()`; prefer an unambiguous name |
|
|
39
|
+
| `signalCallee` | `string \| string[]` | `['reticleSignal', 'signal']` |
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
'reticle/require-signal-on-mutation': ['warn', {
|
|
43
|
+
mutators: ['setState', 'commit', 'dispatch'],
|
|
44
|
+
signalCallee: ['reticleSignal'],
|
|
45
|
+
}]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The check is scoped per function: a mutation and its signal must live in the same function body.
|
|
49
|
+
|
|
50
|
+
### `reticle/no-internal-tags`
|
|
51
|
+
|
|
52
|
+
Errors on internal design-doc reference codes and internal version strings appearing in comments, file names, directory names or test descriptions. **Message id:** `internalTag`, with a `{ tag }` placeholder. No options.
|
|
53
|
+
|
|
54
|
+
This one is mostly for contributors to Reticle itself, but the `recommended` config turns it on for everyone.
|
|
55
|
+
|
|
56
|
+
## The recommended config
|
|
57
|
+
|
|
58
|
+
One config, `recommended`:
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
import reticle from '@reticlehq/eslint-plugin';
|
|
62
|
+
|
|
63
|
+
export default [reticle.configs.recommended];
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Which is exactly:
|
|
67
|
+
|
|
68
|
+
```js
|
|
69
|
+
{
|
|
70
|
+
plugins: { reticle: plugin },
|
|
71
|
+
rules: {
|
|
72
|
+
'reticle/require-signal-on-mutation': 'warn',
|
|
73
|
+
'reticle/no-internal-tags': 'error',
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
<Warning>
|
|
79
|
+
`recommended` enables **both** rules, and `no-internal-tags` at `error`. An older README
|
|
80
|
+
documented only the first rule, so the second can arrive as a surprise. Enable the rules
|
|
81
|
+
individually if you want just the signal check.
|
|
82
|
+
</Warning>
|
|
83
|
+
|
|
84
|
+
<Card title="Why signals are the strongest evidence" icon="tower-broadcast" href="/instrumentation">
|
|
85
|
+
What a signal proves that a rendered pixel cannot.
|
|
86
|
+
</Card>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '@reticlehq/next'
|
|
3
|
+
description: Next.js source mapping for Reticle without giving up SWC, via a dev-only loader.
|
|
4
|
+
icon: n
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`@reticlehq/next` gives a Next.js app the same `data-reticle-source` stamping the Vite plugin does, without asking it to migrate off SWC to Babel. Install it if your app is Next.js; on Vite use [`@reticlehq/vite-plugin`](/packages/vite-plugin) instead. Unlike the Vite plugin it does **not** inject `connect()`, so you still call that yourself.
|
|
8
|
+
|
|
9
|
+
**Apache 2.0. CommonJS, no build step. Depends on `@babel/core` and `@reticlehq/babel-plugin`. Peer dependency: `next >= 13`.**
|
|
10
|
+
|
|
11
|
+
## Why it exists
|
|
12
|
+
|
|
13
|
+
Next users are on SWC. Telling them to switch to Babel for a dev tool would be a rude trade, and it would slow down every build they run. This adds a dev-only pre-loader for `.jsx` and `.tsx` and leaves the rest of the pipeline alone.
|
|
14
|
+
|
|
15
|
+
## Install and use
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i -D @reticlehq/next @reticlehq/react
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
// next.config.js
|
|
23
|
+
const { withReticle } = require('@reticlehq/next');
|
|
24
|
+
|
|
25
|
+
module.exports = withReticle({/* your config */});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
<Note>
|
|
29
|
+
This package is CommonJS on purpose. `next.config.js` is loaded by Node before any ESM transform,
|
|
30
|
+
so an ESM-only helper would fail at the least helpful possible moment.
|
|
31
|
+
</Note>
|
|
32
|
+
|
|
33
|
+
## Exports
|
|
34
|
+
|
|
35
|
+
### `.`
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
function withReticle<T = unknown>(nextConfig?: T): T;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Returns the config unchanged when `NODE_ENV === 'production'`. Otherwise it merges in:
|
|
42
|
+
|
|
43
|
+
| Addition | What it does |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `webpack` | Pushes an `enforce: 'pre'` rule for `/\.(t\|j)sx$/`, excluding `node_modules`, using this package's loader. Your own `webpack` function still runs afterwards |
|
|
46
|
+
| `turbopack` | On Next 15.3 and above only: rules for `*.tsx` and `*.jsx` pointing at `@reticlehq/next/loader` |
|
|
47
|
+
| `env.NEXT_PUBLIC_RETICLE_TOKEN` | The pairing token, when one exists on disk |
|
|
48
|
+
| `env.NEXT_PUBLIC_RETICLE_ROOT` | `process.cwd()`, so source paths come back repository-relative |
|
|
49
|
+
| `env.NEXT_PUBLIC_RETICLE_SDK_VERSION` | The version of the app's installed `@reticlehq/react` |
|
|
50
|
+
|
|
51
|
+
`readPairingToken()` is also exported at runtime. It is not declared in `index.d.ts`, so TypeScript will not see it.
|
|
52
|
+
|
|
53
|
+
### `./loader`
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
declare function reticleNextLoader(this: unknown, source: string, inputMap?: unknown): void;
|
|
57
|
+
export = reticleNextLoader;
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
An async webpack loader. It skips anything that is not `.jsx` or `.tsx`, and anything under `node_modules`. It lazily imports `@reticlehq/babel-plugin` and runs `babel.transformAsync` with `configFile: false`, `babelrc: false`, `retainLines`, and source maps on.
|
|
61
|
+
|
|
62
|
+
<Note>
|
|
63
|
+
The loader never fails the build. Any error falls back to the original source, because a dev-only
|
|
64
|
+
source stamp is not worth breaking someone's `next dev` over.
|
|
65
|
+
</Note>
|
|
66
|
+
|
|
67
|
+
## What it does not do
|
|
68
|
+
|
|
69
|
+
It does not inject `connect()`. On Next you call it yourself, once, in a client component:
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
'use client';
|
|
73
|
+
import { useEffect } from 'react';
|
|
74
|
+
import { reticle, install } from '@reticlehq/react';
|
|
75
|
+
|
|
76
|
+
export function ReticleDev() {
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
79
|
+
install();
|
|
80
|
+
reticle.connect();
|
|
81
|
+
}
|
|
82
|
+
}, []);
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
<Card title="Framework by framework" icon="layer-group" href="/frameworks">
|
|
88
|
+
What each supported stack needs, and what it gets for free.
|
|
89
|
+
</Card>
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: '@reticlehq/react'
|
|
3
|
+
description: The React kit for Reticle, mapping a DOM node to its component stack, its hook state, and its source file.
|
|
4
|
+
icon: react
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`@reticlehq/react` is the Reticle kit for React apps, and usually the only SDK package a React user needs: it re-exports the whole browser SDK and adds fiber-tree work that maps a DOM node to its component stack, its hook state, and its source file. If your app is React, install this one and not `@reticlehq/browser`.
|
|
8
|
+
|
|
9
|
+
**Apache 2.0. Depends on `@reticlehq/browser` and `@reticlehq/core`. Peer dependency: `react >= 18`.**
|
|
10
|
+
|
|
11
|
+
## Why it exists
|
|
12
|
+
|
|
13
|
+
This is the package that turns "the button is broken" into `src/components/Login.tsx:81`. Finding a bug is half the job; Reticle's answer to the other half lives here.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i -D @reticlehq/react
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## It re-exports the browser SDK
|
|
20
|
+
|
|
21
|
+
`export * from '@reticlehq/browser'` is in the barrel, so one install gives you `reticle`, `registerCapabilities`, every store adapter, and everything else on the [browser page](/packages/browser). You do not add `@reticlehq/browser` separately.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { reticle, install } from '@reticlehq/react';
|
|
25
|
+
install();
|
|
26
|
+
reticle.connect();
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Exports
|
|
30
|
+
|
|
31
|
+
### Setup
|
|
32
|
+
|
|
33
|
+
| Export | Signature | What it does |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `install` | `(): void` | Idempotent. Registers the `react` adapter and installs the render meter. Call it once, before `connect()` |
|
|
36
|
+
|
|
37
|
+
The [Vite plugin](/packages/vite-plugin) injects `install()` and `reticle.connect()` for you, so a Vite user never writes either line.
|
|
38
|
+
|
|
39
|
+
### Mapping a node to its component
|
|
40
|
+
|
|
41
|
+
| Export | Signature |
|
|
42
|
+
| ------------------ | ---------------------------------------- |
|
|
43
|
+
| `identify` | `(el: Element) => ComponentInfo \| null` |
|
|
44
|
+
| `readState` | `(el: Element) => ComponentStateResult` |
|
|
45
|
+
| `hasHoverHandlers` | `(el: Element) => boolean` |
|
|
46
|
+
| `relativeToRoot` | `(file: string) => string` |
|
|
47
|
+
|
|
48
|
+
`identify` walks the fiber tree to build the component stack and source location. `readState` reads hook state, bounded. `relativeToRoot` turns an absolute source path into a repository-relative one using the root the plugin stamped.
|
|
49
|
+
|
|
50
|
+
### Render measurement
|
|
51
|
+
|
|
52
|
+
`installRenderMeter`, `resetRenderMeter`, `getRenderStats`, and the `RenderStats` type. This is what makes a render loop visible as a number rather than a hunch.
|
|
53
|
+
|
|
54
|
+
### Hydration
|
|
55
|
+
|
|
56
|
+
`HYDRATION_COMPLETE_SIGNAL`, `createHydrationTracker`, type `HydrationTracker`.
|
|
57
|
+
|
|
58
|
+
### Error boundaries
|
|
59
|
+
|
|
60
|
+
`buildErrorBoundaryData`, `reticleOnCaughtError`, type `ErrorBoundaryData`. Wire `reticleOnCaughtError` into React's `onCaughtError` and a boundary that swallows an error stops being invisible.
|
|
61
|
+
|
|
62
|
+
### Hydration mismatches
|
|
63
|
+
|
|
64
|
+
`buildHydrationErrorData`, `isHydrationMismatch`, `reticleOnRecoverableError`, type `HydrationErrorData`.
|
|
65
|
+
|
|
66
|
+
### Commits and CDP
|
|
67
|
+
|
|
68
|
+
`createCommitAggregator`, type `CommitAggregator`. `readComponentAt`, `buildReaderExpression`, `parseComponentRead`, type `CdpComponentRead`.
|
|
69
|
+
|
|
70
|
+
## The `./store` subpath
|
|
71
|
+
|
|
72
|
+
One export, and the only module in the package that imports React:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { useReticleStore } from '@reticlehq/react/store';
|
|
76
|
+
|
|
77
|
+
function Cart() {
|
|
78
|
+
const [items, setItems] = useState([]);
|
|
79
|
+
useReticleStore('cart', items); // now readable via reticle_state
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`useReticleStore(name: string, value: unknown): void`.
|
|
84
|
+
|
|
85
|
+
## Source mapping needs a build step
|
|
86
|
+
|
|
87
|
+
React 19 dropped `_debugSource`, so `identify` can name the component but not the file unless something stamps the source at build time. That is [`@reticlehq/babel-plugin`](/packages/babel-plugin), pulled in for you by [`@reticlehq/vite-plugin`](/packages/vite-plugin) or [`@reticlehq/next`](/packages/next).
|
|
88
|
+
|
|
89
|
+
<Card title="Reading component state" icon="layer-group" href="/state-management">
|
|
90
|
+
What `reticle_state` can see, and how to widen it.
|
|
91
|
+
</Card>
|