@phnx-labs/agents-cli 1.22.35 → 1.22.38

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 (500) hide show
  1. package/CHANGELOG.md +708 -2
  2. package/README.md +83 -43
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.d.ts +15 -0
  5. package/dist/bootstrap.js +1212 -0
  6. package/dist/commands/accounts.d.ts +4 -11
  7. package/dist/commands/accounts.js +159 -27
  8. package/dist/commands/artifacts-setup.d.ts +53 -0
  9. package/dist/commands/artifacts-setup.js +161 -0
  10. package/dist/commands/artifacts.d.ts +18 -0
  11. package/dist/commands/artifacts.js +58 -0
  12. package/dist/commands/attach.js +17 -4
  13. package/dist/commands/audit.d.ts +8 -8
  14. package/dist/commands/audit.js +57 -47
  15. package/dist/commands/browser.js +17 -11
  16. package/dist/commands/cloud.js +1 -1
  17. package/dist/commands/commands.js +0 -11
  18. package/dist/commands/computer-actions.js +33 -0
  19. package/dist/commands/computer-sessions-picker.d.ts +21 -0
  20. package/dist/commands/computer-sessions-picker.js +141 -0
  21. package/dist/commands/computer.d.ts +16 -0
  22. package/dist/commands/computer.js +37 -0
  23. package/dist/commands/config.d.ts +17 -0
  24. package/dist/commands/config.js +401 -0
  25. package/dist/commands/cp.d.ts +84 -0
  26. package/dist/commands/cp.js +231 -0
  27. package/dist/commands/daemon.js +243 -14
  28. package/dist/commands/detach-core.d.ts +1 -1
  29. package/dist/commands/detach-core.js +12 -2
  30. package/dist/commands/detach.js +1 -1
  31. package/dist/commands/doctor.js +64 -5
  32. package/dist/commands/events.d.ts +24 -12
  33. package/dist/commands/events.js +144 -28
  34. package/dist/commands/exec.js +86 -42
  35. package/dist/commands/feed.d.ts +1 -1
  36. package/dist/commands/feed.js +16 -8
  37. package/dist/commands/focus.d.ts +33 -1
  38. package/dist/commands/focus.js +177 -17
  39. package/dist/commands/funnel.d.ts +1 -1
  40. package/dist/commands/go.js +9 -8
  41. package/dist/commands/harness-wizard.d.ts +1 -0
  42. package/dist/commands/harness-wizard.js +18 -20
  43. package/dist/commands/harness.d.ts +2 -0
  44. package/dist/commands/harness.js +59 -26
  45. package/dist/commands/hooks.js +0 -11
  46. package/dist/commands/inspect.d.ts +94 -1
  47. package/dist/commands/inspect.js +866 -40
  48. package/dist/commands/lease.d.ts +4 -4
  49. package/dist/commands/lease.js +6 -6
  50. package/dist/commands/login.js +0 -13
  51. package/dist/commands/logs.d.ts +2 -2
  52. package/dist/commands/logs.js +2 -2
  53. package/dist/commands/mcp.js +7 -2
  54. package/dist/commands/memory.js +7 -2
  55. package/dist/commands/message.d.ts +1 -1
  56. package/dist/commands/message.js +37 -6
  57. package/dist/commands/models.js +71 -0
  58. package/dist/commands/monitors.d.ts +0 -1
  59. package/dist/commands/monitors.js +199 -16
  60. package/dist/commands/open.d.ts +18 -0
  61. package/dist/commands/open.js +57 -0
  62. package/dist/commands/packages.js +2 -107
  63. package/dist/commands/plugins.js +6 -3
  64. package/dist/commands/profiles.d.ts +1 -0
  65. package/dist/commands/profiles.js +16 -160
  66. package/dist/commands/projects.d.ts +28 -0
  67. package/dist/commands/projects.js +125 -5
  68. package/dist/commands/reconnect.js +9 -3
  69. package/dist/commands/repo.js +42 -1
  70. package/dist/commands/resource-view.d.ts +17 -0
  71. package/dist/commands/resource-view.js +36 -14
  72. package/dist/commands/resume.js +9 -2
  73. package/dist/commands/routines.d.ts +0 -2
  74. package/dist/commands/routines.js +473 -289
  75. package/dist/commands/secrets.js +52 -9
  76. package/dist/commands/sessions-export.d.ts +47 -0
  77. package/dist/commands/sessions-export.js +116 -6
  78. package/dist/commands/sessions-import.d.ts +17 -0
  79. package/dist/commands/sessions-import.js +114 -6
  80. package/dist/commands/sessions-migrate.d.ts +27 -0
  81. package/dist/commands/sessions-migrate.js +50 -9
  82. package/dist/commands/sessions-picker.js +23 -4
  83. package/dist/commands/sessions-resume.d.ts +5 -3
  84. package/dist/commands/sessions-resume.js +30 -8
  85. package/dist/commands/sessions-watch.d.ts +2 -0
  86. package/dist/commands/sessions-watch.js +53 -0
  87. package/dist/commands/sessions.d.ts +66 -3
  88. package/dist/commands/sessions.js +298 -47
  89. package/dist/commands/setup-browser.js +2 -2
  90. package/dist/commands/setup-mine.js +0 -1
  91. package/dist/commands/setup-preferences.js +1 -1
  92. package/dist/commands/setup.d.ts +5 -0
  93. package/dist/commands/setup.js +31 -5
  94. package/dist/commands/share.d.ts +87 -7
  95. package/dist/commands/share.js +320 -58
  96. package/dist/commands/skills.js +0 -11
  97. package/dist/commands/snapshot.js +1 -1
  98. package/dist/commands/ssh.d.ts +18 -0
  99. package/dist/commands/ssh.js +549 -210
  100. package/dist/commands/sync.d.ts +5 -0
  101. package/dist/commands/sync.js +212 -32
  102. package/dist/commands/teams.d.ts +13 -0
  103. package/dist/commands/teams.js +187 -30
  104. package/dist/commands/tickets.d.ts +2 -0
  105. package/dist/commands/tickets.js +43 -0
  106. package/dist/commands/update.js +2 -4
  107. package/dist/commands/usage.js +5 -3
  108. package/dist/commands/versions.js +11 -5
  109. package/dist/commands/view.js +15 -7
  110. package/dist/commands/webhook.d.ts +2 -2
  111. package/dist/commands/webhook.js +7 -7
  112. package/dist/index.d.ts +18 -2
  113. package/dist/index.js +53 -1264
  114. package/dist/lib/account-catalog.d.ts +18 -0
  115. package/dist/lib/account-catalog.js +38 -0
  116. package/dist/lib/account-provider-registry.d.ts +18 -0
  117. package/dist/lib/account-provider-registry.js +59 -0
  118. package/dist/lib/account-registry.d.ts +40 -0
  119. package/dist/lib/account-registry.js +239 -0
  120. package/dist/lib/account-schema.d.ts +44 -0
  121. package/dist/lib/account-schema.js +91 -0
  122. package/dist/lib/account-state-service.d.ts +21 -0
  123. package/dist/lib/account-state-service.js +60 -0
  124. package/dist/lib/activity.d.ts +1 -1
  125. package/dist/lib/activity.js +8 -1
  126. package/dist/lib/add-dir.d.ts +80 -0
  127. package/dist/lib/add-dir.js +241 -0
  128. package/dist/lib/agent-cli-commands.d.ts +11 -0
  129. package/dist/lib/agent-cli-commands.js +30 -0
  130. package/dist/lib/agents.js +44 -36
  131. package/dist/lib/answer-router.js +1 -1
  132. package/dist/lib/audit/log.d.ts +10 -27
  133. package/dist/lib/audit/log.js +20 -33
  134. package/dist/lib/auth-health.d.ts +9 -2
  135. package/dist/lib/auth-health.js +42 -9
  136. package/dist/lib/auto-pull-worker.js +7 -3
  137. package/dist/lib/auto-pull.d.ts +44 -3
  138. package/dist/lib/auto-pull.js +88 -5
  139. package/dist/lib/binary-shadow.d.ts +28 -0
  140. package/dist/lib/binary-shadow.js +121 -0
  141. package/dist/lib/brand.js +9 -3
  142. package/dist/lib/browser/hygiene.d.ts +90 -0
  143. package/dist/lib/browser/hygiene.js +146 -0
  144. package/dist/lib/browser/ipc.d.ts +30 -0
  145. package/dist/lib/browser/ipc.js +93 -4
  146. package/dist/lib/browser/profiles.d.ts +3 -2
  147. package/dist/lib/browser/profiles.js +65 -22
  148. package/dist/lib/browser/service.d.ts +79 -1
  149. package/dist/lib/browser/service.js +231 -14
  150. package/dist/lib/browser/sessions-list.d.ts +22 -2
  151. package/dist/lib/browser/sessions-list.js +54 -6
  152. package/dist/lib/browser/stream.d.ts +2 -0
  153. package/dist/lib/browser/stream.js +1 -0
  154. package/dist/lib/browser/types.d.ts +63 -1
  155. package/dist/lib/byok-usage.d.ts +9 -2
  156. package/dist/lib/byok-usage.js +133 -31
  157. package/dist/lib/cli-entry.d.ts +11 -0
  158. package/dist/lib/cli-entry.js +46 -0
  159. package/dist/lib/cloud/host.d.ts +1 -1
  160. package/dist/lib/cloud/host.js +2 -2
  161. package/dist/lib/cloud/registry.js +1 -1
  162. package/dist/lib/cloud/types.d.ts +1 -1
  163. package/dist/lib/commands.d.ts +2 -0
  164. package/dist/lib/commands.js +2 -0
  165. package/dist/lib/computer/sessions-list.d.ts +150 -0
  166. package/dist/lib/computer/sessions-list.js +363 -0
  167. package/dist/lib/config-keys.d.ts +86 -0
  168. package/dist/lib/config-keys.js +193 -0
  169. package/dist/lib/config-machine-keys.d.ts +12 -0
  170. package/dist/lib/config-machine-keys.js +17 -0
  171. package/dist/lib/config-transfer.js +3 -4
  172. package/dist/lib/crabbox/cli.d.ts +2 -2
  173. package/dist/lib/crabbox/cli.js +3 -3
  174. package/dist/lib/daemon-health.d.ts +22 -0
  175. package/dist/lib/daemon-health.js +33 -3
  176. package/dist/lib/daemon-services.d.ts +50 -0
  177. package/dist/lib/daemon-services.js +147 -0
  178. package/dist/lib/daemon-ticks.d.ts +35 -66
  179. package/dist/lib/daemon-ticks.js +77 -159
  180. package/dist/lib/daemon.d.ts +72 -4
  181. package/dist/lib/daemon.js +792 -202
  182. package/dist/lib/deeplink/register.d.ts +49 -0
  183. package/dist/lib/deeplink/register.js +253 -0
  184. package/dist/lib/deeplink/url.d.ts +34 -0
  185. package/dist/lib/deeplink/url.js +78 -0
  186. package/dist/lib/device-config.d.ts +124 -29
  187. package/dist/lib/device-config.js +346 -141
  188. package/dist/lib/devices/config-migration.d.ts +42 -0
  189. package/dist/lib/devices/config-migration.js +203 -0
  190. package/dist/lib/devices/connect.js +14 -7
  191. package/dist/lib/devices/doctor-findings.d.ts +4 -1
  192. package/dist/lib/devices/doctor-findings.js +20 -1
  193. package/dist/lib/devices/harness-inventory.d.ts +11 -2
  194. package/dist/lib/devices/harness-inventory.js +0 -0
  195. package/dist/lib/devices/health.d.ts +1 -1
  196. package/dist/lib/devices/health.js +1 -1
  197. package/dist/lib/devices/pending.d.ts +22 -1
  198. package/dist/lib/devices/pending.js +67 -2
  199. package/dist/lib/devices/registry.d.ts +0 -25
  200. package/dist/lib/devices/registry.js +2 -83
  201. package/dist/lib/devices/resolve-profile.d.ts +20 -0
  202. package/dist/lib/devices/resolve-profile.js +44 -0
  203. package/dist/lib/devices/rollout-verify.d.ts +101 -0
  204. package/dist/lib/devices/rollout-verify.js +193 -0
  205. package/dist/lib/devices/ssh-config.js +10 -6
  206. package/dist/lib/event-families.d.ts +28 -0
  207. package/dist/lib/event-families.js +159 -0
  208. package/dist/lib/event-stream.d.ts +9 -1
  209. package/dist/lib/event-stream.js +26 -9
  210. package/dist/lib/events.d.ts +9 -1
  211. package/dist/lib/events.js +21 -6
  212. package/dist/lib/exec.d.ts +30 -0
  213. package/dist/lib/exec.js +219 -121
  214. package/dist/lib/feed-broadcast.d.ts +25 -0
  215. package/dist/lib/feed-broadcast.js +33 -0
  216. package/dist/lib/feed.d.ts +1 -1
  217. package/dist/lib/feed.js +12 -2
  218. package/dist/lib/fleet/capture.js +15 -0
  219. package/dist/lib/fleet/manifest.js +9 -0
  220. package/dist/lib/fleet/types.d.ts +9 -0
  221. package/dist/lib/fleet-status.js +10 -8
  222. package/dist/lib/git.d.ts +21 -7
  223. package/dist/lib/git.js +122 -18
  224. package/dist/lib/hosts/dispatch.d.ts +8 -3
  225. package/dist/lib/hosts/dispatch.js +29 -3
  226. package/dist/lib/hosts/logs.d.ts +2 -2
  227. package/dist/lib/hosts/logs.js +2 -2
  228. package/dist/lib/hosts/option.js +1 -1
  229. package/dist/lib/hosts/passthrough.d.ts +2 -3
  230. package/dist/lib/hosts/passthrough.js +10 -24
  231. package/dist/lib/hosts/progress.js +2 -2
  232. package/dist/lib/hosts/providers/devices.d.ts +3 -3
  233. package/dist/lib/hosts/providers/devices.js +18 -12
  234. package/dist/lib/hosts/ready.d.ts +5 -1
  235. package/dist/lib/hosts/ready.js +9 -3
  236. package/dist/lib/hosts/reconcile.d.ts +2 -2
  237. package/dist/lib/hosts/reconcile.js +2 -2
  238. package/dist/lib/hosts/registry.js +14 -9
  239. package/dist/lib/hosts/remote-cmd.js +1 -1
  240. package/dist/lib/hosts/remote-os.d.ts +9 -6
  241. package/dist/lib/hosts/remote-os.js +13 -6
  242. package/dist/lib/hosts/routing-flag.d.ts +23 -0
  243. package/dist/lib/hosts/routing-flag.js +41 -0
  244. package/dist/lib/hosts/run-target.js +1 -1
  245. package/dist/lib/hosts/session-index.js +1 -1
  246. package/dist/lib/hosts/tasks.d.ts +6 -6
  247. package/dist/lib/hosts/tasks.js +4 -4
  248. package/dist/lib/hosts/types.js +1 -2
  249. package/dist/lib/installations/resolve.js +2 -8
  250. package/dist/lib/isolation-boundary-report.js +0 -1
  251. package/dist/lib/linear-cache.d.ts +7 -0
  252. package/dist/lib/linear-cache.js +31 -4
  253. package/dist/lib/linear-project-counts.d.ts +1 -1
  254. package/dist/lib/linear-project-counts.js +2 -3
  255. package/dist/lib/linear-projects.js +1 -1
  256. package/dist/lib/loop.d.ts +2 -2
  257. package/dist/lib/loop.js +1 -1
  258. package/dist/lib/mailbox-target.d.ts +1 -1
  259. package/dist/lib/mailbox-target.js +1 -1
  260. package/dist/lib/manifest.js +7 -4
  261. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  262. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  263. package/dist/lib/menubar/snapshot.d.ts +3 -2
  264. package/dist/lib/menubar/snapshot.js +6 -2
  265. package/dist/lib/migrate-fold.d.ts +33 -0
  266. package/dist/lib/migrate-fold.js +130 -0
  267. package/dist/lib/migrate.d.ts +34 -34
  268. package/dist/lib/migrate.js +106 -128
  269. package/dist/lib/model-tier-overrides.d.ts +1 -1
  270. package/dist/lib/model-tier-overrides.js +15 -2
  271. package/dist/lib/monitors/config.d.ts +17 -3
  272. package/dist/lib/monitors/config.js +52 -18
  273. package/dist/lib/monitors/engine.d.ts +32 -1
  274. package/dist/lib/monitors/engine.js +94 -11
  275. package/dist/lib/monitors/fingerprint.d.ts +46 -0
  276. package/dist/lib/monitors/fingerprint.js +100 -0
  277. package/dist/lib/monitors/remote.d.ts +47 -0
  278. package/dist/lib/monitors/remote.js +81 -0
  279. package/dist/lib/monitors/state.d.ts +39 -0
  280. package/dist/lib/monitors/state.js +56 -0
  281. package/dist/lib/onepassword.d.ts +17 -0
  282. package/dist/lib/onepassword.js +52 -22
  283. package/dist/lib/open-url.js +1 -1
  284. package/dist/lib/picker.d.ts +14 -2
  285. package/dist/lib/picker.js +35 -13
  286. package/dist/lib/placement.d.ts +1 -1
  287. package/dist/lib/placement.js +1 -1
  288. package/dist/lib/pr-land-detach.d.ts +32 -0
  289. package/dist/lib/pr-land-detach.js +79 -0
  290. package/dist/lib/profiles-presets.js +13 -0
  291. package/dist/lib/profiles.d.ts +2 -0
  292. package/dist/lib/profiles.js +44 -1
  293. package/dist/lib/project-focus.d.ts +1 -1
  294. package/dist/lib/project-focus.js +1 -1
  295. package/dist/lib/project-probe.d.ts +4 -1
  296. package/dist/lib/project-probe.js +5 -4
  297. package/dist/lib/project-resources.js +2 -18
  298. package/dist/lib/project-root.d.ts +16 -0
  299. package/dist/lib/project-root.js +20 -2
  300. package/dist/lib/projects.d.ts +20 -1
  301. package/dist/lib/projects.js +78 -1
  302. package/dist/lib/refresh-coordinator.d.ts +24 -0
  303. package/dist/lib/refresh-coordinator.js +52 -0
  304. package/dist/lib/registry.d.ts +2 -2
  305. package/dist/lib/registry.js +1 -1
  306. package/dist/lib/resource-aliases.d.ts +13 -0
  307. package/dist/lib/resource-aliases.js +26 -0
  308. package/dist/lib/resources/types.d.ts +1 -1
  309. package/dist/lib/resources.d.ts +16 -0
  310. package/dist/lib/resources.js +66 -10
  311. package/dist/lib/rotate.d.ts +3 -4
  312. package/dist/lib/rotate.js +4 -5
  313. package/dist/lib/routine-activation.d.ts +22 -2
  314. package/dist/lib/routine-activation.js +63 -16
  315. package/dist/lib/routine-context.d.ts +9 -2
  316. package/dist/lib/routine-context.js +21 -6
  317. package/dist/lib/routines-project.d.ts +58 -48
  318. package/dist/lib/routines-project.js +190 -159
  319. package/dist/lib/routines.d.ts +44 -7
  320. package/dist/lib/routines.js +92 -34
  321. package/dist/lib/run-defaults.d.ts +5 -0
  322. package/dist/lib/run-defaults.js +11 -1
  323. package/dist/lib/runner.d.ts +10 -8
  324. package/dist/lib/runner.js +122 -39
  325. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  326. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  327. package/dist/lib/secrets/agent.d.ts +10 -3
  328. package/dist/lib/secrets/agent.js +43 -8
  329. package/dist/lib/secrets/bundles.d.ts +1 -0
  330. package/dist/lib/secrets/bundles.js +92 -80
  331. package/dist/lib/secrets/index.js +32 -9
  332. package/dist/lib/secrets/install-helper.d.ts +4 -4
  333. package/dist/lib/secrets/install-helper.js +4 -4
  334. package/dist/lib/secrets/push.d.ts +40 -6
  335. package/dist/lib/secrets/push.js +58 -11
  336. package/dist/lib/secrets/read-backoff.d.ts +1 -1
  337. package/dist/lib/secrets/read-backoff.js +1 -1
  338. package/dist/lib/secrets/remote.d.ts +24 -0
  339. package/dist/lib/secrets/remote.js +54 -4
  340. package/dist/lib/self-update.d.ts +108 -0
  341. package/dist/lib/self-update.js +276 -1
  342. package/dist/lib/session/active.d.ts +89 -5
  343. package/dist/lib/session/active.js +165 -10
  344. package/dist/lib/session/actor-sidecar.d.ts +1 -1
  345. package/dist/lib/session/actor-sidecar.js +2 -1
  346. package/dist/lib/session/db.d.ts +176 -2
  347. package/dist/lib/session/db.js +484 -17
  348. package/dist/lib/session/discover.js +27 -4
  349. package/dist/lib/session/hook-sessions.js +2 -2
  350. package/dist/lib/session/host-link.d.ts +2 -2
  351. package/dist/lib/session/host-link.js +2 -2
  352. package/dist/lib/session/pid-registry.d.ts +21 -0
  353. package/dist/lib/session/pid-registry.js +57 -0
  354. package/dist/lib/session/remote-active.js +15 -1
  355. package/dist/lib/session/remote.js +2 -2
  356. package/dist/lib/session/session-cache.d.ts +14 -7
  357. package/dist/lib/session/session-cache.js +51 -9
  358. package/dist/lib/session/state.d.ts +2 -2
  359. package/dist/lib/session/state.js +1 -1
  360. package/dist/lib/session/sync/config.d.ts +10 -10
  361. package/dist/lib/session/sync/config.js +10 -10
  362. package/dist/lib/session/sync/r2.d.ts +34 -0
  363. package/dist/lib/session/sync/r2.js +123 -0
  364. package/dist/lib/session/throughput.d.ts +1 -1
  365. package/dist/lib/session/throughput.js +1 -1
  366. package/dist/lib/session/types.d.ts +23 -1
  367. package/dist/lib/session/types.js +15 -0
  368. package/dist/lib/session/viewing-in.d.ts +1 -1
  369. package/dist/lib/session/viewing-in.js +1 -1
  370. package/dist/lib/session/watch.d.ts +101 -0
  371. package/dist/lib/session/watch.js +242 -0
  372. package/dist/lib/share/analytics.js +1 -1
  373. package/dist/lib/share/capture.d.ts +1 -1
  374. package/dist/lib/share/capture.js +3 -3
  375. package/dist/lib/share/config.d.ts +6 -2
  376. package/dist/lib/share/config.js +6 -5
  377. package/dist/lib/share/delete.js +3 -3
  378. package/dist/lib/share/provision.d.ts +38 -0
  379. package/dist/lib/share/provision.js +51 -1
  380. package/dist/lib/share/publish.d.ts +40 -1
  381. package/dist/lib/share/publish.js +119 -6
  382. package/dist/lib/share/worker-template.d.ts +12 -1
  383. package/dist/lib/share/worker-template.js +83 -7
  384. package/dist/lib/shims.d.ts +17 -3
  385. package/dist/lib/shims.js +98 -26
  386. package/dist/lib/signin-badge.js +3 -2
  387. package/dist/lib/skills.js +2 -0
  388. package/dist/lib/smart-launch.d.ts +8 -8
  389. package/dist/lib/smart-launch.js +80 -59
  390. package/dist/lib/ssh-exec.d.ts +1 -1
  391. package/dist/lib/ssh-exec.js +1 -1
  392. package/dist/lib/staleness/prune.d.ts +88 -0
  393. package/dist/lib/staleness/prune.js +69 -0
  394. package/dist/lib/staleness/registry.d.ts +1 -1
  395. package/dist/lib/staleness/writers/commands.js +34 -2
  396. package/dist/lib/staleness/writers/hooks.js +16 -0
  397. package/dist/lib/staleness/writers/kinds.d.ts +6 -0
  398. package/dist/lib/staleness/writers/skills.js +19 -0
  399. package/dist/lib/staleness/writers/subagents.d.ts +2 -3
  400. package/dist/lib/staleness/writers/subagents.js +0 -4
  401. package/dist/lib/staleness/writers/types.d.ts +32 -0
  402. package/dist/lib/startup/command-registry.d.ts +16 -14
  403. package/dist/lib/startup/command-registry.js +26 -37
  404. package/dist/lib/startup/dev-build.d.ts +10 -0
  405. package/dist/lib/startup/dev-build.js +13 -1
  406. package/dist/lib/startup/spellcheck.d.ts +18 -0
  407. package/dist/lib/startup/spellcheck.js +45 -0
  408. package/dist/lib/state.d.ts +36 -9
  409. package/dist/lib/state.js +96 -46
  410. package/dist/lib/subagents-registry.d.ts +0 -7
  411. package/dist/lib/subagents-registry.js +38 -65
  412. package/dist/lib/subagents.d.ts +0 -33
  413. package/dist/lib/subagents.js +0 -75
  414. package/dist/lib/sync-umbrella.js +1 -1
  415. package/dist/lib/teams/agents.d.ts +41 -1
  416. package/dist/lib/teams/agents.js +187 -9
  417. package/dist/lib/teams/api.d.ts +11 -1
  418. package/dist/lib/teams/api.js +11 -2
  419. package/dist/lib/teams/delivery.d.ts +41 -0
  420. package/dist/lib/teams/delivery.js +60 -0
  421. package/dist/lib/teams/registry.d.ts +14 -0
  422. package/dist/lib/teams/registry.js +51 -1
  423. package/dist/lib/teams/remoteWorktree.d.ts +19 -0
  424. package/dist/lib/teams/remoteWorktree.js +29 -0
  425. package/dist/lib/teams/scheduler.d.ts +1 -1
  426. package/dist/lib/teams/scheduler.js +1 -1
  427. package/dist/lib/teams/worktree.d.ts +24 -0
  428. package/dist/lib/teams/worktree.js +42 -0
  429. package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
  430. package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
  431. package/dist/lib/terminal/engine.d.ts +4 -0
  432. package/dist/lib/terminal/engine.js +8 -2
  433. package/dist/lib/terminal/types.d.ts +21 -2
  434. package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
  435. package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
  436. package/dist/lib/tickets/list.d.ts +53 -0
  437. package/dist/lib/tickets/list.js +153 -0
  438. package/dist/lib/tmux/orphan-reap.d.ts +316 -0
  439. package/dist/lib/tmux/orphan-reap.js +638 -0
  440. package/dist/lib/tmux/session.d.ts +68 -3
  441. package/dist/lib/tmux/session.js +96 -5
  442. package/dist/lib/triggers/handlers.d.ts +20 -0
  443. package/dist/lib/triggers/handlers.js +16 -1
  444. package/dist/lib/triggers/webhook.js +10 -0
  445. package/dist/lib/types.d.ts +47 -35
  446. package/dist/lib/usage-fleet.d.ts +32 -0
  447. package/dist/lib/usage-fleet.js +125 -0
  448. package/dist/lib/usage-refresh.d.ts +3 -3
  449. package/dist/lib/usage-refresh.js +19 -16
  450. package/dist/lib/usage.d.ts +51 -47
  451. package/dist/lib/usage.js +145 -153
  452. package/dist/lib/version-duplicates.js +2 -2
  453. package/dist/lib/versions.d.ts +56 -13
  454. package/dist/lib/versions.js +195 -45
  455. package/dist/lib/watchdog/log.d.ts +1 -1
  456. package/dist/lib/watchdog/log.js +3 -3
  457. package/dist/lib/watchdog/rotate.d.ts +6 -6
  458. package/dist/lib/watchdog/rotate.js +6 -6
  459. package/dist/lib/workflows.d.ts +1 -1
  460. package/dist/lib/yaml-io.d.ts +47 -0
  461. package/dist/lib/yaml-io.js +55 -0
  462. package/package.json +2 -1
  463. package/scripts/install-helper.js +2 -2
  464. package/scripts/postinstall.js +23 -20
  465. package/dist/commands/defaults.d.ts +0 -7
  466. package/dist/commands/defaults.js +0 -107
  467. package/dist/commands/export.d.ts +0 -11
  468. package/dist/commands/export.js +0 -215
  469. package/dist/commands/helper.d.ts +0 -12
  470. package/dist/commands/helper.js +0 -87
  471. package/dist/commands/hosts.d.ts +0 -11
  472. package/dist/commands/hosts.js +0 -330
  473. package/dist/commands/lock.d.ts +0 -12
  474. package/dist/commands/lock.js +0 -70
  475. package/dist/commands/pull.d.ts +0 -17
  476. package/dist/commands/pull.js +0 -39
  477. package/dist/commands/push.d.ts +0 -14
  478. package/dist/commands/push.js +0 -30
  479. package/dist/commands/set.d.ts +0 -15
  480. package/dist/commands/set.js +0 -79
  481. package/dist/commands/setup-share.d.ts +0 -17
  482. package/dist/commands/setup-share.js +0 -85
  483. package/dist/commands/wallet.d.ts +0 -20
  484. package/dist/commands/wallet.js +0 -216
  485. package/dist/commands/worktree.d.ts +0 -19
  486. package/dist/commands/worktree.js +0 -272
  487. package/dist/lib/account-labels.d.ts +0 -24
  488. package/dist/lib/account-labels.js +0 -72
  489. package/dist/lib/auto-dispatch-linear.d.ts +0 -18
  490. package/dist/lib/auto-dispatch-linear.js +0 -107
  491. package/dist/lib/auto-dispatch-provider.d.ts +0 -10
  492. package/dist/lib/auto-dispatch-provider.js +0 -30
  493. package/dist/lib/auto-dispatch.d.ts +0 -93
  494. package/dist/lib/auto-dispatch.js +0 -128
  495. package/dist/lib/export.d.ts +0 -72
  496. package/dist/lib/export.js +0 -269
  497. package/dist/lib/lock.d.ts +0 -93
  498. package/dist/lib/lock.js +0 -207
  499. package/dist/lib/wallet/index.d.ts +0 -78
  500. package/dist/lib/wallet/index.js +0 -253
