@reticlehq/server 3.1.0 → 3.2.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.
Files changed (228) hide show
  1. package/SKILL.md +17 -18
  2. package/dist/command/cli/auth/device-flow.d.ts +2 -2
  3. package/dist/command/cli/cli-doctor.js +13 -1
  4. package/dist/command/cli/cli-flow-commands.d.ts +2 -1
  5. package/dist/command/cli/cli-kill.js +1 -1
  6. package/dist/command/cli/cli-parse.d.ts +2 -1
  7. package/dist/command/cli/cli-parse.js +5 -2
  8. package/dist/command/cli/cli-verify.js +2 -2
  9. package/dist/command/cli/cloud-cli.js +7 -6
  10. package/dist/command/cli/cloud-kit.js +2 -6
  11. package/dist/command/cli/config/config-discovery.d.ts +12 -0
  12. package/dist/command/cli/config/config-discovery.js +19 -0
  13. package/dist/command/cli/doctor/doctor-rows.d.ts +12 -0
  14. package/dist/command/cli/doctor/doctor-rows.js +12 -0
  15. package/dist/command/cli/drive/drive-command.js +1 -1
  16. package/dist/command/cli/launch/cli-launch.d.ts +10 -2
  17. package/dist/command/cli/launch/cli-launch.js +32 -39
  18. package/dist/command/cli/lifecycle/daemon-lifecycle.d.ts +33 -0
  19. package/dist/command/cli/lifecycle/daemon-lifecycle.js +198 -0
  20. package/dist/command/cli/mcp-command.js +5 -3
  21. package/dist/command/cli/ports/resolve/cli-port.d.ts +2 -1
  22. package/dist/command/cli/ports/resolve/cli-port.js +5 -1
  23. package/dist/command/cli/status/status-lines.d.ts +28 -0
  24. package/dist/command/cli/status/status-lines.js +117 -0
  25. package/dist/command/cli.d.ts +1 -1
  26. package/dist/command/cli.js +24 -177
  27. package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
  28. package/dist/command/daemon/binding/daemon-status-probe.js +48 -0
  29. package/dist/command/daemon/binding/loopback-reach.d.ts +42 -0
  30. package/dist/command/daemon/binding/loopback-reach.js +63 -0
  31. package/dist/command/daemon/daemon-resilience.d.ts +13 -1
  32. package/dist/command/daemon/daemon-resilience.js +12 -1
  33. package/dist/command/daemon/daemon.d.ts +2 -11
  34. package/dist/command/daemon/daemon.js +8 -11
  35. package/dist/command/daemon/lifetime/heartbeat.d.ts +8 -0
  36. package/dist/command/daemon/lifetime/heartbeat.js +10 -0
  37. package/dist/command/daemon/lifetime/log-cap.d.ts +68 -0
  38. package/dist/command/daemon/lifetime/log-cap.js +115 -0
  39. package/dist/command/setup/agent-notice-memory.d.ts +16 -0
  40. package/dist/command/setup/agent-notice-memory.js +65 -0
  41. package/dist/command/setup/bringup/dev-server-wait.d.ts +1 -0
  42. package/dist/command/setup/bringup/dev-server-wait.js +16 -0
  43. package/dist/command/setup/bringup/ensure-daemon.js +1 -1
  44. package/dist/command/setup/init/init-runtime.js +13 -1
  45. package/dist/command/setup/node-effects.js +1 -1
  46. package/dist/command/setup/probe/page-probe.js +9 -2
  47. package/dist/command/setup/run-setup.d.ts +25 -7
  48. package/dist/command/setup/run-setup.js +51 -9
  49. package/dist/command/setup/setup-command.js +31 -3
  50. package/dist/command/setup/terminal/confirm.js +2 -1
  51. package/dist/command/update/updater.d.ts +27 -0
  52. package/dist/command/update/updater.js +35 -2
  53. package/dist/features/crawl/crawl-tools.js +3 -1
  54. package/dist/features/crawl/crawl.js +2 -1
  55. package/dist/features/harness/drive-report.d.ts +73 -0
  56. package/dist/features/harness/drive-report.js +196 -0
  57. package/dist/features/harness/driver.js +29 -8
  58. package/dist/features/harness/drivers.d.ts +19 -0
  59. package/dist/features/harness/drivers.js +19 -0
  60. package/dist/features/harness/fill-values.d.ts +67 -0
  61. package/dist/features/harness/fill-values.js +153 -0
  62. package/dist/features/harness/jev-driver.d.ts +188 -0
  63. package/dist/features/harness/jev-driver.js +664 -0
  64. package/dist/features/harness/openai-driver.d.ts +46 -0
  65. package/dist/features/harness/openai-driver.js +197 -0
  66. package/dist/features/harness/platform-config.d.ts +52 -0
  67. package/dist/features/harness/platform-config.js +89 -0
  68. package/dist/features/visual/visual-tools.js +26 -2
  69. package/dist/index.js +60 -55
  70. package/dist/judgement/domain/domain-tools.js +4 -2
  71. package/dist/judgement/runs/verification-sync.d.ts +2 -2
  72. package/dist/judgement/runs/verification-sync.js +9 -2
  73. package/dist/language/flows/affected-tools.js +6 -3
  74. package/dist/language/flows/flow-replay-run.d.ts +25 -2
  75. package/dist/language/flows/flow-replay-run.js +73 -27
  76. package/dist/language/flows/flow-replay.d.ts +17 -0
  77. package/dist/language/flows/flow-replay.js +148 -100
  78. package/dist/language/flows/flow-result.d.ts +18 -1
  79. package/dist/language/flows/flow-result.js +18 -2
  80. package/dist/language/flows/flow-store-for-session.d.ts +2 -1
  81. package/dist/language/flows/flow-tools.js +8 -4
  82. package/dist/language/flows/flows.d.ts +8 -7
  83. package/dist/language/flows/flows.js +7 -3
  84. package/dist/language/flows/narrow-write.d.ts +4 -4
  85. package/dist/language/flows/replay.js +1 -1
  86. package/dist/language/flows/suite-selection.d.ts +15 -1
  87. package/dist/language/flows/suite-selection.js +1 -1
  88. package/dist/language/flows/verify-change-tools.js +7 -4
  89. package/dist/memory/cloud/account-state.d.ts +1 -1
  90. package/dist/memory/cloud/account-state.js +5 -4
  91. package/dist/memory/cloud/cloud-config.d.ts +9 -0
  92. package/dist/memory/cloud/cloud-config.js +9 -0
  93. package/dist/memory/cloud/cloud-sync.d.ts +7 -2
  94. package/dist/memory/cloud/cloud-sync.js +10 -5
  95. package/dist/memory/cloud/harness-config.d.ts +10 -0
  96. package/dist/memory/cloud/harness-config.js +58 -0
  97. package/dist/memory/cloud/harness-offer.d.ts +44 -0
  98. package/dist/memory/cloud/harness-offer.js +146 -0
  99. package/dist/memory/cloud/harness-switch.d.ts +11 -0
  100. package/dist/memory/cloud/harness-switch.js +53 -0
  101. package/dist/memory/cloud/sync-daemon.d.ts +22 -2
  102. package/dist/memory/cloud/sync-daemon.js +24 -0
  103. package/dist/memory/impact/impact-recorder.d.ts +8 -0
  104. package/dist/memory/impact/impact-recorder.js +2 -1
  105. package/dist/memory/impact/impact-store.d.ts +5 -0
  106. package/dist/memory/impact/impact-store.js +19 -0
  107. package/dist/memory/intent/intent-shard-store.js +2 -2
  108. package/dist/memory/intent/intent-shard.d.ts +12 -12
  109. package/dist/memory/journal/attach-journal.d.ts +11 -0
  110. package/dist/memory/journal/attach-journal.js +1 -1
  111. package/dist/memory/journal/journal-query.d.ts +35 -1
  112. package/dist/memory/journal/journal-query.js +46 -0
  113. package/dist/memory/journal/journal-recorder.d.ts +50 -2
  114. package/dist/memory/journal/journal-recorder.js +45 -7
  115. package/dist/memory/journal/on-disk/retention.d.ts +87 -2
  116. package/dist/memory/journal/on-disk/retention.js +177 -8
  117. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +9 -0
  118. package/dist/memory/journal/on-disk/workspace-gitignore.js +9 -2
  119. package/dist/memory/journal/self-observation.d.ts +3 -0
  120. package/dist/memory/journal/self-observation.js +67 -0
  121. package/dist/memory/journal/session-end.d.ts +13 -3
  122. package/dist/memory/journal/session-end.js +24 -4
  123. package/dist/memory/journal/session-journal.d.ts +115 -5
  124. package/dist/memory/journal/session-journal.js +479 -32
  125. package/dist/memory/project/artifact-root-resolver.d.ts +3 -0
  126. package/dist/memory/project/artifact-root-resolver.js +89 -0
  127. package/dist/memory/project/artifact-root.d.ts +39 -2
  128. package/dist/memory/project/artifact-root.js +58 -1
  129. package/dist/memory/project/dir/fill-value-store.d.ts +32 -0
  130. package/dist/memory/project/dir/fill-value-store.js +88 -0
  131. package/dist/memory/project/dir/reticle-dir.d.ts +14 -4
  132. package/dist/memory/project/dir/reticle-dir.js +11 -0
  133. package/dist/memory/project/fs/fs-port.d.ts +22 -1
  134. package/dist/memory/project/fs/fs-port.js +33 -5
  135. package/dist/memory/project/learned-routes.d.ts +16 -2
  136. package/dist/memory/project/learned-routes.js +26 -10
  137. package/dist/memory/project/project-for-root.d.ts +30 -0
  138. package/dist/memory/project/project-for-root.js +43 -0
  139. package/dist/memory/project/project-tools.js +10 -5
  140. package/dist/memory/project/session-root.d.ts +35 -6
  141. package/dist/memory/project/session-root.js +70 -8
  142. package/dist/portal/bridge/auth-failure-reason.d.ts +9 -0
  143. package/dist/portal/bridge/auth-failure-reason.js +15 -1
  144. package/dist/portal/bridge/bridge.d.ts +6 -1
  145. package/dist/portal/bridge/bridge.js +36 -2
  146. package/dist/portal/session/facts/session-replaced.d.ts +19 -0
  147. package/dist/portal/session/facts/session-replaced.js +22 -0
  148. package/dist/portal/session/no-session-diagnosis.d.ts +1 -0
  149. package/dist/portal/session/no-session-diagnosis.js +67 -60
  150. package/dist/portal/session/no-session-next-action.js +3 -2
  151. package/dist/portal/session/no-session-watch.js +14 -10
  152. package/dist/portal/session/rebind.d.ts +18 -0
  153. package/dist/portal/session/rebind.js +38 -0
  154. package/dist/portal/session/session-manager.d.ts +4 -0
  155. package/dist/portal/session/session-manager.js +19 -1
  156. package/dist/portal/session/session.d.ts +21 -10
  157. package/dist/portal/session/session.js +29 -42
  158. package/dist/status-payload.d.ts +12 -1
  159. package/dist/status-payload.js +4 -1
  160. package/dist/surface/http-server.js +3 -5
  161. package/dist/surface/mcp/faults/mcp-outage.d.ts +2 -1
  162. package/dist/surface/mcp/faults/mcp-outage.js +20 -4
  163. package/dist/surface/mcp/mcp-proxy.d.ts +10 -1
  164. package/dist/surface/mcp/mcp-proxy.js +20 -9
  165. package/dist/surface/mcp/mcp.d.ts +10 -1
  166. package/dist/surface/mcp/mcp.js +59 -29
  167. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +15 -2
  168. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +22 -5
  169. package/dist/surface/mcp/proxy/proxy-log.d.ts +5 -11
  170. package/dist/surface/mcp/proxy/proxy-log.js +7 -22
  171. package/dist/surface/tools/act/act-preflight.js +6 -1
  172. package/dist/surface/tools/act/sequence-grade.js +13 -0
  173. package/dist/surface/tools/act-capsule.js +27 -1
  174. package/dist/surface/tools/assert/assert-verdict.js +44 -17
  175. package/dist/surface/tools/coverage-tools.js +5 -2
  176. package/dist/surface/tools/dynamic-tools.js +37 -46
  177. package/dist/surface/tools/error-recovery.d.ts +6 -0
  178. package/dist/surface/tools/error-recovery.js +15 -0
  179. package/dist/surface/tools/explore-tools.js +80 -7
  180. package/dist/surface/tools/feedback-tools.js +49 -2
  181. package/dist/surface/tools/first-sentence.d.ts +24 -0
  182. package/dist/surface/tools/first-sentence.js +0 -0
  183. package/dist/surface/tools/harness-explore.d.ts +125 -1
  184. package/dist/surface/tools/harness-explore.js +401 -15
  185. package/dist/surface/tools/harness-plan.d.ts +76 -0
  186. package/dist/surface/tools/harness-plan.js +156 -0
  187. package/dist/surface/tools/harness-toolset.js +12 -1
  188. package/dist/surface/tools/invoke-tool.js +65 -5
  189. package/dist/surface/tools/live-call-text.d.ts +6 -0
  190. package/dist/surface/tools/live-call-text.js +36 -2
  191. package/dist/surface/tools/observe-tools.js +55 -9
  192. package/dist/surface/tools/read/query-windowed.d.ts +1 -1
  193. package/dist/surface/tools/read/query-windowed.js +1 -1
  194. package/dist/surface/tools/read-tools.js +1 -2
  195. package/dist/surface/tools/tool-kit.d.ts +18 -3
  196. package/dist/surface/tools/tools-helpers.d.ts +8 -7
  197. package/dist/surface/tools/tools-helpers.js +11 -13
  198. package/dist/surface/tools/tools.js +6 -1
  199. package/dist/telemetry/bug-found.js +32 -2
  200. package/dist/telemetry/feedback-context.js +3 -3
  201. package/dist/telemetry/harness-drive.d.ts +6 -0
  202. package/dist/telemetry/harness-drive.js +39 -0
  203. package/dist/telemetry/mcp-connection.d.ts +14 -1
  204. package/dist/telemetry/mcp-connection.js +17 -2
  205. package/dist/telemetry/onboarding-firsts.d.ts +30 -1
  206. package/dist/telemetry/onboarding-firsts.js +54 -12
  207. package/dist/telemetry/verification-of.js +31 -3
  208. package/docs/agent-cheatsheet.md +7 -3
  209. package/docs/autodrive.md +42 -2
  210. package/docs/benchmarks.md +1 -1
  211. package/docs/capabilities.mdx +1 -1
  212. package/docs/cli/cloud.mdx +3 -3
  213. package/docs/cli/doctor.mdx +1 -0
  214. package/docs/cli/status.mdx +35 -20
  215. package/docs/cli.mdx +8 -18
  216. package/docs/desktop.mdx +1 -1
  217. package/docs/faq.mdx +1 -1
  218. package/docs/install-manual.mdx +1 -1
  219. package/docs/packages/tauri.mdx +1 -1
  220. package/docs/packages.mdx +1 -1
  221. package/docs/predicates.mdx +16 -0
  222. package/docs/system-map.md +6 -4
  223. package/docs/telemetry.md +2 -1
  224. package/docs/token-efficiency.md +2 -2
  225. package/docs/tools/overview.mdx +1 -1
  226. package/docs/troubleshooting.mdx +8 -2
  227. package/docs/usage.md +1 -1
  228. package/package.json +6 -6
