@phnx-labs/agents-cli 1.22.35 → 1.22.37

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 (487) hide show
  1. package/CHANGELOG.md +666 -2
  2. package/README.md +75 -35
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.d.ts +15 -0
  5. package/dist/bootstrap.js +1211 -0
  6. package/dist/commands/accounts.d.ts +4 -11
  7. package/dist/commands/accounts.js +159 -27
  8. package/dist/commands/attach.js +17 -4
  9. package/dist/commands/audit.d.ts +8 -8
  10. package/dist/commands/audit.js +57 -47
  11. package/dist/commands/browser.js +15 -11
  12. package/dist/commands/cloud.js +1 -1
  13. package/dist/commands/commands.js +0 -11
  14. package/dist/commands/computer-actions.js +33 -0
  15. package/dist/commands/computer-sessions-picker.d.ts +21 -0
  16. package/dist/commands/computer-sessions-picker.js +141 -0
  17. package/dist/commands/computer.d.ts +16 -0
  18. package/dist/commands/computer.js +37 -0
  19. package/dist/commands/config.d.ts +17 -0
  20. package/dist/commands/config.js +401 -0
  21. package/dist/commands/cp.d.ts +84 -0
  22. package/dist/commands/cp.js +231 -0
  23. package/dist/commands/daemon.js +243 -14
  24. package/dist/commands/detach-core.d.ts +1 -1
  25. package/dist/commands/detach-core.js +12 -2
  26. package/dist/commands/detach.js +1 -1
  27. package/dist/commands/doctor.js +64 -5
  28. package/dist/commands/events.d.ts +24 -12
  29. package/dist/commands/events.js +144 -28
  30. package/dist/commands/exec.js +85 -41
  31. package/dist/commands/feed.d.ts +1 -1
  32. package/dist/commands/feed.js +16 -8
  33. package/dist/commands/focus.d.ts +33 -1
  34. package/dist/commands/focus.js +177 -17
  35. package/dist/commands/funnel.d.ts +1 -1
  36. package/dist/commands/go.js +9 -8
  37. package/dist/commands/harness-wizard.d.ts +1 -0
  38. package/dist/commands/harness-wizard.js +18 -20
  39. package/dist/commands/harness.d.ts +2 -0
  40. package/dist/commands/harness.js +59 -26
  41. package/dist/commands/hooks.js +0 -11
  42. package/dist/commands/inspect.d.ts +94 -1
  43. package/dist/commands/inspect.js +866 -40
  44. package/dist/commands/lease.d.ts +4 -4
  45. package/dist/commands/lease.js +6 -6
  46. package/dist/commands/login.js +0 -13
  47. package/dist/commands/logs.d.ts +2 -2
  48. package/dist/commands/logs.js +2 -2
  49. package/dist/commands/mcp.js +7 -2
  50. package/dist/commands/memory.js +7 -2
  51. package/dist/commands/message.d.ts +1 -1
  52. package/dist/commands/message.js +37 -6
  53. package/dist/commands/models.js +4 -0
  54. package/dist/commands/monitors.d.ts +0 -1
  55. package/dist/commands/monitors.js +199 -16
  56. package/dist/commands/open.d.ts +18 -0
  57. package/dist/commands/open.js +57 -0
  58. package/dist/commands/packages.js +2 -107
  59. package/dist/commands/plugins.js +6 -3
  60. package/dist/commands/profiles.d.ts +1 -0
  61. package/dist/commands/profiles.js +16 -160
  62. package/dist/commands/projects.d.ts +28 -0
  63. package/dist/commands/projects.js +125 -5
  64. package/dist/commands/reconnect.js +9 -3
  65. package/dist/commands/repo.js +42 -1
  66. package/dist/commands/resource-view.d.ts +17 -0
  67. package/dist/commands/resource-view.js +36 -14
  68. package/dist/commands/resume.js +9 -2
  69. package/dist/commands/routines.d.ts +0 -2
  70. package/dist/commands/routines.js +473 -289
  71. package/dist/commands/secrets.js +52 -9
  72. package/dist/commands/sessions-export.d.ts +47 -0
  73. package/dist/commands/sessions-export.js +116 -6
  74. package/dist/commands/sessions-import.d.ts +17 -0
  75. package/dist/commands/sessions-import.js +114 -6
  76. package/dist/commands/sessions-migrate.d.ts +27 -0
  77. package/dist/commands/sessions-migrate.js +50 -9
  78. package/dist/commands/sessions-picker.js +23 -4
  79. package/dist/commands/sessions-resume.d.ts +5 -3
  80. package/dist/commands/sessions-resume.js +30 -8
  81. package/dist/commands/sessions-watch.d.ts +2 -0
  82. package/dist/commands/sessions-watch.js +53 -0
  83. package/dist/commands/sessions.d.ts +66 -3
  84. package/dist/commands/sessions.js +298 -47
  85. package/dist/commands/set.d.ts +1 -1
  86. package/dist/commands/set.js +2 -2
  87. package/dist/commands/setup-browser.js +2 -2
  88. package/dist/commands/setup-mine.js +0 -1
  89. package/dist/commands/setup-preferences.js +1 -1
  90. package/dist/commands/setup-share.js +34 -4
  91. package/dist/commands/setup.d.ts +5 -0
  92. package/dist/commands/setup.js +26 -0
  93. package/dist/commands/share.d.ts +67 -0
  94. package/dist/commands/share.js +275 -12
  95. package/dist/commands/skills.js +0 -11
  96. package/dist/commands/snapshot.js +1 -1
  97. package/dist/commands/ssh.d.ts +18 -0
  98. package/dist/commands/ssh.js +549 -210
  99. package/dist/commands/sync.d.ts +5 -0
  100. package/dist/commands/sync.js +212 -32
  101. package/dist/commands/teams.d.ts +13 -0
  102. package/dist/commands/teams.js +187 -30
  103. package/dist/commands/tickets.d.ts +2 -0
  104. package/dist/commands/tickets.js +43 -0
  105. package/dist/commands/update.js +2 -4
  106. package/dist/commands/usage.js +5 -3
  107. package/dist/commands/versions.js +11 -5
  108. package/dist/commands/view.js +15 -7
  109. package/dist/commands/webhook.d.ts +2 -2
  110. package/dist/commands/webhook.js +7 -7
  111. package/dist/index.d.ts +18 -2
  112. package/dist/index.js +53 -1264
  113. package/dist/lib/account-catalog.d.ts +18 -0
  114. package/dist/lib/account-catalog.js +38 -0
  115. package/dist/lib/account-provider-registry.d.ts +18 -0
  116. package/dist/lib/account-provider-registry.js +59 -0
  117. package/dist/lib/account-registry.d.ts +40 -0
  118. package/dist/lib/account-registry.js +239 -0
  119. package/dist/lib/account-schema.d.ts +44 -0
  120. package/dist/lib/account-schema.js +91 -0
  121. package/dist/lib/account-state-service.d.ts +21 -0
  122. package/dist/lib/account-state-service.js +60 -0
  123. package/dist/lib/activity.d.ts +1 -1
  124. package/dist/lib/activity.js +8 -1
  125. package/dist/lib/add-dir.d.ts +80 -0
  126. package/dist/lib/add-dir.js +241 -0
  127. package/dist/lib/agent-cli-commands.d.ts +11 -0
  128. package/dist/lib/agent-cli-commands.js +30 -0
  129. package/dist/lib/agents.js +44 -36
  130. package/dist/lib/answer-router.js +1 -1
  131. package/dist/lib/audit/log.d.ts +10 -27
  132. package/dist/lib/audit/log.js +20 -33
  133. package/dist/lib/auth-health.d.ts +9 -2
  134. package/dist/lib/auth-health.js +42 -9
  135. package/dist/lib/auto-pull-worker.js +7 -3
  136. package/dist/lib/auto-pull.d.ts +44 -3
  137. package/dist/lib/auto-pull.js +88 -5
  138. package/dist/lib/binary-shadow.d.ts +28 -0
  139. package/dist/lib/binary-shadow.js +121 -0
  140. package/dist/lib/brand.js +9 -3
  141. package/dist/lib/browser/ipc.d.ts +30 -0
  142. package/dist/lib/browser/ipc.js +81 -4
  143. package/dist/lib/browser/profiles.d.ts +3 -2
  144. package/dist/lib/browser/profiles.js +65 -22
  145. package/dist/lib/browser/service.d.ts +4 -0
  146. package/dist/lib/browser/service.js +30 -3
  147. package/dist/lib/browser/sessions-list.d.ts +22 -2
  148. package/dist/lib/browser/sessions-list.js +54 -6
  149. package/dist/lib/browser/stream.d.ts +2 -0
  150. package/dist/lib/browser/stream.js +1 -0
  151. package/dist/lib/browser/types.d.ts +19 -0
  152. package/dist/lib/byok-usage.d.ts +9 -2
  153. package/dist/lib/byok-usage.js +133 -31
  154. package/dist/lib/cli-entry.d.ts +11 -0
  155. package/dist/lib/cli-entry.js +46 -0
  156. package/dist/lib/cloud/host.d.ts +1 -1
  157. package/dist/lib/cloud/host.js +2 -2
  158. package/dist/lib/cloud/registry.js +1 -1
  159. package/dist/lib/cloud/types.d.ts +1 -1
  160. package/dist/lib/commands.d.ts +2 -0
  161. package/dist/lib/commands.js +2 -0
  162. package/dist/lib/computer/sessions-list.d.ts +150 -0
  163. package/dist/lib/computer/sessions-list.js +363 -0
  164. package/dist/lib/config-keys.d.ts +86 -0
  165. package/dist/lib/config-keys.js +193 -0
  166. package/dist/lib/config-machine-keys.d.ts +12 -0
  167. package/dist/lib/config-machine-keys.js +17 -0
  168. package/dist/lib/config-transfer.js +3 -4
  169. package/dist/lib/crabbox/cli.d.ts +2 -2
  170. package/dist/lib/crabbox/cli.js +3 -3
  171. package/dist/lib/daemon-health.d.ts +22 -0
  172. package/dist/lib/daemon-health.js +33 -3
  173. package/dist/lib/daemon-services.d.ts +50 -0
  174. package/dist/lib/daemon-services.js +147 -0
  175. package/dist/lib/daemon-ticks.d.ts +35 -66
  176. package/dist/lib/daemon-ticks.js +77 -159
  177. package/dist/lib/daemon.d.ts +72 -4
  178. package/dist/lib/daemon.js +792 -202
  179. package/dist/lib/deeplink/register.d.ts +49 -0
  180. package/dist/lib/deeplink/register.js +253 -0
  181. package/dist/lib/deeplink/url.d.ts +34 -0
  182. package/dist/lib/deeplink/url.js +78 -0
  183. package/dist/lib/device-config.d.ts +124 -29
  184. package/dist/lib/device-config.js +346 -141
  185. package/dist/lib/devices/config-migration.d.ts +42 -0
  186. package/dist/lib/devices/config-migration.js +203 -0
  187. package/dist/lib/devices/connect.js +14 -7
  188. package/dist/lib/devices/doctor-findings.d.ts +4 -1
  189. package/dist/lib/devices/doctor-findings.js +20 -1
  190. package/dist/lib/devices/harness-inventory.d.ts +11 -2
  191. package/dist/lib/devices/harness-inventory.js +0 -0
  192. package/dist/lib/devices/health.d.ts +1 -1
  193. package/dist/lib/devices/health.js +1 -1
  194. package/dist/lib/devices/pending.d.ts +22 -1
  195. package/dist/lib/devices/pending.js +67 -2
  196. package/dist/lib/devices/registry.d.ts +0 -25
  197. package/dist/lib/devices/registry.js +2 -83
  198. package/dist/lib/devices/resolve-profile.d.ts +20 -0
  199. package/dist/lib/devices/resolve-profile.js +44 -0
  200. package/dist/lib/devices/rollout-verify.d.ts +101 -0
  201. package/dist/lib/devices/rollout-verify.js +193 -0
  202. package/dist/lib/devices/ssh-config.js +10 -6
  203. package/dist/lib/event-families.d.ts +28 -0
  204. package/dist/lib/event-families.js +159 -0
  205. package/dist/lib/event-stream.d.ts +9 -1
  206. package/dist/lib/event-stream.js +26 -9
  207. package/dist/lib/events.d.ts +9 -1
  208. package/dist/lib/events.js +21 -6
  209. package/dist/lib/exec.d.ts +30 -0
  210. package/dist/lib/exec.js +219 -121
  211. package/dist/lib/feed-broadcast.d.ts +25 -0
  212. package/dist/lib/feed-broadcast.js +33 -0
  213. package/dist/lib/feed.d.ts +1 -1
  214. package/dist/lib/feed.js +12 -2
  215. package/dist/lib/fleet/capture.js +15 -0
  216. package/dist/lib/fleet/manifest.js +9 -0
  217. package/dist/lib/fleet/types.d.ts +9 -0
  218. package/dist/lib/fleet-status.js +10 -8
  219. package/dist/lib/git.d.ts +20 -6
  220. package/dist/lib/git.js +121 -17
  221. package/dist/lib/hosts/dispatch.d.ts +8 -3
  222. package/dist/lib/hosts/dispatch.js +29 -3
  223. package/dist/lib/hosts/logs.d.ts +2 -2
  224. package/dist/lib/hosts/logs.js +2 -2
  225. package/dist/lib/hosts/option.js +1 -1
  226. package/dist/lib/hosts/passthrough.d.ts +2 -3
  227. package/dist/lib/hosts/passthrough.js +10 -24
  228. package/dist/lib/hosts/progress.js +2 -2
  229. package/dist/lib/hosts/providers/devices.d.ts +3 -3
  230. package/dist/lib/hosts/providers/devices.js +18 -12
  231. package/dist/lib/hosts/ready.d.ts +5 -1
  232. package/dist/lib/hosts/ready.js +9 -3
  233. package/dist/lib/hosts/reconcile.d.ts +2 -2
  234. package/dist/lib/hosts/reconcile.js +2 -2
  235. package/dist/lib/hosts/registry.js +14 -9
  236. package/dist/lib/hosts/remote-cmd.js +1 -1
  237. package/dist/lib/hosts/remote-os.d.ts +9 -6
  238. package/dist/lib/hosts/remote-os.js +13 -6
  239. package/dist/lib/hosts/routing-flag.d.ts +23 -0
  240. package/dist/lib/hosts/routing-flag.js +41 -0
  241. package/dist/lib/hosts/run-target.js +1 -1
  242. package/dist/lib/hosts/session-index.js +1 -1
  243. package/dist/lib/hosts/tasks.d.ts +6 -6
  244. package/dist/lib/hosts/tasks.js +4 -4
  245. package/dist/lib/hosts/types.js +1 -2
  246. package/dist/lib/installations/resolve.js +2 -8
  247. package/dist/lib/isolation-boundary-report.js +0 -1
  248. package/dist/lib/linear-cache.d.ts +7 -0
  249. package/dist/lib/linear-cache.js +31 -4
  250. package/dist/lib/linear-project-counts.d.ts +1 -1
  251. package/dist/lib/linear-project-counts.js +2 -3
  252. package/dist/lib/linear-projects.js +1 -1
  253. package/dist/lib/loop.d.ts +2 -2
  254. package/dist/lib/loop.js +1 -1
  255. package/dist/lib/mailbox-target.d.ts +1 -1
  256. package/dist/lib/mailbox-target.js +1 -1
  257. package/dist/lib/manifest.js +7 -4
  258. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  259. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  260. package/dist/lib/menubar/snapshot.d.ts +3 -2
  261. package/dist/lib/menubar/snapshot.js +6 -2
  262. package/dist/lib/migrate-fold.d.ts +33 -0
  263. package/dist/lib/migrate-fold.js +130 -0
  264. package/dist/lib/migrate.d.ts +34 -34
  265. package/dist/lib/migrate.js +106 -128
  266. package/dist/lib/model-tier-overrides.d.ts +1 -1
  267. package/dist/lib/model-tier-overrides.js +15 -2
  268. package/dist/lib/monitors/config.d.ts +17 -3
  269. package/dist/lib/monitors/config.js +52 -18
  270. package/dist/lib/monitors/engine.d.ts +32 -1
  271. package/dist/lib/monitors/engine.js +94 -11
  272. package/dist/lib/monitors/fingerprint.d.ts +46 -0
  273. package/dist/lib/monitors/fingerprint.js +100 -0
  274. package/dist/lib/monitors/remote.d.ts +47 -0
  275. package/dist/lib/monitors/remote.js +81 -0
  276. package/dist/lib/monitors/state.d.ts +39 -0
  277. package/dist/lib/monitors/state.js +56 -0
  278. package/dist/lib/onepassword.d.ts +17 -0
  279. package/dist/lib/onepassword.js +52 -22
  280. package/dist/lib/open-url.js +1 -1
  281. package/dist/lib/picker.d.ts +14 -2
  282. package/dist/lib/picker.js +35 -13
  283. package/dist/lib/placement.d.ts +1 -1
  284. package/dist/lib/placement.js +1 -1
  285. package/dist/lib/pr-land-detach.d.ts +32 -0
  286. package/dist/lib/pr-land-detach.js +79 -0
  287. package/dist/lib/profiles-presets.js +13 -0
  288. package/dist/lib/profiles.d.ts +2 -0
  289. package/dist/lib/profiles.js +44 -1
  290. package/dist/lib/project-focus.d.ts +1 -1
  291. package/dist/lib/project-focus.js +1 -1
  292. package/dist/lib/project-probe.d.ts +4 -1
  293. package/dist/lib/project-probe.js +5 -4
  294. package/dist/lib/project-resources.js +2 -18
  295. package/dist/lib/project-root.d.ts +16 -0
  296. package/dist/lib/project-root.js +20 -2
  297. package/dist/lib/projects.d.ts +20 -1
  298. package/dist/lib/projects.js +78 -1
  299. package/dist/lib/refresh-coordinator.d.ts +24 -0
  300. package/dist/lib/refresh-coordinator.js +52 -0
  301. package/dist/lib/registry.d.ts +2 -2
  302. package/dist/lib/registry.js +1 -1
  303. package/dist/lib/resource-aliases.d.ts +13 -0
  304. package/dist/lib/resource-aliases.js +26 -0
  305. package/dist/lib/resources/types.d.ts +1 -1
  306. package/dist/lib/resources.d.ts +16 -0
  307. package/dist/lib/resources.js +66 -10
  308. package/dist/lib/rotate.d.ts +3 -4
  309. package/dist/lib/rotate.js +4 -5
  310. package/dist/lib/routine-activation.d.ts +22 -2
  311. package/dist/lib/routine-activation.js +63 -16
  312. package/dist/lib/routine-context.d.ts +9 -2
  313. package/dist/lib/routine-context.js +21 -6
  314. package/dist/lib/routines-project.d.ts +58 -48
  315. package/dist/lib/routines-project.js +190 -159
  316. package/dist/lib/routines.d.ts +41 -6
  317. package/dist/lib/routines.js +92 -34
  318. package/dist/lib/run-defaults.d.ts +5 -0
  319. package/dist/lib/run-defaults.js +11 -1
  320. package/dist/lib/runner.d.ts +10 -8
  321. package/dist/lib/runner.js +122 -39
  322. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  323. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  324. package/dist/lib/secrets/agent.d.ts +10 -3
  325. package/dist/lib/secrets/agent.js +43 -8
  326. package/dist/lib/secrets/bundles.d.ts +1 -0
  327. package/dist/lib/secrets/bundles.js +92 -80
  328. package/dist/lib/secrets/index.js +32 -9
  329. package/dist/lib/secrets/install-helper.d.ts +4 -4
  330. package/dist/lib/secrets/install-helper.js +4 -4
  331. package/dist/lib/secrets/push.d.ts +40 -6
  332. package/dist/lib/secrets/push.js +58 -11
  333. package/dist/lib/secrets/read-backoff.d.ts +1 -1
  334. package/dist/lib/secrets/read-backoff.js +1 -1
  335. package/dist/lib/secrets/remote.d.ts +24 -0
  336. package/dist/lib/secrets/remote.js +54 -4
  337. package/dist/lib/self-update.d.ts +108 -0
  338. package/dist/lib/self-update.js +276 -1
  339. package/dist/lib/session/active.d.ts +89 -5
  340. package/dist/lib/session/active.js +165 -10
  341. package/dist/lib/session/actor-sidecar.d.ts +1 -1
  342. package/dist/lib/session/actor-sidecar.js +2 -1
  343. package/dist/lib/session/db.d.ts +176 -2
  344. package/dist/lib/session/db.js +484 -17
  345. package/dist/lib/session/discover.js +27 -4
  346. package/dist/lib/session/hook-sessions.js +2 -2
  347. package/dist/lib/session/host-link.d.ts +2 -2
  348. package/dist/lib/session/host-link.js +2 -2
  349. package/dist/lib/session/pid-registry.d.ts +21 -0
  350. package/dist/lib/session/pid-registry.js +57 -0
  351. package/dist/lib/session/remote-active.js +15 -1
  352. package/dist/lib/session/remote.js +2 -2
  353. package/dist/lib/session/session-cache.d.ts +14 -7
  354. package/dist/lib/session/session-cache.js +51 -9
  355. package/dist/lib/session/state.d.ts +2 -2
  356. package/dist/lib/session/state.js +1 -1
  357. package/dist/lib/session/sync/config.d.ts +10 -10
  358. package/dist/lib/session/sync/config.js +10 -10
  359. package/dist/lib/session/sync/r2.d.ts +34 -0
  360. package/dist/lib/session/sync/r2.js +123 -0
  361. package/dist/lib/session/throughput.d.ts +1 -1
  362. package/dist/lib/session/throughput.js +1 -1
  363. package/dist/lib/session/types.d.ts +23 -1
  364. package/dist/lib/session/types.js +15 -0
  365. package/dist/lib/session/viewing-in.d.ts +1 -1
  366. package/dist/lib/session/viewing-in.js +1 -1
  367. package/dist/lib/session/watch.d.ts +101 -0
  368. package/dist/lib/session/watch.js +242 -0
  369. package/dist/lib/share/config.d.ts +4 -0
  370. package/dist/lib/share/config.js +1 -0
  371. package/dist/lib/share/provision.d.ts +38 -0
  372. package/dist/lib/share/provision.js +50 -0
  373. package/dist/lib/share/publish.d.ts +40 -1
  374. package/dist/lib/share/publish.js +116 -3
  375. package/dist/lib/share/worker-template.js +71 -6
  376. package/dist/lib/shims.d.ts +17 -3
  377. package/dist/lib/shims.js +98 -26
  378. package/dist/lib/signin-badge.js +3 -2
  379. package/dist/lib/skills.js +2 -0
  380. package/dist/lib/smart-launch.d.ts +8 -8
  381. package/dist/lib/smart-launch.js +80 -59
  382. package/dist/lib/ssh-exec.d.ts +1 -1
  383. package/dist/lib/ssh-exec.js +1 -1
  384. package/dist/lib/staleness/prune.d.ts +88 -0
  385. package/dist/lib/staleness/prune.js +69 -0
  386. package/dist/lib/staleness/registry.d.ts +1 -1
  387. package/dist/lib/staleness/writers/commands.js +34 -2
  388. package/dist/lib/staleness/writers/hooks.js +16 -0
  389. package/dist/lib/staleness/writers/kinds.d.ts +6 -0
  390. package/dist/lib/staleness/writers/skills.js +19 -0
  391. package/dist/lib/staleness/writers/subagents.d.ts +2 -3
  392. package/dist/lib/staleness/writers/subagents.js +0 -4
  393. package/dist/lib/staleness/writers/types.d.ts +32 -0
  394. package/dist/lib/startup/command-registry.d.ts +6 -12
  395. package/dist/lib/startup/command-registry.js +11 -31
  396. package/dist/lib/startup/dev-build.d.ts +10 -0
  397. package/dist/lib/startup/dev-build.js +13 -1
  398. package/dist/lib/startup/spellcheck.d.ts +18 -0
  399. package/dist/lib/startup/spellcheck.js +45 -0
  400. package/dist/lib/state.d.ts +36 -9
  401. package/dist/lib/state.js +96 -46
  402. package/dist/lib/subagents-registry.d.ts +0 -7
  403. package/dist/lib/subagents-registry.js +38 -65
  404. package/dist/lib/subagents.d.ts +0 -33
  405. package/dist/lib/subagents.js +0 -75
  406. package/dist/lib/sync-umbrella.js +1 -1
  407. package/dist/lib/teams/agents.d.ts +41 -1
  408. package/dist/lib/teams/agents.js +187 -9
  409. package/dist/lib/teams/api.d.ts +11 -1
  410. package/dist/lib/teams/api.js +11 -2
  411. package/dist/lib/teams/delivery.d.ts +41 -0
  412. package/dist/lib/teams/delivery.js +60 -0
  413. package/dist/lib/teams/registry.d.ts +14 -0
  414. package/dist/lib/teams/registry.js +51 -1
  415. package/dist/lib/teams/remoteWorktree.d.ts +19 -0
  416. package/dist/lib/teams/remoteWorktree.js +29 -0
  417. package/dist/lib/teams/scheduler.d.ts +1 -1
  418. package/dist/lib/teams/scheduler.js +1 -1
  419. package/dist/lib/teams/worktree.d.ts +24 -0
  420. package/dist/lib/teams/worktree.js +42 -0
  421. package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
  422. package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
  423. package/dist/lib/terminal/engine.d.ts +4 -0
  424. package/dist/lib/terminal/engine.js +8 -2
  425. package/dist/lib/terminal/types.d.ts +21 -2
  426. package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
  427. package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
  428. package/dist/lib/tickets/list.d.ts +53 -0
  429. package/dist/lib/tickets/list.js +153 -0
  430. package/dist/lib/tmux/orphan-reap.d.ts +320 -0
  431. package/dist/lib/tmux/orphan-reap.js +644 -0
  432. package/dist/lib/tmux/session.d.ts +68 -3
  433. package/dist/lib/tmux/session.js +95 -5
  434. package/dist/lib/triggers/handlers.d.ts +20 -0
  435. package/dist/lib/triggers/handlers.js +6 -1
  436. package/dist/lib/types.d.ts +46 -34
  437. package/dist/lib/usage-fleet.d.ts +32 -0
  438. package/dist/lib/usage-fleet.js +125 -0
  439. package/dist/lib/usage-refresh.d.ts +3 -3
  440. package/dist/lib/usage-refresh.js +19 -16
  441. package/dist/lib/usage.d.ts +51 -47
  442. package/dist/lib/usage.js +145 -153
  443. package/dist/lib/version-duplicates.js +2 -2
  444. package/dist/lib/versions.d.ts +56 -13
  445. package/dist/lib/versions.js +195 -45
  446. package/dist/lib/watchdog/log.d.ts +1 -1
  447. package/dist/lib/watchdog/log.js +3 -3
  448. package/dist/lib/watchdog/rotate.d.ts +6 -6
  449. package/dist/lib/watchdog/rotate.js +6 -6
  450. package/dist/lib/workflows.d.ts +1 -1
  451. package/dist/lib/yaml-io.d.ts +47 -0
  452. package/dist/lib/yaml-io.js +55 -0
  453. package/package.json +2 -1
  454. package/scripts/install-helper.js +2 -2
  455. package/scripts/postinstall.js +23 -20
  456. package/dist/commands/defaults.d.ts +0 -7
  457. package/dist/commands/defaults.js +0 -107
  458. package/dist/commands/export.d.ts +0 -11
  459. package/dist/commands/export.js +0 -215
  460. package/dist/commands/helper.d.ts +0 -12
  461. package/dist/commands/helper.js +0 -87
  462. package/dist/commands/hosts.d.ts +0 -11
  463. package/dist/commands/hosts.js +0 -330
  464. package/dist/commands/lock.d.ts +0 -12
  465. package/dist/commands/lock.js +0 -70
  466. package/dist/commands/pull.d.ts +0 -17
  467. package/dist/commands/pull.js +0 -39
  468. package/dist/commands/push.d.ts +0 -14
  469. package/dist/commands/push.js +0 -30
  470. package/dist/commands/wallet.d.ts +0 -20
  471. package/dist/commands/wallet.js +0 -216
  472. package/dist/commands/worktree.d.ts +0 -19
  473. package/dist/commands/worktree.js +0 -272
  474. package/dist/lib/account-labels.d.ts +0 -24
  475. package/dist/lib/account-labels.js +0 -72
  476. package/dist/lib/auto-dispatch-linear.d.ts +0 -18
  477. package/dist/lib/auto-dispatch-linear.js +0 -107
  478. package/dist/lib/auto-dispatch-provider.d.ts +0 -10
  479. package/dist/lib/auto-dispatch-provider.js +0 -30
  480. package/dist/lib/auto-dispatch.d.ts +0 -93
  481. package/dist/lib/auto-dispatch.js +0 -128
  482. package/dist/lib/export.d.ts +0 -72
  483. package/dist/lib/export.js +0 -269
  484. package/dist/lib/lock.d.ts +0 -93
  485. package/dist/lib/lock.js +0 -207
  486. package/dist/lib/wallet/index.d.ts +0 -78
  487. package/dist/lib/wallet/index.js +0 -253