@@ -13,12 +13,30 @@
13
13
  */
14
14
  import { listMonitors, monitorRunsOnThisDevice, parseInterval, setMonitorEnabled, } from './config.js';
15
15
  import { evaluateSource } from './sources/index.js';
16
- import { hasChanged, readState, writeState, recordFireTime, writeFireRecord, } from './state.js';
16
+ import { hasChanged, readState, writeState, recordFireTime, writeFireRecord, recordCheck, markDroughtNotified, } from './state.js';
17
17
  import { dispatchAction } from './dispatch.js';
18
+ import { sendToOwner } from '../notify.js';
18
19
  /** How often the engine wakes to check which monitors are due. */
19
20
  const TICK_MS = 5_000;
20
21
  /** Default evaluation cadence for sources that carry no explicit interval. */
21
22
  const DEFAULT_INTERVAL_MS = 60_000;
23
+ /**
24
+ * Consecutive failed polls before the engine escalates a drought to the owner.
25
+ * A monitor that looks healthy (enabled, daemon up) but whose source errors
26
+ * every poll does no real work — the "every signal reads healthy while zero work
27
+ * happened" failure RUSH-2485 is about. One notification per drought.
28
+ */
29
+ const DROUGHT_THRESHOLD = 5;
30
+ /** Poll-model source types the engine actually evaluates on a cadence; ws/webhook are push-only and inert here. */
31
+ export const POLL_SOURCE_TYPES = new Set(['command', 'poll', 'poll-http', 'file', 'device']);
32
+ /**
33
+ * Whether a monitor's liveness has crossed into a drought worth notifying the
34
+ * owner about: enough consecutive failed checks, and not already notified for
35
+ * this drought. Pure so the branch is unit-testable without a real notify.
36
+ */
37
+ export function shouldEscalateDrought(liveness) {
38
+ return liveness.consecutiveErrors >= DROUGHT_THRESHOLD && !liveness.droughtNotifiedAt;
39
+ }
22
40
  function truncateSummary(text) {
23
41
  const oneLine = text.replace(/\s+/g, ' ').trim();
24
42
  return oneLine.length > 240 ? oneLine.slice(0, 240) + '…' : oneLine;
@@ -36,6 +54,15 @@ export function decideFire(monitor, observation) {
36
54
  const payload = observation.meta ?? {};
37
55
  const dedupeKey = cond.dedupeKey;
38
56
  if (cond.mode === 'every') {
57
+ // Fire on every tick that carries a real observation. An empty (or
58
+ // whitespace-only) observation means "nothing to report": firing an action
59
+ // with an empty {event} is never useful, and skipping it lets a poll whose
60
+ // command yields no rows (e.g. no mergeable PR) stay silent while still
61
+ // re-firing every tick the set is non-empty — the retry semantics a
62
+ // silently-failed action dispatch needs (RUSH-2488).
63
+ if (raw.trim() === '') {
64
+ return { fire: false, value: raw, dedupeKey, persist: false, event: null };
65
+ }
39
66
  return {
40
67
  fire: true,
41
68
  value: raw,
@@ -145,21 +172,74 @@ export class MonitorEngine {
145
172
  this.ticking = false;
146
173
  }
147
174
  }
175
+ /**
176
+ * Evaluate one monitor once and record the outcome. Public so the daemon tick
177
+ * and tests drive the exact same path. A "failed check" is an evaluation that
178
+ * produced no observation, threw, OR fired an action that failed — all three
179
+ * are "the monitor ran and accomplished nothing", the drought signal. A poll
180
+ * that observes and either fires cleanly or matches nothing is a success and
181
+ * resets the streak.
182
+ */
148
183
  async runMonitor(monitor) {
184
+ // Push-only sources (ws/webhook) deliver through subscribe, not this loop —
185
+ // they return null from evaluate by design, so they have no poll to record.
186
+ const isPollSource = POLL_SOURCE_TYPES.has(monitor.source.type);
187
+ if (!isPollSource)
188
+ return;
189
+ const checkedAt = new Date().toISOString();
190
+ let checkError;
149
191
  try {
150
- const { observation, decision } = await evaluateMonitorOnce(monitor);
151
- if (!observation || !decision)
152
- return;
153
- if (decision.fire && decision.event) {
154
- await this.fire(monitor, decision, decision.event);
192
+ const observation = await evaluateSource(monitor.source);
193
+ if (!observation) {
194
+ checkError = 'source produced no observation';
155
195
  }
156
- else if (decision.persist) {
157
- // Silent baseline / no-change: record the value so we don't re-fire.
158
- writeState(monitor.name, decision.value, decision.dedupeKey);
196
+ else {
197
+ const decision = decideFire(monitor, observation);
198
+ if (decision.fire && decision.event) {
199
+ const result = await this.fire(monitor, decision, decision.event);
200
+ if (!result.ok)
201
+ checkError = `action ${result.kind} failed: ${result.error ?? 'unknown'}`;
202
+ }
203
+ else if (decision.persist) {
204
+ // Silent baseline / no-change: record the value so we don't re-fire.
205
+ writeState(monitor.name, decision.value, decision.dedupeKey);
206
+ }
159
207
  }
160
208
  }
161
209
  catch (err) {
162
- this.logFn('ERROR', `monitor '${monitor.name}' evaluation failed: ${err.message}`);
210
+ checkError = err.message;
211
+ this.logFn('ERROR', `monitor '${monitor.name}' evaluation failed: ${checkError}`);
212
+ }
213
+ this.afterCheck(monitor, checkedAt, checkError);
214
+ }
215
+ /**
216
+ * Record the poll heartbeat and, on a sustained failure streak, escalate a
217
+ * drought to the owner exactly once. The heartbeat is what makes a
218
+ * polling-but-not-matching monitor visibly distinct from one the engine never
219
+ * touched (RUSH-2485); the streak is what turns "every poll fails and the owner
220
+ * never hears about it" into one notification.
221
+ */
222
+ afterCheck(monitor, checkedAt, error) {
223
+ const liveness = recordCheck(monitor.name, checkedAt, error);
224
+ if (error && shouldEscalateDrought(liveness)) {
225
+ void this.escalateDrought(monitor, liveness.consecutiveErrors, error);
226
+ }
227
+ }
228
+ /** Notify the owner that an enabled monitor has failed N checks in a row and done nothing. */
229
+ async escalateDrought(monitor, consecutiveErrors, error) {
230
+ const at = new Date().toISOString();
231
+ // Stamp the marker BEFORE the send so a slow/failing notify can't re-fire the
232
+ // drought on the next tick; recordCheck clears it on the first good check.
233
+ markDroughtNotified(monitor.name, at);
234
+ const text = `Monitor '${monitor.name}' has failed ${consecutiveErrors} checks in a row and accomplished nothing. ` +
235
+ `Last error: ${error}`;
236
+ try {
237
+ const result = await sendToOwner(text);
238
+ this.logFn(result.ok ? 'WARN' : 'ERROR', `monitor '${monitor.name}' drought (${consecutiveErrors} failed checks) → notify owner` +
239
+ (result.ok ? '' : ` FAILED: ${result.error}`));
240
+ }
241
+ catch (err) {
242
+ this.logFn('ERROR', `monitor '${monitor.name}' drought notify threw: ${err.message}`);
163
243
  }
164
244
  }
165
245
  async fire(monitor, decision, event) {
@@ -181,7 +261,9 @@ export class MonitorEngine {
181
261
  catch { /* best-effort pause */ }
182
262
  this.logFn('WARN', `monitor '${monitor.name}' exceeded rate limit (${monitor.rateLimit.max}/${monitor.rateLimit.per}) — auto-paused`);
183
263
  this.loadAll();
184
- return;
264
+ // An auto-pause is a deliberate stop, not a failed action — don't let it
265
+ // feed the drought streak (the monitor is now disabled anyway).
266
+ return { kind: monitor.action.type, ok: true };
185
267
  }
186
268
  }
187
269
  let result;
@@ -201,5 +283,6 @@ export class MonitorEngine {
201
283
  this.logFn(result.ok ? 'INFO' : 'ERROR', `monitor '${monitor.name}' fired → ${result.kind}` +
202
284
  (result.runId ? ` (run: ${result.runId})` : '') +
203
285
  (result.ok ? '' : ` FAILED: ${result.error}`));
286
+ return result;
204
287
  }
205
288
  }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Semantic identity of a monitor — "are these two definitions the same watcher?"
3
+ *
4
+ * A monitor's NAME is not its identity. Two monitors can poll the same command
5
+ * on the same interval and fire the same action under two different names, and
6
+ * nothing today notices: `writeMonitor` overwrites by name and never compares
7
+ * arguments. Observed on one box: `open-pr-watch`, `pr-ci-fail`, three stale
8
+ * `pr2222-*` watchers, and an agent-added lander, all polling
9
+ * `gh pr list ... phnx-labs/agents-cli` — four overlapping triggers on one PR
10
+ * queue, added without a single warning.
11
+ *
12
+ * That is the double-trigger bug class. The fingerprint is what lets `add`
13
+ * refuse it.
14
+ *
15
+ * WHAT IS HASHED: only fields that change what the monitor DOES — the source it
16
+ * watches, how often, the condition that fires, and the action it takes. Name,
17
+ * description, and `enabled` are deliberately excluded, because a duplicate
18
+ * under a new name is exactly the case being caught, and a paused duplicate is
19
+ * still a duplicate the moment someone resumes it.
20
+ *
21
+ * WHAT IS NOT HASHED: `device`/`devices`/`runOn`. Placement is who executes, not
22
+ * what runs — and two boxes deliberately owning the same watcher is a different
23
+ * decision (see `monitorRunsOnThisDevice`). Including placement would let the
24
+ * same watcher be added N times by varying only the owner, which is the very
25
+ * duplication this guards.
26
+ */
27
+ import type { MonitorConfig } from './config.js';
28
+ /**
29
+ * The behavioral identity of a monitor, as a short hex digest. Two monitors with
30
+ * the same fingerprint watch the same thing and do the same thing on fire —
31
+ * whatever they are called and wherever they are pinned.
32
+ *
33
+ * Pure: no I/O, so the duplicate check is unit-tested without a monitors dir.
34
+ */
35
+ export declare function monitorFingerprint(config: Pick<MonitorConfig, 'source' | 'condition' | 'action'>): string;
36
+ /**
37
+ * The already-existing monitor that this config would duplicate, or null.
38
+ *
39
+ * `existing` is the full monitor set (user + system layers), so a user monitor
40
+ * duplicating a shipped built-in is caught too. A monitor never collides with
41
+ * itself: a same-NAME entry is a rewrite of that monitor, which `add` reports
42
+ * separately and more precisely than "duplicate".
43
+ *
44
+ * Pure — the caller supplies the list.
45
+ */
46
+ export declare function findDuplicateMonitor(config: Pick<MonitorConfig, 'name' | 'source' | 'condition' | 'action'>, existing: Array<Pick<MonitorConfig, 'name' | 'source' | 'condition' | 'action'>>): string | null;
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Semantic identity of a monitor — "are these two definitions the same watcher?"
3
+ *
4
+ * A monitor's NAME is not its identity. Two monitors can poll the same command
5
+ * on the same interval and fire the same action under two different names, and
6
+ * nothing today notices: `writeMonitor` overwrites by name and never compares
7
+ * arguments. Observed on one box: `open-pr-watch`, `pr-ci-fail`, three stale
8
+ * `pr2222-*` watchers, and an agent-added lander, all polling
9
+ * `gh pr list ... phnx-labs/agents-cli` — four overlapping triggers on one PR
10
+ * queue, added without a single warning.
11
+ *
12
+ * That is the double-trigger bug class. The fingerprint is what lets `add`
13
+ * refuse it.
14
+ *
15
+ * WHAT IS HASHED: only fields that change what the monitor DOES — the source it
16
+ * watches, how often, the condition that fires, and the action it takes. Name,
17
+ * description, and `enabled` are deliberately excluded, because a duplicate
18
+ * under a new name is exactly the case being caught, and a paused duplicate is
19
+ * still a duplicate the moment someone resumes it.
20
+ *
21
+ * WHAT IS NOT HASHED: `device`/`devices`/`runOn`. Placement is who executes, not
22
+ * what runs — and two boxes deliberately owning the same watcher is a different
23
+ * decision (see `monitorRunsOnThisDevice`). Including placement would let the
24
+ * same watcher be added N times by varying only the owner, which is the very
25
+ * duplication this guards.
26
+ */
27
+ import { createHash } from 'crypto';
28
+ /**
29
+ * Stable JSON: object keys sorted, so key order in the YAML cannot change the hash.
30
+ *
31
+ * Cycle-safe by construction. A monitor can arrive from arbitrary YAML
32
+ * (`agents monitors add ./watcher.yml`), and a recursive anchor produces a
33
+ * genuinely cyclic object that `validateMonitor` accepts — it checks named
34
+ * fields, while this walks the whole graph. Without the seen-set the recursion
35
+ * blew the stack before `JSON.stringify` could raise its own circular-structure
36
+ * error, turning a bad input into a stack trace instead of a clear refusal.
37
+ *
38
+ * A `Date` is serialized to its ISO string rather than falling into the object
39
+ * branch, where every Date collapsed to `{}` and two different timestamps
40
+ * fingerprinted identically.
41
+ */
42
+ function stable(value, seen = new WeakSet()) {
43
+ if (value instanceof Date)
44
+ return value.toISOString();
45
+ if (Array.isArray(value)) {
46
+ if (seen.has(value))
47
+ return '[circular]';
48
+ seen.add(value);
49
+ return value.map((v) => stable(v, seen));
50
+ }
51
+ if (value && typeof value === 'object') {
52
+ if (seen.has(value))
53
+ return '[circular]';
54
+ seen.add(value);
55
+ const out = {};
56
+ for (const key of Object.keys(value).sort()) {
57
+ const v = value[key];
58
+ if (v === undefined)
59
+ continue;
60
+ out[key] = stable(v, seen);
61
+ }
62
+ return out;
63
+ }
64
+ return value;
65
+ }
66
+ /**
67
+ * The behavioral identity of a monitor, as a short hex digest. Two monitors with
68
+ * the same fingerprint watch the same thing and do the same thing on fire —
69
+ * whatever they are called and wherever they are pinned.
70
+ *
71
+ * Pure: no I/O, so the duplicate check is unit-tested without a monitors dir.
72
+ */
73
+ export function monitorFingerprint(config) {
74
+ const identity = stable({
75
+ source: config.source,
76
+ condition: config.condition,
77
+ action: config.action,
78
+ });
79
+ return createHash('sha256').update(JSON.stringify(identity)).digest('hex').slice(0, 16);
80
+ }
81
+ /**
82
+ * The already-existing monitor that this config would duplicate, or null.
83
+ *
84
+ * `existing` is the full monitor set (user + system layers), so a user monitor
85
+ * duplicating a shipped built-in is caught too. A monitor never collides with
86
+ * itself: a same-NAME entry is a rewrite of that monitor, which `add` reports
87
+ * separately and more precisely than "duplicate".
88
+ *
89
+ * Pure — the caller supplies the list.
90
+ */
91
+ export function findDuplicateMonitor(config, existing) {
92
+ const fp = monitorFingerprint(config);
93
+ for (const other of existing) {
94
+ if (other.name === config.name)
95
+ continue;
96
+ if (monitorFingerprint(other) === fp)
97
+ return other.name;
98
+ }
99
+ return null;
100
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Fleet-wide monitor lookup — "is any box already watching this?"
3
+ *
4
+ * A monitor's identity is its ARGUMENTS, not its name or its device. Agents
5
+ * create monitors per work item, so the same shape runs many times over with
6
+ * different arguments (PR #2517 vs #2600) and those must all coexist. The case
7
+ * that must NOT happen is two agents, on two different machines, creating a
8
+ * watcher with the SAME arguments — one work item, two triggers.
9
+ *
10
+ * A local-only check cannot see that: each box reads its own `monitors/` dir and
11
+ * neither sees the other. So the duplicate guard asks the fleet, reusing the
12
+ * same cross-machine fan-out `sessions --active` and `fleet status` already run
13
+ * (`lib/remote-agents-json.ts`).
14
+ *
15
+ * Deliberately NOT solved by syncing `monitors/*.yml` through the DotAgents repo:
16
+ * an agent's per-PR watcher is running state, not config, and syncing would push
17
+ * every one of them onto every box — the accumulation this guard exists to stop.
18
+ */
19
+ import type { MonitorConfig } from './config.js';
20
+ /** Recursion guard: a peer answering the fan-out must not fan out again. */
21
+ export declare const NO_MONITOR_FANOUT_ENV = "AGENTS_MONITORS_LOCAL";
22
+ /** One monitor as seen on a peer, tagged with the box it lives on. */
23
+ export interface RemoteMonitor {
24
+ machine: string;
25
+ monitor: Pick<MonitorConfig, 'name' | 'source' | 'condition' | 'action'>;
26
+ }
27
+ /**
28
+ * Parse a peer's `monitors list --json`. Defensive against version skew: a peer
29
+ * on an older CLI may emit a different shape or no JSON at all, and one bad peer
30
+ * must never blank the guard for the rest of the fleet.
31
+ */
32
+ export declare function parseRemoteMonitors(stdout: string, machine: string): RemoteMonitor[];
33
+ export interface FleetMonitorsResult {
34
+ monitors: RemoteMonitor[];
35
+ /** Target discovery failed before any peer was dialed — the fleet was not
36
+ * consulted at all, which must not read as "no duplicate anywhere". */
37
+ discoveryFailed: boolean;
38
+ /** Peers dialed but unreachable / erroring — the guard reports these rather than
39
+ * silently treating "we could not ask" as "there is no duplicate". */
40
+ skipped: string[];
41
+ }
42
+ /**
43
+ * Every monitor on every other registered device. Never throws: an unreachable
44
+ * fleet degrades to an empty list plus the names we could not consult, and the
45
+ * caller decides what to say about them.
46
+ */
47
+ export declare function gatherFleetMonitors(): Promise<FleetMonitorsResult>;
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Fleet-wide monitor lookup — "is any box already watching this?"
3
+ *
4
+ * A monitor's identity is its ARGUMENTS, not its name or its device. Agents
5
+ * create monitors per work item, so the same shape runs many times over with
6
+ * different arguments (PR #2517 vs #2600) and those must all coexist. The case
7
+ * that must NOT happen is two agents, on two different machines, creating a
8
+ * watcher with the SAME arguments — one work item, two triggers.
9
+ *
10
+ * A local-only check cannot see that: each box reads its own `monitors/` dir and
11
+ * neither sees the other. So the duplicate guard asks the fleet, reusing the
12
+ * same cross-machine fan-out `sessions --active` and `fleet status` already run
13
+ * (`lib/remote-agents-json.ts`).
14
+ *
15
+ * Deliberately NOT solved by syncing `monitors/*.yml` through the DotAgents repo:
16
+ * an agent's per-PR watcher is running state, not config, and syncing would push
17
+ * every one of them onto every box — the accumulation this guard exists to stop.
18
+ */
19
+ import { gatherRemoteAgentsJson } from '../remote-agents-json.js';
20
+ /** Recursion guard: a peer answering the fan-out must not fan out again. */
21
+ export const NO_MONITOR_FANOUT_ENV = 'AGENTS_MONITORS_LOCAL';
22
+ /**
23
+ * Parse a peer's `monitors list --json`. Defensive against version skew: a peer
24
+ * on an older CLI may emit a different shape or no JSON at all, and one bad peer
25
+ * must never blank the guard for the rest of the fleet.
26
+ */
27
+ export function parseRemoteMonitors(stdout, machine) {
28
+ let parsed;
29
+ try {
30
+ parsed = JSON.parse(stdout);
31
+ }
32
+ catch {
33
+ return [];
34
+ }
35
+ // `monitors list --json` writes a BARE array (stdoutJson -> JSON.stringify of
36
+ // monitors.map(...)); it has never wrapped. Guarding an envelope shape that has
37
+ // never existed would be a fallback for an imaginary bug.
38
+ if (!Array.isArray(parsed))
39
+ return [];
40
+ const rows = parsed;
41
+ const out = [];
42
+ for (const row of rows) {
43
+ if (!row || typeof row !== 'object' || Array.isArray(row))
44
+ continue;
45
+ const m = row;
46
+ // Without source+condition+action there is no identity to compare, so the
47
+ // row cannot participate in the duplicate check either way.
48
+ if (!m.name || !m.source || !m.condition || !m.action)
49
+ continue;
50
+ out.push({
51
+ machine,
52
+ monitor: { name: m.name, source: m.source, condition: m.condition, action: m.action },
53
+ });
54
+ }
55
+ return out;
56
+ }
57
+ /**
58
+ * Every monitor on every other registered device. Never throws: an unreachable
59
+ * fleet degrades to an empty list plus the names we could not consult, and the
60
+ * caller decides what to say about them.
61
+ */
62
+ export async function gatherFleetMonitors() {
63
+ try {
64
+ const result = await gatherRemoteAgentsJson({
65
+ args: ['monitors', 'list', '--json'],
66
+ noFanoutEnv: NO_MONITOR_FANOUT_ENV,
67
+ parse: parseRemoteMonitors,
68
+ quiet: true,
69
+ });
70
+ return {
71
+ monitors: result.items,
72
+ skipped: [...result.skipped, ...result.parseFailed],
73
+ discoveryFailed: result.discoveryFailed,
74
+ };
75
+ }
76
+ catch {
77
+ // Could not consult the fleet at all. Reported as such by the caller, never
78
+ // as an absence of duplicates.
79
+ return { monitors: [], skipped: [], discoveryFailed: true };
80
+ }
81
+ }
@@ -25,6 +25,31 @@ export interface MonitorState {
25
25
  /** Epoch-ms timestamps of recent fires, for the rate-limit / firehose guard. */
26
26
  fireTimes?: number[];
27
27
  }
28
+ /**
29
+ * Per-monitor liveness heartbeat, recorded on EVERY poll — fire or not, match or
30
+ * not. This is deliberately a separate record from MonitorState: change-detection
31
+ * state (lastHash/lastValue) is written only when a monitor fires or establishes
32
+ * a baseline, so a monitor that polls steadily but never matches leaves no
33
+ * change-detection trace. Without a heartbeat, `view` on such a monitor showed
34
+ * `state: null` — indistinguishable from a monitor the engine never touched, the
35
+ * exact confusion RUSH-2485 reports. The heartbeat makes "never checked" (no
36
+ * record) visibly distinct from "checked N times, not matching" (recent record,
37
+ * zero fires). Kept in its own file so it can never perturb the baseline logic in
38
+ * decideFire/hasChanged.
39
+ */
40
+ export interface MonitorLiveness {
41
+ monitorName: string;
42
+ /** RFC3339 timestamp of the last poll attempt. */
43
+ lastCheckedAt: string;
44
+ /** Total polls the engine has run against this monitor's source. */
45
+ checkCount: number;
46
+ /** The last poll's error (source produced nothing / threw), cleared on the next good poll. */
47
+ lastError?: string;
48
+ /** Consecutive failed polls; reset to 0 on any successful observation. Drives drought escalation. */
49
+ consecutiveErrors: number;
50
+ /** RFC3339 timestamp of the last drought notification, so the engine notifies once per drought. */
51
+ droughtNotifiedAt?: string;
52
+ }
28
53
  /** Per-monitor history root, with the (untrusted) name contained to one segment. */
29
54
  export declare function getMonitorHistoryDir(name: string): string;
30
55
  /** Directory holding a monitor's fire history. */
@@ -51,6 +76,20 @@ export declare function dedupeSignature(observation: string, dedupeKey?: string)
51
76
  * caller persists the new value via writeState only on a real fire.
52
77
  */
53
78
  export declare function hasChanged(name: string, observation: string, dedupeKey?: string): boolean;
79
+ /** Read a monitor's liveness heartbeat, or null if the engine has never polled it. */
80
+ export declare function readLiveness(name: string): MonitorLiveness | null;
81
+ /**
82
+ * Record one poll attempt as the monitor's liveness heartbeat — the single call
83
+ * the engine makes on every evaluation, regardless of fire/match. A successful
84
+ * observation clears `lastError`/`consecutiveErrors` and any drought flag; a
85
+ * failed one (source threw or produced nothing) records the error and increments
86
+ * the consecutive-failure counter the drought escalation reads. Written
87
+ * atomically (temp + rename) like writeStateRaw, and never touches state.json, so
88
+ * change-detection is untouched.
89
+ */
90
+ export declare function recordCheck(name: string, checkedAt: string, error?: string): MonitorLiveness;
91
+ /** Stamp the drought-notified marker so the engine notifies at most once per drought. */
92
+ export declare function markDroughtNotified(name: string, at: string): void;
54
93
  /**
55
94
  * Append a fire timestamp and return the pruned window (fires within `windowMs`).
56
95
  * The engine uses the returned length to decide whether the rate limit tripped.
@@ -23,6 +23,9 @@ export function getMonitorHistoryDir(name) {
23
23
  function getStatePath(name) {
24
24
  return path.join(getMonitorHistoryDir(name), 'state.json');
25
25
  }
26
+ function getLivenessPath(name) {
27
+ return path.join(getMonitorHistoryDir(name), 'liveness.json');
28
+ }
26
29
  /** Directory holding a monitor's fire history. */
27
30
  export function getMonitorFiresDir(name) {
28
31
  return path.join(getMonitorHistoryDir(name), 'fires');
@@ -100,6 +103,59 @@ export function hasChanged(name, observation, dedupeKey) {
100
103
  return true;
101
104
  return prev.lastHash !== hashSignature(observation, dedupeKey);
102
105
  }
106
+ /** Read a monitor's liveness heartbeat, or null if the engine has never polled it. */
107
+ export function readLiveness(name) {
108
+ const livenessPath = getLivenessPath(name);
109
+ if (!fs.existsSync(livenessPath))
110
+ return null;
111
+ try {
112
+ return JSON.parse(fs.readFileSync(livenessPath, 'utf-8'));
113
+ }
114
+ catch {
115
+ return null;
116
+ }
117
+ }
118
+ /**
119
+ * Record one poll attempt as the monitor's liveness heartbeat — the single call
120
+ * the engine makes on every evaluation, regardless of fire/match. A successful
121
+ * observation clears `lastError`/`consecutiveErrors` and any drought flag; a
122
+ * failed one (source threw or produced nothing) records the error and increments
123
+ * the consecutive-failure counter the drought escalation reads. Written
124
+ * atomically (temp + rename) like writeStateRaw, and never touches state.json, so
125
+ * change-detection is untouched.
126
+ */
127
+ export function recordCheck(name, checkedAt, error) {
128
+ const prev = readLiveness(name);
129
+ const consecutiveErrors = error ? (prev?.consecutiveErrors ?? 0) + 1 : 0;
130
+ const liveness = {
131
+ monitorName: name,
132
+ lastCheckedAt: checkedAt,
133
+ checkCount: (prev?.checkCount ?? 0) + 1,
134
+ consecutiveErrors,
135
+ ...(error ? { lastError: error } : {}),
136
+ // A drought flag only survives while the drought does — cleared on recovery.
137
+ ...(error && prev?.droughtNotifiedAt ? { droughtNotifiedAt: prev.droughtNotifiedAt } : {}),
138
+ };
139
+ ensureAgentsDir();
140
+ const dir = getMonitorHistoryDir(name);
141
+ fs.mkdirSync(dir, { recursive: true });
142
+ const livenessPath = path.join(dir, 'liveness.json');
143
+ const tmp = `${livenessPath}.tmp-${process.pid}`;
144
+ fs.writeFileSync(tmp, JSON.stringify(liveness, null, 2), 'utf-8');
145
+ fs.renameSync(tmp, livenessPath);
146
+ return liveness;
147
+ }
148
+ /** Stamp the drought-notified marker so the engine notifies at most once per drought. */
149
+ export function markDroughtNotified(name, at) {
150
+ const prev = readLiveness(name);
151
+ if (!prev)
152
+ return;
153
+ const livenessPath = getLivenessPath(name);
154
+ const next = { ...prev, droughtNotifiedAt: at };
155
+ const tmp = `${livenessPath}.tmp-${process.pid}`;
156
+ fs.writeFileSync(tmp, JSON.stringify(next, null, 2), 'utf-8');
157
+ fs.renameSync(tmp, livenessPath);
158
+ }
103
159
  /**
104
160
  * Append a fire timestamp and return the pruned window (fires within `windowMs`).
105
161
  * The engine uses the returned length to decide whether the rate limit tripped.
@@ -29,6 +29,12 @@ export interface ImportableSecret {
29
29
  itemTitle: string;
30
30
  fieldLabel: string;
31
31
  value: string;
32
+ /**
33
+ * The item's free-form notes (1Password's `notesPlain` / any NOTES-purpose
34
+ * field), carried as descriptive metadata for the imported secret. Never the
35
+ * secret value — omitted when the item has no notes.
36
+ */
37
+ description?: string;
32
38
  }
33
39
  export interface SkippedField {
34
40
  itemTitle: string;
@@ -41,6 +47,17 @@ export declare function listItems(vaultName: string): OpItemSummary[];
41
47
  export declare function getItem(itemId: string, vaultName: string): OpItem;
42
48
  export declare function toEnvKey(title: string): string;
43
49
  export declare function slugify(name: string): string;
50
+ /**
51
+ * Pure transform from a fetched 1Password item to an importable secret (or the
52
+ * reason it was skipped). Split out of extractSecrets so the field-selection
53
+ * and notes-extraction logic is exercised directly by tests without shelling
54
+ * out to `op`.
55
+ */
56
+ export declare function itemToSecret(item: OpItem): {
57
+ secret: ImportableSecret;
58
+ } | {
59
+ skipped: SkippedField;
60
+ };
44
61
  export declare function extractSecrets(items: OpItemSummary[], vaultName: string): {
45
62
  secrets: ImportableSecret[];
46
63
  skipped: SkippedField[];