@reticlehq/server 3.5.0 → 3.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (721) hide show
  1. package/README.md +1 -1
  2. package/SKILL.md +123 -116
  3. package/dist/chromium-launch-options.d.ts +3 -1
  4. package/dist/chromium-launch-options.js +2 -1
  5. package/dist/command/cli/adhoc-suite.d.ts +14 -0
  6. package/dist/command/cli/adhoc-suite.js +42 -7
  7. package/dist/command/cli/adhoc-verdict.d.ts +19 -2
  8. package/dist/command/cli/adhoc-verdict.js +76 -9
  9. package/dist/command/cli/answers/gate-exit.d.ts +23 -0
  10. package/dist/command/cli/answers/gate-exit.js +45 -0
  11. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  12. package/dist/command/cli/answers/gate-hook-message.js +3 -1
  13. package/dist/command/cli/answers/open-note.d.ts +2 -0
  14. package/dist/command/cli/answers/open-note.js +22 -0
  15. package/dist/command/cli/auth/device-flow.d.ts +13 -2
  16. package/dist/command/cli/auth/device-flow.js +17 -0
  17. package/dist/command/cli/cli-doctor.js +14 -0
  18. package/dist/command/cli/cli-flow-commands.d.ts +0 -11
  19. package/dist/command/cli/cli-flow-commands.js +31 -112
  20. package/dist/command/cli/cli-kill.js +3 -2
  21. package/dist/command/cli/cli-parse-grammar.d.ts +24 -0
  22. package/dist/command/cli/cli-parse-grammar.js +75 -0
  23. package/dist/command/cli/cli-parse-verify.d.ts +2 -0
  24. package/dist/command/cli/cli-parse-verify.js +18 -0
  25. package/dist/command/cli/cli-parse.d.ts +19 -28
  26. package/dist/command/cli/cli-parse.js +82 -182
  27. package/dist/command/cli/cli-update-commands.d.ts +1 -1
  28. package/dist/command/cli/cli-update-commands.js +61 -9
  29. package/dist/command/cli/cli-usage.d.ts +33 -0
  30. package/dist/command/cli/cli-usage.js +287 -0
  31. package/dist/command/cli/cli-verify.d.ts +35 -5
  32. package/dist/command/cli/cli-verify.js +114 -35
  33. package/dist/command/cli/cloud-cli.d.ts +13 -0
  34. package/dist/command/cli/cloud-cli.js +192 -341
  35. package/dist/command/cli/cloud-kit.d.ts +12 -0
  36. package/dist/command/cli/cloud-kit.js +41 -2
  37. package/dist/command/cli/cloud-link.d.ts +57 -0
  38. package/dist/command/cli/cloud-link.js +308 -0
  39. package/dist/command/cli/cloud-login.d.ts +22 -0
  40. package/dist/command/cli/cloud-login.js +96 -8
  41. package/dist/command/cli/context-command.d.ts +1 -0
  42. package/dist/command/cli/context-command.js +33 -0
  43. package/dist/command/cli/daemon-start-options.d.ts +3 -0
  44. package/dist/command/cli/daemon-start-options.js +24 -3
  45. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +46 -0
  46. package/dist/command/cli/doctor/browser/chromium-hint.js +99 -1
  47. package/dist/command/cli/doctor/doctor-coverage-line.d.ts +2 -0
  48. package/dist/command/cli/doctor/doctor-coverage-line.js +47 -0
  49. package/dist/command/cli/doctor/doctor-project-line.d.ts +0 -12
  50. package/dist/command/cli/doctor/doctor-project-line.js +5 -4
  51. package/dist/command/cli/doctor/doctor-rows.d.ts +6 -0
  52. package/dist/command/cli/doctor/doctor-rows.js +6 -0
  53. package/dist/command/cli/doctor/doctor-signing-line.d.ts +38 -0
  54. package/dist/command/cli/doctor/doctor-signing-line.js +114 -0
  55. package/dist/command/cli/drive/drive-attach.d.ts +27 -2
  56. package/dist/command/cli/drive/drive-attach.js +71 -4
  57. package/dist/command/cli/drive/drive-command.d.ts +2 -1
  58. package/dist/command/cli/drive/drive-command.js +13 -7
  59. package/dist/command/cli/known-regression.d.ts +13 -0
  60. package/dist/command/cli/known-regression.js +34 -0
  61. package/dist/command/cli/launch/sdk-version-match.d.ts +12 -0
  62. package/dist/command/cli/launch/sdk-version-match.js +25 -0
  63. package/dist/command/cli/lifecycle/daemon-lifecycle.js +15 -3
  64. package/dist/command/cli/mcp-command.d.ts +6 -0
  65. package/dist/command/cli/mcp-command.js +13 -5
  66. package/dist/command/cli/ports/port-holder.d.ts +10 -0
  67. package/dist/command/cli/ports/port-holder.js +25 -1
  68. package/dist/command/cli/project-name.d.ts +29 -1
  69. package/dist/command/cli/project-name.js +107 -2
  70. package/dist/command/cli/setup-mcp-cli.d.ts +17 -1
  71. package/dist/command/cli/setup-mcp-cli.js +35 -12
  72. package/dist/command/cli/status/status-lines.d.ts +1 -0
  73. package/dist/command/cli/status/status-lines.js +47 -2
  74. package/dist/command/cli/status/workspace-links.d.ts +10 -0
  75. package/dist/command/cli/status/workspace-links.js +29 -0
  76. package/dist/command/cli/try-command.d.ts +96 -0
  77. package/dist/command/cli/try-command.js +362 -0
  78. package/dist/command/cli/tutorial.d.ts +0 -100
  79. package/dist/command/cli/tutorial.js +0 -181
  80. package/dist/command/cli/verify-results.d.ts +19 -0
  81. package/dist/command/cli/verify-results.js +29 -0
  82. package/dist/command/cli-onboarding.d.ts +0 -11
  83. package/dist/command/cli-onboarding.js +0 -15
  84. package/dist/command/cli.d.ts +20 -0
  85. package/dist/command/cli.js +130 -104
  86. package/dist/command/daemon/binding/daemon-status-probe.d.ts +2 -0
  87. package/dist/command/daemon/binding/daemon-status-probe.js +1 -0
  88. package/dist/command/daemon/daemon-resilience.js +4 -4
  89. package/dist/command/daemon/daemon-resolve.d.ts +23 -1
  90. package/dist/command/daemon/daemon-resolve.js +79 -9
  91. package/dist/command/setup/agent-writer.d.ts +1 -1
  92. package/dist/command/setup/agent-writer.js +3 -2
  93. package/dist/command/setup/bringup/bridge-port.d.ts +3 -1
  94. package/dist/command/setup/bringup/bridge-port.js +13 -3
  95. package/dist/command/setup/bringup/connect-lease.d.ts +1 -0
  96. package/dist/command/setup/bringup/connect-lease.js +1 -0
  97. package/dist/command/setup/bringup/dev-server-log-cap.js +2 -0
  98. package/dist/command/setup/bringup/dev-server-wait.d.ts +8 -0
  99. package/dist/command/setup/bringup/dev-server-wait.js +19 -0
  100. package/dist/command/setup/bringup/ensure-daemon.js +9 -2
  101. package/dist/command/setup/init/agent-restart.d.ts +23 -0
  102. package/dist/command/setup/init/agent-restart.js +28 -0
  103. package/dist/command/setup/init/init-port.d.ts +14 -1
  104. package/dist/command/setup/init/init-port.js +32 -2
  105. package/dist/command/setup/init/init-runtime.d.ts +22 -2
  106. package/dist/command/setup/init/init-runtime.js +114 -38
  107. package/dist/command/setup/node-effects.d.ts +2 -0
  108. package/dist/command/setup/node-effects.js +38 -9
  109. package/dist/command/setup/probe/existing-app.d.ts +12 -0
  110. package/dist/command/setup/probe/existing-app.js +14 -0
  111. package/dist/command/setup/remaining-steps.js +2 -1
  112. package/dist/command/setup/run-setup.d.ts +34 -9
  113. package/dist/command/setup/run-setup.js +65 -51
  114. package/dist/command/setup/setup-command.d.ts +25 -1
  115. package/dist/command/setup/setup-command.js +59 -4
  116. package/dist/command/setup/setup-mcp.js +25 -2
  117. package/dist/command/setup/tauri-signing.d.ts +19 -0
  118. package/dist/command/setup/tauri-signing.js +79 -0
  119. package/dist/command/setup/terminal/listeners.d.ts +10 -1
  120. package/dist/command/setup/terminal/listeners.js +37 -6
  121. package/dist/command/update/update-nudge.d.ts +9 -0
  122. package/dist/command/update/update-nudge.js +1 -1
  123. package/dist/command/update/updater.js +11 -15
  124. package/dist/command/version/version-nudge.js +3 -0
  125. package/dist/command/version/version-skew.d.ts +20 -1
  126. package/dist/command/version/version-skew.js +49 -4
  127. package/dist/features/crawl/crawl-tools.js +4 -0
  128. package/dist/features/crawl/crawl.d.ts +6 -0
  129. package/dist/features/crawl/crawl.js +23 -2
  130. package/dist/features/exhaust/ledger.d.ts +21 -14
  131. package/dist/features/exhaust/ledger.js +35 -9
  132. package/dist/features/harness/app-findings.d.ts +2 -0
  133. package/dist/features/harness/app-findings.js +52 -0
  134. package/dist/features/harness/drive-report.d.ts +61 -1
  135. package/dist/features/harness/drive-report.js +394 -26
  136. package/dist/features/harness/drive-runs.d.ts +120 -0
  137. package/dist/features/harness/drive-runs.js +289 -0
  138. package/dist/features/harness/drivers.d.ts +10 -14
  139. package/dist/features/harness/drivers.js +10 -14
  140. package/dist/features/harness/explore/console-pages.d.ts +15 -0
  141. package/dist/features/harness/explore/console-pages.js +146 -0
  142. package/dist/features/harness/explore/disparity.d.ts +19 -0
  143. package/dist/features/harness/explore/disparity.js +71 -0
  144. package/dist/features/harness/explore/fake-app.d.ts +16 -0
  145. package/dist/features/harness/explore/fake-app.js +49 -0
  146. package/dist/features/harness/explore/goal-search.d.ts +26 -0
  147. package/dist/features/harness/explore/goal-search.js +144 -0
  148. package/dist/features/harness/explore/page-tree.d.ts +49 -0
  149. package/dist/features/harness/explore/page-tree.js +148 -0
  150. package/dist/features/harness/explore/site-map.d.ts +34 -0
  151. package/dist/features/harness/explore/site-map.js +150 -0
  152. package/dist/features/harness/fill-values.d.ts +3 -73
  153. package/dist/features/harness/fill-values.js +3 -169
  154. package/dist/features/harness/goals.d.ts +82 -0
  155. package/dist/features/harness/goals.js +330 -0
  156. package/dist/features/harness/harness.d.ts +51 -1
  157. package/dist/features/harness/harness.js +207 -6
  158. package/dist/features/harness/platform/drive-target.d.ts +30 -0
  159. package/dist/features/harness/platform/drive-target.js +81 -0
  160. package/dist/features/harness/platform/local-apps.d.ts +127 -0
  161. package/dist/features/harness/platform/local-apps.js +280 -0
  162. package/dist/features/harness/platform/persona-credentials.d.ts +20 -0
  163. package/dist/features/harness/platform/persona-credentials.js +69 -0
  164. package/dist/features/harness/platform/platform-drives.d.ts +61 -0
  165. package/dist/features/harness/platform/platform-drives.js +114 -0
  166. package/dist/features/harness/platform/refusal.d.ts +52 -0
  167. package/dist/features/harness/platform/refusal.js +71 -0
  168. package/dist/features/harness/platform/remote-drive.d.ts +186 -0
  169. package/dist/features/harness/platform/remote-drive.js +378 -0
  170. package/dist/features/harness/platform/script.d.ts +94 -0
  171. package/dist/features/harness/platform/script.js +260 -0
  172. package/dist/features/harness/platform/server-driver.d.ts +54 -0
  173. package/dist/features/harness/platform/server-driver.js +182 -0
  174. package/dist/features/harness/platform-config.d.ts +41 -1
  175. package/dist/features/harness/platform-config.js +106 -9
  176. package/dist/features/harness/route-guess.d.ts +13 -0
  177. package/dist/features/harness/route-guess.js +49 -0
  178. package/dist/features/harness/script/app-controls.d.ts +5 -0
  179. package/dist/features/harness/script/app-controls.js +40 -0
  180. package/dist/features/harness/script/lane-ids.d.ts +14 -0
  181. package/dist/features/harness/script/lane-ids.js +16 -0
  182. package/dist/features/harness/script/script-run.d.ts +70 -0
  183. package/dist/features/harness/script/script-run.js +606 -0
  184. package/dist/features/license/license.d.ts +2 -2
  185. package/dist/features/visual/step-shots.d.ts +31 -0
  186. package/dist/features/visual/step-shots.js +231 -0
  187. package/dist/features/visual/visual-tools.d.ts +10 -1
  188. package/dist/features/visual/visual-tools.js +62 -17
  189. package/dist/hooks/client-directory.d.ts +18 -0
  190. package/dist/hooks/client-directory.js +57 -0
  191. package/dist/hooks/coding-agents.d.ts +34 -0
  192. package/dist/hooks/coding-agents.js +117 -0
  193. package/dist/hooks/driven-by.d.ts +23 -0
  194. package/dist/hooks/driven-by.js +56 -0
  195. package/dist/hooks/hook-bus.d.ts +4 -0
  196. package/dist/hooks/hook-bus.js +18 -0
  197. package/dist/hooks/hook-commands.js +15 -4
  198. package/dist/hooks/tool-log.d.ts +9 -0
  199. package/dist/hooks/tool-log.js +29 -0
  200. package/dist/index.d.ts +2 -0
  201. package/dist/index.js +80 -243
  202. package/dist/judgement/capsule/capsule-store.d.ts +2 -2
  203. package/dist/judgement/capsule/causal-summary.d.ts +15 -1
  204. package/dist/judgement/capsule/causal-summary.js +33 -0
  205. package/dist/judgement/runs/artifact/build-verification-run.d.ts +1 -1
  206. package/dist/judgement/runs/artifact/build-verification-run.js +25 -3
  207. package/dist/judgement/runs/artifact/gap-summary.d.ts +0 -18
  208. package/dist/judgement/runs/artifact/gap-summary.js +12 -3
  209. package/dist/judgement/runs/artifact/replay-mapping.d.ts +1 -1
  210. package/dist/judgement/runs/artifact/replay-mapping.js +37 -11
  211. package/dist/judgement/runs/artifact/run-store.d.ts +14 -2
  212. package/dist/judgement/runs/artifact/run-store.js +195 -3
  213. package/dist/judgement/runs/context-tools.js +59 -1
  214. package/dist/judgement/runs/default-run-id.d.ts +3 -0
  215. package/dist/judgement/runs/default-run-id.js +16 -0
  216. package/dist/judgement/runs/drive-run.d.ts +71 -1
  217. package/dist/judgement/runs/drive-run.js +317 -5
  218. package/dist/judgement/runs/repair-prompt.js +1 -1
  219. package/dist/judgement/runs/resume.d.ts +44 -0
  220. package/dist/judgement/runs/resume.js +137 -0
  221. package/dist/judgement/runs/reticle-runner.js +13 -3
  222. package/dist/judgement/runs/runner-port.d.ts +5 -1
  223. package/dist/judgement/runs/runner-port.js +8 -2
  224. package/dist/judgement/runs/verification-sync.d.ts +5 -2
  225. package/dist/judgement/runs/verification-sync.js +40 -18
  226. package/dist/language/flows/change/gate.d.ts +10 -0
  227. package/dist/language/flows/change/gate.js +22 -0
  228. package/dist/language/flows/decision.js +36 -1
  229. package/dist/language/flows/fields/flow-secret-field.d.ts +12 -0
  230. package/dist/language/flows/fields/flow-secret-field.js +25 -2
  231. package/dist/language/flows/flow-anchor.d.ts +61 -10
  232. package/dist/language/flows/flow-anchor.js +98 -6
  233. package/dist/language/flows/flow-cross-step.d.ts +15 -0
  234. package/dist/language/flows/flow-cross-step.js +21 -0
  235. package/dist/language/flows/flow-intent.d.ts +1 -0
  236. package/dist/language/flows/flow-journey.d.ts +6 -0
  237. package/dist/language/flows/flow-journey.js +20 -0
  238. package/dist/language/flows/flow-learning.d.ts +4 -0
  239. package/dist/language/flows/flow-learning.js +45 -14
  240. package/dist/language/flows/flow-mutate-tools.js +5 -3
  241. package/dist/language/flows/flow-replay-run.d.ts +23 -9
  242. package/dist/language/flows/flow-replay-run.js +115 -110
  243. package/dist/language/flows/flow-replay-types.d.ts +1 -1
  244. package/dist/language/flows/flow-replay.d.ts +40 -1
  245. package/dist/language/flows/flow-replay.js +110 -22
  246. package/dist/language/flows/flow-result.d.ts +22 -1
  247. package/dist/language/flows/flow-result.js +47 -2
  248. package/dist/language/flows/flow-scope.js +5 -1
  249. package/dist/language/flows/flow-step-runners.d.ts +22 -2
  250. package/dist/language/flows/flow-step-runners.js +247 -47
  251. package/dist/language/flows/flow-store-for-session.d.ts +2 -2
  252. package/dist/language/flows/flow-store-for-session.js +7 -3
  253. package/dist/language/flows/flow-tools.d.ts +10 -0
  254. package/dist/language/flows/flow-tools.js +112 -89
  255. package/dist/language/flows/flows.d.ts +16 -1
  256. package/dist/language/flows/flows.js +74 -12
  257. package/dist/language/flows/heal-run.js +6 -4
  258. package/dist/language/flows/narrow-write.d.ts +7 -0
  259. package/dist/language/flows/narrow-write.js +36 -1
  260. package/dist/language/flows/recording/flake.d.ts +2 -2
  261. package/dist/language/flows/recording/recording-backtrack.js +14 -1
  262. package/dist/language/flows/recording/tape/recordings.d.ts +58 -4
  263. package/dist/language/flows/recording/tape/recordings.js +95 -13
  264. package/dist/language/flows/replay-from-hud.d.ts +20 -0
  265. package/dist/language/flows/replay-from-hud.js +51 -0
  266. package/dist/language/flows/replay.d.ts +9 -5
  267. package/dist/language/flows/replay.js +56 -15
  268. package/dist/language/flows/single-replay.d.ts +7 -0
  269. package/dist/language/flows/single-replay.js +26 -0
  270. package/dist/language/flows/suite/suite-flakes.js +2 -0
  271. package/dist/language/flows/suite-selection.d.ts +2 -15
  272. package/dist/language/flows/suite-selection.js +4 -3
  273. package/dist/language/flows/verify-change-tools.d.ts +1 -0
  274. package/dist/language/flows/verify-change-tools.js +202 -191
  275. package/dist/launch-chromium.d.ts +27 -5
  276. package/dist/launch-chromium.js +38 -8
  277. package/dist/memory/cloud/cloud-config.d.ts +22 -1
  278. package/dist/memory/cloud/cloud-config.js +34 -5
  279. package/dist/memory/cloud/cloud-sync.d.ts +17 -14
  280. package/dist/memory/cloud/cloud-sync.js +15 -4
  281. package/dist/memory/cloud/harness-config.d.ts +75 -1
  282. package/dist/memory/cloud/harness-config.js +115 -24
  283. package/dist/memory/cloud/hud-notices-source.d.ts +21 -0
  284. package/dist/memory/cloud/hud-notices-source.js +128 -0
  285. package/dist/memory/cloud/memory-scope.d.ts +161 -0
  286. package/dist/memory/cloud/memory-scope.js +227 -0
  287. package/dist/memory/cloud/sync-cycle.d.ts +44 -7
  288. package/dist/memory/cloud/sync-cycle.js +129 -15
  289. package/dist/memory/cloud/sync-daemon.d.ts +11 -0
  290. package/dist/memory/cloud/sync-daemon.js +121 -9
  291. package/dist/memory/cloud/sync-disk.d.ts +1 -1
  292. package/dist/memory/cloud/sync-disk.js +31 -10
  293. package/dist/memory/cloud/sync-screenshots.d.ts +32 -0
  294. package/dist/memory/cloud/sync-screenshots.js +105 -0
  295. package/dist/memory/cloud/unsynced-roots.d.ts +47 -0
  296. package/dist/memory/cloud/unsynced-roots.js +166 -0
  297. package/dist/memory/impact/account-watch.d.ts +34 -0
  298. package/dist/memory/impact/account-watch.js +59 -0
  299. package/dist/memory/impact/impact-recorder.d.ts +8 -0
  300. package/dist/memory/impact/impact-recorder.js +12 -2
  301. package/dist/memory/impact/impact-store.d.ts +17 -4
  302. package/dist/memory/impact/impact-store.js +169 -63
  303. package/dist/memory/intent/inline-intent.d.ts +1 -0
  304. package/dist/memory/intent/intent-shard-store.js +16 -4
  305. package/dist/memory/intent/intent-shard.d.ts +14 -2
  306. package/dist/memory/intent/intent-store.d.ts +1 -0
  307. package/dist/memory/intent/intent-tools.js +122 -4
  308. package/dist/memory/intent/open-intents.d.ts +6 -0
  309. package/dist/memory/intent/open-intents.js +10 -1
  310. package/dist/memory/intent/settled-words.d.ts +24 -0
  311. package/dist/memory/intent/settled-words.js +130 -0
  312. package/dist/memory/journal/drive-flow.d.ts +16 -0
  313. package/dist/memory/journal/drive-flow.js +34 -2
  314. package/dist/memory/journal/drive-run-flush.d.ts +2 -0
  315. package/dist/memory/journal/drive-run-flush.js +20 -5
  316. package/dist/memory/journal/envelope.d.ts +8 -8
  317. package/dist/memory/journal/journal-recorder.js +52 -3
  318. package/dist/memory/journal/on-disk/retention.d.ts +8 -0
  319. package/dist/memory/journal/on-disk/retention.js +32 -2
  320. package/dist/memory/journal/on-disk/startup-maintenance.js +3 -1
  321. package/dist/memory/journal/on-disk/workspace-tiers.js +9 -4
  322. package/dist/memory/journal/session-end.d.ts +15 -1
  323. package/dist/memory/journal/session-end.js +42 -9
  324. package/dist/memory/project/artifact-root-resolver.d.ts +26 -1
  325. package/dist/memory/project/artifact-root-resolver.js +125 -16
  326. package/dist/memory/project/artifact-root.d.ts +46 -8
  327. package/dist/memory/project/artifact-root.js +89 -10
  328. package/dist/memory/project/dir/reticle-dir.d.ts +18 -2
  329. package/dist/memory/project/dir/reticle-dir.js +26 -3
  330. package/dist/memory/project/link-directory.d.ts +15 -0
  331. package/dist/memory/project/link-directory.js +44 -0
  332. package/dist/memory/project/project-tools.js +22 -3
  333. package/dist/memory/project/root-claims.d.ts +6 -0
  334. package/dist/memory/project/root-claims.js +39 -0
  335. package/dist/memory/project/session-root.d.ts +26 -1
  336. package/dist/memory/project/session-root.js +49 -5
  337. package/dist/memory/project/sync-status.d.ts +85 -0
  338. package/dist/memory/project/sync-status.js +224 -0
  339. package/dist/memory/recall/memory-tools.js +47 -2
  340. package/dist/memory/recall/platform-memory.d.ts +34 -0
  341. package/dist/memory/recall/platform-memory.js +139 -0
  342. package/dist/memory/recall/project-memory.d.ts +19 -0
  343. package/dist/memory/recall/project-memory.js +80 -13
  344. package/dist/portal/bridge/bridge.d.ts +9 -3
  345. package/dist/portal/bridge/bridge.js +82 -22
  346. package/dist/portal/bridge/harness-request.d.ts +23 -0
  347. package/dist/portal/bridge/harness-request.js +27 -0
  348. package/dist/portal/bridge/pairing-token.d.ts +9 -0
  349. package/dist/portal/bridge/pairing-token.js +17 -0
  350. package/dist/portal/bridge/wrong-path.d.ts +17 -0
  351. package/dist/portal/bridge/wrong-path.js +35 -0
  352. package/dist/portal/input/network-mock-tools.js +11 -2
  353. package/dist/portal/input/real-input.d.ts +83 -10
  354. package/dist/portal/input/real-input.js +218 -30
  355. package/dist/portal/input/viewport-tools.js +3 -3
  356. package/dist/portal/pool/browser-pool.d.ts +70 -9
  357. package/dist/portal/pool/browser-pool.js +190 -37
  358. package/dist/portal/pool/context-permissions.d.ts +33 -0
  359. package/dist/portal/pool/context-permissions.js +33 -0
  360. package/dist/portal/pool/lease-marker-stamp.d.ts +23 -0
  361. package/dist/portal/pool/lease-marker-stamp.js +49 -0
  362. package/dist/portal/pool/playwright-launcher.d.ts +35 -0
  363. package/dist/portal/pool/playwright-launcher.js +64 -3
  364. package/dist/portal/pool/pool-contract.d.ts +28 -5
  365. package/dist/portal/session/agent-link.d.ts +8 -0
  366. package/dist/portal/session/agent-link.js +17 -0
  367. package/dist/portal/session/command-payload.d.ts +8 -0
  368. package/dist/portal/session/command-payload.js +24 -0
  369. package/dist/portal/session/daemon-answers.d.ts +3 -3
  370. package/dist/portal/session/daemon-answers.js +4 -2
  371. package/dist/portal/session/dev-server/dev-command.d.ts +21 -0
  372. package/dist/portal/session/dev-server/dev-command.js +87 -12
  373. package/dist/portal/session/facts/departure-note.d.ts +22 -0
  374. package/dist/portal/session/facts/departure-note.js +47 -0
  375. package/dist/portal/session/facts/observed-state.d.ts +16 -18
  376. package/dist/portal/session/facts/observed-state.js +46 -3
  377. package/dist/portal/session/facts/session-replaced.d.ts +5 -0
  378. package/dist/portal/session/facts/session-replaced.js +5 -0
  379. package/dist/portal/session/first-run-wiring.d.ts +42 -0
  380. package/dist/portal/session/first-run-wiring.js +132 -0
  381. package/dist/portal/session/human/live-control.d.ts +9 -2
  382. package/dist/portal/session/human/live-control.js +12 -3
  383. package/dist/portal/session/human/notes-ledger.d.ts +20 -0
  384. package/dist/portal/session/human/notes-ledger.js +55 -0
  385. package/dist/portal/session/human/review-store.d.ts +12 -0
  386. package/dist/portal/session/human/review-store.js +18 -10
  387. package/dist/portal/session/live-control-tools.d.ts +0 -13
  388. package/dist/portal/session/live-control-tools.js +107 -13
  389. package/dist/portal/session/narration-args.d.ts +5 -0
  390. package/dist/portal/session/narration-args.js +17 -0
  391. package/dist/portal/session/no-session-diagnosis.d.ts +8 -1
  392. package/dist/portal/session/no-session-diagnosis.js +46 -9
  393. package/dist/portal/session/no-session-next-action.d.ts +31 -0
  394. package/dist/portal/session/no-session-next-action.js +159 -60
  395. package/dist/portal/session/no-session-watch.d.ts +14 -1
  396. package/dist/portal/session/no-session-watch.js +227 -17
  397. package/dist/portal/session/presence/session-lease.js +1 -1
  398. package/dist/portal/session/presence/session-mirror.js +3 -0
  399. package/dist/portal/session/recorded-gaps.d.ts +97 -0
  400. package/dist/portal/session/recorded-gaps.js +251 -0
  401. package/dist/portal/session/serving-directory.d.ts +27 -0
  402. package/dist/portal/session/serving-directory.js +45 -0
  403. package/dist/portal/session/session-health.d.ts +18 -0
  404. package/dist/portal/session/session-health.js +9 -1
  405. package/dist/portal/session/session-info.d.ts +8 -1
  406. package/dist/portal/session/session-info.js +8 -1
  407. package/dist/portal/session/session-manager.d.ts +39 -0
  408. package/dist/portal/session/session-manager.js +98 -11
  409. package/dist/portal/session/session-reaper.js +4 -1
  410. package/dist/portal/session/session-successor.d.ts +13 -0
  411. package/dist/portal/session/session-successor.js +1 -1
  412. package/dist/portal/session/session-tools.js +26 -3
  413. package/dist/portal/session/session.d.ts +22 -30
  414. package/dist/portal/session/session.js +81 -79
  415. package/dist/portal/session/timing/command-timeout.js +25 -1
  416. package/dist/portal/session/timing/wall-clock.d.ts +1 -1
  417. package/dist/portal/session/timing/wall-clock.js +1 -1
  418. package/dist/portal/session/zero-install-first-call.d.ts +31 -0
  419. package/dist/portal/session/zero-install-first-call.js +88 -0
  420. package/dist/start-options.d.ts +12 -0
  421. package/dist/start-wiring.d.ts +63 -0
  422. package/dist/start-wiring.js +169 -0
  423. package/dist/status-payload.d.ts +23 -1
  424. package/dist/status-payload.js +36 -1
  425. package/dist/surface/http-server.js +18 -2
  426. package/dist/surface/mcp/attach-memory.d.ts +1 -0
  427. package/dist/surface/mcp/attach-memory.js +12 -1
  428. package/dist/surface/mcp/mcp-proxy.d.ts +9 -0
  429. package/dist/surface/mcp/mcp-proxy.js +65 -13
  430. package/dist/surface/mcp/mcp.d.ts +34 -6
  431. package/dist/surface/mcp/mcp.js +61 -17
  432. package/dist/surface/mcp/proxy/drive-calls.d.ts +10 -0
  433. package/dist/surface/mcp/proxy/drive-calls.js +27 -0
  434. package/dist/surface/mcp/proxy/mcp-post-transport.js +5 -0
  435. package/dist/surface/mcp/server-instructions.d.ts +4 -2
  436. package/dist/surface/mcp/server-instructions.js +32 -14
  437. package/dist/surface/mcp/shared-params.js +2 -2
  438. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  439. package/dist/surface/mcp/surface-vocabulary.js +1 -0
  440. package/dist/surface/tools/account-tool.d.ts +22 -0
  441. package/dist/surface/tools/account-tool.js +157 -0
  442. package/dist/surface/tools/act/act-danger.d.ts +11 -0
  443. package/dist/surface/tools/act/act-danger.js +38 -1
  444. package/dist/surface/tools/act/act-observation.d.ts +33 -0
  445. package/dist/surface/tools/act/act-observation.js +57 -0
  446. package/dist/surface/tools/act/act-preflight.js +25 -2
  447. package/dist/surface/tools/act/act-target.js +8 -3
  448. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +8 -0
  449. package/dist/surface/tools/act/navigation/navigate-arrival.js +56 -2
  450. package/dist/surface/tools/act/resolve-target.d.ts +1 -1
  451. package/dist/surface/tools/act/resolve-target.js +18 -3
  452. package/dist/surface/tools/act/screen-request.d.ts +34 -0
  453. package/dist/surface/tools/act/screen-request.js +113 -0
  454. package/dist/surface/tools/act/sequence-grade.d.ts +8 -0
  455. package/dist/surface/tools/act/sequence-grade.js +13 -2
  456. package/dist/surface/tools/act/settle-in-flight.js +25 -3
  457. package/dist/surface/tools/act-sequence-tool.js +138 -29
  458. package/dist/surface/tools/act-tools.d.ts +0 -9
  459. package/dist/surface/tools/act-tools.js +71 -41
  460. package/dist/surface/tools/agent/app-notes-learning.d.ts +7 -0
  461. package/dist/surface/tools/agent/app-notes-learning.js +80 -0
  462. package/dist/surface/tools/agent/app-notes.d.ts +4 -0
  463. package/dist/surface/tools/agent/app-notes.js +48 -0
  464. package/dist/surface/tools/agent/build-staleness.d.ts +7 -0
  465. package/dist/surface/tools/agent/build-staleness.js +62 -0
  466. package/dist/surface/tools/agent/compact-envelope.d.ts +80 -0
  467. package/dist/surface/tools/agent/compact-envelope.js +374 -0
  468. package/dist/surface/tools/agent/for-the-agent.d.ts +12 -0
  469. package/dist/surface/tools/agent/for-the-agent.js +44 -0
  470. package/dist/surface/tools/agent/notices.d.ts +50 -0
  471. package/dist/surface/tools/agent/notices.js +152 -0
  472. package/dist/surface/tools/agent/reteach.d.ts +11 -0
  473. package/dist/surface/tools/agent/reteach.js +50 -0
  474. package/dist/surface/tools/args/alias-args.d.ts +5 -0
  475. package/dist/surface/tools/args/alias-args.js +10 -0
  476. package/dist/surface/tools/args/confirm-dangerous-arg.d.ts +6 -0
  477. package/dist/surface/tools/args/confirm-dangerous-arg.js +6 -0
  478. package/dist/surface/tools/assert/assert-source.d.ts +15 -0
  479. package/dist/surface/tools/assert/assert-source.js +40 -0
  480. package/dist/surface/tools/assert/assert-verdict.d.ts +1 -1
  481. package/dist/surface/tools/assert/assert-verdict.js +42 -17
  482. package/dist/surface/tools/browser-tools.js +51 -2
  483. package/dist/surface/tools/chat-drives.d.ts +101 -0
  484. package/dist/surface/tools/chat-drives.js +409 -0
  485. package/dist/surface/tools/coverage-tools.d.ts +2 -10
  486. package/dist/surface/tools/coverage-tools.js +2 -53
  487. package/dist/surface/tools/dynamic-tools.js +29 -1
  488. package/dist/surface/tools/empty-session-list.d.ts +51 -0
  489. package/dist/surface/tools/empty-session-list.js +120 -0
  490. package/dist/surface/tools/error-recovery.d.ts +14 -0
  491. package/dist/surface/tools/error-recovery.js +105 -8
  492. package/dist/surface/tools/explore-tools.d.ts +31 -1
  493. package/dist/surface/tools/explore-tools.js +438 -66
  494. package/dist/surface/tools/feedback-tools.d.ts +2 -3
  495. package/dist/surface/tools/feedback-tools.js +18 -3
  496. package/dist/surface/tools/gap-novelty.d.ts +3 -1
  497. package/dist/surface/tools/gap-novelty.js +8 -1
  498. package/dist/surface/tools/harness-explore.d.ts +118 -57
  499. package/dist/surface/tools/harness-explore.js +344 -292
  500. package/dist/surface/tools/harness-gate.d.ts +88 -0
  501. package/dist/surface/tools/harness-gate.js +235 -0
  502. package/dist/surface/tools/harness-hunt.d.ts +43 -0
  503. package/dist/surface/tools/harness-hunt.js +215 -0
  504. package/dist/surface/tools/harness-plan.d.ts +17 -0
  505. package/dist/surface/tools/harness-plan.js +38 -0
  506. package/dist/surface/tools/harness-script.d.ts +30 -0
  507. package/dist/surface/tools/harness-script.js +560 -0
  508. package/dist/surface/tools/harness-tab-guard.d.ts +5 -0
  509. package/dist/surface/tools/harness-tab-guard.js +27 -0
  510. package/dist/surface/tools/harness-toolset.d.ts +22 -1
  511. package/dist/surface/tools/harness-toolset.js +101 -7
  512. package/dist/surface/tools/human-notes.d.ts +16 -0
  513. package/dist/surface/tools/human-notes.js +27 -0
  514. package/dist/surface/tools/invoke-tool.d.ts +5 -2
  515. package/dist/surface/tools/invoke-tool.js +263 -85
  516. package/dist/surface/tools/lease-hint.js +26 -5
  517. package/dist/surface/tools/lease-permissions.d.ts +33 -0
  518. package/dist/surface/tools/lease-permissions.js +73 -0
  519. package/dist/surface/tools/lease-readiness.d.ts +38 -0
  520. package/dist/surface/tools/lease-readiness.js +57 -0
  521. package/dist/surface/tools/lease-seed.d.ts +49 -0
  522. package/dist/surface/tools/lease-seed.js +167 -0
  523. package/dist/surface/tools/lease-tools.d.ts +13 -24
  524. package/dist/surface/tools/lease-tools.js +146 -197
  525. package/dist/surface/tools/live-call-text.js +4 -4
  526. package/dist/surface/tools/merge-tools.js +42 -2
  527. package/dist/surface/tools/merged-name-redirect.js +4 -0
  528. package/dist/surface/tools/next-step.d.ts +29 -0
  529. package/dist/surface/tools/next-step.js +214 -0
  530. package/dist/surface/tools/observe-tools.js +45 -9
  531. package/dist/surface/tools/platform-moment.d.ts +72 -0
  532. package/dist/surface/tools/platform-moment.js +296 -0
  533. package/dist/surface/tools/query-hint-schema.d.ts +7 -0
  534. package/dist/surface/tools/query-hint-schema.js +10 -0
  535. package/dist/surface/tools/read-tools.js +71 -14
  536. package/dist/surface/tools/real-input-attempt.js +96 -13
  537. package/dist/surface/tools/reticle-result.d.ts +120 -0
  538. package/dist/surface/tools/reticle-result.js +364 -0
  539. package/dist/surface/tools/tool-kit.d.ts +83 -3
  540. package/dist/surface/tools/tool-kit.js +77 -7
  541. package/dist/surface/tools/tools.js +43 -59
  542. package/dist/telemetry/account-envelope.d.ts +7 -0
  543. package/dist/telemetry/account-envelope.js +61 -0
  544. package/dist/telemetry/agent-client.d.ts +15 -0
  545. package/dist/telemetry/agent-client.js +57 -0
  546. package/dist/telemetry/app-instrumented.js +9 -2
  547. package/dist/telemetry/argument-shape.d.ts +7 -0
  548. package/dist/telemetry/argument-shape.js +86 -1
  549. package/dist/telemetry/automation-hint.d.ts +2 -3
  550. package/dist/telemetry/automation-hint.js +33 -8
  551. package/dist/telemetry/cli-telemetry.js +7 -2
  552. package/dist/telemetry/daemon-telemetry.js +3 -0
  553. package/dist/telemetry/error-fingerprint.d.ts +10 -1
  554. package/dist/telemetry/error-fingerprint.js +61 -5
  555. package/dist/telemetry/feedback-cli.d.ts +0 -13
  556. package/dist/telemetry/feedback-cli.js +0 -77
  557. package/dist/telemetry/feedback.d.ts +13 -0
  558. package/dist/telemetry/feedback.js +183 -17
  559. package/dist/telemetry/harness-run.d.ts +18 -0
  560. package/dist/telemetry/harness-run.js +80 -0
  561. package/dist/telemetry/hud-events.d.ts +16 -0
  562. package/dist/telemetry/hud-events.js +27 -0
  563. package/dist/telemetry/hud-metrics.d.ts +29 -6
  564. package/dist/telemetry/hud-metrics.js +116 -25
  565. package/dist/telemetry/init-telemetry.js +2 -2
  566. package/dist/telemetry/install-source.d.ts +13 -25
  567. package/dist/telemetry/install-source.js +44 -3
  568. package/dist/telemetry/mcp-connection.d.ts +0 -14
  569. package/dist/telemetry/mcp-connection.js +5 -1
  570. package/dist/telemetry/onboarding-firsts.d.ts +32 -0
  571. package/dist/telemetry/onboarding-firsts.js +81 -6
  572. package/dist/telemetry/platform-linked.d.ts +5 -0
  573. package/dist/telemetry/platform-linked.js +32 -0
  574. package/dist/telemetry/project-profile.js +5 -3
  575. package/dist/telemetry/proxy-telemetry.js +4 -1
  576. package/dist/telemetry/session-metrics.d.ts +15 -4
  577. package/dist/telemetry/session-metrics.js +88 -52
  578. package/dist/telemetry/telemetry.d.ts +38 -2
  579. package/dist/telemetry/telemetry.js +144 -34
  580. package/dist/telemetry/verification-of.d.ts +3 -1
  581. package/dist/telemetry/verification-of.js +13 -4
  582. package/dist/wire-journal.d.ts +2 -2
  583. package/dist/wire-journal.js +20 -6
  584. package/docs/README.md +3 -3
  585. package/docs/actions.mdx +6 -3
  586. package/docs/adapters.md +1 -1
  587. package/docs/agent-cheatsheet.md +25 -28
  588. package/docs/architecture.md +5 -5
  589. package/docs/autodrive.md +33 -28
  590. package/docs/benchmarks.md +5 -5
  591. package/docs/best-practices.mdx +27 -9
  592. package/docs/capabilities.mdx +14 -16
  593. package/docs/cli/affected.mdx +1 -1
  594. package/docs/cli/cloud.mdx +54 -75
  595. package/docs/cli/doctor.mdx +14 -3
  596. package/docs/cli/drive.mdx +20 -14
  597. package/docs/cli/feedback.mdx +3 -3
  598. package/docs/cli/gate.mdx +7 -2
  599. package/docs/cli/help.mdx +50 -55
  600. package/docs/cli/init.mdx +43 -28
  601. package/docs/cli/license.mdx +12 -8
  602. package/docs/cli/mcp.mdx +4 -4
  603. package/docs/cli/open.mdx +3 -3
  604. package/docs/cli/report.mdx +4 -2
  605. package/docs/cli/restart.mdx +2 -2
  606. package/docs/cli/rollback.mdx +14 -8
  607. package/docs/cli/serve.mdx +4 -4
  608. package/docs/cli/setup.mdx +23 -0
  609. package/docs/cli/status.mdx +18 -5
  610. package/docs/cli/stop.mdx +67 -8
  611. package/docs/cli/try.mdx +62 -0
  612. package/docs/cli/update.mdx +4 -3
  613. package/docs/cli/verify.mdx +17 -6
  614. package/docs/cli/version.mdx +5 -4
  615. package/docs/cli.mdx +111 -42
  616. package/docs/debugging.md +3 -3
  617. package/docs/deploy-checks.md +1 -1
  618. package/docs/desktop.mdx +9 -3
  619. package/docs/enterprise.md +11 -10
  620. package/docs/environment.mdx +7 -8
  621. package/docs/faq.mdx +3 -3
  622. package/docs/first-drive.md +5 -4
  623. package/docs/flows.md +35 -27
  624. package/docs/for-agents.md +4 -5
  625. package/docs/frameworks.mdx +32 -21
  626. package/docs/getting-started.md +65 -61
  627. package/docs/human-control.md +16 -16
  628. package/docs/index.mdx +15 -42
  629. package/docs/install-agentic.mdx +22 -37
  630. package/docs/install-manual.mdx +23 -13
  631. package/docs/instrumentation.mdx +5 -3
  632. package/docs/integration-patterns.md +7 -7
  633. package/docs/license-activation.mdx +1 -1
  634. package/docs/multi-agent-testing.md +24 -6
  635. package/docs/packages/babel-plugin.mdx +4 -2
  636. package/docs/packages/browser.mdx +16 -10
  637. package/docs/packages/core.mdx +12 -5
  638. package/docs/packages/electron.mdx +3 -2
  639. package/docs/packages/engine.mdx +1 -1
  640. package/docs/packages/eslint-plugin.mdx +18 -12
  641. package/docs/packages/next.mdx +8 -7
  642. package/docs/packages/open-verification.mdx +1 -1
  643. package/docs/packages/server.mdx +5 -5
  644. package/docs/packages/tauri.mdx +9 -9
  645. package/docs/packages/test.mdx +4 -10
  646. package/docs/packages/vite-plugin.mdx +32 -4
  647. package/docs/packages.mdx +11 -15
  648. package/docs/platform-integration.md +6 -5
  649. package/docs/predicates.mdx +40 -24
  650. package/docs/quickstart.mdx +69 -30
  651. package/docs/required-checks.md +8 -7
  652. package/docs/reticle-manual.md +15 -5
  653. package/docs/skill-file.mdx +17 -79
  654. package/docs/skill-setup.md +9 -9
  655. package/docs/skill.md +200 -0
  656. package/docs/system-map.md +7 -7
  657. package/docs/telemetry.md +23 -25
  658. package/docs/testing.md +4 -4
  659. package/docs/token-efficiency.md +12 -12
  660. package/docs/tools/act-and-wait.mdx +9 -2
  661. package/docs/tools/act-sequence.mdx +6 -7
  662. package/docs/tools/act.mdx +2 -2
  663. package/docs/tools/assert.mdx +18 -17
  664. package/docs/tools/console.mdx +9 -9
  665. package/docs/tools/inspect.mdx +16 -7
  666. package/docs/tools/look.mdx +24 -0
  667. package/docs/tools/navigate.mdx +5 -3
  668. package/docs/tools/network.mdx +2 -2
  669. package/docs/tools/observe.mdx +6 -6
  670. package/docs/tools/overview.mdx +34 -33
  671. package/docs/tools/query.mdx +5 -5
  672. package/docs/tools/session-and-feedback.mdx +22 -13
  673. package/docs/tools/sessions.mdx +8 -8
  674. package/docs/tools/snapshot.mdx +6 -5
  675. package/docs/tools/state.mdx +9 -9
  676. package/docs/tools/tools-and-run.mdx +26 -24
  677. package/docs/tools/verify.mdx +28 -0
  678. package/docs/tools/wait-for.mdx +8 -4
  679. package/docs/troubleshooting.mdx +21 -6
  680. package/docs/usage.md +55 -46
  681. package/docs/use-cases.mdx +3 -3
  682. package/docs/vs-chrome-devtools-mcp.mdx +9 -6
  683. package/docs/vs-playwright-mcp.mdx +3 -1
  684. package/docs/what-is-recorded.md +17 -5
  685. package/docs/what-is-reticle.mdx +5 -3
  686. package/docs/why-reticle.mdx +1 -1
  687. package/package.json +9 -12
  688. package/dist/command/cli/demo/demo-page.d.ts +0 -78
  689. package/dist/command/cli/demo/demo-page.js +0 -241
  690. package/dist/command/cli/demo/demo-run.d.ts +0 -38
  691. package/dist/command/cli/demo/demo-run.js +0 -138
  692. package/dist/features/harness/driver.d.ts +0 -50
  693. package/dist/features/harness/driver.js +0 -236
  694. package/dist/features/harness/jev-driver.d.ts +0 -188
  695. package/dist/features/harness/jev-driver.js +0 -678
  696. package/dist/features/harness/openai-driver.d.ts +0 -58
  697. package/dist/features/harness/openai-driver.js +0 -206
  698. package/dist/judgement/hunt/hunt-report.d.ts +0 -49
  699. package/dist/judgement/hunt/hunt-report.js +0 -84
  700. package/dist/language/flows/buddy-status.d.ts +0 -25
  701. package/dist/language/flows/buddy-status.js +0 -32
  702. package/dist/language/flows/change/watch-batcher.d.ts +0 -18
  703. package/dist/language/flows/change/watch-batcher.js +0 -19
  704. package/dist/memory/cloud/harness-offer.d.ts +0 -44
  705. package/dist/memory/cloud/harness-offer.js +0 -145
  706. package/dist/memory/project/dir/fill-value-store.d.ts +0 -32
  707. package/dist/memory/project/dir/fill-value-store.js +0 -88
  708. package/dist/surface/tools/feature-capture.d.ts +0 -151
  709. package/dist/surface/tools/feature-capture.js +0 -235
  710. package/dist/surface/tools/tool-hit-rate.d.ts +0 -87
  711. package/dist/surface/tools/tool-hit-rate.js +0 -90
  712. package/dist/telemetry/harness-drive.d.ts +0 -4
  713. package/dist/telemetry/harness-drive.js +0 -35
  714. package/dist/telemetry/identify.d.ts +0 -22
  715. package/dist/telemetry/identify.js +0 -73
  716. package/docs/cli/capsules.mdx +0 -70
  717. package/docs/cli/hunt.mdx +0 -73
  718. package/docs/cli/identify.mdx +0 -76
  719. package/docs/cli/kill.mdx +0 -91
  720. package/docs/cli/watch.mdx +0 -62
  721. package/docs/local-registry.md +0 -143
