@reticlehq/server 2.10.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +73 -11
- package/dist/bridge/bridge.d.ts +0 -13
- package/dist/bridge/bridge.js +1 -1
- package/dist/bridge/bridge.test-harness.d.ts +2 -0
- package/dist/bridge/bridge.test-harness.js +8 -1
- package/dist/capsule/capsule-store.d.ts +2 -1
- package/dist/capsule/capsule-store.js +1 -1
- package/dist/capsule/causal-summary.d.ts +2 -2
- package/dist/chromium-launch-options.d.ts +28 -0
- package/dist/chromium-launch-options.js +29 -0
- package/dist/cli/cli-doctor.js +8 -0
- package/dist/cli/cli-flow-commands.d.ts +3 -1
- package/dist/cli/cli-flow-commands.js +34 -4
- package/dist/cli/cli-kill.d.ts +2 -1
- package/dist/cli/cli-parse.d.ts +3 -1
- package/dist/cli/cli-parse.js +29 -7
- package/dist/cli/cli-update-commands.js +20 -1
- package/dist/cli/cli-verify.d.ts +1 -1
- package/dist/cli/cli-verify.js +2 -2
- package/dist/cli/cloud-cli.js +12 -6
- package/dist/cli/config-discovery.d.ts +2 -1
- package/dist/cli/doctor-rows.d.ts +3 -1
- package/dist/cli/doctor-rows.js +3 -1
- package/dist/cli/gate-exit.d.ts +21 -0
- package/dist/cli/gate-exit.js +21 -0
- package/dist/cli/gate-hook-message.d.ts +33 -0
- package/dist/cli/gate-hook-message.js +46 -0
- package/dist/cli/mcp-command.d.ts +25 -0
- package/dist/cli/mcp-command.js +143 -0
- package/dist/cli/sibling-ports.d.ts +37 -0
- package/dist/cli/sibling-ports.js +56 -0
- package/dist/cli.js +37 -110
- package/dist/cloud/cloud-config.d.ts +2 -1
- package/dist/cloud/cloud-sync.d.ts +11 -0
- package/dist/cloud/cloud-sync.js +32 -0
- package/dist/crawl/crawl.d.ts +9 -13
- package/dist/crawl/crawl.js +20 -3
- package/dist/daemon/daemon-resolve.d.ts +79 -0
- package/dist/daemon/daemon-resolve.js +118 -0
- package/dist/daemon/free-port.d.ts +29 -0
- package/dist/daemon/free-port.js +55 -0
- package/dist/daemon/heartbeat.d.ts +0 -4
- package/dist/daemon/heartbeat.js +2 -2
- package/dist/dev/stale-issue-guard.d.ts +41 -0
- package/dist/dev/stale-issue-guard.js +75 -0
- package/dist/domain/domain-tools.js +3 -2
- package/dist/events/contradictions.d.ts +41 -0
- package/dist/events/contradictions.js +125 -12
- package/dist/events/declared.d.ts +14 -0
- package/dist/events/declared.js +33 -0
- package/dist/events/echo-mismatch.js +14 -0
- package/dist/events/observed-in-window.d.ts +12 -0
- package/dist/events/observed-in-window.js +17 -0
- package/dist/events/predicate-asks.d.ts +30 -0
- package/dist/events/predicate-asks.js +48 -0
- package/dist/events/predicate-eval.js +254 -25
- package/dist/events/predicate-parse.d.ts +0 -6
- package/dist/events/predicate-parse.js +51 -5
- package/dist/events/predicate-schema.d.ts +62 -0
- package/dist/events/predicate-schema.js +162 -4
- package/dist/events/predicate.d.ts +15 -0
- package/dist/events/predicate.js +41 -2
- package/dist/flows/coverage.d.ts +0 -8
- package/dist/flows/coverage.js +1 -1
- package/dist/flows/decision.d.ts +5 -1
- package/dist/flows/decision.js +33 -7
- package/dist/flows/flake.d.ts +0 -2
- package/dist/flows/flake.js +1 -1
- package/dist/flows/flow-intent.d.ts +52 -0
- package/dist/flows/flow-intent.js +123 -0
- package/dist/flows/flow-replay-run.js +27 -4
- package/dist/flows/flow-success.js +15 -3
- package/dist/flows/flow-tools.js +65 -8
- package/dist/flows/flows.d.ts +6 -1
- package/dist/flows/flows.js +34 -22
- package/dist/flows/predicate-to-expect.js +14 -3
- package/dist/flows/server-verify.js +16 -2
- package/dist/flows/verify-change-tools.js +9 -2
- package/dist/honesty/blind-spots.d.ts +8 -16
- package/dist/honesty/blind-spots.js +18 -5
- package/dist/honesty/feature-capture.d.ts +150 -0
- package/dist/honesty/feature-capture.js +233 -0
- package/dist/honesty/gap-ledger.d.ts +52 -0
- package/dist/honesty/gap-ledger.js +63 -0
- package/dist/honesty/instrumentation-gaps.d.ts +79 -0
- package/dist/honesty/instrumentation-gaps.js +77 -0
- package/dist/honesty/observability.d.ts +37 -0
- package/dist/honesty/observability.js +40 -0
- package/dist/honesty/tool-hit-rate.d.ts +86 -0
- package/dist/honesty/tool-hit-rate.js +90 -0
- package/dist/honesty/undeclared-change.d.ts +51 -0
- package/dist/honesty/undeclared-change.js +56 -0
- package/dist/honesty/verified.d.ts +15 -0
- package/dist/honesty/verified.js +68 -4
- package/dist/http-server.d.ts +0 -1
- package/dist/http-server.js +1 -1
- package/dist/hunt/hunt-report.d.ts +0 -2
- package/dist/hunt/hunt-report.js +1 -1
- package/dist/impact/impact-store.d.ts +0 -5
- package/dist/impact/impact-store.js +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +41 -0
- package/dist/init/agent-rules.d.ts +17 -0
- package/dist/init/agent-rules.js +31 -1
- package/dist/init/capabilities.d.ts +0 -2
- package/dist/init/capabilities.js +1 -1
- package/dist/init/closing-hint.d.ts +36 -0
- package/dist/init/closing-hint.js +120 -0
- package/dist/init/confirm.d.ts +0 -25
- package/dist/init/confirm.js +3 -3
- package/dist/init/cra.d.ts +14 -1
- package/dist/init/cra.js +43 -12
- package/dist/init/dev-script.d.ts +48 -0
- package/dist/init/dev-script.js +63 -0
- package/dist/init/mcp.d.ts +16 -5
- package/dist/init/mcp.js +26 -10
- package/dist/init/node-io.js +3 -0
- package/dist/init/plan-framework.d.ts +0 -5
- package/dist/init/plan-framework.js +83 -9
- package/dist/init/plan.d.ts +10 -30
- package/dist/init/plan.js +30 -15
- package/dist/init/refresh-rules.d.ts +39 -0
- package/dist/init/refresh-rules.js +51 -0
- package/dist/init/run.d.ts +2 -10
- package/dist/init/run.js +26 -68
- package/dist/init/slash-command.d.ts +1 -1
- package/dist/init/slash-command.js +33 -10
- package/dist/init/snippets.js +53 -10
- package/dist/input/real-input.d.ts +2 -0
- package/dist/input/real-input.js +3 -2
- package/dist/input/scroll-find.d.ts +7 -4
- package/dist/input/scroll-find.js +63 -25
- package/dist/intent/inline-intent.d.ts +46 -0
- package/dist/intent/inline-intent.js +103 -0
- package/dist/intent/intent-store.d.ts +37 -0
- package/dist/intent/intent-store.js +112 -0
- package/dist/intent/intent-tools.d.ts +2 -0
- package/dist/intent/intent-tools.js +80 -0
- package/dist/intent/open-intents.d.ts +21 -0
- package/dist/intent/open-intents.js +25 -0
- package/dist/journal/envelope.d.ts +2 -2
- package/dist/journal/journal-recorder.d.ts +23 -0
- package/dist/journal/journal-recorder.js +35 -0
- package/dist/license/license.d.ts +8 -2
- package/dist/license/license.js +10 -15
- package/dist/mcp/attach-memory.d.ts +67 -0
- package/dist/mcp/attach-memory.js +142 -0
- package/dist/mcp/mcp-proxy.d.ts +0 -7
- package/dist/mcp/mcp-proxy.js +14 -2
- package/dist/mcp/mcp.d.ts +2 -0
- package/dist/mcp/mcp.js +45 -23
- package/dist/mcp/server-instructions.js +45 -3
- package/dist/mcp/tool-catalog-cache.d.ts +8 -0
- package/dist/mcp/tool-catalog-cache.js +10 -0
- package/dist/oracles/flow-instrument-gaps.d.ts +4 -4
- package/dist/oracles/flow-instrument-gaps.js +4 -5
- package/dist/oracles/self-instrument.d.ts +9 -9
- package/dist/oracles/self-instrument.js +19 -13
- package/dist/pool/browser-pool.d.ts +12 -1
- package/dist/pool/browser-pool.js +31 -1
- package/dist/pool/playwright-launcher.js +3 -1
- package/dist/project/artifact-root.d.ts +83 -0
- package/dist/project/artifact-root.js +112 -0
- package/dist/project/fs-port.d.ts +3 -0
- package/dist/project/fs-port.js +3 -2
- package/dist/project/memory-fs.d.ts +9 -0
- package/dist/project/memory-fs.js +93 -0
- package/dist/project/project-store.d.ts +17 -0
- package/dist/project/project-store.js +33 -0
- package/dist/project/project-tools.js +3 -32
- package/dist/project/remember-project.d.ts +24 -0
- package/dist/project/remember-project.js +40 -0
- package/dist/project/reticle-dir.d.ts +2 -0
- package/dist/project/reticle-dir.js +1 -0
- package/dist/project/session-root.d.ts +15 -0
- package/dist/project/session-root.js +31 -0
- package/dist/runs/context-tools.d.ts +2 -0
- package/dist/runs/context-tools.js +89 -0
- package/dist/runs/run-context.d.ts +40 -0
- package/dist/runs/run-context.js +158 -0
- package/dist/runs/run-diff.d.ts +2 -1
- package/dist/runs/run-tools.js +2 -1
- package/dist/runs/verification-sync.js +2 -2
- package/dist/session/dev-server-probe.d.ts +0 -8
- package/dist/session/dev-server-probe.js +1 -1
- package/dist/session/last-act.d.ts +7 -1
- package/dist/session/last-act.js +2 -2
- package/dist/session/lease-availability.d.ts +40 -0
- package/dist/session/lease-availability.js +43 -0
- package/dist/session/live-control-tools.js +1 -42
- package/dist/session/no-session-diagnosis.d.ts +20 -0
- package/dist/session/no-session-diagnosis.js +41 -12
- package/dist/session/no-session-next-action.d.ts +5 -0
- package/dist/session/no-session-next-action.js +35 -3
- package/dist/session/no-session-watch.d.ts +8 -0
- package/dist/session/no-session-watch.js +83 -65
- package/dist/session/output-budget.js +4 -1
- package/dist/session/session-health.d.ts +9 -0
- package/dist/session/session-health.js +23 -0
- package/dist/session/session-manager.js +50 -1
- package/dist/session/session-successor.d.ts +37 -0
- package/dist/session/session-successor.js +78 -0
- package/dist/session/session.d.ts +40 -1
- package/dist/session/session.js +84 -2
- package/dist/session/stall-clock.d.ts +18 -0
- package/dist/session/stall-clock.js +48 -0
- package/dist/telemetry/automation-hint.d.ts +2 -1
- package/dist/telemetry/daemon-telemetry.js +12 -23
- package/dist/telemetry/feedback-outbox.d.ts +2 -1
- package/dist/telemetry/project-profile.d.ts +0 -8
- package/dist/telemetry/project-profile.js +1 -1
- package/dist/telemetry/run-telemetry.d.ts +0 -2
- package/dist/telemetry/run-telemetry.js +1 -1
- package/dist/telemetry/session-metrics.d.ts +1 -1
- package/dist/telemetry/session-metrics.js +1 -1
- package/dist/telemetry/telemetry.d.ts +12 -3
- package/dist/telemetry/telemetry.js +25 -5
- package/dist/telemetry/verification-of.js +2 -2
- package/dist/tools/act-tools.js +159 -24
- package/dist/tools/assert-source.d.ts +22 -0
- package/dist/tools/assert-source.js +53 -0
- package/dist/tools/assert-verdict.d.ts +21 -2
- package/dist/tools/assert-verdict.js +59 -4
- package/dist/tools/browser-tools.js +0 -20
- package/dist/tools/complete-snapshot.d.ts +48 -0
- package/dist/tools/complete-snapshot.js +75 -0
- package/dist/tools/contract-tools.js +5 -3
- package/dist/tools/coverage-tools.d.ts +10 -1
- package/dist/tools/coverage-tools.js +124 -37
- package/dist/tools/dynamic-tools.js +29 -8
- package/dist/tools/error-recovery.d.ts +24 -14
- package/dist/tools/error-recovery.js +70 -9
- package/dist/tools/feedback-tools.d.ts +1 -1
- package/dist/tools/feedback-tools.js +2 -2
- package/dist/tools/invoke-tool.js +62 -2
- package/dist/tools/lease-hint.d.ts +10 -0
- package/dist/tools/lease-hint.js +53 -4
- package/dist/tools/lease-tools.d.ts +5 -1
- package/dist/tools/lease-tools.js +22 -8
- package/dist/tools/navigate-arrival.d.ts +0 -2
- package/dist/tools/navigate-arrival.js +1 -1
- package/dist/tools/observe-tools.js +70 -27
- package/dist/tools/read-tools.js +5 -3
- package/dist/tools/real-input-attempt.d.ts +22 -0
- package/dist/tools/real-input-attempt.js +153 -1
- package/dist/tools/reconcile-tools.js +18 -4
- package/dist/tools/resolve-target.d.ts +0 -7
- package/dist/tools/sdk-marker-probe.d.ts +29 -0
- package/dist/tools/sdk-marker-probe.js +57 -0
- package/dist/tools/snapshot-delta.d.ts +1 -1
- package/dist/tools/tool-kit.d.ts +28 -1
- package/dist/tools/tool-kit.js +16 -0
- package/dist/tools/tool-names.d.ts +3 -0
- package/dist/tools/tool-names.js +3 -0
- package/dist/tools/tool-surface.d.ts +85 -6
- package/dist/tools/tool-surface.js +122 -2
- package/dist/tools/tools.js +22 -4
- package/dist/tools/unadvertised-help.js +4 -4
- package/dist/tools/verify-next-baton.d.ts +53 -0
- package/dist/tools/verify-next-baton.js +52 -0
- package/dist/update/update-nudge.d.ts +7 -10
- package/dist/update/update-nudge.js +12 -3
- package/dist/update/updater.d.ts +1 -1
- package/docs/README.md +3 -1
- package/docs/cli/cloud.mdx +1 -1
- package/docs/cli/doctor.mdx +1 -0
- package/docs/cli/verify.mdx +4 -5
- package/docs/desktop.mdx +1 -1
- package/docs/docs.json +3 -3
- package/docs/enterprise.md +3 -1
- package/docs/gates.md +1 -1
- package/docs/install-manual.mdx +1 -1
- package/docs/license-activation.mdx +145 -0
- package/docs/packages/browser.mdx +2 -2
- package/docs/packages/server.mdx +1 -1
- package/docs/packages.mdx +8 -6
- package/docs/platform-integration.md +17 -0
- package/docs/predicates.mdx +8 -0
- package/docs/reticle-manual.md +106 -0
- package/docs/telemetry-contract.md +1 -12
- package/docs/telemetry-events.mdx +1 -34
- package/docs/telemetry.md +0 -1
- package/docs/tools-tools-and-run.mdx +2 -4
- package/docs/troubleshooting.mdx +9 -0
- package/docs/usage.md +3 -2
- package/package.json +2 -2
- package/dist/session/session-readiness.d.ts +0 -34
- package/dist/session/session-readiness.js +0 -36
- package/dist/telemetry/instrumentation-stall.d.ts +0 -57
- package/dist/telemetry/instrumentation-stall.js +0 -103
|
@@ -70,6 +70,45 @@ export const TOOL_SURFACE = {
|
|
|
70
70
|
* supplies the evidence the surface would otherwise have to go and find.
|
|
71
71
|
*/
|
|
72
72
|
VERIFY: 'verify',
|
|
73
|
+
/**
|
|
74
|
+
* EXPERIMENTAL, opt-in, and UNDER MEASUREMENT. Not a recommendation, and not on a path to becoming
|
|
75
|
+
* the default until it has a number of its own.
|
|
76
|
+
*
|
|
77
|
+
* It exists because of the finding recorded on VERIFY above, read forwards instead of backwards.
|
|
78
|
+
* That surface cut the bill 37% and TRIPLED false alarms, and the five new false alarms were not
|
|
79
|
+
* scattered: every one of them was a defect whose evidence lives in `reticle_state`,
|
|
80
|
+
* `reticle_network` or `reticle_observe`. So the token saving and the accuracy loss came from two
|
|
81
|
+
* different cuts, and only one of them has to be paid for. `lean` keeps every observation tool and
|
|
82
|
+
* cuts the rest.
|
|
83
|
+
*
|
|
84
|
+
* What stays, and why each one is not a candidate for removal:
|
|
85
|
+
* SNAPSHOT / QUERY look. Without them the agent cannot name an element it did not already know.
|
|
86
|
+
* STATE / NETWORK / CONSOLE / OBSERVE the four evidence tools. Dropping these is the MEASURED
|
|
87
|
+
* cause of the tripled false-alarm rate. They are the point of the profile.
|
|
88
|
+
* ACT_AND_WAIT the only tool that acts AND returns a verdict. Omitting `until` makes it
|
|
89
|
+
* act-then-settle, which is what `reticle_act` does, so `act` is redundant here.
|
|
90
|
+
* ASSERT the only way to get a verdict WITHOUT acting. `act_and_wait` requires an
|
|
91
|
+
* `action`, so this is a capability it genuinely cannot express, not a synonym.
|
|
92
|
+
*
|
|
93
|
+
* What goes, and what it costs (one `reticle_run` hop each — `unadvertisedToolHelp` hands the agent
|
|
94
|
+
* the exact call, so a dropped name never comes back as "not found"):
|
|
95
|
+
* ACT subsumed: `act_and_wait` with `until` omitted is act-then-settle.
|
|
96
|
+
* WAIT_FOR subsumed: `act_and_wait { until }` takes the same PredicateSchema.
|
|
97
|
+
* ACT_SEQUENCE batching is a cost optimisation on top of a surface built to be cheap.
|
|
98
|
+
* NAVIGATE once per run, not once per turn — the wrong thing to pay for every turn.
|
|
99
|
+
* SESSIONS the CLI answers this (`reticle status`) without spending any turn budget.
|
|
100
|
+
* INSPECT fix-side, not verdict-side: it is called once a bug is FOUND, so its hop is
|
|
101
|
+
* paid once per finding rather than once per turn. Nothing else maps a node to
|
|
102
|
+
* a source file, which is why it is a hop and not a deletion.
|
|
103
|
+
* SESSION the lease block and the pause hint name it in prose, which is what made it
|
|
104
|
+
* load-bearing on the default surface. Under a trimmed surface the
|
|
105
|
+
* unadvertised-tool help turns that into a working `reticle_run` call.
|
|
106
|
+
* FEEDBACK the one drop with a KNOWN CEILING: an unadvertised feedback channel collects
|
|
107
|
+
* little to nothing, so a long-lived profile must not ship without it. Acceptable
|
|
108
|
+
* only because this profile is opt-in and short-lived by construction; if it
|
|
109
|
+
* ever stops being an experiment, feedback comes back first.
|
|
110
|
+
*/
|
|
111
|
+
LEAN: 'lean',
|
|
73
112
|
};
|
|
74
113
|
/**
|
|
75
114
|
* The switch that turns on the full, output-schema-carrying surface. A boolean, not a menu.
|
|
@@ -79,7 +118,7 @@ export const TOOL_SURFACE = {
|
|
|
79
118
|
*/
|
|
80
119
|
export const ADVERTISE_ALL_ENV = 'RETICLE_ADVERTISE_ALL_TOOLS';
|
|
81
120
|
/** Opt into the smallest verdict-capable surface. Read by the DAEMON at startup, like the others. */
|
|
82
|
-
|
|
121
|
+
const VERIFY_SURFACE_ENV = 'RETICLE_VERIFY_SURFACE';
|
|
83
122
|
/**
|
|
84
123
|
* The retired setting, still read so nobody's shell profile breaks.
|
|
85
124
|
*
|
|
@@ -185,6 +224,17 @@ export const CORE_TOOL_NAMES = new Set([
|
|
|
185
224
|
* 48 by itself can push a user's other servers out or be dropped wholesale. The budget is a count,
|
|
186
225
|
* so no amount of trimming parameter prose buys anything back — only advertising fewer names does.
|
|
187
226
|
*
|
|
227
|
+
* That is true of the COUNT cap and false of everything else, which is worth separating here before
|
|
228
|
+
* somebody reads it as "prose is free". Measured against two competitor MCP servers on the same
|
|
229
|
+
* agent loop: this server advertises the FEWEST tools of the three and ships the HEAVIEST schema
|
|
230
|
+
* block, and 83% of that weight is parameter descriptions, not tool descriptions. The block is
|
|
231
|
+
* re-sent every turn, so it is multiplied by turn count before one byte of evidence is counted, and
|
|
232
|
+
* it was most of the gap in that run.
|
|
233
|
+
*
|
|
234
|
+
* Which does NOT license trimming by eye. Those descriptions are what make a tool get called
|
|
235
|
+
* correctly, and one malformed call costs a whole extra turn — more than the bytes saved. The
|
|
236
|
+
* outcome to measure is turn count and error rate, not size.
|
|
237
|
+
*
|
|
188
238
|
* Everything omitted stays in the registry, stays catalogued by `reticle_tools`, and stays callable
|
|
189
239
|
* by name through `reticle_run { tool, args }`. The cost is one discovery hop on the cold tail, which
|
|
190
240
|
* is the same trade the default surface has always made, applied one level further out.
|
|
@@ -206,6 +256,13 @@ export const EXTENDED_TOOL_NAMES = new Set([
|
|
|
206
256
|
ReticleTool.CAPABILITIES,
|
|
207
257
|
ReticleTool.FLOW_SAVE,
|
|
208
258
|
ReticleTool.FLOW_REPLAY,
|
|
259
|
+
// New and unproven, so it does not take a default-surface slot under the cap. Same terms the
|
|
260
|
+
// capabilities demotion set: reachable in one reticle_run hop by any agent that wants it.
|
|
261
|
+
ReticleTool.INTENT,
|
|
262
|
+
// Same terms again, plus one argument specific to it: its caller is BY CONSTRUCTION an agent that
|
|
263
|
+
// just lost its context and is re-reading the tool list, so the discovery hop it costs is a call
|
|
264
|
+
// that caller was already going to make. See context-tools.ts for the full argument.
|
|
265
|
+
ReticleTool.CONTEXT,
|
|
209
266
|
ReticleTool.RECORD,
|
|
210
267
|
ReticleTool.SCREENSHOT,
|
|
211
268
|
ReticleTool.VISUAL_DIFF,
|
|
@@ -220,7 +277,53 @@ export const EXTENDED_TOOL_NAMES = new Set([
|
|
|
220
277
|
* everything else. `act_and_wait` can resolve its own target, so no query tool is needed to name an
|
|
221
278
|
* element — that round trip was half the token cost of a verification.
|
|
222
279
|
*/
|
|
223
|
-
|
|
280
|
+
const VERIFY_TOOL_NAMES = new Set([ReticleTool.ACT_AND_WAIT]);
|
|
281
|
+
/**
|
|
282
|
+
* The lean surface: look, observe, act-with-a-verdict, assert. Pinned by lean-surface.test.ts,
|
|
283
|
+
* because an experiment whose independent variable drifts mid-flight measures nothing. Every
|
|
284
|
+
* inclusion and every exclusion is argued at TOOL_SURFACE.LEAN.
|
|
285
|
+
*
|
|
286
|
+
* ## MEASURED: it is cheaper and less correct. Do not promote it to the default.
|
|
287
|
+
*
|
|
288
|
+
* Run as its own arm of the fix-and-verify benchmark — same five bugs, same model, same budget, the
|
|
289
|
+
* full surface as its control:
|
|
290
|
+
*
|
|
291
|
+
* | | full surface | lean |
|
|
292
|
+
* |---|---|---|
|
|
293
|
+
* | bugs fixed | **5/5** | **3/5** |
|
|
294
|
+
* | FALSE GREENS | **0** | **1** |
|
|
295
|
+
*
|
|
296
|
+
* The false green is the finding, and it is the first this benchmark has ever produced. On
|
|
297
|
+
* `broken-form-validation` the lean agent finished in SIX turns and 62k tokens — the cheapest cell
|
|
298
|
+
* of the whole run, a fifth of what the full surface spent — edited the file, took one snapshot,
|
|
299
|
+
* and ended with a hypothetical walkthrough: "Enter spaces + valid name -> spaces are trimmed,
|
|
300
|
+
* valid part is used. VERDICT: FIXED". The submit button was still enabled for a whitespace-only
|
|
301
|
+
* service. It reasoned about what its own code would now do instead of driving it, which is exactly
|
|
302
|
+
* the failure this product exists to catch, produced by our own surface.
|
|
303
|
+
*
|
|
304
|
+
* The other loss has the same root from the other side. On `cross-component-regression` the agent
|
|
305
|
+
* called `reticle_tools` three times and `reticle_run` eight, saying "since Reticle isn't
|
|
306
|
+
* connecting, let me see what reticle_tools offers" — it spent the run hunting for capabilities
|
|
307
|
+
* this surface does not advertise instead of using them, and never fixed the bug.
|
|
308
|
+
*
|
|
309
|
+
* That is the same result the `verify` surface already recorded — dropping the observation tools
|
|
310
|
+
* TRIPLED false alarms — arriving from the other direction: strip the surface and the agent stops
|
|
311
|
+
* verifying, then claims anyway. The known ceiling written here was that `reticle_feedback` goes
|
|
312
|
+
* uncollected. This is a bigger one and it was not predicted.
|
|
313
|
+
*
|
|
314
|
+
* It stays opt-in and it stays measured. The one thing it genuinely bought — the ceiling-bound cell
|
|
315
|
+
* halved, 30 turns to 14 — is not worth a verdict that lies, because the product is the verdict.
|
|
316
|
+
*/
|
|
317
|
+
export const LEAN_TOOL_NAMES = new Set([
|
|
318
|
+
ReticleTool.SNAPSHOT,
|
|
319
|
+
ReticleTool.QUERY,
|
|
320
|
+
ReticleTool.ACT_AND_WAIT,
|
|
321
|
+
ReticleTool.ASSERT,
|
|
322
|
+
ReticleTool.OBSERVE,
|
|
323
|
+
ReticleTool.NETWORK,
|
|
324
|
+
ReticleTool.CONSOLE,
|
|
325
|
+
ReticleTool.STATE,
|
|
326
|
+
]);
|
|
224
327
|
/** Is the truthy form of a boolean env var set? `1`, `true`, `yes` — anything else is off. */
|
|
225
328
|
function envFlagOn(raw) {
|
|
226
329
|
if (raw === undefined)
|
|
@@ -235,6 +338,8 @@ function envFlagOn(raw) {
|
|
|
235
338
|
* switch decides, and the retired setting is honoured last so an old shell profile still works.
|
|
236
339
|
*/
|
|
237
340
|
export function resolveToolSurface(explicit) {
|
|
341
|
+
if (explicit === TOOL_SURFACE.LEAN)
|
|
342
|
+
return TOOL_SURFACE.LEAN;
|
|
238
343
|
if (explicit === TOOL_SURFACE.VERIFY)
|
|
239
344
|
return TOOL_SURFACE.VERIFY;
|
|
240
345
|
if (explicit === TOOL_SURFACE.ALL)
|
|
@@ -244,6 +349,11 @@ export function resolveToolSurface(explicit) {
|
|
|
244
349
|
const retiredExplicit = explicit === undefined ? undefined : RETIRED_PROFILE_VALUES[explicit];
|
|
245
350
|
if (retiredExplicit !== undefined)
|
|
246
351
|
return retiredExplicit;
|
|
352
|
+
// The one LIVE value of the otherwise-retired setting. It rides there rather than on a switch of
|
|
353
|
+
// its own because the experiment is an A/B between two surfaces, and a boolean cannot name an arm.
|
|
354
|
+
if (TOOL_SURFACE.LEAN === process.env[TOOL_PROFILE_ENV]?.trim().toLowerCase()) {
|
|
355
|
+
return TOOL_SURFACE.LEAN;
|
|
356
|
+
}
|
|
247
357
|
if (envFlagOn(process.env[VERIFY_SURFACE_ENV]))
|
|
248
358
|
return TOOL_SURFACE.VERIFY;
|
|
249
359
|
if (envFlagOn(process.env[ADVERTISE_ALL_ENV]))
|
|
@@ -262,6 +372,14 @@ export function resolveToolSurface(explicit) {
|
|
|
262
372
|
*/
|
|
263
373
|
export function describeToolSurface(active, requested) {
|
|
264
374
|
const retired = requested ?? process.env[TOOL_PROFILE_ENV];
|
|
375
|
+
// `lean` is the one value of this setting that is NOT retired. Reporting it as retired would tell
|
|
376
|
+
// an agent its arm did not take, which on an A/B is worse than saying nothing.
|
|
377
|
+
if (TOOL_SURFACE.LEAN === active) {
|
|
378
|
+
return {
|
|
379
|
+
active,
|
|
380
|
+
source: `${TOOL_PROFILE_ENV}=${TOOL_SURFACE.LEAN} — an EXPERIMENTAL surface under measurement; unadvertised tools stay callable via ${ReticleTool.RUN}`,
|
|
381
|
+
};
|
|
382
|
+
}
|
|
265
383
|
if (retired !== undefined && retired in RETIRED_PROFILE_VALUES) {
|
|
266
384
|
return {
|
|
267
385
|
active,
|
|
@@ -293,6 +411,8 @@ export function filterTools(tools, surface) {
|
|
|
293
411
|
// interesting thing about the `core` PROFILE, whose only distinction was a second name for this.
|
|
294
412
|
if (surface === TOOL_SURFACE.VERIFY)
|
|
295
413
|
return tools.filter((t) => VERIFY_TOOL_NAMES.has(t.name));
|
|
414
|
+
if (surface === TOOL_SURFACE.LEAN)
|
|
415
|
+
return tools.filter((t) => LEAN_TOOL_NAMES.has(t.name));
|
|
296
416
|
if (surface === TOOL_SURFACE.DEFAULT)
|
|
297
417
|
return tools.filter((t) => CORE_TOOL_NAMES.has(t.name));
|
|
298
418
|
// `all` is the extended surface, not the whole registry — the cap is a hard budget shared with
|
package/dist/tools/tools.js
CHANGED
|
@@ -21,11 +21,13 @@ import { CONTRACT_TOOLS } from './contract-tools.js';
|
|
|
21
21
|
import { DOMAIN_TOOLS } from '../domain/domain-tools.js';
|
|
22
22
|
import { BROWSER_TOOLS } from './browser-tools.js';
|
|
23
23
|
import { FLOW_TOOLS } from '../flows/flow-tools.js';
|
|
24
|
+
import { INTENT_TOOLS } from '../intent/intent-tools.js';
|
|
25
|
+
import { CONTEXT_TOOLS } from '../runs/context-tools.js';
|
|
24
26
|
import { PROJECT_TOOLS } from '../project/project-tools.js';
|
|
25
27
|
import { RUN_TOOLS } from '../runs/run-tools.js';
|
|
26
28
|
import { VISUAL_TOOLS } from '../visual/visual-tools.js';
|
|
27
29
|
import { AFFECTED_TOOLS } from '../flows/affected-tools.js';
|
|
28
|
-
import {
|
|
30
|
+
import { buildCoverageTools } from './coverage-tools.js';
|
|
29
31
|
import { VERIFY_CHANGE_TOOLS } from '../flows/verify-change-tools.js';
|
|
30
32
|
import { CRAWL_TOOLS } from '../crawl/crawl-tools.js';
|
|
31
33
|
import { SCROLL_TOOLS } from '../input/scroll-tools.js';
|
|
@@ -47,7 +49,7 @@ const SNAPSHOT_CACHE = new SnapshotCache();
|
|
|
47
49
|
const RAW_TOOLS = [
|
|
48
50
|
{
|
|
49
51
|
name: ReticleTool.SESSIONS,
|
|
50
|
-
description: 'List connected browser sessions (tab url/title, sessionId, last-seen, health: hidden/focused/throttled, and `realInputAvailable` — true when native CDP/launched real input is driving this tab), plus a `recommendation`
|
|
52
|
+
description: 'List connected browser sessions (tab url/title, sessionId, last-seen, health: hidden/focused/throttled, and `realInputAvailable` — true when native CDP/launched real input is driving this tab), plus a `recommendation` naming the in-protocol escape hatch (`reticle_run { tool: "reticle_lease" }`, with `reticle drive` as the human-side equivalent) when a tab is hidden/throttled and may be un-scriptable from here.',
|
|
51
53
|
inputSchema: {},
|
|
52
54
|
outputSchema: {
|
|
53
55
|
sessions: z
|
|
@@ -76,6 +78,18 @@ const RAW_TOOLS = [
|
|
|
76
78
|
pendingMarks: z.number().optional(),
|
|
77
79
|
review_suggestion: z.string().optional(),
|
|
78
80
|
recommendation: z.string().optional(),
|
|
81
|
+
// Attached by SessionManager.list() (#117): whether this tab ever dropped and came back,
|
|
82
|
+
// how often, and how long the last drop lasted. Undeclared here, a validating client
|
|
83
|
+
// stripped the outage history while the row still looked complete — a verdict over a
|
|
84
|
+
// window with a four-second blind gap read as trustworthy.
|
|
85
|
+
attachment: z
|
|
86
|
+
.object({
|
|
87
|
+
connectedSinceMs: z.number(),
|
|
88
|
+
outages: z.number(),
|
|
89
|
+
lastOutage: z.object({ startedMs: z.number(), durationMs: z.number() }).optional(),
|
|
90
|
+
})
|
|
91
|
+
.optional()
|
|
92
|
+
.describe('Present only when this tab has dropped and reconnected at least once: how long it has been attached in total, how many outages occurred, and when the last one started and how long it lasted. A verdict over this window spans a gap where nothing was observed.'),
|
|
79
93
|
}))
|
|
80
94
|
.describe('Connected browser sessions with health state. `projectId` groups sessions by app (stable across port changes); `leased` marks a pool-managed headless context vs a human tab.'),
|
|
81
95
|
why: z
|
|
@@ -218,7 +232,7 @@ const RAW_TOOLS = [
|
|
|
218
232
|
{
|
|
219
233
|
name: ReticleTool.QUERY,
|
|
220
234
|
example: { by: 'testid', value: 'todo-list' },
|
|
221
|
-
description: `Find elements by Testing-Library semantics, INCLUDING open shadow roots — \`count_only:true\` gives just the count (~30x smaller); \`limit\` caps descriptors. Pass \`by\` (${QUERY_BY_LIST}) and \`value\` (the query string). Returns matching refs + descriptors + visibility. Pass \`attrs:["href"]\` to project attributes (link/image URLs) onto each match. Pass \`limit\` to cap descriptors (broad role queries can be large) or \`count_only:true\` for just the match count — both cut tokens. On zero matches, also returns hint:{ route, presentRegions[], knownEmptyState } so you can distinguish an empty state from a missing element WITHOUT taking a snapshot.`,
|
|
235
|
+
description: `Find elements by Testing-Library semantics, INCLUDING open shadow roots — \`count_only:true\` gives just the count (~30x smaller); \`limit\` caps descriptors. Pass \`by\` (${QUERY_BY_LIST}) and \`value\` (the query string). Returns matching refs + descriptors + visibility. Pass \`attrs:["href"]\` to project attributes (link/image URLs) onto each match. Pass \`limit\` to cap descriptors (broad role queries can be large) or \`count_only:true\` for just the match count — both cut tokens. On zero matches, also returns hint:{ route, presentRegions[], knownEmptyState } so you can distinguish an empty state from a missing element WITHOUT taking a snapshot. ASKING SEVERAL QUESTIONS ABOUT THE PAGE? One reticle_snapshot answers them all at once — a run of queries costs a round trip each and returns what the snapshot already held.`,
|
|
222
236
|
inputSchema: {
|
|
223
237
|
// Constrained to the enum, NOT z.string(). A free string let `by:'css'` through to the
|
|
224
238
|
// browser's `default: return []`, so an unsupported strategy answered "0 matches" — which
|
|
@@ -446,6 +460,8 @@ const RAW_TOOLS = [
|
|
|
446
460
|
// reticle_capabilities (live | fromDisk) + reticle_contract_save. See contract-tools.ts.
|
|
447
461
|
...RECONCILE_TOOLS,
|
|
448
462
|
...CONTRACT_TOOLS,
|
|
463
|
+
...INTENT_TOOLS,
|
|
464
|
+
...CONTEXT_TOOLS,
|
|
449
465
|
...DOMAIN_TOOLS,
|
|
450
466
|
// reticle_flow_save / reticle_flow_list / reticle_flow_load. See flow-tools.ts.
|
|
451
467
|
...FLOW_TOOLS,
|
|
@@ -469,7 +485,9 @@ const RAW_TOOLS = [
|
|
|
469
485
|
// reachable through reticle_run. See affected-tools.ts.
|
|
470
486
|
...AFFECTED_TOOLS,
|
|
471
487
|
// reticle_coverage — which controls were driven vs never touched. Unadvertised; via reticle_run.
|
|
472
|
-
|
|
488
|
+
// The table is passed as a thunk so the coverage tool can report which of it was called without
|
|
489
|
+
// importing it back — see buildCoverageTools. Called from the handler, long after TOOLS exists.
|
|
490
|
+
...buildCoverageTools(() => TOOLS.map((t) => t.name)),
|
|
473
491
|
// reticle_verify_change — "did my change break anything" in one call. See verify-change-tools.ts.
|
|
474
492
|
...VERIFY_CHANGE_TOOLS,
|
|
475
493
|
// Live-control: reticle_end_session / reticle_resume / reticle_messages. See live-control-tools.ts.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* What to say when an agent calls a real Reticle tool that this profile does not advertise.
|
|
3
3
|
*
|
|
4
|
-
* The default surface
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* The default surface is the verify loop plus the two meta-tools; the extended one is larger but
|
|
5
|
+
* still capped. Counts live in `surface-sizes.test.ts` — restating them here is how they drift.
|
|
6
|
+
* Everything omitted stays fully callable through `reticle_run`, which `surface-reachability.test.ts`
|
|
7
|
+
* guards.
|
|
8
8
|
*
|
|
9
9
|
* The gap was in the ERROR. The MCP SDK answers `Tool <name> not found`, which is indistinguishable
|
|
10
10
|
* from "this tool does not exist", so an agent that trusts it stops trying. Reported from a real
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The verdict nudge, as a call the agent can make rather than a sentence it has to translate.
|
|
3
|
+
*
|
|
4
|
+
* `verify_next` already fires when an agent has driven the page several times and asked for no
|
|
5
|
+
* verdict, which is the commonest shape of a wasted session: almost every verdict-less session in
|
|
6
|
+
* the field never called a verdict-producing tool once. What it carried was prose. Prose has to be
|
|
7
|
+
* turned back into a call, and the translation is exactly where the agent was already going wrong —
|
|
8
|
+
* `until` omitted, arguments flat instead of nested under `args`, a predicate written as a bare
|
|
9
|
+
* array.
|
|
10
|
+
*
|
|
11
|
+
* So it carries the call. `ref` and `action` come from the act that actually dispatched, so the
|
|
12
|
+
* suggestion is about the element the agent really touched rather than a worked example from a
|
|
13
|
+
* document. `until` is deliberately left as a placeholder the agent must replace: naming the
|
|
14
|
+
* consequence is the one part nothing but the agent can know, and filling it in with a guess would
|
|
15
|
+
* be Reticle inventing the assertion — the failure `no-fault` exists to prevent.
|
|
16
|
+
*
|
|
17
|
+
* Emitted only when there is a real call to suggest. A baton with nothing behind it is the router
|
|
18
|
+
* failure in miniature: an agent that follows a fabricated next step follows it confidently.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Set to `1` to withhold the baton from tool results — the control arm of its A/B, and nothing else.
|
|
22
|
+
*
|
|
23
|
+
* A measurement flag, not a product setting: it is read at one call site, documented here, and named
|
|
24
|
+
* loudly enough that nobody sets it by accident. It exists because this feature has shipped, been
|
|
25
|
+
* declared the largest lever on whether a session verifies at all, and never been measured — and a
|
|
26
|
+
* control arm is the only way to tell "agents that see it verify" from "agents that were going to
|
|
27
|
+
* verify anyway also saw it".
|
|
28
|
+
*/
|
|
29
|
+
export declare const SUPPRESS_VERIFY_NEXT_ENV = "RETICLE_SUPPRESS_VERIFY_NEXT";
|
|
30
|
+
/** What the agent must supply itself. Phrased as an instruction so it cannot be sent verbatim. */
|
|
31
|
+
export declare const UNTIL_PLACEHOLDER = "<name the consequence this action causes>";
|
|
32
|
+
export interface VerifyNextBaton {
|
|
33
|
+
/** The fact that produced this, in the agent's own terms. */
|
|
34
|
+
why: string;
|
|
35
|
+
/** A call, ready to make once `until` is filled in. */
|
|
36
|
+
call?: {
|
|
37
|
+
tool: string;
|
|
38
|
+
args: Record<string, unknown>;
|
|
39
|
+
};
|
|
40
|
+
/** Where the argument shapes are stated, on disk and version-exact rather than on the web. */
|
|
41
|
+
docs?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build the baton from what the session actually did.
|
|
45
|
+
*
|
|
46
|
+
* `ref` absent means no act dispatched under a ref this session — a navigation, or a run that only
|
|
47
|
+
* read. There is then no honest call to name, so the prose stands alone rather than pointing at an
|
|
48
|
+
* element nobody touched.
|
|
49
|
+
*/
|
|
50
|
+
export declare function verifyNextBaton(prose: string, lastAct: {
|
|
51
|
+
action?: string | undefined;
|
|
52
|
+
ref?: string | undefined;
|
|
53
|
+
}): VerifyNextBaton;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The verdict nudge, as a call the agent can make rather than a sentence it has to translate.
|
|
3
|
+
*
|
|
4
|
+
* `verify_next` already fires when an agent has driven the page several times and asked for no
|
|
5
|
+
* verdict, which is the commonest shape of a wasted session: almost every verdict-less session in
|
|
6
|
+
* the field never called a verdict-producing tool once. What it carried was prose. Prose has to be
|
|
7
|
+
* turned back into a call, and the translation is exactly where the agent was already going wrong —
|
|
8
|
+
* `until` omitted, arguments flat instead of nested under `args`, a predicate written as a bare
|
|
9
|
+
* array.
|
|
10
|
+
*
|
|
11
|
+
* So it carries the call. `ref` and `action` come from the act that actually dispatched, so the
|
|
12
|
+
* suggestion is about the element the agent really touched rather than a worked example from a
|
|
13
|
+
* document. `until` is deliberately left as a placeholder the agent must replace: naming the
|
|
14
|
+
* consequence is the one part nothing but the agent can know, and filling it in with a guess would
|
|
15
|
+
* be Reticle inventing the assertion — the failure `no-fault` exists to prevent.
|
|
16
|
+
*
|
|
17
|
+
* Emitted only when there is a real call to suggest. A baton with nothing behind it is the router
|
|
18
|
+
* failure in miniature: an agent that follows a fabricated next step follows it confidently.
|
|
19
|
+
*/
|
|
20
|
+
import { ReticleTool } from './tool-names.js';
|
|
21
|
+
/**
|
|
22
|
+
* Set to `1` to withhold the baton from tool results — the control arm of its A/B, and nothing else.
|
|
23
|
+
*
|
|
24
|
+
* A measurement flag, not a product setting: it is read at one call site, documented here, and named
|
|
25
|
+
* loudly enough that nobody sets it by accident. It exists because this feature has shipped, been
|
|
26
|
+
* declared the largest lever on whether a session verifies at all, and never been measured — and a
|
|
27
|
+
* control arm is the only way to tell "agents that see it verify" from "agents that were going to
|
|
28
|
+
* verify anyway also saw it".
|
|
29
|
+
*/
|
|
30
|
+
export const SUPPRESS_VERIFY_NEXT_ENV = 'RETICLE_SUPPRESS_VERIFY_NEXT';
|
|
31
|
+
/** What the agent must supply itself. Phrased as an instruction so it cannot be sent verbatim. */
|
|
32
|
+
export const UNTIL_PLACEHOLDER = '<name the consequence this action causes>';
|
|
33
|
+
/**
|
|
34
|
+
* Build the baton from what the session actually did.
|
|
35
|
+
*
|
|
36
|
+
* `ref` absent means no act dispatched under a ref this session — a navigation, or a run that only
|
|
37
|
+
* read. There is then no honest call to name, so the prose stands alone rather than pointing at an
|
|
38
|
+
* element nobody touched.
|
|
39
|
+
*/
|
|
40
|
+
export function verifyNextBaton(prose, lastAct) {
|
|
41
|
+
const { ref, action } = lastAct;
|
|
42
|
+
if (ref === undefined || action === undefined)
|
|
43
|
+
return { why: prose };
|
|
44
|
+
return {
|
|
45
|
+
why: prose,
|
|
46
|
+
call: {
|
|
47
|
+
tool: ReticleTool.ACT_AND_WAIT,
|
|
48
|
+
args: { ref, action, until: { kind: 'text', value: UNTIL_PLACEHOLDER } },
|
|
49
|
+
},
|
|
50
|
+
docs: `reticle_tools { names: ["${ReticleTool.ACT_AND_WAIT}"] }`,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Is `candidate` a strictly NEWER release than `current`?
|
|
3
|
-
*
|
|
4
|
-
* Replaces a plain `!==`, which told anyone on a version newer than the published one — a
|
|
5
|
-
* prerelease, a local build, a rollback in progress — to "update" to something older. A nudge that
|
|
6
|
-
* prompts a downgrade is one people learn to ignore, and this is the mechanism the entire adoption
|
|
7
|
-
* story rests on. Numeric per segment, so 2.10.0 correctly beats 2.9.0 (string order does not), and
|
|
8
|
-
* a bare release beats its own prerelease.
|
|
9
|
-
*/
|
|
10
|
-
export declare function isNewerVersion(candidate: string, current: string): boolean;
|
|
11
1
|
interface UpdateNudge {
|
|
12
2
|
/** The version available, so the agent can tell the human what they would be moving to. */
|
|
13
3
|
latestVersion: string;
|
|
@@ -30,6 +20,13 @@ interface UpdateNudge {
|
|
|
30
20
|
*
|
|
31
21
|
* Bounded on purpose: this rides on a tool result every turn until it is delivered, so a long
|
|
32
22
|
* changelog is a per-turn tax. The count of anything elided is stated rather than silently dropped.
|
|
23
|
+
*
|
|
24
|
+
* It also names what `update` does to the RULE FILES, which is the half nobody would guess. A new
|
|
25
|
+
* release changes what the always-loaded instructions should say — that is the whole reason
|
|
26
|
+
* `refreshAgentRules` exists — and an agent that reads "it restarts the daemon" has no reason to
|
|
27
|
+
* think its CLAUDE.md is now a release behind. Saying so costs one clause on a message that is
|
|
28
|
+
* delivered once per daemon, and it is the difference between a fleet that upgrades its rules and
|
|
29
|
+
* one that upgrades its binary and keeps last release's instructions forever.
|
|
33
30
|
*/
|
|
34
31
|
export declare function buildNudge(latestVersion: string, currentVersion: string, release?: {
|
|
35
32
|
changelog?: string;
|
|
@@ -29,7 +29,7 @@ import { creditNudge } from './nudge-credit.js';
|
|
|
29
29
|
* story rests on. Numeric per segment, so 2.10.0 correctly beats 2.9.0 (string order does not), and
|
|
30
30
|
* a bare release beats its own prerelease.
|
|
31
31
|
*/
|
|
32
|
-
|
|
32
|
+
function isNewerVersion(candidate, current) {
|
|
33
33
|
const parse = (v) => {
|
|
34
34
|
const [core = '', ...rest] = v.split(/[-+]/);
|
|
35
35
|
return { parts: core.split('.').map((n) => Number.parseInt(n, 10) || 0), pre: rest.length > 0 };
|
|
@@ -72,6 +72,13 @@ const MAX_LISTED_BREAKING = 4;
|
|
|
72
72
|
*
|
|
73
73
|
* Bounded on purpose: this rides on a tool result every turn until it is delivered, so a long
|
|
74
74
|
* changelog is a per-turn tax. The count of anything elided is stated rather than silently dropped.
|
|
75
|
+
*
|
|
76
|
+
* It also names what `update` does to the RULE FILES, which is the half nobody would guess. A new
|
|
77
|
+
* release changes what the always-loaded instructions should say — that is the whole reason
|
|
78
|
+
* `refreshAgentRules` exists — and an agent that reads "it restarts the daemon" has no reason to
|
|
79
|
+
* think its CLAUDE.md is now a release behind. Saying so costs one clause on a message that is
|
|
80
|
+
* delivered once per daemon, and it is the difference between a fleet that upgrades its rules and
|
|
81
|
+
* one that upgrades its binary and keeps last release's instructions forever.
|
|
75
82
|
*/
|
|
76
83
|
export function buildNudge(latestVersion, currentVersion, release) {
|
|
77
84
|
const changelog = (release?.changelog ?? '').trim();
|
|
@@ -89,8 +96,10 @@ export function buildNudge(latestVersion, currentVersion, release) {
|
|
|
89
96
|
: `This release has BREAKING changes: ${listed.join('; ')}` +
|
|
90
97
|
(0 < rest ? ` (+${String(rest)} more — see the changelog)` : '') +
|
|
91
98
|
'. Read them before updating. ') +
|
|
92
|
-
`Tell the human, and run \`${UPDATE_COMMAND}\` if they agree — it
|
|
93
|
-
|
|
99
|
+
`Tell the human, and run \`${UPDATE_COMMAND}\` if they agree — it upgrades the packages, ` +
|
|
100
|
+
"refreshes the Reticle rules in this project's CLAUDE.md / AGENTS.md, and restarts the " +
|
|
101
|
+
'daemon, so do it between tasks rather than mid-verification. Continue your current task ' +
|
|
102
|
+
'first.',
|
|
94
103
|
};
|
|
95
104
|
}
|
|
96
105
|
export function startUpdateCheck(now = () => Date.now()) {
|
package/dist/update/updater.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ declare const VersionChangeDirection: {
|
|
|
3
3
|
readonly UPDATE: "update";
|
|
4
4
|
readonly ROLLBACK: "rollback";
|
|
5
5
|
};
|
|
6
|
-
|
|
6
|
+
type VersionChangeDirection = (typeof VersionChangeDirection)[keyof typeof VersionChangeDirection];
|
|
7
7
|
/**
|
|
8
8
|
* Report a completed version move. Never throws — an install that worked must still be reported done.
|
|
9
9
|
*
|
package/docs/README.md
CHANGED
|
@@ -26,7 +26,7 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
|
|
|
26
26
|
| [faq.mdx](faq.mdx) | production, frameworks, comparisons, and the honest limits |
|
|
27
27
|
| [tools-overview.mdx](tools-overview.mdx) | the 18 advertised tools, the 30 in the cold tail, and why |
|
|
28
28
|
| [tools-snapshot.mdx](tools-snapshot.mdx) | `reticle_snapshot`: three modes, from full tree to a 25-token route check |
|
|
29
|
-
| [tools-query.mdx](tools-query.mdx) | `reticle_query` finds elements by
|
|
29
|
+
| [tools-query.mdx](tools-query.mdx) | `reticle_query` finds elements by their reported roles, names and labels |
|
|
30
30
|
| [tools-inspect.mdx](tools-inspect.mdx) | `reticle_inspect`: one element, down to source and design tokens |
|
|
31
31
|
| [tools-navigate.mdx](tools-navigate.mdx) | `reticle_navigate`, and why `ok` does not mean the page arrived |
|
|
32
32
|
| [tools-act.mdx](tools-act.mdx) | `reticle_act` acts, proves nothing, and says so |
|
|
@@ -46,6 +46,7 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
|
|
|
46
46
|
| [best-practices.mdx](best-practices.mdx) | the habits that make a verdict worth trusting |
|
|
47
47
|
| [skill-file.mdx](skill-file.mdx) | the paste-one-URL skill that teaches an agent Reticle |
|
|
48
48
|
| [agent-cheatsheet.md](agent-cheatsheet.md) | the condensed version an agent keeps in context |
|
|
49
|
+
| [reticle-manual.md](reticle-manual.md) | GENERATED: what each tool actually returned when it was called, per argument shape |
|
|
49
50
|
| [for-agents.md](for-agents.md) | how to fetch these docs as Markdown or `llms.txt` |
|
|
50
51
|
| [architecture.md](architecture.md) | how it works, and why it is built this way |
|
|
51
52
|
| [platform-integration.md](platform-integration.md) | Vite, Next, Remix, Astro, plain HTML |
|
|
@@ -69,6 +70,7 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
|
|
|
69
70
|
| [vs-screenshots.mdx](vs-screenshots.mdx) | why a better vision model does not fix a non-visual bug |
|
|
70
71
|
| [telemetry.md](telemetry.md) | what is collected, and how to turn it off |
|
|
71
72
|
| [local-registry.md](local-registry.md) | installing an unpublished build |
|
|
73
|
+
| [license-activation.mdx](license-activation.mdx) | you have a key: where to set it, how to confirm it, what to do when it fails |
|
|
72
74
|
| [enterprise.md](enterprise.md) | the licensed surface |
|
|
73
75
|
|
|
74
76
|
## For people working on Reticle
|
package/docs/cli/cloud.mdx
CHANGED
|
@@ -20,7 +20,7 @@ These are thin clients over the `/v1` API. The moat is the server, not the verbs
|
|
|
20
20
|
| `~/.reticle/credentials.json` | Project-scoped API keys from `reticle link`, keyed by `projectId` | Yes |
|
|
21
21
|
| `<repo>/.reticle/cloud.json` | `{ projectId, projectName, url, sync, verify }`. The non-secret binding | No, commit it |
|
|
22
22
|
|
|
23
|
-
Auth for any command is `RETICLE_CLOUD_KEY` from the environment (the agent path) if set, otherwise the login token. `RETICLE_CLOUD_URL` overrides the endpoint; the default is `http://localhost:8890`.
|
|
23
|
+
Auth for any command is `RETICLE_CLOUD_KEY` from the environment (the agent path) if set, otherwise the login token. `RETICLE_CLOUD_URL` overrides the endpoint; the default is `http://localhost:8890`. When a command falls back to that default without `RETICLE_CLOUD_URL` (or a saved session URL), it prints a one-line notice on stderr; stdout stays pure JSON for agents.
|
|
24
24
|
|
|
25
25
|
## The commands
|
|
26
26
|
|
package/docs/cli/doctor.mdx
CHANGED
|
@@ -53,6 +53,7 @@ When nothing has connected, the `sessions` line fails and the daemon's own diagn
|
|
|
53
53
|
| `sessions` | Whether any page has actually connected. Zero is a FAILING check rather than a neutral note, because it is the state the setup most often stalls in: wired correctly, daemon up, nothing dialled in. When it is zero the daemon's own no-session diagnosis prints below the checklist |
|
|
54
54
|
| `bridge port` | The port your app must dial, spelled out because mixing it up with the dev server port is the most common setup failure |
|
|
55
55
|
| `port check` | Only when your project's configured port disagrees with the one the daemon is on. Prints the mismatch rather than leaving you to spot it across two lines |
|
|
56
|
+
| `sibling` | Only when a well-known Reticle port other than this daemon's has a listener. An observation, not a diagnosis: that listener may or may not be related |
|
|
56
57
|
| `daemon log` | Where the structured daemon log lives |
|
|
57
58
|
| `tracing` | How to turn that log into a per-stage trace |
|
|
58
59
|
| `desktop` | Only on a desktop project. Every Electron and Tauri misconfiguration here fails silently, so it is diagnosed explicitly |
|
package/docs/cli/verify.mdx
CHANGED
|
@@ -50,11 +50,10 @@ Call log:
|
|
|
50
50
|
|
|
51
51
|
<Warning>
|
|
52
52
|
`verify` binds the bridge port itself and has **no `--port` flag**: passing one is rejected as
|
|
53
|
-
`unknown argument '--port'`. If a daemon is already on the port, `verify`
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
port is normally free.
|
|
53
|
+
`unknown argument '--port'`. If a daemon is already on the port, `verify` does not start a second
|
|
54
|
+
one: it prints three ways out (ask the running daemon via `reticle_run`, stop it, or move with
|
|
55
|
+
`RETICLE_PORT`) rather than a raw listen error. This bites most often on a developer machine,
|
|
56
|
+
where an agent has usually left a daemon running; in CI the port is normally free.
|
|
58
57
|
</Warning>
|
|
59
58
|
|
|
60
59
|
## Exit codes
|
package/docs/desktop.mdx
CHANGED
package/docs/docs.json
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"navigation": {
|
|
33
33
|
"versions": [
|
|
34
34
|
{
|
|
35
|
-
"version": "2.
|
|
35
|
+
"version": "2.12.0",
|
|
36
36
|
"default": true,
|
|
37
37
|
"tabs": [
|
|
38
38
|
{
|
|
@@ -153,7 +153,7 @@
|
|
|
153
153
|
},
|
|
154
154
|
{
|
|
155
155
|
"group": "Long form",
|
|
156
|
-
"pages": ["agent-cheatsheet", "usage", "faq"]
|
|
156
|
+
"pages": ["agent-cheatsheet", "reticle-manual", "usage", "faq"]
|
|
157
157
|
}
|
|
158
158
|
]
|
|
159
159
|
},
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
},
|
|
184
184
|
{
|
|
185
185
|
"group": "Trust & licensing",
|
|
186
|
-
"pages": ["telemetry", "enterprise"]
|
|
186
|
+
"pages": ["telemetry", "license-activation", "enterprise"]
|
|
187
187
|
}
|
|
188
188
|
]
|
|
189
189
|
},
|
package/docs/enterprise.md
CHANGED
|
@@ -8,6 +8,8 @@ Enterprise features ship inside the open package and are unlocked by a signed li
|
|
|
8
8
|
|
|
9
9
|
> Premium access (how you get + activate it), what's gated, the security/data-handling posture, and the licensing model. Integration mechanics live in [`platform-integration.md`](./platform-integration.md).
|
|
10
10
|
|
|
11
|
+
> **Already have a key and just need to switch it on?** [Activating a license key](./license-activation) is the step-by-step version: where to set it on each platform, the editor and CI cases, how to read every status, and what to do when it does not work.
|
|
12
|
+
|
|
11
13
|
## How premium access works (offline, no phone-home)
|
|
12
14
|
|
|
13
15
|
Enterprise (`ee/`) features ship **inside the open package**; they're source-available (free for development, testing, and evaluation). A **license key activates them in production**. Activation is verified locally with Ed25519; nothing about your usage ever leaves your machine.
|
|
@@ -29,7 +31,7 @@ Enterprise (`ee/`) features ship **inside the open package**; they're source-ava
|
|
|
29
31
|
expired license expired. Renew with hey@reticle.sh to keep using enterprise features
|
|
30
32
|
```
|
|
31
33
|
|
|
32
|
-
Every status also reports `gated
|
|
34
|
+
Every status reports `contact`, so a reader who is stuck always has somebody to write to. An unlicensed status also reports `gated`, what a licence unlocks in the build you are running, so the command answers "what would this buy me, and how do I get one" without anybody having to find this page first. It is derived from the features the gate actually enforces, so it names what your build will really refuse rather than a roadmap. An `active` licence does not report it: that reader has already bought, and listing feature names at them answers nothing they asked.
|
|
33
35
|
|
|
34
36
|
4. **Unlock.** Enterprise features now run in production; without a valid key they refuse to run there (a clear error, never a silent half-feature). In eval/dev they always run free.
|
|
35
37
|
5. **Renew.** Keys carry an expiry; `reticle license` warns before it lapses.
|
package/docs/gates.md
CHANGED
|
@@ -69,7 +69,7 @@ Each gate exists because the ones above it are blind to something. That blindnes
|
|
|
69
69
|
| **Integration** | `pnpm test:integration` | real headless Chromium: browser pool, crash isolation, framework adapters, `withReticle` | the MCP surface, the daemon | `e2e` |
|
|
70
70
|
| **Web e2e battery** | `pnpm test:e2e` | 32 specs against 3 booted servers and a real browser (the tool surface, the daemon lifecycle, transport faults, telemetry, trace shape), plus the soak | desktop runtimes; the install | `e2e` |
|
|
71
71
|
| **Desktop battery** | `pnpm test:e2e:desktop` | a real Electron main process and a **packaged** Tauri binary, driven headless | web-only paths | `desktop-e2e` |
|
|
72
|
-
| **Install gate** | `pnpm gate:install` | scaffolds 3 pristine apps, publishes this checkout to a local Verdaccio, lets `init` install itself, boots each app in a real browser, polls for a session | install _complexity_; see [`fixtures.md`](./fixtures.md) | `install-gate` |
|
|
72
|
+
| **Install gate** | `pnpm gate:install` | scaffolds 3 pristine apps, publishes this checkout to a local Verdaccio, lets `init` install itself, boots each app in a real browser, polls for a session that advertised capabilities | install _complexity_; see [`fixtures.md`](./fixtures.md) | `install-gate` |
|
|
73
73
|
| **Matrix records** | `pnpm matrix:validate` | every submitted client-compat record is well-formed | whether the client actually works | `matrix-records` |
|
|
74
74
|
| **Windows** | (CI only) | that the code runs at all on the majority platform | e2e; Windows is unit-only | `windows` |
|
|
75
75
|
| **Rust** | `cargo fmt/clippy/check` | `packages/tauri` compiles and lints on Linux, macOS, and cross-checks Windows | everything JS | `rust`, `rust-macos` |
|