@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
@@ -40,6 +40,7 @@ import { SYNC_GET_CMD, SYNC_PING_CMD, SYNC_LOCK_CMD } from './sync-commands.js';
40
40
  import { MAX_LEASE_MS, MIN_LEASE_MS } from './lease.js';
41
41
  import { selectLeasedEnv } from './lease.js';
42
42
  import { emitSecretAudit } from './audit.js';
43
+ import { isDaemonServiceEnabled } from '../daemon-services.js';
43
44
  // Re-exported so callers already reaching for agent.js keep one obvious home for
44
45
  // the scope vocabulary; the definitions live in the leaf module scope.ts because
45
46
  // agent.ts and session-store.ts import each other and a cyclic `const` read can
@@ -50,6 +51,14 @@ export { GLOBAL_HARNESS, bundleScopeChain };
50
51
  const PROTOCOL_VERSION = 3;
51
52
  /** Default lifetime of an unlocked bundle when `--ttl` is not given. */
52
53
  export const DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7d
54
+ /**
55
+ * Whether the secrets broker service is enabled in the daemon service config.
56
+ * Off-darwin this is irrelevant (the broker is never used), but the helper is
57
+ * kept synchronous and safe everywhere so callers can fail loud without a prompt.
58
+ */
59
+ export function isSecretsBrokerEnabled() {
60
+ return isDaemonServiceEnabled('secrets-broker');
61
+ }
53
62
  /**
54
63
  * Reserved store-key prefix for the `secrets list` metadata snapshot cache.
55
64
  * The broker holds the resolved bundle-metadata array (names/policy/timestamps,
@@ -361,7 +370,12 @@ export function realBundleCount(store) {
361
370
  export function scopedBundleKey(name, harness) {
362
371
  return `${harness}:${name}`;
363
372
  }
364
- export function handleAgentRequest(store, req, now = Date.now()) {
373
+ export function handleAgentRequest(store, req, now = Date.now(),
374
+ // Eviction tombstones: `lock` records when each bundle was wiped so a load
375
+ // whose snapshot predates the eviction (a detached auto-load that raced a
376
+ // mutating write) is rejected instead of re-populating the store with a
377
+ // pre-mutation copy. Broker-lifetime state, owned by the caller like `store`.
378
+ evictedAt = new Map()) {
365
379
  switch (req.cmd) {
366
380
  case 'ping':
367
381
  // Report the version of the code this broker is RUNNING (getCliVersion
@@ -390,6 +404,13 @@ export function handleAgentRequest(store, req, now = Date.now()) {
390
404
  return { ok: true, cmd: 'get', hit: false };
391
405
  }
392
406
  case 'load': {
407
+ const evictedTs = evictedAt.get(req.name);
408
+ if (evictedTs !== undefined && req.snapshotAt !== undefined && req.snapshotAt <= evictedTs) {
409
+ // The loader captured its bundle/env before a mutating write evicted
410
+ // this name; accepting it would serve (and later re-persist) stale
411
+ // state. A load with no snapshotAt (older client) is accepted as before.
412
+ return { ok: false, error: `stale load for '${req.name}': snapshot predates an eviction` };
413
+ }
393
414
  const harness = req.harness || GLOBAL_HARNESS;
394
415
  let env = req.env;
395
416
  if (req.lease) {
@@ -409,9 +430,12 @@ export function handleAgentRequest(store, req, now = Date.now()) {
409
430
  for (const [key, entry] of store)
410
431
  if (entry.bundle.name === req.name && store.delete(key))
411
432
  wiped++;
433
+ evictedAt.set(req.name, now);
412
434
  return { ok: true, cmd: 'lock', wiped };
413
435
  }
414
436
  const wiped = store.size;
437
+ for (const entry of store.values())
438
+ evictedAt.set(entry.bundle.name, now);
415
439
  store.clear();
416
440
  return { ok: true, cmd: 'lock', wiped };
417
441
  }
@@ -721,8 +745,9 @@ export async function runSecretsAgent(opts = {}) {
721
745
  emptySince = now;
722
746
  }
723
747
  };
748
+ const evictedAt = new Map();
724
749
  const handle = (req) => {
725
- const resp = handleAgentRequest(store, req);
750
+ const resp = handleAgentRequest(store, req, Date.now(), evictedAt);
726
751
  if (realBundleCount(store) > 0)
727
752
  emptySince = Date.now();
728
753
  return resp;
@@ -854,7 +879,8 @@ export async function startHostedBroker() {
854
879
  return null;
855
880
  const store = rehydrateStore();
856
881
  const sock = socketPath(); // agentDir() creates the 0700 dir as a side effect
857
- const handle = (req) => handleAgentRequest(store, req);
882
+ const evictedAt = new Map();
883
+ const handle = (req) => handleAgentRequest(store, req, Date.now(), evictedAt);
858
884
  const onConn = makeConnectionHandler(handle, readAgentToken);
859
885
  const server = await bindBrokerSocket(sock, onConn);
860
886
  if (!server)
@@ -1039,6 +1065,8 @@ function syncClient(sub, timeout) {
1039
1065
  * (soft — caller falls through to the real keychain). macOS only.
1040
1066
  */