@@ -0,0 +1,280 @@
1
+ /**
2
+ * The apps this machine has connected, told to the platform so its chat can list them by name.
3
+ *
4
+ * The chat used to ask for a `localhost` address, and an address names nothing: two projects on
5
+ * `localhost:3000` are one address, and one project restarted on another port is two. So an app here
6
+ * is a project checkout on a machine, keyed by a hash of both, and its address is only where it was
7
+ * last open. Neither the project's path nor the home directory leaves the machine, only their hash.
8
+ *
9
+ * Every few seconds, with or without an app open, each linked project's credential reports its apps.
10
+ * The answer can name apps somebody asked to bring back (opened here, headless) and say a drive is
11
+ * waiting, which is how a daemon with nothing open hears about one without polling every few seconds.
12
+ */
13
+ import { createHash } from 'node:crypto';
14
+ import { relative, sep } from 'node:path';
15
+ import { LinkReportKey, LinkPath, PLATFORM_LINK_VERSION, RETICLE_URL_PARAM, parseLinkNotices, } from '@reticlehq/core';
16
+ import { pickDriveSession } from './remote-drive.js';
17
+ /** How often apps are reported. The platform counts an app live for two and a half of these. */
18
+ export const LOCAL_APPS_REPORT_MS = 10_000;
19
+ const REQUEST_TIMEOUT_MS = 10_000;
20
+ /** How long a drive waits for an app it opened to connect before it is refused. */
21
+ export const APP_OPEN_WAIT_MS = 20_000;
22
+ const APP_OPEN_POLL_MS = 250;
23
+ const KEY_LENGTH = 16;
24
+ /** The shell a plain browser tab reports: not worth a word on a card that says what it is built with. */
25
+ const WEB_RUNTIME = 'web';
26
+ /** `path` under `home` as `~/...`, so no home directory leaves the machine in a report. */
27
+ export function homeRelative(path, home) {
28
+ const inside = relative(home, path);
29
+ if (0 === inside.length)
30
+ return '~';
31
+ if (inside.startsWith('..') || inside.startsWith(sep) || /^[a-zA-Z]:/.test(inside))
32
+ return path;
33
+ return `~/${inside.split(sep).join('/')}`;
34
+ }
35
+ const hash = (text) => createHash('sha256').update(text).digest('hex').slice(0, KEY_LENGTH);
36
+ /** This machine: a stable id that is not its home path, and the name a person knows it by. */
37
+ export const machineOf = (hostname, home) => ({
38
+ id: hash(`${hostname}\u0000${home}`),
39
+ name: hostname.replace(/\.local$/i, ''),
40
+ });
41
+ /**
42
+ * One project checkout on one machine. Its port is not part of it. The tab's projectId is: a daemon
43
+ * that cannot map a project to its checkout files every such project under one shared directory.
44
+ */
45
+ export const appKeyOf = (machineId, projectDir, projectId) => hash(`${machineId}\u0000${projectDir}\u0000${projectId ?? ''}`);
46
+ const LOOPBACK_HOSTS = new Set(['localhost', '127.0.0.1', '[::1]']);
47
+ /** What a refused open is told. */
48
+ export const NOT_AN_APP_ADDRESS = 'Reticle only opens a web address on this machine or one of the apps already open here.';
49
+ /**
50
+ * Whether the daemon may open an address the platform named: a web page on this machine, or one on
51
+ * an origin a connected tab already has. Never a file, and never anywhere else on the network.
52
+ */
53
+ export function mayOpen(url, openUrls) {
54
+ let target;
55
+ try {
56
+ target = new URL(url);
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ if ('http:' !== target.protocol && 'https:' !== target.protocol)
62
+ return false;
63
+ if (LOOPBACK_HOSTS.has(target.hostname) || target.hostname.endsWith('.localhost'))
64
+ return true;
65
+ return openUrls.some((open) => {
66
+ try {
67
+ return new URL(open).origin === target.origin;
68
+ }
69
+ catch {
70
+ return false;
71
+ }
72
+ });
73
+ }
74
+ /** A project id as a name: the SDK stamps `<package>-<8 hex>`, and the hash means nothing to a person. */
75
+ export const nameFromProjectId = (projectId) => projectId.replace(/-[0-9a-f]{8}$/, '');
76
+ const RETICLE_MARKS = new Set(Object.values(RETICLE_URL_PARAM));
77
+ /** The address as the app knows it: the params Reticle put on it to adopt a tab are not the app's. */
78
+ export const withoutMarks = (raw) => {
79
+ try {
80
+ const url = new URL(raw);
81
+ for (const mark of [...url.searchParams.keys()])
82
+ if (RETICLE_MARKS.has(mark))
83
+ url.searchParams.delete(mark);
84
+ return url.href;
85
+ }
86
+ catch {
87
+ return raw;
88
+ }
89
+ };
90
+ /** Every channel either tab announced, once each; undefined when neither said. */
91
+ function mergedChannels(a, b) {
92
+ return a === undefined && b === undefined
93
+ ? undefined
94
+ : [...new Set([...(a ?? []), ...(b ?? [])])];
95
+ }
96
+ /** Every gap either tab recorded, once per kind + missing, the first seen kept. */
97
+ function mergedGaps(a, b) {
98
+ const out = new Map();
99
+ for (const gap of [...(a ?? []), ...(b ?? [])]) {
100
+ const id = `${gap.kind}\u0000${gap.missing}`;
101
+ if (!out.has(id))
102
+ out.set(id, gap);
103
+ }
104
+ return [...out.values()];
105
+ }
106
+ /** `app` carrying the merged channels and gaps, omitting each when there is nothing to say. */
107
+ function withSeen(app, channels, gaps) {
108
+ return {
109
+ ...app,
110
+ ...(channels === undefined ? {} : { [LinkReportKey.CHANNELS]: channels }),
111
+ ...(0 === gaps.length ? {} : { [LinkReportKey.GAPS]: gaps }),
112
+ };
113
+ }
114
+ /**
115
+ * The apps to report, grouped by the platform credential each one's project is linked with. The
116
+ * linked credential is reported even with no app open: it is how the chat knows the machine is there
117
+ * to open one. A tab whose project is not linked is left out: no chat can drive it.
118
+ */
119
+ export async function appsByPlatform(tabs, linked, machineId, describe) {
120
+ const groups = new Map();
121
+ const group = (platform) => {
122
+ const id = `${platform.url}\u0000${platform.apiKey}`;
123
+ const found = groups.get(id) ?? { platform, apps: new Map() };
124
+ groups.set(id, found);
125
+ return found;
126
+ };
127
+ if (undefined !== linked)
128
+ group(linked);
129
+ // A visible tab speaks for its project over a hidden one.
130
+ const ordered = [...tabs].sort((a, b) => Number(a.hidden) - Number(b.hidden));
131
+ for (const tab of ordered) {
132
+ const about = await describe(tab).catch(() => undefined);
133
+ if (undefined === about?.platform)
134
+ continue;
135
+ const key = appKeyOf(machineId, about.dir, tab.projectId);
136
+ const apps = group(about.platform).apps;
137
+ // Of two tabs of one app, the one that has seen the most speaks for it (a tie keeps the earlier,
138
+ // so a visible one still speaks over a hidden one). What they have SEEN is merged, so the setup
139
+ // score does not depend on which tab happened to report: a fresh tab opened beside a driven one
140
+ // once dropped it and locked the Harness.
141
+ const held = apps.get(key);
142
+ const channels = mergedChannels(held?.[LinkReportKey.CHANNELS], tab.channels);
143
+ const gaps = mergedGaps(held?.[LinkReportKey.GAPS], tab.gaps);
144
+ if (held !== undefined &&
145
+ (tab.channels?.length ?? 0) <= (held[LinkReportKey.CHANNELS]?.length ?? 0)) {
146
+ apps.set(key, withSeen(held, channels, gaps));
147
+ continue;
148
+ }
149
+ const stack = [
150
+ ...new Set([...tab.adapters, ...(tab.runtime === undefined ? [] : [tab.runtime])]),
151
+ ].filter((part) => WEB_RUNTIME !== part);
152
+ apps.set(key, {
153
+ key,
154
+ name: about.name,
155
+ url: withoutMarks(tab.url),
156
+ ...(tab.title === undefined ? {} : { title: tab.title }),
157
+ stack,
158
+ ...(tab.sdkVersion === undefined ? {} : { sdkVersion: tab.sdkVersion }),
159
+ ...(0 === tab.adapters.length ? {} : { [LinkReportKey.ADAPTERS]: tab.adapters }),
160
+ ...(tab.notApplicable === undefined
161
+ ? {}
162
+ : { [LinkReportKey.NOT_APPLICABLE]: tab.notApplicable }),
163
+ ...withSeen({}, channels, gaps),
164
+ });
165
+ }
166
+ return [...groups.values()].map(({ platform, apps }) => ({ platform, apps: [...apps.values()] }));
167
+ }
168
+ export function startAppReports(deps) {
169
+ const doFetch = deps.fetch ?? ((url, init) => fetch(url, init));
170
+ let busy = false;
171
+ /** Notices already shown, by what they say: the platform repeats them on every report. */
172
+ const told = new Set();
173
+ const tick = async () => {
174
+ if (busy)
175
+ return;
176
+ busy = true;
177
+ try {
178
+ const extras = (await deps.extras?.().catch(() => undefined)) ?? {};
179
+ for (const { platform, apps } of await deps.apps()) {
180
+ try {
181
+ const res = await doFetch(`${platform.url}${LinkPath.APPS}`, {
182
+ method: 'POST',
183
+ headers: {
184
+ 'content-type': 'application/json',
185
+ authorization: `Bearer ${platform.apiKey}`,
186
+ },
187
+ body: JSON.stringify({
188
+ machine: deps.machine,
189
+ reticleVersion: deps.version,
190
+ protocol: PLATFORM_LINK_VERSION,
191
+ capabilities: deps.capabilities,
192
+ apps,
193
+ ...(extras.devServers === undefined
194
+ ? {}
195
+ : { [LinkReportKey.DEV_SERVERS]: extras.devServers }),
196
+ ...(extras.helloFailure === undefined
197
+ ? {}
198
+ : { [LinkReportKey.HELLO_FAILURE]: extras.helloFailure }),
199
+ ...(extras.unsynced === undefined
200
+ ? {}
201
+ : { [LinkReportKey.UNSYNCED]: extras.unsynced }),
202
+ }),
203
+ signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
204
+ });
205
+ if (!res.ok)
206
+ continue;
207
+ const answer = (await res.json());
208
+ for (const notice of parseLinkNotices(answer.notices)) {
209
+ const key = `${platform.apiKey}\u0000${notice.text}`;
210
+ if (told.has(key))
211
+ continue;
212
+ told.add(key);
213
+ deps.notify?.(notice, platform);
214
+ }
215
+ const open = new Set(apps.map((app) => app.key));
216
+ for (const wake of Array.isArray(answer.wake) ? answer.wake : []) {
217
+ const { key, url } = (wake ?? {});
218
+ if ('string' !== typeof key || 'string' !== typeof url || open.has(key))
219
+ continue;
220
+ open.add(key);
221
+ deps.log?.(`reticle: opening ${url}, asked for from the platform chat`);
222
+ await deps.open(url, key).catch((error) => {
223
+ deps.log?.(`reticle: could not open ${url}: ${String(error)}`);
224
+ });
225
+ }
226
+ if (true === answer.pendingDrive)
227
+ deps.drivePending(platform);
228
+ }
229
+ catch {
230
+ // Offline, or the platform is down: the next report tries again.
231
+ }
232
+ }
233
+ }
234
+ catch {
235
+ // The credentials could not be read: nothing to report this time.
236
+ }
237
+ finally {
238
+ busy = false;
239
+ }
240
+ };
241
+ const timer = setInterval(() => void tick(), deps.intervalMs ?? LOCAL_APPS_REPORT_MS);
242
+ timer.unref();
243
+ const reports = {
244
+ tick,
245
+ stop: () => {
246
+ clearInterval(timer);
247
+ if (running === reports)
248
+ running = undefined;
249
+ },
250
+ };
251
+ running = reports;
252
+ return reports;
253
+ }
254
+ /** The daemon's running reports. ponytail: one per daemon, the last one started. */
255
+ let running;
256
+ /**
257
+ * Report now rather than on the next tick: the Harness gate just learned what an app's pages carry,
258
+ * and the platform, which locks a drive on its last report, would otherwise refuse on the old one.
259
+ */
260
+ export const reportAppsNow = () => running?.tick() ?? Promise.resolve();
261
+ /**
262
+ * The tab a drive the chat attached to one app uses: a tab of that app and no other, even on the
263
+ * same port. None open: open the app, and wait for it to connect. Null when it never does.
264
+ */
265
+ export async function pickAppTab(app, goal, tabs, keyOf, open, waitMs = APP_OPEN_WAIT_MS) {
266
+ const ofApp = () => tabs().filter((tab) => keyOf(tab.sessionId) === app.key);
267
+ const now = pickDriveSession(ofApp(), goal);
268
+ if (now !== undefined)
269
+ return now;
270
+ if (null === app.url)
271
+ return null;
272
+ await open(app.url).catch(() => undefined);
273
+ for (let waited = 0; waited <= waitMs; waited += APP_OPEN_POLL_MS) {
274
+ const opened = pickDriveSession(ofApp(), goal);
275
+ if (opened !== undefined)
276
+ return opened;
277
+ await new Promise((resolve) => setTimeout(resolve, APP_OPEN_POLL_MS));
278
+ }
279
+ return null;
280
+ }
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The credentials a persona names, taken out of it before it leaves this machine.
3
+ *
4
+ * A persona that said "sign in as ana@acme.test, password: hunter2" was driven with the platform's
5
+ * default address and a 401, so every journey behind a login failed; and the persona travelled
6
+ * verbatim, so the password was stored in the synced run. The values become secret fields this
7
+ * machine fills (the platform types a placeholder for a field it knows only by name, see
8
+ * `server-driver.ts`), the password is redacted from the text, and the persona's own values win over
9
+ * a `RETICLE_SECRET_*` set in the environment, which wins over the platform's default.
10
+ */
11
+ /** What stands in for a password in the text that is sent and stored. */
12
+ export declare const REDACTED_SECRET = "[redacted]";
13
+ export interface PersonaCredentials {
14
+ /** The persona with its password redacted: what may be sent to the platform and stored. */
15
+ persona: string;
16
+ /** Secret-field variables the drive fills from, persona values only. */
17
+ secrets: Record<string, string>;
18
+ }
19
+ /** Take the email and password a persona names out of it. */
20
+ export declare function personaCredentials(persona: string): PersonaCredentials;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The credentials a persona names, taken out of it before it leaves this machine.
3
+ *
4
+ * A persona that said "sign in as ana@acme.test, password: hunter2" was driven with the platform's
5
+ * default address and a 401, so every journey behind a login failed; and the persona travelled
6
+ * verbatim, so the password was stored in the synced run. The values become secret fields this
7
+ * machine fills (the platform types a placeholder for a field it knows only by name, see
8
+ * `server-driver.ts`), the password is redacted from the text, and the persona's own values win over
9
+ * a `RETICLE_SECRET_*` set in the environment, which wins over the platform's default.
10
+ */
11
+ /** The prefix a secret field's variable carries; the server driver reads the same. */
12
+ const SECRET_ENV_PREFIX = 'RETICLE_SECRET_';
13
+ /**
14
+ * The field names an email is offered under, as the platform derives them from a label.
15
+ * ponytail: the common sign-in labels only; a form labelled otherwise gets the platform's default.
16
+ */
17
+ const EMAIL_FIELDS = ['EMAIL', 'EMAIL_ADDRESS', 'WORK_EMAIL', 'YOUR_EMAIL'];
18
+ const PASSWORD_FIELDS = [
19
+ 'PASSWORD',
20
+ 'CURRENT_PASSWORD',
21
+ 'NEW_PASSWORD',
22
+ 'CREATE_A_PASSWORD',
23
+ 'CHOOSE_A_PASSWORD',
24
+ 'CONFIRM_PASSWORD',
25
+ ];
26
+ /**
27
+ * The person a persona is, when it opens with their name: "Nina Patel, who …". A sign-up form asks
28
+ * for it, and the Harness typed "reticle harness" into First name. Only a leading name followed by a
29
+ * comma counts; "an admin who …" names nobody and fills nothing.
30
+ */
31
+ const NAME = /^\s*(\p{Lu}\p{Ll}+)(?:\s+(\p{Lu}\p{Ll}+))?\s*,/u;
32
+ /** What stands in for a password in the text that is sent and stored. */
33
+ export const REDACTED_SECRET = '[redacted]';
34
+ const EMAIL = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/;
35
+ /**
36
+ * "password: x", "password is x", "password = x", a quoted value right after the word, or an
37
+ * unquoted one with a digit in it ("password Nina-pass-12345!"): a word with no digit after
38
+ * "password" is prose ("reset the password from the menu"), never a value.
39
+ */
40
+ /**
41
+ * An unquoted value stops at a closing bracket, and a sentence's full stop is not part of it:
42
+ * "(password: x!)" typed "x!)" and every sign-in was refused.
43
+ */
44
+ const PASSWORD = /\bpass(?:word|code)\b(?:\s*(?::|=|\bis\b)\s*(?:"([^"\n]+)"|“([^”\n]+)”|([^\s"“,;()]+?)(?=\.?(?:\s|$|[,;)])))|\s+(?:"([^"\n]+)"|“([^”\n]+)”)|\s+([^\s"“,;()]*\d[^\s"“,;()]*?)(?=\.?(?:\s|$|[,;)])))/i;
45
+ /** Take the email and password a persona names out of it. */
46
+ export function personaCredentials(persona) {
47
+ const secrets = {};
48
+ const name = NAME.exec(persona);
49
+ if (name?.[1] !== undefined) {
50
+ const full = name[2] === undefined ? name[1] : `${name[1]} ${name[2]}`;
51
+ secrets[`${SECRET_ENV_PREFIX}FIRST_NAME`] = name[1];
52
+ secrets[`${SECRET_ENV_PREFIX}FULL_NAME`] = full;
53
+ secrets[`${SECRET_ENV_PREFIX}NAME`] = full;
54
+ if (name[2] !== undefined)
55
+ secrets[`${SECRET_ENV_PREFIX}LAST_NAME`] = name[2];
56
+ }
57
+ const email = EMAIL.exec(persona)?.[0];
58
+ if (email !== undefined)
59
+ for (const field of EMAIL_FIELDS)
60
+ secrets[`${SECRET_ENV_PREFIX}${field}`] = email;
61
+ const match = PASSWORD.exec(persona);
62
+ const password = match?.slice(1).find((group) => group !== undefined);
63
+ if (null === match || password === undefined)
64
+ return { persona, secrets };
65
+ for (const field of PASSWORD_FIELDS)
66
+ secrets[`${SECRET_ENV_PREFIX}${field}`] = password;
67
+ const redacted = match[0].replace(password, REDACTED_SECRET);
68
+ return { persona: persona.replace(match[0], redacted), secrets };
69
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The two platform calls a drive needs outside its own turns: the grant that pays for a drive, and
3
+ * the run the platform kept once the local record is gone.
4
+ *
5
+ * Both answer with a value and never throw: an unreachable platform is a sentence to show, not a
6
+ * crash in the CLI or in the HUD's button handler.
7
+ */
8
+ /** What the grant is for: `reticle try`'s one drive, or a drive started from the HUD or an agent. */
9
+ export declare const FreeDriveKind: {
10
+ readonly TRY: "try";
11
+ readonly EXPLORE: "explore";
12
+ };
13
+ export type FreeDriveKind = (typeof FreeDriveKind)[keyof typeof FreeDriveKind];
14
+ /** One HTTP request, narrowed so a test answers it without a network. */
15
+ export type PlatformFetch = (url: string, init: {
16
+ method: string;
17
+ headers: Record<string, string>;
18
+ body?: string;
19
+ }) => Promise<{
20
+ status: number;
21
+ text(): Promise<string>;
22
+ }>;
23
+ /** The drive the platform granted, or why it would not. */
24
+ export type FreeDrive = {
25
+ granted: true;
26
+ driveId: string;
27
+ } | {
28
+ granted: false;
29
+ needsCard: boolean;
30
+ message: string;
31
+ hint?: string;
32
+ };
33
+ interface Platform {
34
+ url: string;
35
+ apiKey: string;
36
+ }
37
+ /** The dashboard page where a trial starts, at the origin of whatever link the platform gave. */
38
+ export declare function planUrl(dashboard: string): string;
39
+ /** Ask the platform for a drive it will pay for. Every failure is an answer, never a throw. */
40
+ export declare function requestFreeDrive(platform: Platform, kind: FreeDriveKind, doFetch?: PlatformFetch): Promise<FreeDrive>;
41
+ /**
42
+ * A synced run as the explore poll answers it, in the poll's own fields.
43
+ *
44
+ * The platform serves the run file under `run` with the authoritative verdict (a review overturn
45
+ * wins) beside it — the dashboard's shape. The poll's agent needs the outcome and where it came from,
46
+ * not the whole file; `reticle runs <id>` prints the full answer for anyone who wants it.
47
+ */
48
+ export declare function platformRunAnswer(runId: string, body: Record<string, unknown>): {
49
+ status: string;
50
+ runId: string;
51
+ summary: string;
52
+ };
53
+ /** Said when the platform has no such run: it may simply not have synced yet. */
54
+ export declare const msgRunNotOnPlatform: (runId: string) => string;
55
+ /** The platform's answer for one run (`{ run, verdict, grade, projectName, … }`), or why not. */
56
+ export declare function fetchPlatformRun(platform: Platform, runId: string, doFetch?: PlatformFetch): Promise<{
57
+ run: Record<string, unknown>;
58
+ } | {
59
+ error: string;
60
+ }>;
61
+ export {};
@@ -0,0 +1,114 @@
1
+ /**
2
+ * The two platform calls a drive needs outside its own turns: the grant that pays for a drive, and
3
+ * the run the platform kept once the local record is gone.
4
+ *
5
+ * Both answer with a value and never throw: an unreachable platform is a sentence to show, not a
6
+ * crash in the CLI or in the HUD's button handler.
7
+ */
8
+ const FREE_DRIVE_PATH = '/v1/harness/free-drive';
9
+ const RUNS_PATH = '/v1/runs';
10
+ const NEEDS_CARD = 'needs_card';
11
+ const HTTP_PAYMENT_REQUIRED = 402;
12
+ const HTTP_NOT_FOUND = 404;
13
+ /** Where a workspace starts its trial: the dashboard's billing settings, at its origin. */
14
+ const PLAN_PATH = '/settings?group=billing';
15
+ /** What the grant is for: `reticle try`'s one drive, or a drive started from the HUD or an agent. */
16
+ export const FreeDriveKind = { TRY: 'try', EXPLORE: 'explore' };
17
+ const defaultFetch = (url, init) => fetch(url, init);
18
+ const base = (platform) => platform.url.replace(/\/+$/, '');
19
+ const headers = (platform) => ({
20
+ 'content-type': 'application/json',
21
+ authorization: `Bearer ${platform.apiKey}`,
22
+ });
23
+ function record(text) {
24
+ try {
25
+ const parsed = JSON.parse(text);
26
+ return 'object' === typeof parsed && null !== parsed ? parsed : {};
27
+ }
28
+ catch {
29
+ return {};
30
+ }
31
+ }
32
+ const str = (value) => ('string' === typeof value ? value : undefined);
33
+ /** The dashboard page where a trial starts, at the origin of whatever link the platform gave. */
34
+ export function planUrl(dashboard) {
35
+ try {
36
+ return `${new URL(dashboard).origin}${PLAN_PATH}`;
37
+ }
38
+ catch {
39
+ return `${dashboard.replace(/\/+$/, '')}${PLAN_PATH}`;
40
+ }
41
+ }
42
+ /** Ask the platform for a drive it will pay for. Every failure is an answer, never a throw. */
43
+ export async function requestFreeDrive(platform, kind, doFetch = defaultFetch) {
44
+ try {
45
+ const res = await doFetch(`${base(platform)}${FREE_DRIVE_PATH}`, {
46
+ method: 'POST',
47
+ headers: headers(platform),
48
+ body: JSON.stringify({ kind }),
49
+ });
50
+ const body = record(await res.text());
51
+ const driveId = str(body['driveId']);
52
+ if (true === body['granted'] && driveId !== undefined)
53
+ return { granted: true, driveId };
54
+ const message = str(body['message']) ??
55
+ `The Reticle platform did not grant a drive (it answered ${String(res.status)}).`;
56
+ const hint = str(body['hint']);
57
+ return {
58
+ granted: false,
59
+ needsCard: HTTP_PAYMENT_REQUIRED === res.status || NEEDS_CARD === body['error'],
60
+ message,
61
+ ...(hint === undefined ? {} : { hint }),
62
+ };
63
+ }
64
+ catch (error) {
65
+ return {
66
+ granted: false,
67
+ needsCard: false,
68
+ message: `Could not reach the Reticle platform: ${error instanceof Error ? error.message : String(error)}`,
69
+ };
70
+ }
71
+ }
72
+ const DRIVE_DONE = 'done';
73
+ const msgFromDashboard = (verdict, checks) => `From the dashboard (the drive itself is no longer on this machine): ${verdict === undefined ? 'no verdict recorded' : `verdict ${verdict}`}, ${String(checks)} check${1 === checks ? '' : 's'}.`;
74
+ /**
75
+ * A synced run as the explore poll answers it, in the poll's own fields.
76
+ *
77
+ * The platform serves the run file under `run` with the authoritative verdict (a review overturn
78
+ * wins) beside it — the dashboard's shape. The poll's agent needs the outcome and where it came from,
79
+ * not the whole file; `reticle runs <id>` prints the full answer for anyone who wants it.
80
+ */
81
+ export function platformRunAnswer(runId, body) {
82
+ const run = body['run'];
83
+ const checks = 'object' === typeof run &&
84
+ null !== run &&
85
+ Array.isArray(run['checks'])
86
+ ? run['checks'].length
87
+ : 0;
88
+ return { status: DRIVE_DONE, runId, summary: msgFromDashboard(str(body['verdict']), checks) };
89
+ }
90
+ /** Said when the platform has no such run: it may simply not have synced yet. */
91
+ export const msgRunNotOnPlatform = (runId) => `Run ${runId} is not on the Reticle platform: not synced yet, or not found.`;
92
+ /** The platform's answer for one run (`{ run, verdict, grade, projectName, … }`), or why not. */
93
+ export async function fetchPlatformRun(platform, runId, doFetch = defaultFetch) {
94
+ try {
95
+ const res = await doFetch(`${base(platform)}${RUNS_PATH}/${encodeURIComponent(runId)}`, {
96
+ method: 'GET',
97
+ headers: headers(platform),
98
+ });
99
+ if (HTTP_NOT_FOUND === res.status)
100
+ return { error: msgRunNotOnPlatform(runId) };
101
+ const body = record(await res.text());
102
+ if (200 > res.status || 300 <= res.status)
103
+ return {
104
+ error: str(body['message']) ??
105
+ `The Reticle platform answered ${String(res.status)} for ${runId}.`,
106
+ };
107
+ return { run: body };
108
+ }
109
+ catch (error) {
110
+ return {
111
+ error: `Could not reach the Reticle platform: ${error instanceof Error ? error.message : String(error)}`,
112
+ };
113
+ }
114
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Every sentence the Harness refuses with, and the platform's refusal codes they answer.
3
+ *
4
+ * The recogniser that tells an agent "this is a deliberate refusal, here is the way out" rather than
5
+ * "this may be a defect in Reticle" used to match the PLATFORM's wording by regular expression. The
6
+ * platform reworded its lock ("Harness is locked. Setup score: …") and every locked Harness came back
7
+ * inviting a bug report. A refusal now carries the platform's CODE, the code picks a lead sentence
8
+ * owned here, and the recogniser matches these constants — never another repository's prose.
9
+ */
10
+ /** The codes the platform's refusals carry (`{ error: { code, message } }`, or a flat `error`). */
11
+ export declare const PlatformRefusalCode: {
12
+ readonly HARNESS_OFF: "harness_off";
13
+ readonly HARNESS_LOCKED: "harness_locked";
14
+ readonly NEEDS_CARD: "needs_card";
15
+ };
16
+ /** The lead sentence each code's refusal opens with: what the agent reads, and what is recognised. */
17
+ export declare const RefusalLead: {
18
+ readonly harness_locked: "Reticle Harness is locked for this project.";
19
+ readonly harness_off: "The Reticle Harness is off for this project.";
20
+ readonly needs_card: "Reticle Harness credits are used up for this workspace.";
21
+ };
22
+ /** A platform refusal, read from its response body. Two shapes: nested `{ error: { code, message } }` and flat `{ error, message }`. */
23
+ export declare function readRefusal(text: string): {
24
+ code?: string;
25
+ message?: string;
26
+ };
27
+ /** The sentence a refusal is told in: the code's own lead, then the platform's words. */
28
+ export declare function refusalSentence(refusal: {
29
+ code?: string;
30
+ message?: string;
31
+ }, status: number): string;
32
+ /**
33
+ * What a person said about autonomous driving on the platform, honoured here.
34
+ *
35
+ * The switch existed, persisted and round-tripped, and the daemon read it and threw it away — so
36
+ * turning the harness OFF changed a value in a database and nothing else. A control that does not
37
+ * control anything is worse than no control: somebody turns it off, watches Reticle drive their app
38
+ * anyway, and now correctly distrusts every other switch in the product.
39
+ *
40
+ * Absent means OFF. The Harness is opt-in: a new project starts with it off, and an answer that does
41
+ * not say it is on is not a yes to spend credits on.
42
+ */
43
+ export declare const MSG_HARNESS_DISABLED: string;
44
+ /**
45
+ * The other reason a drive can be refused, and it is NOT the same reason.
46
+ *
47
+ * A drive through the platform spends Reticle's model budget, bounded by the workspace's Harness
48
+ * credits. The platform answers this only when something other than the switch stops it.
49
+ */
50
+ export declare const MSG_HARNESS_UNCLAIMED: string;
51
+ /** The platform could not be asked, and the drive would spend Reticle's budget without its yes. */
52
+ export declare const MSG_HARNESS_UNCONFIRMED: string;
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Every sentence the Harness refuses with, and the platform's refusal codes they answer.
3
+ *
4
+ * The recogniser that tells an agent "this is a deliberate refusal, here is the way out" rather than
5
+ * "this may be a defect in Reticle" used to match the PLATFORM's wording by regular expression. The
6
+ * platform reworded its lock ("Harness is locked. Setup score: …") and every locked Harness came back
7
+ * inviting a bug report. A refusal now carries the platform's CODE, the code picks a lead sentence
8
+ * owned here, and the recogniser matches these constants — never another repository's prose.
9
+ */
10
+ /** The codes the platform's refusals carry (`{ error: { code, message } }`, or a flat `error`). */
11
+ export const PlatformRefusalCode = {
12
+ HARNESS_OFF: 'harness_off',
13
+ HARNESS_LOCKED: 'harness_locked',
14
+ NEEDS_CARD: 'needs_card',
15
+ };
16
+ /** The lead sentence each code's refusal opens with: what the agent reads, and what is recognised. */
17
+ export const RefusalLead = {
18
+ [PlatformRefusalCode.HARNESS_LOCKED]: 'Reticle Harness is locked for this project.',
19
+ [PlatformRefusalCode.HARNESS_OFF]: 'The Reticle Harness is off for this project.',
20
+ [PlatformRefusalCode.NEEDS_CARD]: 'Reticle Harness credits are used up for this workspace.',
21
+ };
22
+ /** A platform refusal, read from its response body. Two shapes: nested `{ error: { code, message } }` and flat `{ error, message }`. */
23
+ export function readRefusal(text) {
24
+ try {
25
+ const body = JSON.parse(text);
26
+ const nested = 'object' === typeof body.error && null !== body.error
27
+ ? body.error
28
+ : {};
29
+ const code = 'string' === typeof body.error ? body.error : nested.code;
30
+ const message = 'string' === typeof nested.message ? nested.message : body.message;
31
+ return {
32
+ ...('string' === typeof code ? { code } : {}),
33
+ ...('string' === typeof message ? { message } : {}),
34
+ };
35
+ }
36
+ catch {
37
+ return {};
38
+ }
39
+ }
40
+ const leadOf = (code) => Object.entries(RefusalLead).find(([known]) => known === code)?.[1];
41
+ /** The sentence a refusal is told in: the code's own lead, then the platform's words. */
42
+ export function refusalSentence(refusal, status) {
43
+ const message = refusal.message ?? `the platform answered ${String(status)}`;
44
+ const lead = leadOf(refusal.code);
45
+ return lead === undefined || message.startsWith(lead) ? message : `${lead} ${message}`;
46
+ }
47
+ /**
48
+ * What a person said about autonomous driving on the platform, honoured here.
49
+ *
50
+ * The switch existed, persisted and round-tripped, and the daemon read it and threw it away — so
51
+ * turning the harness OFF changed a value in a database and nothing else. A control that does not
52
+ * control anything is worse than no control: somebody turns it off, watches Reticle drive their app
53
+ * anyway, and now correctly distrusts every other switch in the product.
54
+ *
55
+ * Absent means OFF. The Harness is opt-in: a new project starts with it off, and an answer that does
56
+ * not say it is on is not a yes to spend credits on.
57
+ */
58
+ export const MSG_HARNESS_DISABLED = "The Reticle Harness is off for this project. The user can switch it on in the HUD's Settings " +
59
+ 'or the Reticle dashboard (Settings → Projects → Reticle Harness on <project>); until then, drive the app yourself ' +
60
+ 'through the MCP tools.';
61
+ /**
62
+ * The other reason a drive can be refused, and it is NOT the same reason.
63
+ *
64
+ * A drive through the platform spends Reticle's model budget, bounded by the workspace's Harness
65
+ * credits. The platform answers this only when something other than the switch stops it.
66
+ */
67
+ export const MSG_HARNESS_UNCLAIMED = 'The Reticle platform says this workspace cannot drive the Harness right now, usually because its ' +
68
+ 'credits are spent: see Settings → Plan in the Reticle dashboard.';
69
+ /** The platform could not be asked, and the drive would spend Reticle's budget without its yes. */
70
+ export const MSG_HARNESS_UNCONFIRMED = 'Could not confirm Harness access with the Reticle platform, so the drive did not start. Try ' +
71
+ 'again in a moment.';