@reticlehq/server 3.7.0 → 3.8.1

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 (578) hide show
  1. package/SKILL.md +59 -68
  2. package/bin/reticle.js +9 -2
  3. package/dist/command/cli/adhoc-suite.js +1 -1
  4. package/dist/command/cli/adhoc-verdict.d.ts +12 -0
  5. package/dist/command/cli/adhoc-verdict.js +62 -4
  6. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  7. package/dist/command/cli/answers/gate-hook-message.js +5 -1
  8. package/dist/command/cli/auth/cloud-session.d.ts +11 -19
  9. package/dist/command/cli/auth/cloud-session.js +23 -0
  10. package/dist/command/cli/auth/device-flow.d.ts +3 -37
  11. package/dist/command/cli/cli-doctor.js +66 -21
  12. package/dist/command/cli/cli-flow-commands.js +53 -11
  13. package/dist/command/cli/cli-kill.d.ts +8 -0
  14. package/dist/command/cli/cli-kill.js +43 -3
  15. package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
  16. package/dist/command/cli/cli-parse-feedback.js +13 -1
  17. package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
  18. package/dist/command/cli/cli-parse-grammar.js +1 -6
  19. package/dist/command/cli/cli-parse-serve.d.ts +24 -0
  20. package/dist/command/cli/cli-parse-serve.js +124 -0
  21. package/dist/command/cli/cli-parse.d.ts +12 -11
  22. package/dist/command/cli/cli-parse.js +100 -123
  23. package/dist/command/cli/cli-usage.d.ts +0 -11
  24. package/dist/command/cli/cli-usage.js +43 -16
  25. package/dist/command/cli/cli-verify.d.ts +1 -1
  26. package/dist/command/cli/cli-verify.js +29 -14
  27. package/dist/command/cli/cloud-cli.js +27 -9
  28. package/dist/command/cli/cloud-kit.js +3 -3
  29. package/dist/command/cli/cloud-link.d.ts +1 -20
  30. package/dist/command/cli/cloud-link.js +2 -0
  31. package/dist/command/cli/cloud-login.d.ts +6 -2
  32. package/dist/command/cli/cloud-login.js +13 -41
  33. package/dist/command/cli/config/checkout.d.ts +10 -0
  34. package/dist/command/cli/config/checkout.js +78 -0
  35. package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
  36. package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
  37. package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
  38. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  39. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  40. package/dist/command/cli/drive/drive-attach.d.ts +5 -0
  41. package/dist/command/cli/drive/drive-attach.js +21 -1
  42. package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
  43. package/dist/command/cli/hook/codex-transcript.js +224 -0
  44. package/dist/command/cli/hook/episode-structure.d.ts +24 -0
  45. package/dist/command/cli/hook/episode-structure.js +138 -0
  46. package/dist/command/cli/hook/hook-command.d.ts +9 -0
  47. package/dist/command/cli/hook/hook-command.js +211 -0
  48. package/dist/command/cli/hook/hook-fast.d.ts +31 -0
  49. package/dist/command/cli/hook/hook-fast.js +136 -0
  50. package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
  51. package/dist/command/cli/hook/prompt-hook.js +199 -0
  52. package/dist/command/cli/hook/tool-hook.d.ts +21 -0
  53. package/dist/command/cli/hook/tool-hook.js +259 -0
  54. package/dist/command/cli/launch/cli-launch.d.ts +2 -0
  55. package/dist/command/cli/launch/cli-launch.js +22 -2
  56. package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
  57. package/dist/command/cli/mcp-command.d.ts +9 -0
  58. package/dist/command/cli/mcp-command.js +127 -41
  59. package/dist/command/cli/open-navigate.d.ts +43 -0
  60. package/dist/command/cli/open-navigate.js +85 -0
  61. package/dist/command/cli/ports/port-holder.d.ts +16 -4
  62. package/dist/command/cli/ports/port-holder.js +58 -12
  63. package/dist/command/cli/ports/resolve/cli-port.js +18 -2
  64. package/dist/command/cli/project-name.d.ts +1 -7
  65. package/dist/command/cli/project-name.js +1 -0
  66. package/dist/command/cli/report-command.d.ts +8 -2
  67. package/dist/command/cli/report-command.js +95 -18
  68. package/dist/command/cli/status-fields.d.ts +9 -2
  69. package/dist/command/cli/status-fields.js +148 -4
  70. package/dist/command/cli/try-command.d.ts +3 -4
  71. package/dist/command/cli/try-command.js +6 -11
  72. package/dist/command/cli/verify-results.d.ts +4 -1
  73. package/dist/command/cli/verify-results.js +3 -1
  74. package/dist/command/cli.d.ts +1 -7
  75. package/dist/command/cli.js +79 -160
  76. package/dist/command/daemon/daemon-resilience.d.ts +6 -1
  77. package/dist/command/daemon/daemon-resilience.js +31 -18
  78. package/dist/command/daemon/daemon.d.ts +11 -0
  79. package/dist/command/daemon/daemon.js +70 -2
  80. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
  81. package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
  82. package/dist/command/daemon/wake-decision.js +4 -2
  83. package/dist/command/daemon/win32-escape.d.ts +32 -0
  84. package/dist/command/daemon/win32-escape.js +119 -0
  85. package/dist/command/setup/agent-configs.d.ts +9 -0
  86. package/dist/command/setup/agent-configs.js +9 -0
  87. package/dist/command/setup/auto-approve.d.ts +10 -3
  88. package/dist/command/setup/auto-approve.js +51 -3
  89. package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
  90. package/dist/command/setup/bringup/dev-server-wait.js +5 -1
  91. package/dist/command/setup/bringup/ensure-daemon.js +4 -7
  92. package/dist/command/setup/init/init-host.js +6 -0
  93. package/dist/command/setup/init/init-port.js +5 -4
  94. package/dist/command/setup/init/init-runtime.js +7 -1
  95. package/dist/command/setup/node-effects.d.ts +8 -0
  96. package/dist/command/setup/node-effects.js +36 -4
  97. package/dist/command/setup/probe/dev-port.d.ts +26 -0
  98. package/dist/command/setup/probe/dev-port.js +117 -0
  99. package/dist/command/setup/probe/page-probe.d.ts +1 -1
  100. package/dist/command/setup/probe/page-probe.js +11 -3
  101. package/dist/command/setup/remaining-steps.d.ts +0 -7
  102. package/dist/command/setup/remaining-steps.js +3 -2
  103. package/dist/command/setup/run-setup.d.ts +11 -0
  104. package/dist/command/setup/run-setup.js +33 -5
  105. package/dist/command/setup/setup-command.d.ts +2 -0
  106. package/dist/command/setup/setup-command.js +22 -4
  107. package/dist/command/update/updater.d.ts +1 -6
  108. package/dist/command/update/updater.js +4 -5
  109. package/dist/command/update/version-seen.d.ts +24 -0
  110. package/dist/command/update/version-seen.js +65 -0
  111. package/dist/command/version/peer-announce.d.ts +9 -1
  112. package/dist/command/version/peer-announce.js +25 -2
  113. package/dist/command/version/sdk-fix.d.ts +5 -6
  114. package/dist/command/version/sdk-fix.js +17 -32
  115. package/dist/command/version/version-skew.d.ts +16 -1
  116. package/dist/command/version/version-skew.js +84 -10
  117. package/dist/features/crawl/crawl-tools.js +2 -2
  118. package/dist/features/crawl/crawl.js +2 -0
  119. package/dist/features/exhaust/ledger.d.ts +15 -96
  120. package/dist/features/exhaust/ledger.js +3 -3
  121. package/dist/features/harness/drive-runs.d.ts +28 -4
  122. package/dist/features/harness/drive-runs.js +99 -7
  123. package/dist/features/harness/drivers.d.ts +1 -1
  124. package/dist/features/harness/drivers.js +1 -1
  125. package/dist/features/harness/harness.d.ts +5 -0
  126. package/dist/features/harness/harness.js +24 -12
  127. package/dist/features/harness/platform/platform-drives.d.ts +7 -1
  128. package/dist/features/harness/platform/platform-drives.js +12 -7
  129. package/dist/features/harness/platform/refusal.d.ts +1 -1
  130. package/dist/features/harness/platform/refusal.js +4 -4
  131. package/dist/features/harness/platform/remote-drive.js +70 -28
  132. package/dist/features/harness/platform/server-driver.js +22 -1
  133. package/dist/features/harness/platform-config.d.ts +1 -10
  134. package/dist/features/harness/platform-config.js +0 -20
  135. package/dist/features/license/license.d.ts +2 -14
  136. package/dist/features/visual/step-shots.d.ts +33 -1
  137. package/dist/features/visual/step-shots.js +155 -1
  138. package/dist/features/visual/visual-tools.js +12 -4
  139. package/dist/hooks/coding-agents.d.ts +6 -0
  140. package/dist/hooks/coding-agents.js +24 -3
  141. package/dist/hooks/episode-stamp.d.ts +32 -0
  142. package/dist/hooks/episode-stamp.js +61 -0
  143. package/dist/hooks/hook-commands.js +19 -9
  144. package/dist/index.d.ts +5 -1
  145. package/dist/index.js +66 -24
  146. package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
  147. package/dist/judgement/app-graph/journal-steps.js +92 -0
  148. package/dist/judgement/capsule/capsule-store.d.ts +2 -39
  149. package/dist/judgement/domain/domain-model.js +1 -10
  150. package/dist/judgement/domain/domain-tools.js +4 -2
  151. package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
  152. package/dist/judgement/runs/artifact/run-store.js +153 -28
  153. package/dist/judgement/runs/default-run-id.d.ts +3 -1
  154. package/dist/judgement/runs/default-run-id.js +15 -3
  155. package/dist/judgement/runs/drive-run.d.ts +3 -3
  156. package/dist/judgement/runs/drive-run.js +11 -7
  157. package/dist/judgement/runs/run-ledger.d.ts +21 -0
  158. package/dist/judgement/runs/run-ledger.js +143 -0
  159. package/dist/judgement/runs/runner-port.d.ts +1 -1
  160. package/dist/judgement/runs/runner-port.js +8 -2
  161. package/dist/judgement/runs/verification-sync.d.ts +4 -3
  162. package/dist/judgement/runs/verification-sync.js +27 -5
  163. package/dist/language/flows/affected-tools.js +2 -1
  164. package/dist/language/flows/annotate-notes/annotate.js +8 -3
  165. package/dist/language/flows/annotate-tools.js +1 -1
  166. package/dist/language/flows/change/affected.d.ts +8 -0
  167. package/dist/language/flows/change/affected.js +20 -7
  168. package/dist/language/flows/decision.js +19 -4
  169. package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
  170. package/dist/language/flows/fields/flow-secret-field.js +67 -5
  171. package/dist/language/flows/flow-anchor.d.ts +5 -0
  172. package/dist/language/flows/flow-anchor.js +4 -0
  173. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  174. package/dist/language/flows/flow-cross-step.js +9 -0
  175. package/dist/language/flows/flow-expect-grammar.js +15 -10
  176. package/dist/language/flows/flow-intent.js +6 -1
  177. package/dist/language/flows/flow-journey.d.ts +8 -0
  178. package/dist/language/flows/flow-journey.js +13 -0
  179. package/dist/language/flows/flow-lease.d.ts +27 -0
  180. package/dist/language/flows/flow-lease.js +59 -0
  181. package/dist/language/flows/flow-replay-run.d.ts +1 -87
  182. package/dist/language/flows/flow-replay-run.js +111 -310
  183. package/dist/language/flows/flow-replay.js +21 -19
  184. package/dist/language/flows/flow-replayable.d.ts +38 -0
  185. package/dist/language/flows/flow-replayable.js +179 -0
  186. package/dist/language/flows/flow-start-path.d.ts +108 -0
  187. package/dist/language/flows/flow-start-path.js +313 -0
  188. package/dist/language/flows/flow-step-runners.d.ts +23 -2
  189. package/dist/language/flows/flow-step-runners.js +191 -32
  190. package/dist/language/flows/flow-store-for-session.d.ts +8 -1
  191. package/dist/language/flows/flow-store-for-session.js +6 -0
  192. package/dist/language/flows/flow-tools.d.ts +2 -23
  193. package/dist/language/flows/flow-tools.js +63 -113
  194. package/dist/language/flows/flows.d.ts +4 -6
  195. package/dist/language/flows/flows.js +90 -15
  196. package/dist/language/flows/heal-run.d.ts +10 -4
  197. package/dist/language/flows/heal-run.js +26 -9
  198. package/dist/language/flows/recording/flake.d.ts +3 -27
  199. package/dist/language/flows/recording/flake.js +1 -1
  200. package/dist/language/flows/recording/recording-backtrack.js +1 -4
  201. package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
  202. package/dist/language/flows/recording/tape/recordings.js +9 -3
  203. package/dist/language/flows/replay.d.ts +25 -5
  204. package/dist/language/flows/replay.js +83 -16
  205. package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
  206. package/dist/language/flows/suite/coverage.d.ts +9 -0
  207. package/dist/language/flows/suite/coverage.js +12 -1
  208. package/dist/language/flows/suite-selection.d.ts +25 -0
  209. package/dist/language/flows/suite-selection.js +41 -9
  210. package/dist/machine/git-tracks.d.ts +6 -0
  211. package/dist/machine/git-tracks.js +36 -0
  212. package/dist/memory/cloud/background-sync.d.ts +25 -0
  213. package/dist/memory/cloud/background-sync.js +79 -0
  214. package/dist/memory/cloud/cloud-config.d.ts +12 -1
  215. package/dist/memory/cloud/cloud-config.js +39 -13
  216. package/dist/memory/cloud/cloud-sync.d.ts +3 -24
  217. package/dist/memory/cloud/cloud-sync.js +5 -2
  218. package/dist/memory/cloud/harness-config.d.ts +0 -7
  219. package/dist/memory/cloud/memory-scope.d.ts +19 -0
  220. package/dist/memory/cloud/memory-scope.js +48 -0
  221. package/dist/memory/cloud/sync-answer.d.ts +43 -0
  222. package/dist/memory/cloud/sync-answer.js +42 -0
  223. package/dist/memory/cloud/sync-cycle.d.ts +40 -10
  224. package/dist/memory/cloud/sync-cycle.js +97 -144
  225. package/dist/memory/cloud/sync-daemon.d.ts +50 -3
  226. package/dist/memory/cloud/sync-daemon.js +473 -83
  227. package/dist/memory/cloud/sync-describe.d.ts +28 -0
  228. package/dist/memory/cloud/sync-describe.js +92 -0
  229. package/dist/memory/cloud/sync-disk.d.ts +9 -1
  230. package/dist/memory/cloud/sync-disk.js +137 -33
  231. package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
  232. package/dist/memory/cloud/sync-flow-versions.js +42 -0
  233. package/dist/memory/impact/impact-store.js +32 -15
  234. package/dist/memory/intent/intent-shard.d.ts +41 -266
  235. package/dist/memory/intent/intent-tools.js +20 -61
  236. package/dist/memory/intent/record-request.d.ts +27 -0
  237. package/dist/memory/intent/record-request.js +88 -0
  238. package/dist/memory/intent/settled-words.js +9 -1
  239. package/dist/memory/journal/drive-flow.d.ts +3 -0
  240. package/dist/memory/journal/drive-flow.js +11 -41
  241. package/dist/memory/journal/envelope-store.js +1 -1
  242. package/dist/memory/journal/envelope.d.ts +6 -154
  243. package/dist/memory/journal/episode-log.d.ts +107 -0
  244. package/dist/memory/journal/episode-log.js +302 -0
  245. package/dist/memory/journal/journal-recorder.d.ts +7 -0
  246. package/dist/memory/journal/journal-recorder.js +22 -9
  247. package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
  248. package/dist/memory/journal/on-disk/ambient-file.js +1 -1
  249. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
  250. package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
  251. package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
  252. package/dist/memory/journal/self-observation.js +3 -1
  253. package/dist/memory/journal/session-end.js +23 -9
  254. package/dist/memory/journal/session-journal.js +39 -20
  255. package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
  256. package/dist/memory/project/artifact-root-resolver.js +68 -23
  257. package/dist/memory/project/artifact-root.d.ts +17 -3
  258. package/dist/memory/project/artifact-root.js +47 -9
  259. package/dist/memory/project/fs/fs-port.d.ts +5 -0
  260. package/dist/memory/project/fs/fs-port.js +13 -0
  261. package/dist/memory/project/learned-routes.d.ts +3 -4
  262. package/dist/memory/project/learned-routes.js +3 -11
  263. package/dist/memory/project/link-directory.js +5 -2
  264. package/dist/memory/project/root-claims.d.ts +3 -1
  265. package/dist/memory/project/root-claims.js +41 -7
  266. package/dist/memory/project/session-root.d.ts +1 -1
  267. package/dist/memory/project/session-root.js +1 -15
  268. package/dist/memory/project/sync-status.js +5 -6
  269. package/dist/memory/recall/memory-tools.js +2 -2
  270. package/dist/memory/recall/platform-memory.d.ts +3 -1
  271. package/dist/memory/recall/platform-memory.js +9 -1
  272. package/dist/memory/recall/project-memory.js +15 -19
  273. package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
  274. package/dist/portal/bridge/auth-failure-reason.js +19 -0
  275. package/dist/portal/bridge/bridge.d.ts +19 -4
  276. package/dist/portal/bridge/bridge.js +150 -177
  277. package/dist/portal/bridge/harness-request.d.ts +15 -0
  278. package/dist/portal/bridge/harness-request.js +19 -0
  279. package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
  280. package/dist/portal/bridge/origin/origin-follow.js +110 -0
  281. package/dist/portal/bridge/pairing-token.d.ts +6 -0
  282. package/dist/portal/bridge/pairing-token.js +47 -16
  283. package/dist/portal/bridge/protocol-skew.d.ts +27 -2
  284. package/dist/portal/bridge/protocol-skew.js +66 -2
  285. package/dist/portal/bridge/session-nonces.d.ts +46 -0
  286. package/dist/portal/bridge/session-nonces.js +72 -0
  287. package/dist/portal/input/viewport-tools.d.ts +31 -0
  288. package/dist/portal/input/viewport-tools.js +106 -15
  289. package/dist/portal/pool/bounded-close.d.ts +23 -0
  290. package/dist/portal/pool/bounded-close.js +38 -0
  291. package/dist/portal/pool/browser-pool.d.ts +44 -39
  292. package/dist/portal/pool/browser-pool.js +247 -95
  293. package/dist/portal/pool/context-permissions.d.ts +9 -1
  294. package/dist/portal/pool/context-permissions.js +26 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +37 -0
  296. package/dist/portal/pool/lease-emulation.js +29 -0
  297. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  298. package/dist/portal/pool/playwright-launcher.js +74 -7
  299. package/dist/portal/pool/pool-contract.d.ts +23 -1
  300. package/dist/portal/pool/pool-lease.d.ts +128 -0
  301. package/dist/portal/pool/pool-lease.js +49 -0
  302. package/dist/portal/pool/zero-install.d.ts +8 -1
  303. package/dist/portal/pool/zero-install.js +24 -2
  304. package/dist/portal/production/production-activation.d.ts +136 -0
  305. package/dist/portal/production/production-activation.js +173 -0
  306. package/dist/portal/production/production-drive.d.ts +52 -0
  307. package/dist/portal/production/production-drive.js +301 -0
  308. package/dist/portal/production/production-hello.d.ts +23 -0
  309. package/dist/portal/production/production-hello.js +23 -0
  310. package/dist/portal/realm/web-realm.js +42 -15
  311. package/dist/portal/session/control-envelope.d.ts +1 -1
  312. package/dist/portal/session/dev-server/served-document.d.ts +0 -5
  313. package/dist/portal/session/dev-server/served-document.js +6 -8
  314. package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
  315. package/dist/portal/session/first-run-wiring.d.ts +3 -36
  316. package/dist/portal/session/first-run-wiring.js +10 -103
  317. package/dist/portal/session/live-control-tools.js +61 -19
  318. package/dist/portal/session/no-session-next-action.d.ts +11 -0
  319. package/dist/portal/session/no-session-next-action.js +40 -15
  320. package/dist/portal/session/no-session-watch.d.ts +7 -0
  321. package/dist/portal/session/no-session-watch.js +67 -23
  322. package/dist/portal/session/output-budget.d.ts +10 -0
  323. package/dist/portal/session/output-budget.js +16 -0
  324. package/dist/portal/session/presence/session-lease.d.ts +2 -0
  325. package/dist/portal/session/presence/session-lease.js +8 -0
  326. package/dist/portal/session/recorded-gaps.d.ts +15 -11
  327. package/dist/portal/session/recorded-gaps.js +39 -18
  328. package/dist/portal/session/serving-directory.d.ts +24 -2
  329. package/dist/portal/session/serving-directory.js +93 -5
  330. package/dist/portal/session/session-info.d.ts +26 -0
  331. package/dist/portal/session/session-info.js +20 -0
  332. package/dist/portal/session/session-manager.d.ts +35 -3
  333. package/dist/portal/session/session-manager.js +69 -14
  334. package/dist/portal/session/session-successor.js +1 -9
  335. package/dist/portal/session/session-tools.js +22 -4
  336. package/dist/portal/session/session.d.ts +10 -10
  337. package/dist/portal/session/session.js +37 -29
  338. package/dist/portal/session/zero-install-first-call.d.ts +7 -2
  339. package/dist/portal/session/zero-install-first-call.js +43 -20
  340. package/dist/start-wiring.d.ts +2 -2
  341. package/dist/start-wiring.js +17 -3
  342. package/dist/status-payload.d.ts +11 -1
  343. package/dist/status-payload.js +7 -1
  344. package/dist/surface/agent-presence-grace.d.ts +11 -0
  345. package/dist/surface/agent-presence-grace.js +34 -0
  346. package/dist/surface/http-server.d.ts +12 -1
  347. package/dist/surface/http-server.js +64 -15
  348. package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
  349. package/dist/surface/mcp/faults/mcp-outage.js +19 -1
  350. package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
  351. package/dist/surface/mcp/mcp-proxy.js +194 -267
  352. package/dist/surface/mcp/mcp.d.ts +20 -3
  353. package/dist/surface/mcp/mcp.js +88 -25
  354. package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
  355. package/dist/surface/mcp/proxy/drive-calls.js +114 -5
  356. package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
  357. package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
  358. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
  359. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
  360. package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
  361. package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
  362. package/dist/surface/mcp/server-instructions.js +35 -16
  363. package/dist/surface/mcp/shared-params.d.ts +8 -0
  364. package/dist/surface/mcp/shared-params.js +15 -1
  365. package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
  366. package/dist/surface/mcp/sse-frame-parser.js +18 -0
  367. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  368. package/dist/surface/mcp/surface-vocabulary.js +13 -0
  369. package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
  370. package/dist/surface/mcp/tool-catalog-cache.js +14 -4
  371. package/dist/surface/tools/account-tool.d.ts +4 -3
  372. package/dist/surface/tools/account-tool.js +20 -31
  373. package/dist/surface/tools/act/act-danger.d.ts +2 -0
  374. package/dist/surface/tools/act/act-danger.js +41 -14
  375. package/dist/surface/tools/act/act-observation.d.ts +11 -0
  376. package/dist/surface/tools/act/act-observation.js +33 -0
  377. package/dist/surface/tools/act/act-preflight.js +10 -3
  378. package/dist/surface/tools/act/act-sequence-retry.js +2 -1
  379. package/dist/surface/tools/act/act-target.js +19 -5
  380. package/dist/surface/tools/act/durable.js +1 -1
  381. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
  382. package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
  383. package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
  384. package/dist/surface/tools/act/unsettled-find.js +71 -0
  385. package/dist/surface/tools/act-sequence-tool.js +53 -24
  386. package/dist/surface/tools/act-tools.d.ts +2 -3
  387. package/dist/surface/tools/act-tools.js +49 -47
  388. package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
  389. package/dist/surface/tools/agent/for-the-agent.js +41 -3
  390. package/dist/surface/tools/assert/assert-grade.js +8 -3
  391. package/dist/surface/tools/assert/assert-verdict.js +4 -2
  392. package/dist/surface/tools/browser-tools.js +7 -4
  393. package/dist/surface/tools/chat-drives.js +50 -25
  394. package/dist/surface/tools/coverage-tools.js +1 -1
  395. package/dist/surface/tools/dynamic-tools.d.ts +8 -0
  396. package/dist/surface/tools/dynamic-tools.js +89 -34
  397. package/dist/surface/tools/empty-session-list.d.ts +18 -25
  398. package/dist/surface/tools/empty-session-list.js +67 -38
  399. package/dist/surface/tools/error-recovery.d.ts +17 -7
  400. package/dist/surface/tools/error-recovery.js +53 -20
  401. package/dist/surface/tools/explore-tools.d.ts +10 -0
  402. package/dist/surface/tools/explore-tools.js +72 -19
  403. package/dist/surface/tools/feedback-tools.js +23 -2
  404. package/dist/surface/tools/gap-novelty.d.ts +6 -0
  405. package/dist/surface/tools/gap-novelty.js +9 -0
  406. package/dist/surface/tools/gaps/capability-absences.js +4 -3
  407. package/dist/surface/tools/harness-explore.d.ts +1 -1
  408. package/dist/surface/tools/harness-explore.js +6 -4
  409. package/dist/surface/tools/harness-gate.d.ts +43 -21
  410. package/dist/surface/tools/harness-gate.js +55 -81
  411. package/dist/surface/tools/harness-script.d.ts +2 -0
  412. package/dist/surface/tools/harness-script.js +11 -6
  413. package/dist/surface/tools/harness-toolset.js +3 -4
  414. package/dist/surface/tools/invoke-tool.d.ts +0 -8
  415. package/dist/surface/tools/invoke-tool.js +164 -178
  416. package/dist/surface/tools/lease-hint.d.ts +9 -0
  417. package/dist/surface/tools/lease-hint.js +22 -3
  418. package/dist/surface/tools/lease-permissions.d.ts +1 -1
  419. package/dist/surface/tools/lease-readiness.d.ts +55 -0
  420. package/dist/surface/tools/lease-readiness.js +150 -2
  421. package/dist/surface/tools/lease-tools.d.ts +3 -75
  422. package/dist/surface/tools/lease-tools.js +124 -188
  423. package/dist/surface/tools/map-tools.d.ts +20 -0
  424. package/dist/surface/tools/map-tools.js +145 -0
  425. package/dist/surface/tools/merge-tools.js +11 -7
  426. package/dist/surface/tools/next-step.js +6 -3
  427. package/dist/surface/tools/observe-tools.js +46 -35
  428. package/dist/surface/tools/platform-moment.d.ts +3 -12
  429. package/dist/surface/tools/platform-moment.js +12 -24
  430. package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
  431. package/dist/surface/tools/read/complete-snapshot.js +13 -2
  432. package/dist/surface/tools/read/query-paginate.js +6 -0
  433. package/dist/surface/tools/read/query-shape.d.ts +9 -0
  434. package/dist/surface/tools/read/query-shape.js +15 -0
  435. package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
  436. package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
  437. package/dist/surface/tools/read-tools.js +5 -5
  438. package/dist/surface/tools/real-input-attempt.d.ts +11 -0
  439. package/dist/surface/tools/real-input-attempt.js +206 -38
  440. package/dist/surface/tools/reconcile-tools.js +21 -8
  441. package/dist/surface/tools/reticle-result.d.ts +3 -0
  442. package/dist/surface/tools/reticle-result.js +8 -1
  443. package/dist/surface/tools/run-report.d.ts +22 -0
  444. package/dist/surface/tools/run-report.js +141 -0
  445. package/dist/surface/tools/session-ports.d.ts +57 -0
  446. package/dist/surface/tools/session-ports.js +102 -0
  447. package/dist/surface/tools/tool-kit.d.ts +58 -4
  448. package/dist/surface/tools/tool-kit.js +140 -6
  449. package/dist/surface/tools/tool-surface.d.ts +2 -0
  450. package/dist/surface/tools/tool-surface.js +45 -0
  451. package/dist/surface/tools/tools.js +49 -87
  452. package/dist/telemetry/automation-hint.d.ts +5 -0
  453. package/dist/telemetry/automation-hint.js +7 -0
  454. package/dist/telemetry/cli-telemetry.d.ts +22 -0
  455. package/dist/telemetry/cli-telemetry.js +80 -11
  456. package/dist/telemetry/daemon-telemetry.d.ts +3 -1
  457. package/dist/telemetry/daemon-telemetry.js +9 -2
  458. package/dist/telemetry/feedback-cli.d.ts +1 -1
  459. package/dist/telemetry/feedback-cli.js +8 -3
  460. package/dist/telemetry/feedback.d.ts +1 -1
  461. package/dist/telemetry/feedback.js +51 -4
  462. package/dist/telemetry/harness-run.d.ts +3 -3
  463. package/dist/telemetry/harness-run.js +18 -7
  464. package/dist/telemetry/hud-events.d.ts +1 -1
  465. package/dist/telemetry/hud-metrics.d.ts +6 -3
  466. package/dist/telemetry/hud-metrics.js +20 -8
  467. package/dist/telemetry/install-source.js +1 -1
  468. package/dist/telemetry/mcp-connection.d.ts +1 -1
  469. package/dist/telemetry/mcp-connection.js +21 -2
  470. package/dist/telemetry/onboarding-firsts.d.ts +6 -1
  471. package/dist/telemetry/onboarding-firsts.js +41 -1
  472. package/dist/telemetry/proxy-telemetry.d.ts +42 -0
  473. package/dist/telemetry/proxy-telemetry.js +70 -1
  474. package/dist/telemetry/session-metrics.d.ts +1 -3
  475. package/dist/telemetry/session-metrics.js +16 -12
  476. package/dist/telemetry/telemetry.d.ts +9 -1
  477. package/dist/telemetry/telemetry.js +16 -1
  478. package/dist/telemetry/verification-of.d.ts +3 -1
  479. package/dist/telemetry/verification-of.js +7 -1
  480. package/dist/wire-journal.js +12 -2
  481. package/docs/README.md +4 -2
  482. package/docs/actions.mdx +7 -6
  483. package/docs/adapters.md +2 -1
  484. package/docs/agent-cheatsheet.md +19 -5
  485. package/docs/architecture.md +13 -10
  486. package/docs/autodrive.md +6 -5
  487. package/docs/benchmarks.md +2 -2
  488. package/docs/capabilities.mdx +1 -1
  489. package/docs/cli/affected.mdx +1 -1
  490. package/docs/cli/cloud.mdx +6 -6
  491. package/docs/cli/doctor.mdx +3 -1
  492. package/docs/cli/feedback.mdx +11 -7
  493. package/docs/cli/gate.mdx +1 -1
  494. package/docs/cli/help.mdx +1 -1
  495. package/docs/cli/init.mdx +20 -16
  496. package/docs/cli/mcp.mdx +5 -2
  497. package/docs/cli/open.mdx +5 -2
  498. package/docs/cli/report.mdx +1 -1
  499. package/docs/cli/restart.mdx +1 -1
  500. package/docs/cli/rollback.mdx +4 -4
  501. package/docs/cli/serve.mdx +7 -5
  502. package/docs/cli/setup.mdx +1 -1
  503. package/docs/cli/status.mdx +6 -2
  504. package/docs/cli/stop.mdx +3 -3
  505. package/docs/cli/telemetry.mdx +5 -1
  506. package/docs/cli/try.mdx +8 -8
  507. package/docs/cli/update.mdx +8 -5
  508. package/docs/cli/verify.mdx +12 -5
  509. package/docs/cli/version.mdx +1 -1
  510. package/docs/cli.mdx +10 -6
  511. package/docs/debugging.md +1 -1
  512. package/docs/deploy-checks.md +8 -6
  513. package/docs/desktop.mdx +14 -18
  514. package/docs/enterprise.md +6 -6
  515. package/docs/environment.mdx +5 -3
  516. package/docs/faq.mdx +9 -6
  517. package/docs/first-drive.md +19 -9
  518. package/docs/flows.md +3 -4
  519. package/docs/for-agents.md +1 -1
  520. package/docs/frameworks.mdx +34 -11
  521. package/docs/getting-started.md +46 -29
  522. package/docs/http-transport.md +2 -2
  523. package/docs/human-control.md +8 -8
  524. package/docs/index.mdx +2 -2
  525. package/docs/install-agentic.mdx +18 -19
  526. package/docs/install-manual.mdx +8 -4
  527. package/docs/integration-patterns.md +5 -5
  528. package/docs/multi-agent-testing.md +7 -5
  529. package/docs/packages/browser.mdx +34 -2
  530. package/docs/packages/core.mdx +2 -1
  531. package/docs/packages/electron.mdx +15 -3
  532. package/docs/packages/eslint-plugin.mdx +1 -1
  533. package/docs/packages/next.mdx +17 -5
  534. package/docs/packages/react.mdx +8 -1
  535. package/docs/packages/server.mdx +3 -3
  536. package/docs/packages/tauri.mdx +3 -3
  537. package/docs/packages/vite-plugin.mdx +1 -1
  538. package/docs/packages.mdx +19 -6
  539. package/docs/platform-integration.md +12 -4
  540. package/docs/predicates.mdx +18 -7
  541. package/docs/production-mode.md +108 -0
  542. package/docs/prompt-capture.md +99 -0
  543. package/docs/quickstart.mdx +14 -12
  544. package/docs/recipes.mdx +9 -8
  545. package/docs/required-checks.md +3 -2
  546. package/docs/skill-file.mdx +4 -3
  547. package/docs/skill-setup.md +2 -2
  548. package/docs/skill.md +62 -70
  549. package/docs/state-files.md +1 -0
  550. package/docs/state-management.mdx +11 -9
  551. package/docs/system-map.md +14 -13
  552. package/docs/telemetry.md +32 -24
  553. package/docs/testing.md +9 -5
  554. package/docs/tools/act-and-wait.mdx +17 -13
  555. package/docs/tools/act-sequence.mdx +40 -66
  556. package/docs/tools/act.mdx +7 -5
  557. package/docs/tools/assert.mdx +1 -1
  558. package/docs/tools/look.mdx +1 -1
  559. package/docs/tools/navigate.mdx +1 -1
  560. package/docs/tools/network.mdx +13 -11
  561. package/docs/tools/overview.mdx +3 -3
  562. package/docs/tools/query.mdx +3 -3
  563. package/docs/tools/session-and-feedback.mdx +9 -6
  564. package/docs/tools/sessions.mdx +7 -0
  565. package/docs/tools/snapshot.mdx +9 -7
  566. package/docs/tools/tools-and-run.mdx +11 -10
  567. package/docs/tools/verify.mdx +1 -1
  568. package/docs/troubleshooting.mdx +21 -9
  569. package/docs/usage.md +58 -43
  570. package/docs/use-cases.mdx +2 -2
  571. package/docs/vs-chrome-devtools-mcp.mdx +5 -5
  572. package/docs/vs-playwright-mcp.mdx +5 -4
  573. package/docs/what-is-recorded.md +12 -7
  574. package/docs/what-is-reticle.mdx +2 -2
  575. package/docs/why-reticle.mdx +1 -1
  576. package/package.json +9 -12
  577. package/dist/command/dev/stale-issue-guard.d.ts +0 -34
  578. package/dist/command/dev/stale-issue-guard.js +0 -69