@@ -1,29 +1,12 @@
1
1
  /**
2
- * Cross-agent, tamper-evident audit log of every dispatched run (issue #347).
2
+ * Run-dispatch recording (issue #347) now a thin write into the unified
3
+ * event stream (`emit('run.dispatched', …)`). The historical hash-chained file
4
+ * at `~/.agents/.history/audit/log.jsonl` is still readable via
5
+ * `readAuditLog` / `verifyAuditChain` for pre-unification history; new runs do
6
+ * NOT append there. Operators list run outcomes with:
3
7
  *
4
- * Every run that reaches the single dispatch chokepoint in `agents run`
5
- * (src/commands/exec.ts) appends ONE record here. Records form a hash chain:
6
- * each record embeds the previous record's `hash` as `prevHash`, and its own
7
- * `hash` is `sha256(canonicalJSON(record-without-hash))`. Because `prevHash`
8
- * is part of the hashed payload, rewriting or reordering any record breaks the
9
- * chain from that point forward — `verifyAuditChain()` reports the first index
10
- * that fails to reproduce.
11
- *
12
- * Storage is append-only JSONL under the durable-runtime bucket
13
- * (`~/.agents/.history/audit/log.jsonl`), one record per line. `.history/` is
14
- * machine-local, gitignored, and NEVER synced by `agents repo push/pull` — so
15
- * the `repo` field (a git remote url that can embed an access token) never
16
- * lands in a version-controlled DotAgents repo, and a cross-machine pull can't
17
- * splice a foreign chain into this one. The write path is deliberately cheap
18
- * and non-fatal: a logging failure must never crash a run (see
19
- * `recordDispatchedRun`). Concurrent writers (parallel teams/routines dispatch)
20
- * are serialized by an advisory lock file so the chain never forks — see
21
- * `appendAuditRecord`.
22
- *
23
- * Governance context: this is the evidence trail an operator needs to answer
24
- * "which agent, at which version, ran against which repo, and did it succeed?"
25
- * — the kind of automated-decision logging the EU AI Act (Art. 12) expects of
26
- * high-risk systems, kept tamper-evident so the log itself can be trusted.
8
+ * agents events --include runs
9
+ * agents audit # alias of the above
27
10
  */