@@ -0,0 +1,153 @@
1
+ /**
2
+ * What to type into a field, and the one place in a drive worth paying a generating model for.
3
+ *
4
+ * A System One model answers typed questions against a state; it cannot write a string. That is not
5
+ * a shortcoming to route around everywhere — it is why the drive is two orders of magnitude cheaper,
6
+ * and every decision it makes (which tool, which element, what should follow) is a decision, not a
7
+ * composition. But a text field is a composition. "A card number", "a search term that returns
8
+ * results", "a description a human would write" cannot be enumerated from the page, and a label-keyed
9
+ * table of guesses is what stands in for them today.
10
+ *
11
+ * ## Why this is escalation rather than partnership
12
+ *
13
+ * Put a generating model in the per-turn loop and you pay its per-turn tax on every step, which is
14
+ * the cost the cheap driver exists to avoid. Typing is a small minority of what a drive does —
15
+ * clicks and navigations are the overwhelming majority — so the model is called for the few steps
16
+ * that compose text, never for the many that select, and a drive with no text fields never calls it
17
+ * at all.
18
+ *
19
+ * ## Why it is cached, and cached where it is
20
+ *
21
+ * A generated value is paid for ONCE and then belongs to the project: the same field on the same
22
+ * app wants the same value tomorrow, and a replay must send exactly what the recording sent or it
23
+ * is not a replay. Writing them to `.reticle` makes the second drive free, makes the values
24
+ * reviewable by a human who can correct a bad one by hand, and keeps them out of the model's way
25
+ * entirely. It is the same economics as the flows themselves: pay once, replay forever.
26
+ *
27
+ * ## What it must never do
28
+ *
29
+ * Fill a slot, never propose a call. The driver decides what to click and what to claim; this
30
+ * answers one question — "what text goes in this box" — and a wrong answer costs one act, not a
31
+ * wrong verdict. Nothing here touches what is judged.
32
+ */
33
+ import { DEFAULT_HARNESS_BASE_URL, } from './driver.js';
34
+ /** Deliberately small. A field value is a phrase; anything longer is the model misunderstanding. */
35
+ const MAX_TOKENS = 64;
36
+ const ANTHROPIC_VERSION = '2023-06-01';
37
+ const MESSAGES_PATH = '/v1/messages';
38
+ /**
39
+ * How many values one drive will generate.
40
+ *
41
+ * The cache makes the steady state nearly free, but the FIRST drive on a form-heavy app is the one
42
+ * that pays, and an uncapped loop on a page with forty inputs is a bill nobody agreed to. Past the
43
+ * cap the heuristic answers, which is what every drive used before this existed.
44
+ */
45
+ const MAX_PER_DRIVE = 12;
46
+ /**
47
+ * The fallback, and still the answer for most fields.
48
+ *
49
+ * An exploration drive needs PLAUSIBLE input, not creative input: the engine is judging what the app
50
+ * did with the value, not the value. A field that rejects everything here is itself worth finding,
51
+ * and shows up as an act that did not settle.
52
+ */
53
+ export function heuristicFillValue(label) {
54
+ const l = label.toLowerCase();
55
+ if (l.includes('email'))
56
+ return 'harness@reticle.dev';
57
+ if (l.includes('password'))
58
+ return 'password';
59
+ if (l.includes('url') || l.includes('link'))
60
+ return 'https://example.com';
61
+ if (l.includes('phone') || l.includes('tel'))
62
+ return '5550100';
63
+ if (l.includes('date'))
64
+ return '2026-01-01';
65
+ if (l.includes('amount') || l.includes('price') || l.includes('qty') || l.includes('quantity'))
66
+ return '2';
67
+ if (l.includes('search') || l.includes('filter'))
68
+ return 'a';
69
+ if (l.includes('number') || l.includes('count'))
70
+ return '42';
71
+ return 'reticle harness';
72
+ }
73
+ /**
74
+ * Whether a label is worth spending a model call on.
75
+ *
76
+ * The heuristic is RIGHT about an email box and an amount box, and a generated "john@example.com"
77
+ * is not an improvement on `harness@reticle.dev`. What it cannot do is a field whose label it does
78
+ * not recognise at all, where it falls back to typing the words "reticle harness" into whatever the
79
+ * app asked for. That fallback is the whole of what generation is for.
80
+ */
81
+ export function needsGeneration(label) {
82
+ return heuristicFillValue(label) === heuristicFillValue('');
83
+ }
84
+ const PROMPT = (label, context) => `A test harness is filling in a form field on a web application so it can check what the app does with the input.\n\n` +
85
+ `The field is labelled: "${label}"\n` +
86
+ `${context}\n\n` +
87
+ `Reply with ONLY the value to type. No quotes, no explanation, no markdown. It must be something a ` +
88
+ `real user would plausibly enter, and short. If the field wants an identifier or a code, invent a ` +
89
+ `well-formed one.`;
90
+ /** One string from a generating model, or nothing. Never throws: a drive must not fail over a field. */
91
+ async function generateOne(options, label, context) {
92
+ const call = options.fetch ?? ((url, init) => fetch(url, init));
93
+ const baseUrl = options.baseUrl ?? DEFAULT_HARNESS_BASE_URL;
94
+ try {
95
+ const res = await call(`${baseUrl}${MESSAGES_PATH}`, {
96
+ method: 'POST',
97
+ headers: {
98
+ 'content-type': 'application/json',
99
+ 'x-api-key': options.apiKey,
100
+ 'anthropic-version': ANTHROPIC_VERSION,
101
+ },
102
+ body: JSON.stringify({
103
+ model: options.model ?? 'claude-sonnet-5',
104
+ max_tokens: MAX_TOKENS,
105
+ messages: [{ role: 'user', content: PROMPT(label, context) }],
106
+ }),
107
+ });
108
+ if (!res.ok)
109
+ return undefined;
110
+ const parsed = JSON.parse(await res.text());
111
+ const content = parsed.content ?? [];
112
+ const text = content
113
+ .filter((block) => 'text' === block.type)
114
+ .map((block) => block.text ?? '')
115
+ .join('')
116
+ .trim()
117
+ .split('\n')[0];
118
+ if (text === undefined || 0 === text.length)
119
+ return undefined;
120
+ // A model asked for one value occasionally answers with a sentence about the value. Anything
121
+ // long enough to be prose is not a field value, and typing prose proves nothing about the app.
122
+ return 80 < text.length ? undefined : text.replace(/^["']|["']$/g, '');
123
+ }
124
+ catch {
125
+ // Offline, refused, rate-limited, malformed. All the same answer: use the heuristic.
126
+ return undefined;
127
+ }
128
+ }
129
+ /**
130
+ * The seam the driver calls: a label in, a value out, always.
131
+ *
132
+ * Three layers, cheapest first, and the expensive one is skipped entirely unless the two above it
133
+ * have nothing better than "type the words reticle harness into this box".
134
+ */
135
+ export function fillValues(deps) {
136
+ let spent = 0;
137
+ return async (label) => {
138
+ const cached = deps.cache?.get(label);
139
+ if (cached !== undefined)
140
+ return cached;
141
+ const fallback = heuristicFillValue(label);
142
+ if (deps.generator === undefined || !needsGeneration(label) || MAX_PER_DRIVE <= spent)
143
+ return fallback;
144
+ spent += 1;
145
+ const generated = await generateOne(deps.generator, label, deps.context?.() ?? '');
146
+ if (generated === undefined)
147
+ return fallback;
148
+ // Cached under the LABEL, not the ref: refs expire with the page, labels are what the next drive
149
+ // and every replay will meet again.
150
+ deps.cache?.set(label, generated);
151
+ return generated;
152
+ };
153
+ }
@@ -0,0 +1,188 @@
1
+ /**
2
+ * A harness driver with no text generator in it.
3
+ *
4
+ * `driver.ts` binds the harness to a frontier model, and the comment at the top of it has always
5
+ * claimed the tier is "a standing test of the design": the driver is not reasoning about business
6
+ * logic, it is choosing what to touch next and saying what it expects, and if that needed a large
7
+ * model then the engine would not be doing its job. Nothing tested the claim, because the only
8
+ * driver in the repo was a large model.
9
+ *
10
+ * This is the test. Jev is a System One model — it evaluates typed questions against a state and
11
+ * answers with probabilities, in one parallel pass, and it does not emit prose. It therefore cannot
12
+ * invent a tool call. So every call this driver makes is built HERE, deterministically, out of what
13
+ * the page actually offers, and the model's only contribution is picking one of them. That is a
14
+ * strictly smaller surface than a generating driver has, and it is the whole reason this is worth
15
+ * having: a driver that cannot name an element that is not on the page cannot hallucinate one.
16
+ *
17
+ * What did NOT move: the verdict. `decideVerified` still decides, on evidence, with no model in it.
18
+ * A System One model cannot hallucinate a type, but it still returns a PROBABILITY, and a
19
+ * probability is not proof. Anyone reading this file as an invitation to let Jev answer
20
+ * "did it work?" should read `engine/src/evidence/verified.ts` first — the seventeen clauses there
21
+ * exist because this product is the verdict, and a verdict sourced from a model's confidence is the
22
+ * thing Reticle sells the absence of.
23
+ */
24
+ import type { ModelDriver } from './harness.js';
25
+ import type { HarnessFetch } from './driver.js';
26
+ export declare const DEFAULT_JEV_MODEL = "jev-latest";
27
+ export declare const DEFAULT_JEV_BASE_URL = "https://api.typesafe.ai";
28
+ /**
29
+ * The consequences the driver can declare, and the predicate each one becomes.
30
+ *
31
+ * Declaring one is not optional decoration — it is the difference between a drive and a click. The
32
+ * first version of this driver emitted `act_and_wait` with no `until` at all, and the engine said
33
+ * so in every single result: "the page settled and no channel reported a problem, but nothing was
34
+ * declared to prove — this is not verification". Six actions, zero proved. A flow recorded from that
35
+ * drive passes even when the feature is broken, which is the exact failure this product exists to
36
+ * catch, sitting inside the thing meant to catch it.
37
+ *
38
+ * Every predicate here is BARE — a kind with no specifics — because before acting the driver does
39
+ * not know which endpoint, signal or route to expect. Bare is still consequence-grade evidence: it
40
+ * asserts the app's own machinery moved, which a presence check on screen text does not.
41
+ *
42
+ * Only SIGNAL and NET can be declared bare, and that is a fact about the engine rather than a
43
+ * preference. `engine/src/evidence/already-true.ts` lists the kinds that read live state — element,
44
+ * text, route and state — and those are checked BEFORE the action as well as after, precisely so a
45
+ * condition that already held cannot be sold as something the action caused. A bare predicate of
46
+ * one of those kinds is unconditionally true: there is always a current route, and there is always
47
+ * some store. That file says so in as many words at its `ROUTE` case.
48
+ *
49
+ * This driver tried all four anyway and the engine refused all four, every time, with
50
+ * `already_true` — "the declared consequence was already true before this action, so it proves
51
+ * nothing about it". Signal and net are event-based and floored at the act's own cursor, so they
52
+ * cannot be answered by the past, which is exactly what makes them safe to declare with no
53
+ * specifics. Route and state come back the moment the driver can name a pathname or a store path
54
+ * instead of a bare kind, and they are the stronger evidence when it can.
55
+ *
56
+ * `anyOf` is not a loophole: it reports as live-reading if ANY branch does, so it holds only the
57
+ * two safe kinds for the same reason.
58
+ *
59
+ * ponytail: bare `net` can in principle be satisfied by unrelated traffic inside the action's
60
+ * window — a page polling every second would answer for a button that did nothing. The window is
61
+ * the action's own, not "ever", so the exposure is small but real. The upgrade is to learn the
62
+ * app's vocabulary first (one `reticle_observe` early in the drive gives the actual signal names
63
+ * and endpoint paths) and declare `urlContains`/`name` instead of a bare kind. Until then `state`
64
+ * and `signal` are the trustworthy ones and `net` is the one to distrust on a chatty app.
65
+ */
66
+ export interface Consequence {
67
+ predicate: Record<string, unknown>;
68
+ describes: string;
69
+ /**
70
+ * Whether a SAVED FLOW can carry this claim, which is a different question from whether the drive
71
+ * can prove it.
72
+ *
73
+ * A recorded step keeps an expectation only in the forms a replay can re-check, and that filter
74
+ * refuses every unbound kind: `signal "export:generated"` survives, a bare "some signal fires"
75
+ * does not; `net { method: "POST" }` survives, a bare "some request happens" does not; `not` and
76
+ * `anyOf` have no representation at all.
77
+ *
78
+ * Measured on a real dashboard before this field existed: every one of the four consequences on
79
+ * offer was unbound, so 0 of 22 steps across 16 machine-driven flows recorded a single
80
+ * expectation, against 211 of 419 in the hand-authored flows beside them. The drive proved things
81
+ * and then saved flows that had forgotten all of it. Since a flow is meant to BE the regression
82
+ * suite, that is the product's own claim failing at its last step: those flows can only ever
83
+ * catch "the click stopped landing", never "the feature broke".
84
+ */
85
+ recordable: boolean;
86
+ }
87
+ /**
88
+ * The app's own route, with Reticle's fingerprints wiped off it.
89
+ *
90
+ * A pooled launcher appends `__reticle_opened=1` to the URL it opens, and that parameter ended up
91
+ * inside a declared consequence: "this click leaves a route containing /?__reticle_opened=1". On a
92
+ * hash-routed app that claim can never hold, because the query string never changes -- only the
93
+ * fragment does -- so every navigation link was a guaranteed red, and the red was about OUR query
94
+ * parameter rather than about the application. Found by making a failed action say what it claimed;
95
+ * before that it read as an ordinary "the declared consequence did not hold".
96
+ *
97
+ * The fragment is kept, and is the point: on a hash-routed app it is the only part that moves.
98
+ */
99
+ export declare function appRoute(route: string): string;
100
+ /**
101
+ * The consequences on offer, given where the app currently is and what it says it can do.
102
+ *
103
+ * Two things shape this list, and the second one was missing for a whole release.
104
+ *
105
+ * It is a function of the CURRENT ROUTE, because "this takes us off the page we are on" is only
106
+ * falsifiable against a route actually read.
107
+ *
108
+ * It is also a function of the app's OWN VOCABULARY, because an unbound claim cannot be saved. A
109
+ * drive that declares "some signal fires" proves something real at the time and writes a flow that
110
+ * asserts nothing, so every later replay passes as long as the clicks still land. Offering the
111
+ * declared signal NAMES turns the same choice into one a flow can keep, and costs nothing extra:
112
+ * the names are already read out of `.reticle` to build the plan.
113
+ */
114
+ export declare function consequencesFor(route: string | undefined, vocabulary?: readonly string[]): Record<string, Consequence>;
115
+ /**
116
+ * One step of the plan the caller built from `.reticle`.
117
+ *
118
+ * Structural rather than imported: this package is a SINK — it is handed a toolset and a driver and
119
+ * reaches into nothing — so the plan arrives as data with the shape it needs and no dependency on
120
+ * where it was built.
121
+ */
122
+ export interface DrivePlanStep {
123
+ /** `replay` for a journey already recorded, `drive` for declared intent nobody has proved. */
124
+ kind: string;
125
+ /** The flow to replay, or the signal/control a drive step is aimed at. */
126
+ target: string;
127
+ /** Why this step is worth taking, in the project's own words. */
128
+ why: string;
129
+ }
130
+ export interface JevDriverOptions {
131
+ apiKey: string;
132
+ model?: string;
133
+ baseUrl?: string;
134
+ /**
135
+ * The loop's step budget, so the driver can stop exploring in time to save what it drove.
136
+ *
137
+ * The loop does not tell a driver how much budget is left — it does not have to, because a
138
+ * generating model is expected to call `finish` when it is ready. This driver has a teardown it
139
+ * must reach, so it needs the number. Absent ⇒ no reserve, and a run that ends on BUDGET keeps
140
+ * nothing, which is why every caller inside the repo passes it.
141
+ */
142
+ maxSteps?: number;
143
+ /**
144
+ * What this drive is FOR, read from `.reticle` before it started.
145
+ *
146
+ * Replay steps run FIRST and deterministically, with no model call at all — a journey already on
147
+ * disk must never be re-driven, which is the whole reason the plan exists. Only once they are
148
+ * done is the model asked anything, and then it is asked against the intent these steps carry
149
+ * rather than against whatever happens to be on the page.
150
+ */
151
+ plan?: readonly DrivePlanStep[];
152
+ /**
153
+ * The signal names the app declares, untested ones first, read out of `.reticle` with the plan.
154
+ *
155
+ * Offered as consequences so a declaration can name something. Absent is not a failure: the
156
+ * method-bound network consequences are still recordable, and an app that declares no signals is
157
+ * simply an app with less to claim.
158
+ */
159
+ vocabulary?: readonly string[];
160
+ /**
161
+ * What to type into a text field, when the label alone is not enough to guess.
162
+ *
163
+ * The one place a drive is a COMPOSITION rather than a decision, and therefore the one place worth
164
+ * paying a generating model for. Absent ⇒ the label heuristic answers, which is what every drive
165
+ * did before this seam existed; a drive with no text fields never reaches it either way. See
166
+ * `fill-values.ts` for why it is escalation rather than a second model in the loop.
167
+ */
168
+ fillValue?: (label: string) => Promise<string>;
169
+ /** Injected for tests. Defaults to the platform `fetch`. */
170
+ fetch?: HarnessFetch;
171
+ }
172
+ /**
173
+ * Read this driver's configuration out of the environment.
174
+ *
175
+ * A direct Jev key wins over the platform key, so that someone debugging the upstream is never
176
+ * quietly talking to the proxy they were trying to bypass. Returns `undefined` when neither is set,
177
+ * which is a routine answer and not a failure — the caller falls back to the Anthropic driver.
178
+ */
179
+ export declare function jevOptionsFromEnv(env: Record<string, string | undefined>): JevDriverOptions | undefined;
180
+ /**
181
+ * Build a driver backed by a System One model.
182
+ *
183
+ * Every turn emits exactly ONE call. The loop dispatches a turn's calls with `Promise.all`, so an
184
+ * act and the snapshot that reads its result cannot be batched into one turn — they would race, and
185
+ * the snapshot would describe a page mid-flight. One call per turn costs a step and buys a reading
186
+ * that is actually of the page the action produced.
187
+ */
188
+ export declare function jevDriver(options: JevDriverOptions): ModelDriver;