@@ -19,7 +19,7 @@
19
19
  * anybody could lose. When it does shut down, the MCP proxy reconnects and `ensureDaemon` spawns a
20
20
  * fresh one on the next call, which is a path already exercised hundreds of times a day.
21
21
  */
22
- import { STATUS_HOLD_MS } from '@reticlehq/core';
22
+ import { SESSION_LIFECYCLE, STATUS_HOLD_MS } from '@reticlehq/core';
23
23
  /** Set the first time any tool is dispatched through runTool — the chokepoint every path shares. */
24
24
  let servedToolCall = false;
25
25
  export function noteToolCall() {
@@ -48,10 +48,20 @@ export function noteSetupHold(now) {
48
48
  function setupHolding(now) {
49
49
  return undefined !== setupHeldAt && now - setupHeldAt < SETUP_HOLD_MS;
50
50
  }
51
+ /** When an agent last attached or detached. Undefined until the first one. */
52
+ let agentSeenAt;
53
+ /** Call on each attach and each detach of an agent. */
54
+ export function noteAgentPresence(now) {
55
+ agentSeenAt = now;
56
+ }
57
+ function agentRecent(now) {
58
+ return undefined !== agentSeenAt && now - agentSeenAt < SESSION_LIFECYCLE.DAEMON_AGENT_RECENT_MS;
59
+ }
51
60
  /** Tests only. */
52
61
  export function resetDaemonUsefulness() {
53
62
  servedToolCall = false;
54
63
  setupHeldAt = undefined;
64
+ agentSeenAt = undefined;
55
65
  }
56
66
  /**
57
67
  * True when the daemon has done nothing for anyone and has nothing to lose by exiting.
@@ -72,8 +82,9 @@ export function isUselessDaemon(facts) {
72
82
  * no app and sit there for the length of an editor session.
73
83
  */
74
84
  export function buildIdlePredicate(agentConnected, sessions, pool, now = () => Date.now()) {
85
+ // An agent that attached recently counts as attached: see DAEMON_AGENT_RECENT_MS.
75
86
  return () => !setupHolding(now()) &&
76
- (!agentConnected() ||
87
+ (!(agentConnected() || agentRecent(now())) ||
77
88
  isUselessDaemon({
78
89
  servedToolCall: everServedToolCall(),
79
90
  everConnected: sessions.everConnected(),
@@ -30,9 +30,11 @@ export const WakeAction = {
30
30
  * prevent.
31
31
  */
32
32
  export function decideWake(presence, daemonProjectId, callerProjectId) {
33
- if (PortPresence.FREE === presence)
33
+ if (PortPresence.FREE === presence) {
34
34
  return WakeAction.SPAWN;
35
- if (PortPresence.DAEMON !== presence)
35
+ }
36
+ if (PortPresence.DAEMON !== presence) {
36
37
  return WakeAction.REFUSE;
38
+ }
37
39
  return adoptable(daemonProjectId, callerProjectId) ? WakeAction.USE : WakeAction.REFUSE;
38
40
  }
@@ -0,0 +1,32 @@
1
+ /** What the launcher must start. */
2
+ export interface EscapeRequest {
3
+ readonly command: string;
4
+ readonly args: readonly string[];
5
+ readonly cwd: string;
6
+ readonly env: Readonly<Record<string, string | undefined>>;
7
+ readonly logPath: string;
8
+ /** The spec file. The launcher writes the daemon pid to `<specPath>.pid`. */
9
+ readonly specPath: string;
10
+ }
11
+ /**
12
+ * `launched: false` means nothing started, so the caller can start the daemon another way.
13
+ * `launched: true` with no pid means a daemon may start, but its pid is not known in time.
14
+ */
15
+ export type EscapeResult = {
16
+ launched: false;
17
+ } | {
18
+ launched: true;
19
+ pid?: number;
20
+ };
21
+ /**
22
+ * The launcher, as `node -e` source. It has no double quote and no backslash, so it passes as one
23
+ * Windows argument in double quotes. Its one argument is the spec path.
24
+ */
25
+ export declare const JOB_ESCAPE_LAUNCHER: string;
26
+ /** The PowerShell script: start the launcher through WMI, then wait for the pid file. */
27
+ export declare function wmiScript(request: EscapeRequest): string;
28
+ /**
29
+ * Start `request` through WMI. Never throws: every failure reads as `launched: false`, unless the
30
+ * launcher already claimed the spec, which means it is starting the daemon.
31
+ */
32
+ export declare function escapeJobViaWmi(request: EscapeRequest, run?: (script: string) => void): EscapeResult;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Start the daemon outside the Windows Job Object of the process that starts it.
3
+ *
4
+ * A child of `spawn(..., { detached: true })` stays in the job of its parent. An agent host can run
5
+ * `reticle mcp` in a job with KILL_ON_JOB_CLOSE, and the close of that job then kills the daemon
6
+ * too. A process that WMI `Win32_Process.Create` starts is in no job of ours.
7
+ *
8
+ * WMI cannot give the new process our stdio or our env. So WMI starts a small launcher, and the
9
+ * launcher does the same detached spawn as `spawnDaemon`: stdout and stderr go to the daemon log,
10
+ * opened for append, and the env is ours. The daemon is a child of the launcher, so it is outside
11
+ * the job too. The launcher reads the spawn spec from a file and writes the daemon pid to a file.
12
+ *
13
+ * The spec file is also the lock between the launcher and the fallback. The launcher claims it with
14
+ * a rename before it starts anything. The parent removes it after the WMI call. Only one of the two
15
+ * can win. If the parent wins, nothing started and the detached fallback is safe.
16
+ */
17
+ import { execFileSync } from 'node:child_process';
18
+ import { readFileSync, unlinkSync, writeFileSync } from 'node:fs';
19
+ /**
20
+ * The launcher, as `node -e` source. It has no double quote and no backslash, so it passes as one
21
+ * Windows argument in double quotes. Its one argument is the spec path.
22
+ */
23
+ export const JOB_ESCAPE_LAUNCHER = [
24
+ "const fs=require('fs'),cp=require('child_process');",
25
+ "const f=process.argv[1],t=f+'.taken';",
26
+ 'fs.renameSync(f,t);',
27
+ "const s=JSON.parse(fs.readFileSync(t,'utf8'));",
28
+ 'fs.unlinkSync(t);',
29
+ "const fd=fs.openSync(s.log,'a');",
30
+ "const c=cp.spawn(s.command,s.args,{cwd:s.cwd,env:s.env,detached:true,stdio:['ignore',fd,fd]});",
31
+ "c.on('error',()=>{});",
32
+ 'c.unref();',
33
+ "fs.writeFileSync(f+'.tmp',String(c.pid));",
34
+ "fs.renameSync(f+'.tmp',f+'.pid');",
35
+ ].join('');
36
+ const PID_SUFFIX = '.pid';
37
+ /** How long the script waits for the launcher to report the daemon pid. */
38
+ const PID_WAIT_MS = 5000;
39
+ /** A hard limit on the whole PowerShell call: its start, the WMI call and the pid wait. */
40
+ const WMI_CALL_TIMEOUT_MS = 8000;
41
+ const POWERSHELL = 'powershell.exe';
42
+ const ENCODING_UTF16LE = 'utf16le';
43
+ /** A PowerShell single-quoted literal. */
44
+ function psLiteral(value) {
45
+ return `'${value.replaceAll("'", "''")}'`;
46
+ }
47
+ /** The PowerShell script: start the launcher through WMI, then wait for the pid file. */
48
+ export function wmiScript(request) {
49
+ const commandLine = `"${request.command}" -e "${JOB_ESCAPE_LAUNCHER}" "${request.specPath}"`;
50
+ const pidPath = `${request.specPath}${PID_SUFFIX}`;
51
+ return [
52
+ "$ErrorActionPreference = 'Stop'",
53
+ // SW_HIDE, so the launcher opens no console window.
54
+ '$startup = New-CimInstance -CimClass (Get-CimClass -ClassName Win32_ProcessStartup) -ClientOnly -Property @{ ShowWindow = [uint16]0 }',
55
+ `$null = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = ${psLiteral(commandLine)}; CurrentDirectory = ${psLiteral(request.cwd)}; ProcessStartupInformation = $startup }`,
56
+ `$deadline = (Get-Date).AddMilliseconds(${PID_WAIT_MS})`,
57
+ `while (-not (Test-Path -LiteralPath ${psLiteral(pidPath)}) -and (Get-Date) -lt $deadline) { Start-Sleep -Milliseconds 50 }`,
58
+ ].join('\n');
59
+ }
60
+ function runPowerShell(script) {
61
+ execFileSync(POWERSHELL, [
62
+ '-NoProfile',
63
+ '-NonInteractive',
64
+ '-EncodedCommand',
65
+ Buffer.from(script, ENCODING_UTF16LE).toString('base64'),
66
+ ], { stdio: 'ignore', timeout: WMI_CALL_TIMEOUT_MS, windowsHide: true });
67
+ }
68
+ function removeIfPresent(path) {
69
+ try {
70
+ unlinkSync(path);
71
+ return true;
72
+ }
73
+ catch {
74
+ return false;
75
+ }
76
+ }
77
+ function readLauncherPid(pidPath) {
78
+ try {
79
+ const pid = parseInt(readFileSync(pidPath, 'utf8').trim(), 10);
80
+ return Number.isInteger(pid) && pid > 0 ? pid : undefined;
81
+ }
82
+ catch {
83
+ return undefined;
84
+ }
85
+ }
86
+ /**
87
+ * Start `request` through WMI. Never throws: every failure reads as `launched: false`, unless the
88
+ * launcher already claimed the spec, which means it is starting the daemon.
89
+ */
90
+ export function escapeJobViaWmi(request, run = runPowerShell) {
91
+ const pidPath = `${request.specPath}${PID_SUFFIX}`;
92
+ try {
93
+ removeIfPresent(pidPath);
94
+ writeFileSync(request.specPath, JSON.stringify({
95
+ command: request.command,
96
+ args: request.args,
97
+ cwd: request.cwd,
98
+ env: request.env,
99
+ log: request.logPath,
100
+ }),
101
+ // The spec holds the env. Only the user may read it, and it lives until the launcher reads it.
102
+ { encoding: 'utf8', mode: 0o600 });
103
+ }
104
+ catch {
105
+ return { launched: false };
106
+ }
107
+ try {
108
+ run(wmiScript(request));
109
+ }
110
+ catch {
111
+ // PowerShell missing, blocked, failed or timed out. The spec says whether the launcher ran.
112
+ }
113
+ if (removeIfPresent(request.specPath)) {
114
+ return { launched: false };
115
+ }
116
+ const pid = readLauncherPid(pidPath);
117
+ removeIfPresent(pidPath);
118
+ return pid === undefined ? { launched: true } : { launched: true, pid };
119
+ }
@@ -40,6 +40,15 @@ export interface PlatformPaths {
40
40
  readonly linux: string;
41
41
  readonly win32: string;
42
42
  }
43
+ /**
44
+ * The `PlatformPaths` row to plan for on a host that reports `platform`.
45
+ *
46
+ * Casting `process.platform` to the three keys broke on every other platform Node reports: on
47
+ * `android` (Termux), `freebsd` or `openbsd` the row lookup returned `undefined`, `join` threw
48
+ * `ERR_INVALID_ARG_TYPE`, and `init` stopped after the wiring and before the dev server. Each of
49
+ * those keeps a Unix home layout, so they plan with the `linux` paths.
50
+ */
51
+ export declare const platformKey: (platform: NodeJS.Platform) => keyof PlatformPaths;
43
52
  interface AgentClient {
44
53
  readonly id: string;
45
54
  readonly name: string;
@@ -39,6 +39,15 @@ const MCP_SUBCOMMAND = 'mcp';
39
39
  const RETICLE_KEY = 'reticle';
40
40
  /** The stdio entry, in the shape most clients expect. */
41
41
  const STDIO = { command: NPX, args: [SERVER_PACKAGE, MCP_SUBCOMMAND] };
42
+ /**
43
+ * The `PlatformPaths` row to plan for on a host that reports `platform`.
44
+ *
45
+ * Casting `process.platform` to the three keys broke on every other platform Node reports: on
46
+ * `android` (Termux), `freebsd` or `openbsd` the row lookup returned `undefined`, `join` threw
47
+ * `ERR_INVALID_ARG_TYPE`, and `init` stopped after the wiring and before the dev server. Each of
48
+ * those keeps a Unix home layout, so they plan with the `linux` paths.
49
+ */
50
+ export const platformKey = (platform) => 'darwin' === platform || 'win32' === platform ? platform : 'linux';
42
51
  const VSCODE_USER = {
43
52
  darwin: 'Library/Application Support/Code/User',
44
53
  linux: '.config/Code/User',
@@ -20,9 +20,10 @@
20
20
  * the in-app step to take instead. Nothing is written at all for an agent that is not installed:
21
21
  * an absent agent has no Accept button to remove.
22
22
  *
23
- * Codex is absent by design: its approval policy is global (`approval_policy`), so there is no
24
- * reticle-shaped rule to write, and its config is TOML, which this repo never rewrites. Its
25
- * headless form, `codex exec`, does not prompt at all — which is the form the drive uses.
23
+ * Codex has a per-server rule, `default_tools_approval_mode`, in the `[mcp_servers.reticle]` table
24
+ * that `codex mcp add` writes. Its config is TOML, which this repo does not reformat: the grant adds
25
+ * one line under our own table header and changes no other line. When that header is not there in
26
+ * its plain form, nothing is written and the setting is named instead.
26
27
  */
27
28
  import { type PlatformPaths } from './agent-configs.js';
28
29
  import type { AgentWriterIo } from './agent-writer.js';
@@ -43,6 +44,12 @@ export interface ApprovalGrant {
43
44
  * a grant is only ever merged into a file the user already owns, never created.
44
45
  */
45
46
  readonly supersedesInApp?: boolean;
47
+ /**
48
+ * For a config that is not JSON: the new text, or null when the edit is not safe. Then nothing is
49
+ * written and `manual` tells the user what to add.
50
+ */
51
+ readonly editText?: (current: string) => string | null;
52
+ readonly manual?: (file: string) => string;
46
53
  }
47
54
  export declare const APPROVAL_GRANTS: readonly ApprovalGrant[];
48
55
  export declare const ApprovalOutcome: {
@@ -20,9 +20,10 @@
20
20
  * the in-app step to take instead. Nothing is written at all for an agent that is not installed:
21
21
  * an absent agent has no Accept button to remove.
22
22
  *
23
- * Codex is absent by design: its approval policy is global (`approval_policy`), so there is no
24
- * reticle-shaped rule to write, and its config is TOML, which this repo never rewrites. Its
25
- * headless form, `codex exec`, does not prompt at all — which is the form the drive uses.
23
+ * Codex has a per-server rule, `default_tools_approval_mode`, in the `[mcp_servers.reticle]` table
24
+ * that `codex mcp add` writes. Its config is TOML, which this repo does not reformat: the grant adds
25
+ * one line under our own table header and changes no other line. When that header is not there in
26
+ * its plain form, nothing is written and the setting is named instead.
26
27
  */
27
28
  import { joinFor, parentOf } from './agent-configs.js';
28
29
  const RETICLE_KEY = 'reticle';
@@ -41,6 +42,26 @@ function addToList(current, outer, key, value) {
41
42
  const next = { ...scope, [key]: [...list, value] };
42
43
  return null === outer ? next : { ...current, [outer]: next };
43
44
  }
45
+ const CODEX_RULE = 'default_tools_approval_mode = "approve"';
46
+ const CODEX_TABLE = new RegExp(`^\\s*\\[\\s*mcp_servers\\s*\\.\\s*(?:${RETICLE_KEY}|"${RETICLE_KEY}"|'${RETICLE_KEY}')\\s*\\]\\s*(?:#.*)?$`);
47
+ const CODEX_MODE_KEY = /^\s*default_tools_approval_mode\s*=/;
48
+ const TOML_HEADER = /^\s*\[/;
49
+ /** One line under our `[mcp_servers.reticle]` header. A mode the user set is kept. */
50
+ function codexApprove(current) {
51
+ const eol = current.includes('\r\n') ? '\r\n' : '\n';
52
+ const lines = current.split(/\r?\n/);
53
+ const at = lines.findIndex((line) => CODEX_TABLE.test(line));
54
+ if (at < 0) {
55
+ return null;
56
+ }
57
+ const next = lines.findIndex((line, i) => i > at && TOML_HEADER.test(line));
58
+ const table = lines.slice(at + 1, next < 0 ? undefined : next);
59
+ if (table.some((line) => CODEX_MODE_KEY.test(line))) {
60
+ return current;
61
+ }
62
+ lines.splice(at + 1, 0, CODEX_RULE);
63
+ return lines.join(eol);
64
+ }
44
65
  export const APPROVAL_GRANTS = [
45
66
  {
46
67
  id: 'claude-code',
@@ -98,6 +119,16 @@ export const APPROVAL_GRANTS = [
98
119
  return { ...c, mcpServers: { ...servers, [RETICLE_KEY]: { ...entry, trust: true } } };
99
120
  },
100
121
  },
122
+ {
123
+ id: 'codex',
124
+ name: 'Codex',
125
+ paths: home('.codex/config.toml'),
126
+ markers: [home('.codex')],
127
+ rule: `mcp_servers.${RETICLE_KEY}.${CODEX_RULE}`,
128
+ grant: (c) => c,
129
+ editText: codexApprove,
130
+ manual: (file) => `add \`${CODEX_RULE}\` under [mcp_servers.${RETICLE_KEY}] in ${file}. Without it, Codex asks before every reticle tool call, and refuses each one under approval_policy = "never".`,
131
+ },
101
132
  ];
102
133
  export const ApprovalOutcome = {
103
134
  GRANTED: 'granted',
@@ -123,6 +154,23 @@ export function grantAutoApproval(io, where, grants = APPROVAL_GRANTS) {
123
154
  return { ...base, outcome: ApprovalOutcome.ABSENT };
124
155
  try {
125
156
  const existed = io.exists(file);
157
+ if (grant.editText !== undefined) {
158
+ const current = existed ? io.readFile(file) : '';
159
+ const next = grant.editText(current);
160
+ if (null === next) {
161
+ const warn = grant.manual?.(file);
162
+ return {
163
+ ...base,
164
+ outcome: ApprovalOutcome.DEFERRED,
165
+ ...(warn === undefined ? {} : { warn }),
166
+ };
167
+ }
168
+ if (next === current) {
169
+ return { ...base, outcome: ApprovalOutcome.ALREADY };
170
+ }
171
+ io.writeFile(file, next);
172
+ return { ...base, outcome: ApprovalOutcome.GRANTED };
173
+ }
126
174
  if (true === grant.supersedesInApp && !existed) {
127
175
  return {
128
176
  ...base,
@@ -13,15 +13,7 @@ declare const HandedOverSchema: z.ZodObject<{
13
13
  pid: z.ZodNumber;
14
14
  url: z.ZodString;
15
15
  appDir: z.ZodString;
16
- }, "strip", z.ZodTypeAny, {
17
- url: string;
18
- pid: number;
19
- appDir: string;
20
- }, {
21
- url: string;
22
- pid: number;
23
- appDir: string;
24
- }>;
16
+ }, z.core.$strip>;
25
17
  export type HandedOver = z.infer<typeof HandedOverSchema>;
26
18
  /**
27
19
  * Written when `init` leaves a server running, so the next `init` can attach to it.
@@ -52,7 +52,11 @@ export function judgeWait(facts) {
52
52
  */
53
53
  const CRA_PORT_BUSY = /Something is already running on port (\d+)/i;
54
54
  const NAMED_PORT_BUSY = /Port (\d+) is (?:already )?in use/i;
55
- const EADDRINUSE_PORT = /(?:EADDRINUSE|address already in use)[^\d]*(\d+)/i;
55
+ // Node prints `address already in use <address>:<port>`; the port sits after the last colon of the
56
+ // address, so the first digit can belong to the host (`0.0.0.0:3000` said port 0, #1846). The scan
57
+ // also stops at the line end: the stack frame under the error (`at Server (node:net:1817:16)`)
58
+ // carries digits of its own, and they are not the port.
59
+ const EADDRINUSE_PORT = /(?:EADDRINUSE|address already in use)[^\d\n]*(?:.*:)?(\d+)/i;
56
60
  export function portBusyMessage(output) {
57
61
  const match = CRA_PORT_BUSY.exec(output) ?? NAMED_PORT_BUSY.exec(output) ?? EADDRINUSE_PORT.exec(output);
58
62
  const port = match?.[1];
@@ -19,11 +19,11 @@
19
19
  * `bridge-port.ts`.
20
20
  */
21
21
  import { log } from '../../../log.js';
22
- import { isAlive, readPid, reticleStateHome, spawnDaemon } from '../../daemon/daemon.js';
22
+ import { isAlive, reticleStateHome, spawnDaemon } from '../../daemon/daemon.js';
23
23
  import { readDaemonRegistry } from '../../daemon/daemon-resolve.js';
24
24
  import { LOOPBACK_HOST, STATUS_HOLD_MS } from '@reticlehq/core';
25
25
  import { probePresence, presenceIsUsable } from '../../daemon/binding/port-presence.js';
26
- import { probeDaemon, waitForDaemonBind } from '../../../surface/mcp/mcp-proxy.js';
26
+ import { daemonProcessAlive, probeDaemon, waitForDaemonBind } from '../../../surface/mcp/mcp-proxy.js';
27
27
  import { daemonSpawnArgs, headlessByDefault } from '../../cli/daemon-start-options.js';
28
28
  import { fetchStatus, summarizeStatus } from '../../daemon/binding/daemon-status-probe.js';
29
29
  import { runKill } from '../../cli/cli-kill.js';
@@ -76,7 +76,7 @@ export async function ensureDaemon(port, deps) {
76
76
  message: `The Reticle daemon on port ${String(port)} is ${theirs}, which speaks a different wire ` +
77
77
  `contract than this init, so it will refuse your app — and ` +
78
78
  `${String(sessionCount)} session(s) are still using it, so init will not stop it. When ` +
79
- `they are done, run \`npx @reticlehq/server kill --port ${String(port)}\` and re-run init.`,
79
+ `they are done, run \`npx @reticlehq/server stop --force --port ${String(port)}\` and re-run init.`,
80
80
  };
81
81
  }
82
82
  if (!(await deps.replace(port)))
@@ -168,10 +168,7 @@ export function nodeEnsureDaemonDeps(skewed) {
168
168
  log('reticle_setup_daemon_started', { port, started });
169
169
  return started;
170
170
  },
171
- starting: (port) => {
172
- const pid = readPid(port);
173
- return null !== pid && isAlive(pid);
174
- },
171
+ starting: daemonProcessAlive,
175
172
  // The same wait `reticle restart` does: poll until `/status` answers as a daemon, bounded. A
176
173
  // cold daemon on a fresh HOME outlived the proxy's shorter reconnect budget this used to borrow.
177
174
  waitReady: async (port) => {
@@ -1,4 +1,6 @@
1
+ import { homedir } from 'node:os';
1
2
  import { spanSync } from '../../../trace.js';
3
+ import { hookBinFor } from '../../cli/hook/hook-fast.js';
2
4
  import { reportInitOutcome } from '../../../telemetry/init-telemetry.js';
3
5
  import { reportOnboardingStep } from '../../../telemetry/onboarding-funnel.js';
4
6
  import { defaultPairingTokenDir, readOrCreatePairingTokenSync, } from '../../../portal/bridge/pairing-token.js';
@@ -38,6 +40,10 @@ export function serverInitHost() {
38
40
  },
39
41
  // Claude Code marks every process it spawns. If the marker ever changes, init falls back to the
40
42
  // notice it printed before, which is the safe direction.
43
+ /** This CLI's own bin, so the agent hooks run it with node instead of paying npx's start. */
44
+ hookBin() {
45
+ return hookBinFor(homedir(), process.platform);
46
+ },
41
47
  insideClaudeCode() {
42
48
  return CLAUDE_CODE_MARKER_VALUE === process.env[CLAUDE_CODE_MARKER_ENV];
43
49
  },
@@ -58,11 +58,12 @@ dir) {
58
58
  // it recorded. Moving off it strands that agent: an MCP resolves its port once, at startup.
59
59
  if (true === deps.daemonStartedHere?.(RETICLE_DEFAULT_PORT))
60
60
  return undefined;
61
- // The bridge's own rule: it refuses a page only when it has served exactly ONE other project. A
62
- // daemon serving nobody, several projects, or ours accepts this one. A project that has never
63
- // been through init has no id yet, so a single named holder is somebody else.
61
+ // A daemon that serves other projects, one or several, is somebody else's: it is rooted in their
62
+ // directory and linked to their cloud project, even when its bridge would accept this page. A
63
+ // daemon serving nobody, or this project among others, is kept. A project that has never been
64
+ // through init has no id yet, so every named holder is somebody else.
64
65
  const holders = await deps.daemonProjects(RETICLE_DEFAULT_PORT);
65
- if (1 !== holders.length || holders[0] === projectId)
66
+ if (0 === holders.length || (projectId !== undefined && holders.includes(projectId)))
66
67
  return undefined;
67
68
  const seed = projectId ?? dir;
68
69
  return deps.pickPort(seed === undefined ? PROJECT_PORT_FIRST : projectPortFor(seed));
@@ -8,7 +8,7 @@
8
8
  import { existsSync, readFileSync, writeFileSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
10
  import { InitConfirmation, RETICLE_DEFAULT_PORT } from '@reticlehq/core';
11
- import { FEEDBACK_HINT, Framework, InitFailure } from '@reticlehq/init';
11
+ import { COMMUNITY_HINT, FEEDBACK_HINT, Framework, InitFailure, } from '@reticlehq/init';
12
12
  import { confirmInstall, nodeConfirmDeps } from '../terminal/confirm.js';
13
13
  import { writeLicenseKey } from '../license-key.js';
14
14
  import { registerOtherAgents, runSetupCommand, } from '../setup-command.js';
@@ -228,6 +228,8 @@ firstFlow) {
228
228
  return undefined === devCommand ? {} : { devCommand, devCommandIsStaticPage: true };
229
229
  })(),
230
230
  ...(undefined === parsed.url ? {} : { suppliedUrl: parsed.url }),
231
+ // So setup can tell which port the dev server will take, before it starts one (#1377).
232
+ framework: context.framework,
231
233
  }, (line) => io.print(line))
232
234
  .then(async (outcome) => {
233
235
  if (result.outcome !== undefined) {
@@ -247,6 +249,8 @@ firstFlow) {
247
249
  outcome.reachedPhase === SetupPhase.DEV_SERVER
248
250
  ? InitFailure.DEV_SERVER
249
251
  : InitFailure.APP_CONNECTION;
252
+ if (outcome.stop !== undefined)
253
+ init.stop = outcome.stop;
250
254
  }
251
255
  reportOnce(init);
252
256
  }
@@ -282,12 +286,14 @@ firstFlow) {
282
286
  io.print(` ${String(i + 1)}. ${step}`);
283
287
  // Already spaced by the blank line above when nothing was listed.
284
288
  ask(0 < outcome.fallback.length);
289
+ io.print(COMMUNITY_HINT);
285
290
  return;
286
291
  }
287
292
  if (outcome.ok) {
288
293
  io.print(`✓ setup complete — ${outcome.url ?? 'the app'} is instrumented and its first flow is ` +
289
294
  'saved. The tab stays open; a linked project sends the flow and its run to your dashboard.');
290
295
  ask();
296
+ io.print(COMMUNITY_HINT);
291
297
  return;
292
298
  }
293
299
  // A run that produced no verdict did not succeed, and the exit code is the one place a caller
@@ -13,6 +13,14 @@
13
13
  */
14
14
  import type { CandidateSession } from './session-pick.js';
15
15
  import type { PageProbe } from './probe/page-probe.js';
16
+ /**
17
+ * The state home when this process can write it, else the project's own `.reticle/logs`.
18
+ *
19
+ * A sandboxed agent host or a locked-down profile cannot write the state home. Init had already
20
+ * wired the project by then, so a log folder must not be the reason it stops. The caller prints the
21
+ * log path, so the fallback is never silent.
22
+ */
23
+ export declare function writableLogDir(preferred: string, projectDir: string): string;
16
24
  /** The dev server this process started, and the only one it will ever stop. */
17
25
  export declare class OwnedDevServer {
18
26
  private readonly logDir;
@@ -12,9 +12,10 @@
12
12
  * listening indefinitely.
13
13
  */
14
14
  import { spawn, spawnSync } from 'node:child_process';
15
- import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';
15
+ import { accessSync, constants as fsConstants, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from 'node:fs';
16
16
  import { join } from 'node:path';
17
17
  import { fileURLToPath } from 'node:url';
18
+ import { ReticleDir } from '@reticlehq/core';
18
19
  import { isAlive } from '../daemon/daemon.js';
19
20
  import { DEV_SERVER_LOG_CAP_BYTES, ROTATED_SUFFIX } from './bringup/dev-server-log-cap.js';
20
21
  import { devServerLogName, recordHandOver, sweepDeadDevServers, } from './bringup/dev-server-files.js';
@@ -29,6 +30,37 @@ const ASTRO_DEV_BACKGROUND_ENV = 'ASTRO_DEV_BACKGROUND';
29
30
  const PROBE_TIMEOUT_MS = 5_000;
30
31
  /** The supervisor that owns the server's output and keeps its log bounded. */
31
32
  const LOG_CAP_SCRIPT = fileURLToPath(new URL('./bringup/dev-server-log-cap.js', import.meta.url));
33
+ /** The error code of a `wx` write to a file that is already there. */
34
+ const EEXIST = 'EEXIST';
35
+ /**
36
+ * The state home when this process can write it, else the project's own `.reticle/logs`.
37
+ *
38
+ * A sandboxed agent host or a locked-down profile cannot write the state home. Init had already
39
+ * wired the project by then, so a log folder must not be the reason it stops. The caller prints the
40
+ * log path, so the fallback is never silent.
41
+ */
42
+ export function writableLogDir(preferred, projectDir) {
43
+ try {
44
+ mkdirSync(preferred, { recursive: true });
45
+ accessSync(preferred, fsConstants.W_OK);
46
+ return preferred;
47
+ }
48
+ catch {
49
+ const fallback = join(projectDir, ReticleDir.ROOT, ReticleDir.LOGS_SUBDIR);
50
+ mkdirSync(fallback, { recursive: true });
51
+ // Its own ignore file, because the workspace one may not be written yet on a first init. `wx`
52
+ // creates it only when it is absent, in one step, so a file that is already there is kept.
53
+ try {
54
+ writeFileSync(join(fallback, '.gitignore'), '*\n', { flag: 'wx' });
55
+ }
56
+ catch (error) {
57
+ if (error.code !== EEXIST) {
58
+ throw error;
59
+ }
60
+ }
61
+ return fallback;
62
+ }
63
+ }
32
64
  /** The dev server this process started, and the only one it will ever stop. */
33
65
  export class OwnedDevServer {
34
66
  logDir;
@@ -51,11 +83,11 @@ export class OwnedDevServer {
51
83
  * dev-server-log-cap.ts. It is the process group leader, so `pid()` and `stop()` cover both.
52
84
  */
53
85
  start(command, cwd, env) {
54
- mkdirSync(this.logDir, { recursive: true });
86
+ const logDir = writableLogDir(this.logDir, cwd);
55
87
  // Logs of servers that are gone, from every project, so the state home stops growing a file
56
88
  // per app ever started. This one's are replaced below anyway.
57
- sweepDeadDevServers(this.logDir, { alive: isAlive, now: Date.now(), keep: cwd });
58
- const log = join(this.logDir, devServerLogName(cwd));
89
+ sweepDeadDevServers(logDir, { alive: isAlive, now: Date.now(), keep: cwd });
90
+ const log = join(logDir, devServerLogName(cwd));
59
91
  // Unlinked rather than truncated: a previous server for this project may still hold the old
60
92
  // file open, and truncating under it would interleave its lines into this run's output.
61
93
  rmSync(log, { force: true });
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The port the dev server will take, when that is known: the one its script pins, else the
3
+ * framework's default unless the dev config names a port of its own. Undefined otherwise, and
4
+ * nothing is probed: a guessed port refusing a start would be a worse failure than this one.
5
+ */
6
+ export declare function expectedDevPort(facts: {
7
+ pinned?: number | undefined;
8
+ framework?: string | undefined;
9
+ devConfig?: string | undefined;
10
+ }): number | undefined;
11
+ /**
12
+ * The one loopback something answers on at `port` while the other is free, or undefined.
13
+ *
14
+ * Only that split is refused. A port busy on both loopbacks is one the dev server sees: Vite and
15
+ * Next move to the next port and print it, and setup reads that, as it always has. A second Vite
16
+ * app on 5173 is the common case, and stopping there would break a start that works. The dev server
17
+ * cannot see a listener on only one loopback, because it binds the other with no error, and then
18
+ * `localhost` and `127.0.0.1` serve two different apps.
19
+ */
20
+ export declare function loneLoopbackOnDevPort(port: number): Promise<string | undefined>;
21
+ /** What setup says instead of starting a dev server on the other half of a split port. */
22
+ export declare function splitDevPortNote(port: number, host: string): string;
23
+ /** The text of every dev config present in `appDir`, joined, or undefined when there is none. */
24
+ export declare function devConfigText(appDir: string): string | undefined;
25
+ /** The port the project's dev script pins (`--port`, `-p`, `PORT=`), or undefined. */
26
+ export declare function pinnedDevPort(appDir: string): number | undefined;