28
11
  import * as fs from 'fs';
29
12
  import * as path from 'path';
@@ -31,6 +14,7 @@ import { spawnSync } from 'child_process';
31
14
  import { sha256 } from '../staleness/fingerprint.js';
32
15
  import { getHistoryDir } from '../state.js';
33
16
  import { ensureLockTarget, withFileLock } from '../fs-atomic.js';
17
+ import { emit } from '../events.js';
34
18
  /** First record's `prevHash` — a fixed anchor so the chain has a root. */
35
19
  export const GENESIS_HASH = 'GENESIS';
36
20
  /**
@@ -155,23 +139,26 @@ function repoLabel(cwd) {
155
139
  }
156
140
  }
157
141
  /**
158
- * Record ONE dispatched run at the single exec chokepoint. Non-fatal by
159
- * contract: any failure is caught and warned, never thrown — an audit-log
160
- * hiccup must not crash a run that already finished.
142
+ * Record ONE dispatched run at the single exec chokepoint into the unified
143
+ * event stream. Non-fatal by contract: any failure is caught and warned, never
144
+ * thrown — a log hiccup must not crash a run that already finished.
161
145
  */
162
146
  export function recordDispatchedRun(run) {
163
147
  try {
164
- appendAuditRecord({
165
- ts: new Date().toISOString(),
148
+ const outcome = run.exitCode === 0 ? 'ok' : 'fail';
149
+ emit('run.dispatched', {
150
+ module: 'run',
166
151
  agent: run.agent,
167
152
  version: run.version,
168
- repo: repoLabel(run.cwd),
169
153
  mode: run.mode,
170
- outcome: run.exitCode === 0 ? 'ok' : 'fail',
171
- exit: run.exitCode,
154
+ repo: repoLabel(run.cwd),
155
+ cwd: run.cwd,
156
+ outcome,
157
+ exitCode: run.exitCode,
158
+ status: outcome,
172
159
  });
173
160
  }
174
161
  catch (err) {
175
- process.stderr.write(`[agents] audit log write failed: ${err.message}\n`);
162
+ process.stderr.write(`[agents] run.dispatched emit failed: ${err.message}\n`);
176
163
  }
177
164
  }
@@ -3,10 +3,15 @@ import type { AgentId } from './types.js';
3
3
  import { type ProviderProbe } from './usage.js';
4
4
  /**
5
5
  * - `live` — completed an authenticated request (200).
6
- * - `revoked` — the server rejected the token (401/403).
6
+ * - `revoked` — the server rejected the token (401/403), except Claude
7
+ * setup-token `user:profile` scope denials (those are
8
+ * `unverified` via `reason: 'usage_scope'` — RUSH-2392).
7
9
  * - `expired` — locally-detected expiry; not network-verified (no refresh on the read path).
8
10
  * - `rate_limited`— token works but is throttled right now (429).
9
- * - `unverified` — credential present, not locally expired, but this agent has no in-repo probe endpoint (codex/grok).
11
+ * - `unverified` — credential present, not locally expired, but this agent has
12
+ * no in-repo probe endpoint (codex/grok), OR the probe
13
+ * endpoint cannot prove live for a known non-revocation
14
+ * reason (Claude setup-token usage-scope gap — RUSH-2392).
10
15
  * - `unconfigured`— no usable credential on disk.
11
16
  * - `error` — network/other failure; verdict indeterminate (keep the last known one).
12
17
  */
@@ -129,6 +134,8 @@ export declare function authCacheKey(host: string, agent: AgentId | string, vers
129
134
  export declare function readAuthHealthCache(): Record<string, AuthHealth>;
130
135
  /** Read one entry, or null. */
131
136
  export declare function readAuthHealth(host: string, agent: AgentId | string, version: string): AuthHealth | null;
137
+ /** Reconstruct one host's published probe rows for a lease waiter/CLI reader. */
138
+ export declare function readFleetAuthRows(host: string): AuthProbeRow[];
132
139
  /**
133
140
  * Merge entries into the cache. An incoming `error` verdict (a network blip,
134
141
  * not a server rejection) is indeterminate, so it must NOT clobber a prior
@@ -20,8 +20,9 @@ import * as fs from 'fs';
20
20
  import * as path from 'path';
21
21
  import { ALL_AGENT_IDS, getAccountInfo } from './agents.js';
22
22
  import { getCacheDir } from './state.js';
23
- import { probeClaudeStatus, probeDroidStatus, probeKimiStatus, } from './usage.js';
23
+ import { probeClaudeStatus, probeDroidStatus, probeKimiStatus, USAGE_HEADLESS_SCOPE_MARKER, } from './usage.js';
24
24
  import { getVersionHomePath, listInstalledVersions } from './versions.js';
25
+ import { atomicWriteFileSync, ensureLockTarget, withFileLock } from './fs-atomic.js';
25
26
  /** Agents with a live network probe wired up today. The rest are best-effort. */
26
27
  export const LIVE_PROBE_AGENTS = new Set(['claude', 'kimi', 'droid']);
27
28
  // ---------------------------------------------------------------------------
@@ -43,12 +44,20 @@ export function verdictFromProbe(probe) {
43
44
  return 'unconfigured';
44
45
  if (probe.token === 'expired')
45
46
  return 'expired';
47
+ // Setup-token can run inference but cannot read usage (RUSH-2392). That 403
48
+ // is NOT a revocation — classifying it as revoked made the best-provisioned
49
+ // headless accounts look the least healthy on `agents view` / fleet ping.
50
+ if (probe.reason === 'usage_scope')
51
+ return 'unverified';
46
52
  if (probe.status == null)
47
53
  return 'error';
48
54
  return classifyHttpStatus(probe.status);
49
55
  }
50
56
  /** A short human detail line for a probe result (rendered under --verbose). */
51
57
  export function probeDetail(probe) {
58
+ if (probe.reason === 'usage_scope') {
59
+ return probe.error ?? USAGE_HEADLESS_SCOPE_MARKER;
60
+ }
52
61
  if (probe.status != null && (probe.status < 200 || probe.status >= 300))
53
62
  return `HTTP ${probe.status}`;
54
63
  if (probe.error)
@@ -226,6 +235,29 @@ export function readAuthHealthCache() {
226
235
  export function readAuthHealth(host, agent, version) {
227
236
  return readAuthHealthCache()[authCacheKey(host, agent, version)] ?? null;
228
237
  }
238
+ /** Reconstruct one host's published probe rows for a lease waiter/CLI reader. */
239
+ export function readFleetAuthRows(host) {
240
+ const prefix = `${host}:`;
241
+ const rows = [];
242
+ for (const [key, health] of Object.entries(readAuthHealthCache())) {
243
+ if (!key.startsWith(prefix))
244
+ continue;
245
+ const identity = key.slice(prefix.length);
246
+ const separator = identity.indexOf(':');
247
+ if (separator <= 0)
248
+ continue;
249
+ const agent = identity.slice(0, separator);
250
+ if (!ALL_AGENT_IDS.includes(agent))
251
+ continue;
252
+ rows.push({
253
+ agent: agent,
254
+ version: identity.slice(separator + 1),
255
+ account: health.account,
256
+ health,
257
+ });
258
+ }
259
+ return rows;
260
+ }
229
261
  /**
230
262
  * Merge entries into the cache. An incoming `error` verdict (a network blip,
231
263
  * not a server rejection) is indeterminate, so it must NOT clobber a prior
@@ -245,14 +277,15 @@ export function mergeAuthHealthEntries(current, incoming) {
245
277
  /** Merge one or more entries into the cache (best-effort write). */
246
278
  export function writeAuthHealthEntries(entries) {
247
279
  try {
248
- const dir = getCacheDir();
249
- if (!fs.existsSync(dir))
250
- fs.mkdirSync(dir, { recursive: true });
251
- const merged = {
252
- version: 1,
253
- entries: mergeAuthHealthEntries(readAuthHealthCache(), entries),
254
- };
255
- fs.writeFileSync(cacheFilePath(), JSON.stringify(merged, null, 2));
280
+ const target = cacheFilePath();
281
+ ensureLockTarget(target, JSON.stringify({ version: 1, entries: {} }));
282
+ withFileLock(target, () => {
283
+ const merged = {
284
+ version: 1,
285
+ entries: mergeAuthHealthEntries(readAuthHealthCache(), entries),
286
+ };
287
+ atomicWriteFileSync(target, JSON.stringify(merged, null, 2));
288
+ });
256
289
  }
257
290
  catch {
258
291
  // best-effort; a failed write just means the next reader falls back to heuristics
@@ -12,8 +12,7 @@ import * as fs from 'fs';
12
12
  import { simpleGit } from 'simple-git';
13
13
  import { tryAutoPull, isGitRepo } from './git.js';
14
14
  import { getSystemAgentsDir, getUserAgentsDir, getEnabledExtraRepos, getFetchCacheDir, } from './state.js';
15
- import { lockFilePath, statusFilePath } from './auto-pull.js';
16
- const LOCK_TTL_MS = 5 * 60 * 1000;
15
+ import { lockFilePath, statusFilePath, markDetachedSyncComplete, SYNC_LOCK_TTL_MS, } from './auto-pull.js';
17
16
  /**
18
17
  * Background auto-pull of ~/.agents/.system/ is off by default. When enabled it
19
18
  * silently fast-forwards a tracked source tree that the CLI then reads as a
@@ -38,7 +37,7 @@ function tryAcquireLock(alias) {
38
37
  const lock = lockFilePath(alias);
39
38
  try {
40
39
  const stat = fs.statSync(lock);
41
- if (Date.now() - stat.mtimeMs < LOCK_TTL_MS)
40
+ if (Date.now() - stat.mtimeMs < SYNC_LOCK_TTL_MS)
42
41
  return false;
43
42
  }
44
43
  catch {
@@ -130,6 +129,11 @@ async function main() {
130
129
  }
131
130
  }
132
131
  await Promise.all(targets.map(processTarget));
132
+ // Stamp the cycle so the next foreground CLI invocation can skip the ~7ms
133
+ // detached spawn for SYNC_LOCK_TTL_MS (RUSH-2324). Written even when every
134
+ // target was lock-skipped or the target list was empty — "nothing to do"
135
+ // is still a completed cycle.
136
+ markDetachedSyncComplete();
133
137
  }
134
138
  main().catch(() => {
135
139
  /* swallow — detached worker must never crash the parent's terminal */
@@ -9,11 +9,26 @@
9
9
  * Public API:
10
10
  * spawnDetachedSync() — fire-and-forget; never blocks the foreground command.
11
11
  * readRepoBehindMarkers() — synchronous; reads markers without consuming them.
12
+ * shouldSkipDetachedSync() — parent-side recency gate (RUSH-2324).
13
+ * markDetachedSyncComplete() — worker stamps a completed cycle for the parent gate.
12
14
  */
15
+ /**
16
+ * Shared 5-minute recency window for per-repo locks (worker) and the parent
17
+ * spawn gate (RUSH-2324). Worker skips a repo when its lock mtime is younger
18
+ * than this; the parent skips the entire detached spawn when a recent cycle
19
+ * completed or every existing lock is still within the window.
20
+ */
21
+ export declare const SYNC_LOCK_TTL_MS: number;
13
22
  /** Per-repo lock file path. mtime acts as a recency check. */
14
- export declare function lockFilePath(alias: string): string;
23
+ export declare function lockFilePath(alias: string, fetchDir?: string): string;
15
24
  /** Per-repo status marker path (for user/extras only). */
16
- export declare function statusFilePath(alias: string): string;
25
+ export declare function statusFilePath(alias: string, fetchDir?: string): string;
26
+ /**
27
+ * Stamp written at the end of every detached-worker cycle (including the
28
+ * no-target / all-locks-skipped path). Parent `spawnDetachedSync` stats this
29
+ * one file instead of forking a child on every ordinary CLI invocation.
30
+ */
31
+ export declare function lastSyncStampPath(fetchDir?: string): string;
17
32
  export interface FetchStatusMarker {
18
33
  alias: string;
19
34
  dir: string;
@@ -22,8 +37,34 @@ export interface FetchStatusMarker {
22
37
  branch: string;
23
38
  fetchedAt: number;
24
39
  }
40
+ /**
41
+ * Whether the parent should skip forking the detached auto-pull worker.
42
+ *
43
+ * True when either:
44
+ * 1. `.last-sync` exists and its mtime is within {@link SYNC_LOCK_TTL_MS}
45
+ * (a prior cycle completed recently — the common warm path), or
46
+ * 2. the fetch dir has at least one `*.lock` and every lock is still within
47
+ * the same window (a worker is mid-flight, or a cycle left locks that
48
+ * still count as fresh).
49
+ *
50
+ * False (spawn) when the stamp is missing/stale and there are no fresh locks
51
+ * — including a missing fetch dir and an empty one. Cheap: one `stat` or one
52
+ * `readdir` + a few `stat`s; never spawns and never reads git.
53
+ *
54
+ * @param fetchDir - Override the fetch state dir (for tests). Defaults to the
55
+ * production getFetchCacheDir() path.
56
+ * @param now - Override the clock (for tests).
57
+ * @param ttlMs - Override the recency window (for tests).
58
+ */
59
+ export declare function shouldSkipDetachedSync(fetchDir?: string, now?: number, ttlMs?: number): boolean;
60
+ /**
61
+ * Record that a detached-worker cycle finished (success, empty targets, or
62
+ * every repo skipped by its lock). Best-effort; a failed write just means the
63
+ * next foreground invocation will re-spawn the worker.
64
+ */
65
+ export declare function markDetachedSyncComplete(fetchDir?: string): void;
25
66
  /** Spawn the detached worker. No-op when AGENTS_NO_AUTOPULL=1 is set. */
26
- export declare function spawnDetachedSync(): void;
67
+ export declare function spawnDetachedSync(fetchDir?: string): void;
27
68
  /**
28
69
  * Read all current status markers and return those where the local repo is
29
70
  * behind upstream. Markers are NOT deleted — they persist until the next
@@ -9,6 +9,8 @@
9
9
  * Public API:
10
10
  * spawnDetachedSync() — fire-and-forget; never blocks the foreground command.
11
11
  * readRepoBehindMarkers() — synchronous; reads markers without consuming them.
12
+ * shouldSkipDetachedSync() — parent-side recency gate (RUSH-2324).
13
+ * markDetachedSyncComplete() — worker stamps a completed cycle for the parent gate.
12
14
  */
13
15
  import * as fs from 'fs';
14
16
  import * as path from 'path';
@@ -16,22 +18,103 @@ import { spawn } from 'child_process';
16
18
  import { fileURLToPath } from 'url';
17
19
  import { getFetchCacheDir } from './state.js';
18
20
  import { backgroundSpawnOptions } from './platform/process.js';
21
+ /**
22
+ * Shared 5-minute recency window for per-repo locks (worker) and the parent
23
+ * spawn gate (RUSH-2324). Worker skips a repo when its lock mtime is younger
24
+ * than this; the parent skips the entire detached spawn when a recent cycle
25
+ * completed or every existing lock is still within the window.
26
+ */
27
+ export const SYNC_LOCK_TTL_MS = 5 * 60 * 1000;
19
28
  /** Where lock files and per-repo status markers live. */
20
29
  function fetchStateDir() {
21
30
  return getFetchCacheDir();
22
31
  }
23
32
  /** Per-repo lock file path. mtime acts as a recency check. */
24
- export function lockFilePath(alias) {
25
- return path.join(fetchStateDir(), `${alias}.lock`);
33
+ export function lockFilePath(alias, fetchDir) {
34
+ return path.join(fetchDir ?? fetchStateDir(), `${alias}.lock`);
26
35
  }
27
36
  /** Per-repo status marker path (for user/extras only). */
28
- export function statusFilePath(alias) {
29
- return path.join(fetchStateDir(), `${alias}.status.json`);
37
+ export function statusFilePath(alias, fetchDir) {
38
+ return path.join(fetchDir ?? fetchStateDir(), `${alias}.status.json`);
39
+ }
40
+ /**
41
+ * Stamp written at the end of every detached-worker cycle (including the
42
+ * no-target / all-locks-skipped path). Parent `spawnDetachedSync` stats this
43
+ * one file instead of forking a child on every ordinary CLI invocation.
44
+ */
45
+ export function lastSyncStampPath(fetchDir) {
46
+ return path.join(fetchDir ?? fetchStateDir(), '.last-sync');
47
+ }
48
+ function isMtimeFresh(filePath, now, ttlMs) {
49
+ try {
50
+ return now - fs.statSync(filePath).mtimeMs < ttlMs;
51
+ }
52
+ catch {
53
+ return false;
54
+ }
55
+ }
56
+ /**
57
+ * Whether the parent should skip forking the detached auto-pull worker.
58
+ *
59
+ * True when either:
60
+ * 1. `.last-sync` exists and its mtime is within {@link SYNC_LOCK_TTL_MS}
61
+ * (a prior cycle completed recently — the common warm path), or
62
+ * 2. the fetch dir has at least one `*.lock` and every lock is still within
63
+ * the same window (a worker is mid-flight, or a cycle left locks that
64
+ * still count as fresh).
65
+ *
66
+ * False (spawn) when the stamp is missing/stale and there are no fresh locks
67
+ * — including a missing fetch dir and an empty one. Cheap: one `stat` or one
68
+ * `readdir` + a few `stat`s; never spawns and never reads git.
69
+ *
70
+ * @param fetchDir - Override the fetch state dir (for tests). Defaults to the
71
+ * production getFetchCacheDir() path.
72
+ * @param now - Override the clock (for tests).
73
+ * @param ttlMs - Override the recency window (for tests).
74
+ */
75
+ export function shouldSkipDetachedSync(fetchDir, now = Date.now(), ttlMs = SYNC_LOCK_TTL_MS) {
76
+ const dir = fetchDir ?? fetchStateDir();
77
+ if (isMtimeFresh(lastSyncStampPath(dir), now, ttlMs))
78
+ return true;
79
+ let entries;
80
+ try {
81
+ entries = fs.readdirSync(dir);
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ const locks = entries.filter((name) => name.endsWith('.lock'));
87
+ if (locks.length === 0)
88
+ return false;
89
+ return locks.every((name) => isMtimeFresh(path.join(dir, name), now, ttlMs));
90
+ }
91
+ /**
92
+ * Record that a detached-worker cycle finished (success, empty targets, or
93
+ * every repo skipped by its lock). Best-effort; a failed write just means the
94
+ * next foreground invocation will re-spawn the worker.
95
+ */
96
+ export function markDetachedSyncComplete(fetchDir) {
97
+ const dir = fetchDir ?? fetchStateDir();
98
+ const stamp = lastSyncStampPath(dir);
99
+ try {
100
+ if (!fs.existsSync(dir))
101
+ fs.mkdirSync(dir, { recursive: true });
102
+ fs.writeFileSync(stamp, String(Date.now()));
103
+ }
104
+ catch {
105
+ /* best-effort */
106
+ }
30
107
  }
31
108
  /** Spawn the detached worker. No-op when AGENTS_NO_AUTOPULL=1 is set. */
32
- export function spawnDetachedSync() {
109
+ export function spawnDetachedSync(fetchDir) {
33
110
  if (process.env.AGENTS_NO_AUTOPULL === '1')
34
111
  return;
112
+ // RUSH-2324: the spawn itself costs ~7ms mean on a warm box, and the worker
113
+ // almost always no-ops when a cycle ran in the last five minutes. Inspect
114
+ // the last-sync stamp + lock mtimes in the parent and skip the fork when
115
+ // everything is still fresh.
116
+ if (shouldSkipDetachedSync(fetchDir))
117
+ return;
35
118
  // Resolve the worker path relative to the compiled location of this module.
36
119
  // After `tsc`, both files land in the same directory under dist/lib/.
37
120
  const here = path.dirname(fileURLToPath(import.meta.url));
@@ -0,0 +1,28 @@
1
+ export interface AgentsBinaryShadow {
2
+ /** Path of the shadowing binary as it appears to the caller. */
3
+ path: string;
4
+ /** Its self-reported version, if we can run it. */
5
+ version?: string;
6
+ }
7
+ /**
8
+ * Whether two path spellings identify the same file.
9
+ *
10
+ * Two spellings of one file rarely compare equal on Windows: `realpathSync` does
11
+ * not expand 8.3 short names, so a path rooted at `os.tmpdir()`
12
+ * (`C:\Users\RUNNER~1\...` on a GitHub runner) never matches the long form
13
+ * (`C:\Users\runneradmin\...`) that `where` reports. Compare by device+inode
14
+ * first and fall back to case-insensitive resolved spellings.
15
+ */
16
+ export declare function sameFile(a: string, b: string): boolean;
17
+ /**
18
+ * Find `agents` installs that are NOT the currently running binary.
19
+ *
20
+ * Checks two sources:
21
+ * 1. The current PATH: if `which agents` / `where agents` resolves to a
22
+ * different real binary than the one executing this code, it is an active
23
+ * shadow.
24
+ * 2. Well-known install directories: any executable `agents` whose realpath
25
+ * differs from the current entry is a latent shadow — it may win under a
26
+ * different PATH (e.g. the daemon's service-managed PATH).
27
+ */
28
+ export declare function detectAgentsBinaryShadows(currentBin?: string, extraDirs?: readonly string[]): AgentsBinaryShadow[];
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Detect `agents` binaries that could shadow the currently running CLI.
3
+ *
4
+ * Scheduled command routines invoke the bare name `agents`. When an older install
5
+ * appears earlier on PATH than the current binary, routines silently run stale
6
+ * code (RUSH-2431). This module finds those shadows so `agents doctor` can warn.
7
+ */
8
+ import { execFileSync } from 'child_process';
9
+ import * as fs from 'fs';
10
+ import * as os from 'os';
11
+ import * as path from 'path';
12
+ import { getAgentsBinPath } from './cli-entry.js';
13
+ /** Realpath of `p`, or `p` itself if it cannot be resolved. */
14
+ function safeRealpath(p) {
15
+ try {
16
+ return fs.realpathSync(p);
17
+ }
18
+ catch {
19
+ return p;
20
+ }
21
+ }
22
+ /**
23
+ * Whether two path spellings identify the same file.
24
+ *
25
+ * Two spellings of one file rarely compare equal on Windows: `realpathSync` does
26
+ * not expand 8.3 short names, so a path rooted at `os.tmpdir()`
27
+ * (`C:\Users\RUNNER~1\...` on a GitHub runner) never matches the long form
28
+ * (`C:\Users\runneradmin\...`) that `where` reports. Compare by device+inode
29
+ * first and fall back to case-insensitive resolved spellings.
30
+ */
31
+ export function sameFile(a, b) {
32
+ try {
33
+ const aStat = fs.statSync(a);
34
+ const bStat = fs.statSync(b);
35
+ if (aStat.dev === bStat.dev && aStat.ino === bStat.ino)
36
+ return true;
37
+ }
38
+ catch { /* compare their resolved path spellings below */ }
39
+ const aReal = safeRealpath(a);
40
+ const bReal = safeRealpath(b);
41
+ return process.platform === 'win32'
42
+ ? aReal.toLowerCase() === bReal.toLowerCase()
43
+ : aReal === bReal;
44
+ }
45
+ /**
46
+ * Find `agents` installs that are NOT the currently running binary.
47
+ *
48
+ * Checks two sources:
49
+ * 1. The current PATH: if `which agents` / `where agents` resolves to a
50
+ * different real binary than the one executing this code, it is an active
51
+ * shadow.
52
+ * 2. Well-known install directories: any executable `agents` whose realpath
53
+ * differs from the current entry is a latent shadow — it may win under a
54
+ * different PATH (e.g. the daemon's service-managed PATH).
55
+ */
56
+ export function detectAgentsBinaryShadows(currentBin = getAgentsBinPath(), extraDirs = defaultWellKnownDirs()) {
57
+ const currentReal = safeRealpath(currentBin);
58
+ const seen = new Set();
59
+ const shadows = [];
60
+ function addIfShadow(candidate) {
61
+ if (seen.has(candidate))
62
+ return;
63
+ seen.add(candidate);
64
+ if (sameFile(candidate, currentReal))
65
+ return;
66
+ let version;
67
+ try {
68
+ version = execFileSync(candidate, ['--version'], { encoding: 'utf-8', env: process.env })
69
+ .trim()
70
+ .split('\n')[0];
71
+ }
72
+ catch { /* binary may be unreadable/unrunnable — still report it */ }
73
+ shadows.push({ path: candidate, version });
74
+ }
75
+ // Active shadow under the current environment's PATH.
76
+ try {
77
+ const resolver = process.platform === 'win32' ? 'where' : 'which';
78
+ const pathAgents = execFileSync(resolver, ['agents'], { encoding: 'utf-8', env: process.env })
79
+ .split(/\r?\n/)
80
+ .map((s) => s.trim())
81
+ .filter(Boolean)[0];
82
+ if (pathAgents && !sameFile(pathAgents, currentReal)) {
83
+ addIfShadow(pathAgents);
84
+ }
85
+ }
86
+ catch { /* no `agents` resolved on PATH */ }
87
+ // Latent shadows in well-known install locations.
88
+ for (const dir of extraDirs) {
89
+ for (const name of agentBinaryNames()) {
90
+ const candidate = path.join(dir, name);
91
+ try {
92
+ fs.accessSync(candidate, fs.constants.X_OK);
93
+ addIfShadow(candidate);
94
+ }
95
+ catch { /* ignore */ }
96
+ }
97
+ }
98
+ return shadows;
99
+ }
100
+ function agentBinaryNames() {
101
+ return process.platform === 'win32' ? ['agents.exe', 'agents.cmd', 'agents'] : ['agents'];
102
+ }
103
+ function defaultWellKnownDirs() {
104
+ const home = os.homedir();
105
+ if (process.platform === 'win32') {
106
+ const programFiles = process.env.ProgramFiles ?? 'C:\\Program Files';
107
+ return [
108
+ path.join(home, 'AppData', 'Roaming', 'npm'),
109
+ path.join(programFiles, 'nodejs'),
110
+ path.dirname(process.execPath),
111
+ ];
112
+ }
113
+ return [
114
+ path.join(home, '.local', 'bin'),
115
+ '/usr/local/bin',
116
+ '/opt/homebrew/bin',
117
+ path.join(home, '.npm-global', 'bin'),
118
+ path.join(home, '.bun', 'bin'),
119
+ path.dirname(process.execPath),
120
+ ];
121
+ }
package/dist/lib/brand.js CHANGED
@@ -17,7 +17,13 @@
17
17
  * where the active profile is resolved brand-first.
18
18
  */
19
19
  import { readMeta, updateMeta } from './state.js';
20
- import { ALL_AGENT_IDS, AGENTS } from './agents.js';
20
+ // Leaf list only do NOT import agents.js here. index.ts imports brand on
21
+ // every invocation (resolveBrandName / disabledCommandsForActiveBrand); a
22
+ // static agents import pulls the full agents.ts → versions.ts graph (~90ms)
23
+ // into --version/--help and the secrets-broker hot path (RUSH-2331).
24
+ // reservedBrandNames is only called when minting a brand; AGENT_CLI_COMMANDS
25
+ // is pinned equal to AGENTS[*].cliCommand by agent-cli-commands.test.ts.
26
+ import { AGENT_CLI_COMMANDS } from './agent-cli-commands.js';
21
27
  /** The default (unbranded) program name. */
22
28
  export const DEFAULT_CLI_NAME = 'agents';
23
29
  /** Valid brand names: a letter, then letters/digits/_/- (matches alias rules). */
@@ -45,8 +51,8 @@ export function isBranded() {
45
51
  /** Names that would clobber an agent CLI shim or the `agents`/`ag` binary. */
46
52
  export function reservedBrandNames() {
47
53
  const reserved = new Set([DEFAULT_CLI_NAME, 'ag']);
48
- for (const id of ALL_AGENT_IDS)
49
- reserved.add(AGENTS[id].cliCommand);
54
+ for (const cmd of AGENT_CLI_COMMANDS)
55
+ reserved.add(cmd);
50
56
  return reserved;
51
57
  }
52
58
  /** Validate a proposed brand name; returns an error string or null when ok. */
@@ -34,9 +34,39 @@ export declare class BrowserIPCConnection {
34
34
  export declare class BrowserIPCServer {
35
35
  private server;
36
36
  private service;
37
+ /** Live client connections, so {@link stop} can end them rather than wait. */
38
+ private connections;
39
+ /** In-flight stop, so a second SIGTERM awaits the same close, never skips it. */
40
+ private stopping;
37
41
  constructor(service: BrowserService);
38
42
  start(): Promise<void>;
43
+ /**
44
+ * Stop accepting, release the binding, and only then resolve.
45
+ *
46
+ * RUSH-2421: this used to call `server.close()` and move on. `close()` is
47
+ * asynchronous — it stops accepting immediately but the binding is not
48
+ * actually released until the `'close'` event fires — so `stop()` resolved
49
+ * while the socket (or named pipe) was still held. The daemon's
50
+ * `handleShutdown` awaits this before it exits, and a successor's
51
+ * `claimDaemonInstance` waits for that exit as its proof the predecessor's
52
+ * resources are free (SING-11). Resolving early made that proof false: the
53
+ * newcomer could bind before the incumbent's binding was gone, which is the
54
+ * two-servers-on-one-socket orphan the eviction protocol exists to prevent.
55
+ *
56
+ * The first version of this waited out a timeout instead, and that made every
57
+ * graceful daemon stop escalate to `killTree`: `close()` does not complete
58
+ * while a connection is open, browser clients hold one open on purpose, and
59
+ * the timeout was set equal to the daemon's own SIGTERM grace window
60
+ * (`STOP_GRACE_MS`) — so `handleShutdown` was still inside `stop()` when
61
+ * `stopDaemon` gave up waiting and killed it. So we END the connections
62
+ * rather than wait for them: `close()` stops accepting, destroying the
63
+ * tracked sockets lets it complete, and the timeout is only a backstop for a
64
+ * socket that will not die, deliberately far below `STOP_GRACE_MS`.
65
+ */
39
66
  stop(): Promise<void>;
67
+ private doStop;
68
+ /** Release the listening binding, resolving only once it is genuinely gone. */
69
+ private closeServer;
40
70
  private handleRequest;
41
71
  }
42
72
  /**