1041
1067
  export function agentGetSync(name, harness = GLOBAL_HARNESS) {
1068
+ if (!isSecretsBrokerEnabled())
1069
+ return null;
1042
1070
  if (!agentSocketExists())
1043
1071
  return null;
1044
1072
  const r = syncClient([SYNC_GET_CMD, name, harness], SYNC_GET_TIMEOUT_MS);
@@ -1270,10 +1298,15 @@ export function clampHoldMs(v) {
1270
1298
  * The worker reuses the robust `ensureAgentRunning` path (spawn-then-ping) rather
1271
1299
  * than a tight inline retry loop. Best-effort; never throws. macOS only.
1272
1300
  */
1273
- export function agentAutoLoadSync(name, bundle, env, ttlMs, harness = GLOBAL_HARNESS, lease) {
1301
+ export function agentAutoLoadSync(name, bundle, env, ttlMs, harness = GLOBAL_HARNESS, lease,
1302
+ // When the caller read the bundle from the keychain — lets the broker
1303
+ // reject this load if an eviction lands in between (tombstones, above).
1304
+ snapshotAt) {
1274
1305
  if (!onDarwin())
1275
1306
  return;
1276
- const payload = JSON.stringify({ name, bundle, env, ttlMs, harness, lease });
1307
+ if (!isSecretsBrokerEnabled())
1308
+ return;
1309
+ const payload = JSON.stringify({ name, bundle, env, ttlMs, harness, lease, snapshotAt });
1277
1310
  // Broker actually LISTENING → deterministic synchronous warm (bounded; the read
1278
1311
  // already paid a Touch ID, so <1s here is invisible). We gate on a real liveness
1279
1312
  // ping, NOT mere socket-file existence: a broker that died leaving its socket
@@ -1340,13 +1373,13 @@ export async function runAgentLoadFromStdin() {
1340
1373
  process.exitCode = 1; // broker couldn't be brought up — did NOT load
1341
1374
  return;
1342
1375
  }
1343
- const loaded = await agentLoad(payload.name, payload.bundle, payload.env, payload.ttlMs ?? DEFAULT_TTL_MS, payload.harness ?? GLOBAL_HARNESS, payload.lease);
1376
+ const loaded = await agentLoad(payload.name, payload.bundle, payload.env, payload.ttlMs ?? DEFAULT_TTL_MS, payload.harness ?? GLOBAL_HARNESS, payload.lease, payload.snapshotAt);
1344
1377
  if (!loaded)
1345
1378
  process.exitCode = 1; // transport failed — did NOT load
1346
1379
  }
1347
1380
  /** Store a resolved bundle in the broker. Returns false on transport failure. */
1348
- export async function agentLoad(name, bundle, env, ttlMs, harness = GLOBAL_HARNESS, lease) {
1349
- const r = await request({ cmd: 'load', name, bundle, env, ttlMs, harness, lease });
1381
+ export async function agentLoad(name, bundle, env, ttlMs, harness = GLOBAL_HARNESS, lease, snapshotAt) {
1382
+ const r = await request({ cmd: 'load', name, bundle, env, ttlMs, harness, lease, snapshotAt });
1350
1383
  return r?.ok === true && r.cmd === 'load';
1351
1384
  }
1352
1385
  /** Wipe one bundle (or all if name omitted) from the broker. Returns the count
@@ -1390,6 +1423,8 @@ export async function agentPing() {
1390
1423
  export async function ensureAgentRunning(timeoutMs = 5000) {
1391
1424
  if (!onDarwin())
1392
1425
  return false;
1426
+ if (!isSecretsBrokerEnabled())
1427
+ return false;
1393
1428
  // Self-heal: if a broker is reachable but running pre-upgrade code (its
1394
1429
  // reported version != the version on disk now), tear it down so the paths
1395
1430
  // below bring up a fresh one on current code. A current, reachable broker is
@@ -211,6 +211,7 @@ export interface BundleEntryInfo {
211
211
  detail: string;
212
212
  }
213
213
  export declare function describeBundle(bundle: SecretsBundle): BundleEntryInfo[];
214
+ export declare function stampLastUsed(bundle: SecretsBundle): void;
214
215
  /** Options for resolveBundleEnv. */
215
216
  export interface ResolveBundleOptions {
216
217
  /**
@@ -31,7 +31,7 @@ import { emit } from '../events.js';
31
31
  import { emitSecretAudit } from './audit.js';
32
32
  import { readMeta, getHelpersDir } from '../state.js';
33
33
  import { assertNameActiveInResourceProfile, filterNamesForActiveResourceProfile } from '../resource-profiles.js';
34
- import { agentGetSync, agentAutoLoadSync, agentGetMetaSync, agentAutoLoadMetaSync, agentEvictSync, secretsAgentAutoEnabled, secretsHoldMs } from './agent.js';
34
+ import { agentGetSync, agentAutoLoadSync, agentGetMetaSync, agentAutoLoadMetaSync, agentEvictSync, secretsAgentAutoEnabled, secretsHoldMs, isSecretsBrokerEnabled } from './agent.js';
35
35
  import { GLOBAL_HARNESS } from './scope.js';
36
36
  import { resolveSession, deleteSession } from './session-store.js';
37
37
  import { createHash } from 'node:crypto';
@@ -907,11 +907,20 @@ export function describeBundle(bundle) {
907
907
  }
908
908
  return out;
909
909
  }
910
- // Bump `bundle.last_used` and persist the bundle, but no more than once per
911
- // throttle window so we don't pay a keychain write on every agent run. Failures
912
- // are swallowed — usage tracking is never allowed to break secret resolution.
910
+ // Bump `last_used` and persist it, but no more than once per throttle window
911
+ // so we don't pay a keychain write on every agent run. Failures are swallowed —
912
+ // usage tracking is never allowed to break secret resolution.
913
913
  // Set AGENTS_NO_USAGE_TRACK=1 to disable the stamp entirely (used by tests).
914
- function stampLastUsed(bundle) {
914
+ //
915
+ // The passed bundle is often the BROKER'S snapshot (this fires on every broker
916
+ // hit), which can be stale — a detached auto-load captured before a mutating
917
+ // write can land after its eviction. Persisting that snapshot wholesale used to
918
+ // write its whole `vars` map back over the authoritative store, resurrecting
919
+ // removed keys (or, for a since-deleted bundle, the bundle itself). The stamp
920
+ // is telemetry: it re-reads the store's own current copy (bundle metadata is a
921
+ // silent no-ACL read) and writes ONLY the timestamp onto that.
922
+ // Exported for regression coverage, like shouldEvictAfterBundleWrite.
923
+ export function stampLastUsed(bundle) {
915
924
  if (process.env.AGENTS_NO_USAGE_TRACK)
916
925
  return;
917
926
  const nowMs = Date.now();
@@ -921,10 +930,14 @@ function stampLastUsed(bundle) {
921
930
  return;
922
931
  }
923
932
  try {
924
- bundle.last_used = new Date(nowMs).toISOString();
933
+ const fresh = readBundle(bundle.name); // throws if the bundle is gone — swallowed below
934
+ const stamp = new Date(nowMs).toISOString();
935
+ fresh.last_used = stamp;
936
+ // Keep the caller's (possibly broker-held) copy throttling correctly.
937
+ bundle.last_used = stamp;
925
938
  // skipBrokerEviction: this stamp fires on every broker HIT; letting it
926
939
  // evict would make the cache destroy itself on first use.
927
- writeBundle(bundle, { skipBrokerEviction: true });
940
+ writeBundle(fresh, { skipBrokerEviction: true });
928
941
  }
929
942
  catch {
930
943
  // Swallow — telemetry must never block secret resolution.
@@ -1272,6 +1285,10 @@ export function readAndResolveBundleEnv(name, opts = {}) {
1272
1285
  // `agents secrets status` is honest. Re-warm under the scope the grant was
1273
1286
  // MADE in (resolved.harness), never the asking scope — re-warming a global
1274
1287
  // grant as `claude` would silently narrow it for every other harness.
1288
+ // No snapshotAt: the session's bundle was read at unlock time, not now —
1289
+ // claiming freshness here would defeat the broker's eviction tombstones.
1290
+ // An undated load is accepted (legacy behavior); the durable-session
1291
+ // staleness window itself is a known, separate concern.
1275
1292
  agentAutoLoadSync(name, session.bundle, session.env, Math.max(1, session.expiresAt - Date.now()), resolved.harness, session.lease);
1276
1293
  emitSecretAudit({
1277
1294
  event: 'secrets.get',
@@ -1303,40 +1320,49 @@ export function readAndResolveBundleEnv(name, opts = {}) {
1303
1320
  `never raises a Touch ID sheet on its own.`);
1304
1321
  }
1305
1322
  }
1323
+ // If the secrets broker is explicitly disabled and this bundle would otherwise
1324
+ // fall through to a keychain read (Touch ID prompt), fail loud now. Never-policy
1325
+ // bundles are verified below and remain silent; vault/file backends are unaffected.
1326
+ if (backend === 'keychain' && !isSecretsBrokerEnabled() && process.env.AGENTS_SECRETS_NO_AGENT !== '1') {
1327
+ throw new Error(`Secrets broker is disabled — re-enable with 'agents daemon services enable secrets-broker'. ` +
1328
+ `If you meant to read directly from the keychain, set AGENTS_SECRETS_NO_AGENT=1.`);
1329
+ }
1306
1330
  if (backend === 'vault')
1307
1331
  assertVaultBackendUsable(name);
1308
1332
  const store = itemStore(backend);
1309
1333
  const metaItem = bundleMetaItem(name);
1310
1334
  const bundleSecretPrefix = `${SECRETS_ITEM_PREFIX}${name}.`;
1311
- let secretItems;
1312
- try {
1313
- secretItems = store.list(bundleSecretPrefix);
1314
- }
1315
- catch {
1316
- secretItems = [];
1335
+ let enumeratedSecretItems = [];
1336
+ // Agent launches must never enumerate the macOS Keychain: a per-bundle
1337
+ // prefix becomes a broad `agents-cli.` scan after service-name hashing and
1338
+ // macOS evaluates unrelated biometry ACLs during that scan (RUSH-2440).
1339
+ // Interactive reads retain the existing enumeration side of the union so
1340
+ // legacy/aliased items keep their established behavior.
1341
+ if (backend !== 'keychain' || !opts.agentOnly) {
1342
+ try {
1343
+ enumeratedSecretItems = store.list(bundleSecretPrefix);
1344
+ }
1345
+ catch {
1346
+ enumeratedSecretItems = [];
1347
+ }
1317
1348
  }
1318
1349
  const reason = opts.caller
1319
1350
  ? `read ${name} secrets (for ${opts.caller})`
1320
1351
  : `read ${name} secrets`;
1321
- // secretItems are storage names as enumerated (opaque hashed names on macOS
1322
- // with #316 hashing active, cleartext elsewhere); metaItem is cleartext and
1323
- // hashed inside getBatch. Deduped because the hashed enumeration spans the
1324
- // bundle's whole namespace.
1325
- const fetched = backend === 'keychain'
1326
- ? getKeychainTokens([...new Set([metaItem, ...secretItems])], {
1327
- agent: opts.agent || process.env.AGENTS_AGENT_NAME || 'Agents CLI',
1328
- bundle: name,
1329
- // The session that triggered the read, so a Touch ID prompt is
1330
- // attributable when several agents run at once. Exported by exec.ts.
1331
- sessionId: process.env.AGENT_SESSION_ID || process.env.AGENTS_SESSION_ID,
1332
- reason: opts.caller ? `to ${opts.caller}` : reason,
1333
- duration: opts.duration || humanUnlockDuration(secretsHoldMs()),
1334
- defaultPolicy: secretsDefaultPolicy(),
1335
- forceDuration: Boolean(opts.duration),
1336
- silentNoAcl: verifiedNoAclBundle,
1337
- })
1338
- : store.getBatch([...new Set([metaItem, ...secretItems])]);
1339
- const json = fetched.get(metaItem);
1352
+ // Captured BEFORE the first keychain read: if a mutating write evicts this
1353
+ // bundle while the read is in flight, the broker's tombstone must beat this
1354
+ // snapshot, so the conservative (earliest) timestamp is the correct one.
1355
+ const snapshotAt = Date.now();
1356
+ // Fetch metadata first (it's always no-ACL), then derive secret item names
1357
+ // from its declared keys instead of enumerating. This eliminates the broad
1358
+ // Keychain scan that triggered Touch ID on every run (RUSH-2440). The
1359
+ // metadata is authoritative for declared keys; undeclared keys (union with
1360
+ // legacy/orphaned items) are not supported in agent-only mode and would
1361
+ // fail the agentOnly gate anyway.
1362
+ const metaFetched = backend === 'keychain'
1363
+ ? getKeychainTokens([metaItem], { silentNoAcl: true })
1364
+ : store.getBatch([...new Set([metaItem, ...enumeratedSecretItems])]);
1365
+ const json = metaFetched.get(metaItem);
1340
1366
  if (json === undefined) {
1341
1367
  if (vaultExists() && !getVaultSession().loggedIn) {
1342
1368
  throw new Error(`Synced secrets are locked. Run: agents login`);
@@ -1353,6 +1379,39 @@ export function readAndResolveBundleEnv(name, opts = {}) {
1353
1379
  if (!parsed || typeof parsed !== 'object') {
1354
1380
  throw new Error(`Bundle '${name}' is malformed.`);
1355
1381
  }
1382
+ // Compute exact storage names from declared keychain references. The env key
1383
+ // and stored item name may differ (`TOKEN=keychain:actual-token`), so deriving
1384
+ // item names from Object.keys(vars) would silently read the wrong secret.
1385
+ const declaredSecretItems = [];
1386
+ if (parsed.vars && typeof parsed.vars === 'object') {
1387
+ for (const raw of Object.values(parsed.vars)) {
1388
+ const value = parseBundleValue(raw);
1389
+ if ('ref' in value && value.ref.provider === 'keychain') {
1390
+ declaredSecretItems.push(secretsKeychainItem(name, value.ref.value));
1391
+ }
1392
+ }
1393
+ }
1394
+ const secretItems = [...new Set([...enumeratedSecretItems, ...declaredSecretItems])];
1395
+ // Now fetch both metadata and secret values in one batch.
1396
+ // The interactive path keeps the enumeration + declared-item union; the
1397
+ // agent-only path contains declared items only and therefore never scans.
1398
+ const fetched = backend === 'keychain'
1399
+ ? getKeychainTokens([...new Set([metaItem, ...secretItems])], {
1400
+ agent: opts.agent || process.env.AGENTS_AGENT_NAME || 'Agents CLI',
1401
+ bundle: name,
1402
+ // The session that triggered the read, so a Touch ID prompt is
1403
+ // attributable when several agents run at once. Exported by exec.ts.
1404
+ sessionId: process.env.AGENT_SESSION_ID || process.env.AGENTS_SESSION_ID,
1405
+ reason: opts.caller ? `to ${opts.caller}` : reason,
1406
+ duration: opts.duration || humanUnlockDuration(secretsHoldMs()),
1407
+ defaultPolicy: secretsDefaultPolicy(),
1408
+ forceDuration: Boolean(opts.duration),
1409
+ silentNoAcl: verifiedNoAclBundle,
1410
+ })
1411
+ // File/vault enumeration is complete and prompt-free. Reuse its initial
1412
+ // batch so metadata-first Keychain safety does not double-decrypt every
1413
+ // file-backed credential read.
1414
+ : metaFetched;
1356
1415
  const bundle = {
1357
1416
  name,
1358
1417
  description: parsed.description,
@@ -1393,53 +1452,6 @@ export function readAndResolveBundleEnv(name, opts = {}) {
1393
1452
  }
1394
1453
  const keys = [...selectedKeys].sort();
1395
1454
  keychainKeys.sort();
1396
- // RUSH-2252: complete the read set from the bundle's DECLARED keys, not only
1397
- // from the enumeration above. `store.list()` derives the batch by enumerating
1398
- // the bundle's namespace, and that enumeration is lossy by construction — the
1399
- // macOS helper's `list` omits every biometry-ACL'd item
1400
- // (`kSecUseAuthenticationUISkip`) and skips the whole data-protection pass when
1401
- // the keychain is locked, so a `hold`-policy bundle's value items never appear
1402
- // and a present secret reads as "not found" (RUSH-2248). A declared key whose
1403
- // item did not enumerate is therefore absent from `fetched`; read those exact
1404
- // items directly — a point read DOES evaluate the ACL, so it triggers Touch ID
1405
- // and returns the value the enumeration could not see. The enumeration still
1406
- // earns its place (it catches hashed/aliased storage names and stale leftovers
1407
- // not named in the metadata), so this is a UNION, not a replacement.
1408
- //
1409
- // One Touch ID sheet is preserved: the items missing from `fetched` are exactly
1410
- // the ACL'd ones the enumeration dropped, so the first batch (metadata plus any
1411
- // no-ACL / `never` items) raised no sheet, and this second batch raises the
1412
- // single sheet that covers all of them. When the enumeration is healthy every
1413
- // declared item is already in `fetched`, `missingDeclared` is empty, and this
1414
- // is skipped entirely — zero behavior change and no extra spawn on the hot path.
1415
- if (backend === 'keychain') {
1416
- const missingDeclared = [];
1417
- for (const key of keychainKeys) {
1418
- const p = parsedByKey.get(key);
1419
- if (!('ref' in p) || p.ref.provider !== 'keychain')
1420
- continue;
1421
- const item = secretsKeychainItem(bundle.name, p.ref.value);
1422
- if (fetched.get(item) === undefined && fetched.get(keychainServiceAlias(item)) === undefined) {
1423
- missingDeclared.push(item);
1424
- }
1425
- }
1426
- if (missingDeclared.length > 0) {
1427
- const declaredFetched = getKeychainTokens([...new Set(missingDeclared)], {
1428
- agent: opts.agent || process.env.AGENTS_AGENT_NAME || 'Agents CLI',
1429
- bundle: name,
1430
- sessionId: process.env.AGENT_SESSION_ID || process.env.AGENTS_SESSION_ID,
1431
- reason: opts.caller ? `to ${opts.caller}` : reason,
1432
- duration: opts.duration || humanUnlockDuration(secretsHoldMs()),
1433
- // The policy is known now (metadata parsed), so the prompt names the real
1434
- // duration instead of the pre-read default the first batch had to guess.
1435
- defaultPolicy: bundlePolicy(bundle),
1436
- forceDuration: Boolean(opts.duration),
1437
- silentNoAcl: verifiedNoAclBundle,
1438
- });
1439
- for (const [k, v] of declaredFetched)
1440
- fetched.set(k, v);
1441
- }
1442
- }
1443
1455
  const emitReadAudit = (status, err) => {
1444
1456
  emitSecretAudit({
1445
1457
  event: 'secrets.get',
@@ -1474,7 +1486,7 @@ export function readAndResolveBundleEnv(name, opts = {}) {
1474
1486
  bundlePolicy(bundle) === 'hold' &&
1475
1487
  secretsAgentAutoEnabled() &&
1476
1488
  canCacheResolvedEnv(bundle, selectedKeys, opts.keyMode)) {
1477
- agentAutoLoadSync(name, bundle, env, secretsHoldMs(), opts.agent || process.env.AGENTS_AGENT_NAME || GLOBAL_HARNESS);
1489
+ agentAutoLoadSync(name, bundle, env, secretsHoldMs(), opts.agent || process.env.AGENTS_AGENT_NAME || GLOBAL_HARNESS, undefined, snapshotAt);
1478
1490
  }
1479
1491
  return { bundle, env };
1480
1492
  }
@@ -298,7 +298,34 @@ export function readHmacKeyRecord() {
298
298
  catch {
299
299
  return null;
300
300
  }
301
- return parseHmacKeyRecord(raw);
301
+ const record = parseHmacKeyRecord(raw);
302
+ // Converge a stale-ACL'd hmackey to silent, on the HOT read path (RUSH-2441 /
303
+ // restore of v1.22.7 / 391017461). An old helper re-stamped this
304
+ // contractually-no-ACL item with a biometry ACL, so the read just above pops
305
+ // the generic "Agents CLI needs to authenticate" sheet on EVERY hashed
306
+ // lookup — the `agents devices list` stats probe the SessionStart hook runs,
307
+ // and every other background hashed read. `maybeAutoRekey`'s one-shot heal
308
+ // only fires on a cleartext-bundle resolve and is bypassed for the
309
+ // hmackey/hashed-name path (`prepareServiceName` returns early for
310
+ // HMAC_KEY_ITEM before maybeAutoRekey), so it never converged exactly these
311
+ // reads and the machine prompted forever. Re-store the record no-ACL once
312
+ // per machine here (the read that produced it has already happened — and
313
+ // already prompted if the item was ACL'd); every subsequent read, in this
314
+ // process and all future ones, is silent.
315
+ //
316
+ // v1.22.10 (bf79dc885 / #1995) moved the heal back into maybeAutoRekey and
317
+ // left the changelog claim in 1.22.7 false until this restore.
318
+ if (record && !record.healedNoAcl) {
319
+ try {
320
+ healHmacKeyNoAclOnce(record);
321
+ record.healedNoAcl = true;
322
+ }
323
+ catch {
324
+ // A failed no-ACL re-store leaves the item still ACL'd (a still-prompting
325
+ // read) rather than a silent wrong state; the next process retries.
326
+ }
327
+ }
328
+ return record;
302
329
  }
303
330
  function writeHmacKeyRecord(rec) {
304
331
  // JSON.stringify drops undefined fields (used to clear pendingDeletes).
@@ -471,14 +498,10 @@ export function maybeAutoRekey() {
471
498
  return;
472
499
  const st = resolveHashState();
473
500
  if (st.active) {
474
- if (st.record && !st.record.healedNoAcl) {
475
- try {
476
- healHmacKeyNoAclOnce(st.record);
477
- }
478
- catch {
479
- /* the next explicit unlock retries */
480
- }
481
- }
501
+ // The stale-ACL'd-hmackey heal runs on the hot read path
502
+ // (readHmacKeyRecord), which resolveHashState() above just went through —
503
+ // so st.record is already healed here regardless of how this machine
504
+ // reached "hashing active". Nothing to do but finish any pending deletes.
482
505
  if (st.record?.pendingDeletes?.length) {
483
506
  try {
484
507
  finishPendingDeletes(st.record);
@@ -33,14 +33,14 @@ export declare function ensureKeychainHelperInstalled(opts?: {
33
33
  * Return the absolute path to the helper executable. If the installed bundle
34
34
  * is missing, or is stale relative to the bundled source helper, performs a
35
35
  * lazy (re)install first. The staleness check is what lets an upgraded CLI
36
- * replace a helper a previous version installed — `agents helper install`
37
- * never runs on `npm i -g`, so this call site is the only one every machine
38
- * is guaranteed to pass through.
36
+ * replace a helper a previous version installed — the install never runs on
37
+ * `npm i -g`, so this call site is the only one every machine is guaranteed to
38
+ * pass through.
39
39
  *
40
40
  * Throws on non-darwin.
41
41
  */
42
42
  export declare function getKeychainHelperPath(): string;
43
- /** Diagnostic snapshot used by `agents helper status`. */
43
+ /** Diagnostic snapshot of the installed Keychain helper. */
44
44
  export interface KeychainHelperStatus {
45
45
  source: string | null;
46
46
  destination: string;
@@ -140,7 +140,7 @@ export function ensureKeychainHelperInstalled(opts = {}) {
140
140
  const verify = codesignVerify(dest);
141
141
  if (!verify.ok) {
142
142
  throw new Error(`Installed helper failed codesign verification at ${dest}.\n${verify.output}\n` +
143
- 'The bundle may be corrupted. Try `agents helper install` to reinstall, or reinstall agents-cli.');
143
+ 'The bundle may be corrupted. Reinstall agents-cli to restore it; the helper reinstalls automatically on the next secrets use.');
144
144
  }
145
145
  heartbeat(); // codesign done; spctl does a network Gatekeeper lookup — refresh again
146
146
  const assess = spctlAssess(dest);
@@ -156,9 +156,9 @@ export function ensureKeychainHelperInstalled(opts = {}) {
156
156
  * Return the absolute path to the helper executable. If the installed bundle
157
157
  * is missing, or is stale relative to the bundled source helper, performs a
158
158
  * lazy (re)install first. The staleness check is what lets an upgraded CLI
159
- * replace a helper a previous version installed — `agents helper install`
160
- * never runs on `npm i -g`, so this call site is the only one every machine
161
- * is guaranteed to pass through.
159
+ * replace a helper a previous version installed — the install never runs on
160
+ * `npm i -g`, so this call site is the only one every machine is guaranteed to
161
+ * pass through.
162
162
  *
163
163
  * Throws on non-darwin.
164
164
  */
@@ -33,6 +33,12 @@ export interface PushBundleOptions {
33
33
  passphrase?: string;
34
34
  /** Label for the audit trail — `export --host` vs `fleet apply`. */
35
35
  operation: string;
36
+ /** Preserve an automation account's permanent prompt-free policy remotely. */
37
+ policyNever?: boolean;
38
+ /** Permit a human-invoked push to read locally without requiring the agent broker. */
39
+ agentOnly?: boolean;
40
+ /** Non-secret literals whose bundle value kind must survive the dotenv transport. */
41
+ literalValues?: Record<string, string>;
36
42
  }
37
43
  export interface PushBundleResult {
38
44
  ok: boolean;
@@ -42,14 +48,34 @@ export interface PushBundleResult {
42
48
  /** One line for the caller to render. Never contains a secret value. */
43
49
  message: string;
44
50
  }
51
+ export interface LiteralRestorePlan {
52
+ key: string;
53
+ removeArgs: string[];
54
+ addArgs: string[];
55
+ }
56
+ /** Preserve the literal-vs-secret schema that dotenv transport cannot encode. */
57
+ export declare function planLiteralRestoration(bundle: string, literalValues?: Record<string, string>): LiteralRestorePlan[];
45
58
  /**
46
59
  * Read and resolve a bundle once, for pushing to one or more hosts.
47
60
  *
48
- * `agentOnly` + `keyMode: 'storage'` match what `export --host` has always
49
- * passed: storage-shaped values, and the headless guard that fails fast rather
50
- * than popping Touch ID inside an automated run.
61
+ * `keyMode: 'storage'` is fixed a push always sends storage-shaped values.
62
+ *
63
+ * `agentOnly` is the caller's to decide, and it is NOT a security level: it
64
+ * selects the broker-only read (fail fast with the `agents secrets unlock` hint)
65
+ * over the interactive read (macOS may raise a Touch ID sheet). The headless
66
+ * guard exists because an AGENT LAUNCH must never enumerate the keychain — a
67
+ * per-bundle prefix becomes a broad `agents-cli.` scan after service-name
68
+ * hashing, and macOS evaluates unrelated biometry ACLs during it, one sheet per
69
+ * installed version (bundles.ts, RUSH-2440). A human at a TTY is not that case:
70
+ * they can answer one prompt, and the interactive sibling reads (`view --reveal`,
71
+ * `exec`) already let them. NOT `get` — it is unconditionally `agentOnly` on
72
+ * purpose, because prompting would hang a `$(agents secrets get …)` capture
73
+ * mid-pipeline (SEC-13b). It defaults to `true` so an automated caller that says
74
+ * nothing stays broker-only.
51
75
  */
52
- export declare function resolveBundleForPush(bundle: string, caller: string): ResolvedBundleForPush;
76
+ export declare function resolveBundleForPush(bundle: string, caller: string, opts?: {
77
+ agentOnly?: boolean;
78
+ }): ResolvedBundleForPush;
53
79
  /**
54
80
  * WHICH transport a (backend, target-OS) pair selects, and the exact bytes it
55
81
  * will send. One of four outcomes, and picking the wrong one is silent: a
@@ -68,17 +94,25 @@ export type PushTransport =
68
94
  kind: 'refuse';
69
95
  message: string;
70
96
  }
71
- /** A command sent over the raw ssh engine, with the .env on stdin. */
97
+ /**
98
+ * A command sent over the raw ssh engine, with the .env on stdin. `multiplex`
99
+ * is always `false`: a push ships credential bytes, so its connection must not
100
+ * reuse — or leave behind — a persistent authenticated control master to the
101
+ * destination the way the default fan-out connections do (RUSH-2527). This
102
+ * mirrors the `--copy-creds` dispatch posture (`multiplex: !opts.copyCreds`).
103
+ */
72
104
  | {
73
105
  kind: 'ssh';
74
106
  remoteCmd: string;
75
107
  input: string;
108
+ multiplex: false;
76
109
  }
77
- /** The OS-aware `agents secrets` wrapper, the READ inverse's own path. */
110
+ /** The OS-aware `agents secrets` wrapper, the READ inverse's own path. Never multiplexed — see the `ssh` kind. */
78
111
  | {
79
112
  kind: 'remote-secrets';
80
113
  args: string[];
81
114
  input: string;
115
+ multiplex: false;
82
116
  };
83
117
  /** Choose the transport for one push. Pure: registry read in, plan out. */
84
118
  export declare function planPushTransport(resolved: ResolvedBundleForPush, bundle: string, host: string, opts: PushBundleOptions): PushTransport;