@phnx-labs/agents-cli 1.22.34 → 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 (493) hide show
  1. package/CHANGELOG.md +672 -2
  2. package/README.md +82 -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 +85 -0
  94. package/dist/commands/share.js +379 -8
  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/codex-policy.d.ts +9 -1
  161. package/dist/lib/codex-policy.js +17 -2
  162. package/dist/lib/commands.d.ts +2 -0
  163. package/dist/lib/commands.js +2 -0
  164. package/dist/lib/computer/sessions-list.d.ts +150 -0
  165. package/dist/lib/computer/sessions-list.js +363 -0
  166. package/dist/lib/config-keys.d.ts +86 -0
  167. package/dist/lib/config-keys.js +193 -0
  168. package/dist/lib/config-machine-keys.d.ts +12 -0
  169. package/dist/lib/config-machine-keys.js +17 -0
  170. package/dist/lib/config-transfer.js +3 -4
  171. package/dist/lib/crabbox/cli.d.ts +2 -2
  172. package/dist/lib/crabbox/cli.js +3 -3
  173. package/dist/lib/daemon-health.d.ts +22 -0
  174. package/dist/lib/daemon-health.js +33 -3
  175. package/dist/lib/daemon-services.d.ts +50 -0
  176. package/dist/lib/daemon-services.js +147 -0
  177. package/dist/lib/daemon-ticks.d.ts +35 -66
  178. package/dist/lib/daemon-ticks.js +77 -159
  179. package/dist/lib/daemon.d.ts +72 -4
  180. package/dist/lib/daemon.js +792 -202
  181. package/dist/lib/deeplink/register.d.ts +49 -0
  182. package/dist/lib/deeplink/register.js +253 -0
  183. package/dist/lib/deeplink/url.d.ts +34 -0
  184. package/dist/lib/deeplink/url.js +78 -0
  185. package/dist/lib/device-config.d.ts +124 -29
  186. package/dist/lib/device-config.js +346 -141
  187. package/dist/lib/devices/config-migration.d.ts +42 -0
  188. package/dist/lib/devices/config-migration.js +203 -0
  189. package/dist/lib/devices/connect.js +14 -7
  190. package/dist/lib/devices/doctor-findings.d.ts +4 -1
  191. package/dist/lib/devices/doctor-findings.js +20 -1
  192. package/dist/lib/devices/harness-inventory.d.ts +11 -2
  193. package/dist/lib/devices/harness-inventory.js +0 -0
  194. package/dist/lib/devices/health.d.ts +1 -1
  195. package/dist/lib/devices/health.js +1 -1
  196. package/dist/lib/devices/pending.d.ts +22 -1
  197. package/dist/lib/devices/pending.js +67 -2
  198. package/dist/lib/devices/registry.d.ts +0 -25
  199. package/dist/lib/devices/registry.js +2 -83
  200. package/dist/lib/devices/resolve-profile.d.ts +20 -0
  201. package/dist/lib/devices/resolve-profile.js +44 -0
  202. package/dist/lib/devices/rollout-verify.d.ts +101 -0
  203. package/dist/lib/devices/rollout-verify.js +193 -0
  204. package/dist/lib/devices/ssh-config.js +10 -6
  205. package/dist/lib/event-families.d.ts +28 -0
  206. package/dist/lib/event-families.js +159 -0
  207. package/dist/lib/event-stream.d.ts +9 -1
  208. package/dist/lib/event-stream.js +26 -9
  209. package/dist/lib/events.d.ts +9 -1
  210. package/dist/lib/events.js +21 -6
  211. package/dist/lib/exec.d.ts +30 -0
  212. package/dist/lib/exec.js +220 -122
  213. package/dist/lib/feed-broadcast.d.ts +25 -0
  214. package/dist/lib/feed-broadcast.js +33 -0
  215. package/dist/lib/feed.d.ts +1 -1
  216. package/dist/lib/feed.js +12 -2
  217. package/dist/lib/fleet/capture.js +15 -0
  218. package/dist/lib/fleet/manifest.js +9 -0
  219. package/dist/lib/fleet/types.d.ts +9 -0
  220. package/dist/lib/fleet-status.js +10 -8
  221. package/dist/lib/git.d.ts +20 -6
  222. package/dist/lib/git.js +121 -17
  223. package/dist/lib/hosts/dispatch.d.ts +8 -3
  224. package/dist/lib/hosts/dispatch.js +29 -3
  225. package/dist/lib/hosts/logs.d.ts +2 -2
  226. package/dist/lib/hosts/logs.js +2 -2
  227. package/dist/lib/hosts/option.js +1 -1
  228. package/dist/lib/hosts/passthrough.d.ts +2 -3
  229. package/dist/lib/hosts/passthrough.js +10 -24
  230. package/dist/lib/hosts/progress.js +2 -2
  231. package/dist/lib/hosts/providers/devices.d.ts +3 -3
  232. package/dist/lib/hosts/providers/devices.js +18 -12
  233. package/dist/lib/hosts/ready.d.ts +5 -1
  234. package/dist/lib/hosts/ready.js +9 -3
  235. package/dist/lib/hosts/reconcile.d.ts +2 -2
  236. package/dist/lib/hosts/reconcile.js +2 -2
  237. package/dist/lib/hosts/registry.js +14 -9
  238. package/dist/lib/hosts/remote-cmd.js +1 -1
  239. package/dist/lib/hosts/remote-os.d.ts +9 -6
  240. package/dist/lib/hosts/remote-os.js +13 -6
  241. package/dist/lib/hosts/routing-flag.d.ts +23 -0
  242. package/dist/lib/hosts/routing-flag.js +41 -0
  243. package/dist/lib/hosts/run-target.js +1 -1
  244. package/dist/lib/hosts/session-index.js +1 -1
  245. package/dist/lib/hosts/tasks.d.ts +6 -6
  246. package/dist/lib/hosts/tasks.js +4 -4
  247. package/dist/lib/hosts/types.js +1 -2
  248. package/dist/lib/installations/resolve.js +2 -8
  249. package/dist/lib/isolation-boundary-report.js +0 -1
  250. package/dist/lib/linear-cache.d.ts +7 -0
  251. package/dist/lib/linear-cache.js +31 -4
  252. package/dist/lib/linear-project-counts.d.ts +1 -1
  253. package/dist/lib/linear-project-counts.js +2 -3
  254. package/dist/lib/linear-projects.js +1 -1
  255. package/dist/lib/loop.d.ts +2 -2
  256. package/dist/lib/loop.js +1 -1
  257. package/dist/lib/mailbox-target.d.ts +1 -1
  258. package/dist/lib/mailbox-target.js +1 -1
  259. package/dist/lib/manifest.js +7 -4
  260. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  261. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  262. package/dist/lib/menubar/snapshot.d.ts +3 -2
  263. package/dist/lib/menubar/snapshot.js +6 -2
  264. package/dist/lib/migrate-fold.d.ts +33 -0
  265. package/dist/lib/migrate-fold.js +130 -0
  266. package/dist/lib/migrate.d.ts +34 -34
  267. package/dist/lib/migrate.js +106 -128
  268. package/dist/lib/model-tier-overrides.d.ts +1 -1
  269. package/dist/lib/model-tier-overrides.js +15 -2
  270. package/dist/lib/monitors/config.d.ts +17 -3
  271. package/dist/lib/monitors/config.js +52 -18
  272. package/dist/lib/monitors/engine.d.ts +32 -1
  273. package/dist/lib/monitors/engine.js +94 -11
  274. package/dist/lib/monitors/fingerprint.d.ts +46 -0
  275. package/dist/lib/monitors/fingerprint.js +100 -0
  276. package/dist/lib/monitors/remote.d.ts +47 -0
  277. package/dist/lib/monitors/remote.js +81 -0
  278. package/dist/lib/monitors/state.d.ts +39 -0
  279. package/dist/lib/monitors/state.js +56 -0
  280. package/dist/lib/onepassword.d.ts +17 -0
  281. package/dist/lib/onepassword.js +52 -22
  282. package/dist/lib/open-url.js +1 -1
  283. package/dist/lib/picker.d.ts +14 -2
  284. package/dist/lib/picker.js +35 -13
  285. package/dist/lib/placement.d.ts +1 -1
  286. package/dist/lib/placement.js +1 -1
  287. package/dist/lib/pr-land-detach.d.ts +32 -0
  288. package/dist/lib/pr-land-detach.js +79 -0
  289. package/dist/lib/profiles-presets.js +13 -0
  290. package/dist/lib/profiles.d.ts +2 -0
  291. package/dist/lib/profiles.js +44 -1
  292. package/dist/lib/project-focus.d.ts +1 -1
  293. package/dist/lib/project-focus.js +1 -1
  294. package/dist/lib/project-key.d.ts +17 -0
  295. package/dist/lib/project-key.js +26 -0
  296. package/dist/lib/project-probe.d.ts +4 -1
  297. package/dist/lib/project-probe.js +5 -4
  298. package/dist/lib/project-resources.js +2 -18
  299. package/dist/lib/project-root.d.ts +16 -0
  300. package/dist/lib/project-root.js +20 -2
  301. package/dist/lib/projects.d.ts +20 -1
  302. package/dist/lib/projects.js +78 -1
  303. package/dist/lib/refresh-coordinator.d.ts +24 -0
  304. package/dist/lib/refresh-coordinator.js +52 -0
  305. package/dist/lib/registry.d.ts +2 -2
  306. package/dist/lib/registry.js +1 -1
  307. package/dist/lib/resource-aliases.d.ts +13 -0
  308. package/dist/lib/resource-aliases.js +26 -0
  309. package/dist/lib/resources/types.d.ts +1 -1
  310. package/dist/lib/resources.d.ts +16 -0
  311. package/dist/lib/resources.js +66 -10
  312. package/dist/lib/rotate.d.ts +3 -4
  313. package/dist/lib/rotate.js +4 -5
  314. package/dist/lib/routine-activation.d.ts +22 -2
  315. package/dist/lib/routine-activation.js +63 -16
  316. package/dist/lib/routine-context.d.ts +9 -2
  317. package/dist/lib/routine-context.js +21 -6
  318. package/dist/lib/routines-project.d.ts +58 -48
  319. package/dist/lib/routines-project.js +190 -159
  320. package/dist/lib/routines.d.ts +41 -6
  321. package/dist/lib/routines.js +92 -34
  322. package/dist/lib/run-defaults.d.ts +5 -0
  323. package/dist/lib/run-defaults.js +11 -1
  324. package/dist/lib/runner.d.ts +10 -8
  325. package/dist/lib/runner.js +122 -39
  326. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  327. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  328. package/dist/lib/secrets/agent.d.ts +10 -3
  329. package/dist/lib/secrets/agent.js +43 -8
  330. package/dist/lib/secrets/bundles.d.ts +1 -0
  331. package/dist/lib/secrets/bundles.js +92 -80
  332. package/dist/lib/secrets/index.js +32 -9
  333. package/dist/lib/secrets/install-helper.d.ts +4 -4
  334. package/dist/lib/secrets/install-helper.js +4 -4
  335. package/dist/lib/secrets/push.d.ts +40 -6
  336. package/dist/lib/secrets/push.js +58 -11
  337. package/dist/lib/secrets/read-backoff.d.ts +1 -1
  338. package/dist/lib/secrets/read-backoff.js +1 -1
  339. package/dist/lib/secrets/remote.d.ts +24 -0
  340. package/dist/lib/secrets/remote.js +54 -4
  341. package/dist/lib/self-update.d.ts +108 -0
  342. package/dist/lib/self-update.js +276 -1
  343. package/dist/lib/session/active.d.ts +89 -5
  344. package/dist/lib/session/active.js +165 -10
  345. package/dist/lib/session/actor-sidecar.d.ts +1 -1
  346. package/dist/lib/session/actor-sidecar.js +2 -1
  347. package/dist/lib/session/db.d.ts +176 -2
  348. package/dist/lib/session/db.js +484 -17
  349. package/dist/lib/session/discover.js +27 -4
  350. package/dist/lib/session/hook-sessions.js +2 -2
  351. package/dist/lib/session/host-link.d.ts +2 -2
  352. package/dist/lib/session/host-link.js +2 -2
  353. package/dist/lib/session/pid-registry.d.ts +21 -0
  354. package/dist/lib/session/pid-registry.js +57 -0
  355. package/dist/lib/session/remote-active.js +15 -1
  356. package/dist/lib/session/remote.js +2 -2
  357. package/dist/lib/session/session-cache.d.ts +14 -7
  358. package/dist/lib/session/session-cache.js +51 -9
  359. package/dist/lib/session/state.d.ts +2 -2
  360. package/dist/lib/session/state.js +1 -1
  361. package/dist/lib/session/sync/config.d.ts +10 -10
  362. package/dist/lib/session/sync/config.js +10 -10
  363. package/dist/lib/session/sync/r2.d.ts +34 -0
  364. package/dist/lib/session/sync/r2.js +123 -0
  365. package/dist/lib/session/throughput.d.ts +1 -1
  366. package/dist/lib/session/throughput.js +1 -1
  367. package/dist/lib/session/types.d.ts +23 -1
  368. package/dist/lib/session/types.js +15 -0
  369. package/dist/lib/session/viewing-in.d.ts +1 -1
  370. package/dist/lib/session/viewing-in.js +1 -1
  371. package/dist/lib/session/watch.d.ts +101 -0
  372. package/dist/lib/session/watch.js +242 -0
  373. package/dist/lib/share/config.d.ts +4 -0
  374. package/dist/lib/share/config.js +1 -0
  375. package/dist/lib/share/delete.d.ts +93 -0
  376. package/dist/lib/share/delete.js +127 -0
  377. package/dist/lib/share/provision.d.ts +38 -0
  378. package/dist/lib/share/provision.js +50 -0
  379. package/dist/lib/share/publish.d.ts +40 -1
  380. package/dist/lib/share/publish.js +116 -3
  381. package/dist/lib/share/worker-template.js +71 -6
  382. package/dist/lib/shims.d.ts +17 -3
  383. package/dist/lib/shims.js +136 -27
  384. package/dist/lib/signin-badge.js +3 -2
  385. package/dist/lib/skills.js +2 -0
  386. package/dist/lib/smart-launch.d.ts +8 -8
  387. package/dist/lib/smart-launch.js +80 -59
  388. package/dist/lib/ssh-exec.d.ts +1 -1
  389. package/dist/lib/ssh-exec.js +1 -1
  390. package/dist/lib/staleness/prune.d.ts +88 -0
  391. package/dist/lib/staleness/prune.js +69 -0
  392. package/dist/lib/staleness/registry.d.ts +1 -1
  393. package/dist/lib/staleness/writers/commands.js +34 -2
  394. package/dist/lib/staleness/writers/hooks.js +16 -0
  395. package/dist/lib/staleness/writers/kinds.d.ts +6 -0
  396. package/dist/lib/staleness/writers/skills.js +19 -0
  397. package/dist/lib/staleness/writers/subagents.d.ts +2 -3
  398. package/dist/lib/staleness/writers/subagents.js +0 -4
  399. package/dist/lib/staleness/writers/types.d.ts +32 -0
  400. package/dist/lib/startup/command-registry.d.ts +6 -12
  401. package/dist/lib/startup/command-registry.js +14 -31
  402. package/dist/lib/startup/dev-build.d.ts +10 -0
  403. package/dist/lib/startup/dev-build.js +13 -1
  404. package/dist/lib/startup/spellcheck.d.ts +18 -0
  405. package/dist/lib/startup/spellcheck.js +45 -0
  406. package/dist/lib/state.d.ts +36 -9
  407. package/dist/lib/state.js +96 -46
  408. package/dist/lib/subagents-registry.d.ts +0 -7
  409. package/dist/lib/subagents-registry.js +38 -65
  410. package/dist/lib/subagents.d.ts +0 -33
  411. package/dist/lib/subagents.js +0 -75
  412. package/dist/lib/sync-umbrella.js +1 -1
  413. package/dist/lib/teams/agents.d.ts +41 -1
  414. package/dist/lib/teams/agents.js +187 -9
  415. package/dist/lib/teams/api.d.ts +11 -1
  416. package/dist/lib/teams/api.js +11 -2
  417. package/dist/lib/teams/delivery.d.ts +41 -0
  418. package/dist/lib/teams/delivery.js +60 -0
  419. package/dist/lib/teams/registry.d.ts +14 -0
  420. package/dist/lib/teams/registry.js +51 -1
  421. package/dist/lib/teams/remoteWorktree.d.ts +19 -0
  422. package/dist/lib/teams/remoteWorktree.js +29 -0
  423. package/dist/lib/teams/scheduler.d.ts +1 -1
  424. package/dist/lib/teams/scheduler.js +1 -1
  425. package/dist/lib/teams/worktree.d.ts +24 -0
  426. package/dist/lib/teams/worktree.js +42 -0
  427. package/dist/lib/terminal/backends/vscodium-agent.d.ts +10 -1
  428. package/dist/lib/terminal/backends/vscodium-agent.js +16 -5
  429. package/dist/lib/terminal/engine.d.ts +4 -0
  430. package/dist/lib/terminal/engine.js +8 -2
  431. package/dist/lib/terminal/types.d.ts +21 -2
  432. package/dist/lib/testdata/refresh-coordinator-worker.d.ts +1 -0
  433. package/dist/lib/testdata/refresh-coordinator-worker.js +23 -0
  434. package/dist/lib/tickets/list.d.ts +53 -0
  435. package/dist/lib/tickets/list.js +153 -0
  436. package/dist/lib/tmux/orphan-reap.d.ts +320 -0
  437. package/dist/lib/tmux/orphan-reap.js +644 -0
  438. package/dist/lib/tmux/session.d.ts +68 -3
  439. package/dist/lib/tmux/session.js +95 -5
  440. package/dist/lib/triggers/handlers.d.ts +20 -0
  441. package/dist/lib/triggers/handlers.js +6 -1
  442. package/dist/lib/types.d.ts +46 -34
  443. package/dist/lib/usage-fleet.d.ts +32 -0
  444. package/dist/lib/usage-fleet.js +125 -0
  445. package/dist/lib/usage-refresh.d.ts +3 -3
  446. package/dist/lib/usage-refresh.js +19 -16
  447. package/dist/lib/usage.d.ts +51 -47
  448. package/dist/lib/usage.js +145 -153
  449. package/dist/lib/version-duplicates.js +2 -2
  450. package/dist/lib/versions.d.ts +56 -13
  451. package/dist/lib/versions.js +195 -45
  452. package/dist/lib/watchdog/log.d.ts +1 -1
  453. package/dist/lib/watchdog/log.js +3 -3
  454. package/dist/lib/watchdog/rotate.d.ts +6 -6
  455. package/dist/lib/watchdog/rotate.js +6 -6
  456. package/dist/lib/workflows.d.ts +1 -1
  457. package/dist/lib/yaml-io.d.ts +47 -0
  458. package/dist/lib/yaml-io.js +55 -0
  459. package/package.json +2 -1
  460. package/scripts/install-helper.js +2 -2
  461. package/scripts/postinstall.js +23 -20
  462. package/dist/commands/defaults.d.ts +0 -7
  463. package/dist/commands/defaults.js +0 -107
  464. package/dist/commands/export.d.ts +0 -11
  465. package/dist/commands/export.js +0 -215
  466. package/dist/commands/helper.d.ts +0 -12
  467. package/dist/commands/helper.js +0 -87
  468. package/dist/commands/hosts.d.ts +0 -11
  469. package/dist/commands/hosts.js +0 -330
  470. package/dist/commands/lock.d.ts +0 -12
  471. package/dist/commands/lock.js +0 -70
  472. package/dist/commands/pull.d.ts +0 -17
  473. package/dist/commands/pull.js +0 -39
  474. package/dist/commands/push.d.ts +0 -14
  475. package/dist/commands/push.js +0 -30
  476. package/dist/commands/wallet.d.ts +0 -20
  477. package/dist/commands/wallet.js +0 -216
  478. package/dist/commands/worktree.d.ts +0 -19
  479. package/dist/commands/worktree.js +0 -272
  480. package/dist/lib/account-labels.d.ts +0 -24
  481. package/dist/lib/account-labels.js +0 -72
  482. package/dist/lib/auto-dispatch-linear.d.ts +0 -18
  483. package/dist/lib/auto-dispatch-linear.js +0 -107
  484. package/dist/lib/auto-dispatch-provider.d.ts +0 -10
  485. package/dist/lib/auto-dispatch-provider.js +0 -30
  486. package/dist/lib/auto-dispatch.d.ts +0 -93
  487. package/dist/lib/auto-dispatch.js +0 -128
  488. package/dist/lib/export.d.ts +0 -72
  489. package/dist/lib/export.js +0 -269
  490. package/dist/lib/lock.d.ts +0 -93
  491. package/dist/lib/lock.js +0 -207
  492. package/dist/lib/wallet/index.d.ts +0 -78
  493. package/dist/lib/wallet/index.js +0 -253
@@ -1,31 +1,43 @@
1
1
  /**
2
- * Device/user config keys — typed read/write over the two-tier agents.yaml store.
2
+ * Device/user config keys — typed read/write over the central agents.yaml store.
3
3
  *
4
4
  * One registry (`CONFIG_KEYS`) maps each CLI dotted name to where it lives:
5
- * - user scope → central `~/.agents/agents.yaml` under `config:` (syncs
6
- * fleet-wide via `agents repo push/pull`)
7
- * - device scope `~/.agents/devices/<host>/agents.yaml` under `config:`
8
- * (per-machine; mirrors how `defaultBrowserProfile` is routed)
5
+ * - user scope → central `~/.agents/agents.yaml` under `config:` (syncs
6
+ * fleet-wide via `agents repo push/pull`)
7
+ * - device scope split by `visibility`, which asks WHO READS IT:
8
+ * · `shared` → central `fleet.devices.<name>.config`, because a PEER
9
+ * reads it (the ssh keys and platform to dial the box,
10
+ * agents.max-concurrent for placement, auto-launch and
11
+ * notes for fleet views). Names and non-secret values only
12
+ * (a secrets-bundle NAME is fine; a credential never is).
13
+ * · `machine` → the owning box's own doc, never the shared file, because
14
+ * nothing off-box reads it (browser.profile,
15
+ * browser.remote-control, scheduler.enabled,
16
+ * daemon.enabled).
9
17
  *
10
- * This machine's keys go through the readMeta/updateMeta funnel (state.ts) so the
11
- * partition/overlay logic stays the single writer. Another device's doc is
12
- * read/written in placethe devices/ tree syncs via the DotAgents repo, so
13
- * editing `devices/mac-mini/agents.yaml` locally is how `configure`/`note`
14
- * target a peer (`--device`-style).
18
+ * That split exists because "central for everything" put 13 machines on one
19
+ * tracked path and they stopped being able to pull. `browser.remote-control` is
20
+ * also a consent flag syncing one box's opt-in to the rest was a security bug,
21
+ * not just churn.
15
22
  *
16
- * `browser.profile` is NOT a `config:` key — it is the existing
17
- * `Meta.defaultBrowserProfile` field; the registry entry documents the mapping
18
- * and set/get route to it so there is one source of truth (no duplicate key).
23
+ * The device registry (`~/.agents/.history/devices/registry.json`) stays the
24
+ * DISCOVERY cache (address, tailscale snapshot, reachability); the profile
25
+ * fields config can override (ssh.*, platform, user) are overlaid onto it at
26
+ * read time by `lib/devices/resolve-profile.ts`.
19
27
  *
20
- * Unset always means today's behavior.
28
+ * Legacy stores (per-device `devices/<host>/agents.yaml` config and
29
+ * `.history/devices/auto-launch.json`) are folded into the central block once
30
+ * by `lib/devices/config-migration.ts`, invoked on the first read/write in a
31
+ * process — after migration there is ONE read path, no fallback branches.
32
+ *
33
+ * Unset always means today's behavior (the documented default).
21
34
  */
22
- import * as fs from 'fs';
23
- import * as path from 'path';
24
- import * as yaml from 'yaml';
25
- import { META_HEADER, getUserAgentsDir, readMeta, updateMeta } from './state.js';
26
- import { atomicWriteFileSync } from './fs-atomic.js';
35
+ import { readMeta, updateMeta } from './state.js';
27
36
  import { machineId } from './machine-id.js';
28
37
  import { assertValidDeviceName } from './devices/registry.js';
38
+ import { fleetDevicesMapForWrite, migrateDeviceConfigToCentral } from './devices/config-migration.js';
39
+ const DEVICE_PLATFORMS = ['windows', 'linux', 'macos', 'unknown'];
40
+ const SSH_AUTH_METHODS = ['key', 'password'];
29
41
  export const CONFIG_KEYS = [
30
42
  {
31
43
  name: 'interactive.host',
@@ -43,35 +55,56 @@ export const CONFIG_KEYS = [
43
55
  }
44
56
  },
45
57
  },
58
+ {
59
+ name: 'usage.primary-host',
60
+ yamlKey: 'usagePrimaryHost',
61
+ scope: 'user',
62
+ type: 'string',
63
+ description: 'Device whose usage snapshots are authoritative for fleet-wide usage reporting.',
64
+ validate: (v) => {
65
+ try {
66
+ assertValidDeviceName(v);
67
+ return null;
68
+ }
69
+ catch (err) {
70
+ return err?.message ?? String(err);
71
+ }
72
+ },
73
+ },
46
74
  {
47
75
  name: 'browser.profile',
48
76
  yamlKey: 'defaultBrowserProfile',
49
77
  scope: 'device',
78
+ visibility: 'machine',
50
79
  type: 'string',
51
- field: 'defaultBrowserProfile',
52
80
  description: 'Browser profile `agents browser start` resolves to without --profile (set via `agents browser profiles set-default`).',
53
81
  },
54
82
  {
55
83
  name: 'agents.max-concurrent',
56
84
  yamlKey: 'maxAgents',
57
85
  scope: 'device',
86
+ visibility: 'shared',
58
87
  type: 'int',
59
88
  description: 'Cap on concurrent agents on this device. What counts toward it depends on the consumer: ' +
60
- 'Factory auto-launch counts device-wide running agents; teams placement counts the team’s own roster on the device.',
89
+ 'AGI EXT auto-launch counts device-wide running agents; teams placement counts the team’s own roster on the device.',
61
90
  validate: (v) => (v >= 1 ? null : 'agents.max-concurrent must be >= 1.'),
62
91
  },
63
92
  {
64
93
  name: 'scheduler.enabled',
65
94
  yamlKey: 'schedulerEnabled',
66
95
  scope: 'device',
96
+ visibility: 'machine',
67
97
  type: 'bool',
98
+ defaultValue: true,
68
99
  description: 'Whether the routines scheduler (daemon) may fire on this device.',
69
100
  },
70
101
  {
71
102
  name: 'daemon.enabled',
72
103
  yamlKey: 'daemonEnabled',
73
104
  scope: 'device',
105
+ visibility: 'machine',
74
106
  type: 'bool',
107
+ defaultValue: true,
75
108
  description: 'Whether the daemon may run on this device at all (secrets broker, browser IPC, watchdog, and the ' +
76
109
  'routines scheduler). Disabling is the top-level kill switch: nothing auto-starts the daemon while it ' +
77
110
  'is set, including `routines add`/`routines start`/`routines catchup`/webhook triggers. ' +
@@ -81,14 +114,18 @@ export const CONFIG_KEYS = [
81
114
  name: 'watchdog.enabled',
82
115
  yamlKey: 'watchdogEnabled',
83
116
  scope: 'device',
117
+ visibility: 'shared',
84
118
  type: 'bool',
119
+ defaultValue: false,
85
120
  description: 'Whether the daemon runs the watchdog pass on this device.',
86
121
  },
87
122
  {
88
123
  name: 'browser.remote-control',
89
124
  yamlKey: 'browserRemoteControl',
90
125
  scope: 'device',
126
+ visibility: 'machine',
91
127
  type: 'bool',
128
+ defaultValue: false,
92
129
  description: "Whether other fleet machines may drive THIS device's browser over `browser --host <this-device>`. " +
93
130
  'Default off — a fleet-remote drive is refused until the owner runs `agents browser remote-control on`.',
94
131
  },
@@ -96,8 +133,81 @@ export const CONFIG_KEYS = [
96
133
  name: 'notes',
97
134
  yamlKey: 'notes',
98
135
  scope: 'device',
136
+ visibility: 'shared',
99
137
  type: 'string-list',
100
- description: 'Free-form operator notes about this device (one entry per `agents devices note`).',
138
+ description: 'Free-form operator notes about this device (one entry per `agents devices config <name> notes <text>`).',
139
+ },
140
+ {
141
+ name: 'ssh.user',
142
+ yamlKey: 'sshUser',
143
+ scope: 'device',
144
+ visibility: 'shared',
145
+ type: 'string',
146
+ description: 'SSH login user for the device — overrides the registry profile’s user at dial time.',
147
+ },
148
+ {
149
+ name: 'ssh.auth',
150
+ yamlKey: 'sshAuth',
151
+ scope: 'device',
152
+ visibility: 'shared',
153
+ type: 'string',
154
+ description: 'SSH auth method: `key` (ssh agent / on-disk keys) or `password` (pulled from a secrets bundle).',
155
+ validate: (v) => SSH_AUTH_METHODS.includes(v)
156
+ ? null
157
+ : `ssh.auth must be one of ${SSH_AUTH_METHODS.join(' | ')}.`,
158
+ },
159
+ {
160
+ name: 'ssh.bundle',
161
+ yamlKey: 'sshBundle',
162
+ scope: 'device',
163
+ visibility: 'shared',
164
+ type: 'string',
165
+ description: 'Secrets bundle holding the SSH password (for ssh.auth=password). A bundle NAME — never a secret value.',
166
+ },
167
+ {
168
+ name: 'ssh.bundle-key',
169
+ yamlKey: 'sshBundleKey',
170
+ scope: 'device',
171
+ visibility: 'shared',
172
+ type: 'string',
173
+ description: "Key within the bundle whose value is the password (default 'password').",
174
+ },
175
+ {
176
+ name: 'ssh.identity-file',
177
+ yamlKey: 'sshIdentityFile',
178
+ scope: 'device',
179
+ visibility: 'shared',
180
+ type: 'string',
181
+ description: 'Explicit private-key path for key auth (passed to OpenSSH with IdentitiesOnly=yes).',
182
+ },
183
+ {
184
+ name: 'platform',
185
+ yamlKey: 'platform',
186
+ scope: 'device',
187
+ visibility: 'shared',
188
+ type: 'string',
189
+ description: 'OS family of the device — picks PowerShell vs POSIX on the remote end. Overrides the discovered platform.',
190
+ validate: (v) => DEVICE_PLATFORMS.includes(v)
191
+ ? null
192
+ : `platform must be one of ${DEVICE_PLATFORMS.join(' | ')}.`,
193
+ },
194
+ {
195
+ name: 'auto-launch.enabled',
196
+ yamlKey: 'autoLaunchEnabled',
197
+ scope: 'device',
198
+ visibility: 'shared',
199
+ type: 'bool',
200
+ defaultValue: true,
201
+ description: 'Whether AGI EXT auto-launch may pick this device (default on).',
202
+ },
203
+ {
204
+ name: 'auto-launch.preferred',
205
+ yamlKey: 'autoLaunchPreferred',
206
+ scope: 'device',
207
+ visibility: 'shared',
208
+ type: 'bool',
209
+ defaultValue: false,
210
+ description: 'Boost this device in AGI EXT auto-launch ranking (default off).',
101
211
  },
102
212
  ];
103
213
  /** Look up a key spec by CLI dotted name, or throw listing the known keys. */
@@ -136,159 +246,254 @@ function assertValidValue(spec, value) {
136
246
  if (err)
137
247
  throw new Error(`Invalid value for '${spec.name}': ${err}`);
138
248
  }
139
- // ─── Sibling-device doc access ────────────────────────────────────────────────
140
- /** Path to any device's doc (self or a peer) under the synced devices/ tree. */
141
- function deviceDocPath(device) {
142
- return path.join(getUserAgentsDir(), 'devices', device, 'agents.yaml');
143
- }
249
+ // ─── Migration hook ───────────────────────────────────────────────────────────
250
+ let migrationDone = false;
144
251
  /**
145
- * Read a device doc directly. Returns null when the file does not exist. A
146
- * malformed file is a hard errorsilently returning null would let the next
147
- * write wipe the device's pins/default (same contract as the device registry).
148
- * A valid-but-non-map document (a bare string, a list) is the same kind of
149
- * corruption: reject it here instead of failing later with a TypeError.
252
+ * Fold the legacy per-device config stores into the central block, once per
253
+ * process. A failure is loud but non-fatalconfig reads must keep working,
254
+ * and the next process retries the fold. Honors AGENTS_SKIP_MIGRATION=1, the
255
+ * same gate bootstrap's runMigration uses (tests pin it so a fork never folds
256
+ * the developer's real ~/.agents as a side effect).
257
+ *
258
+ * Call this ONLY from a lifecycle entry point (daemon boot, `runMigration`).
259
+ * It must never hang off a config read or write: `~/.agents/agents.yaml` is a
260
+ * tracked file shared by every machine in the fleet, so a migration on the read
261
+ * path means an ordinary `agents config get` can dirty the shared file. That is
262
+ * what left yosemite-s0 unable to pull — 13 machines each rewriting one tracked
263
+ * path, on nearly every command.
150
264
  */
151
- function readDeviceDoc(device) {
152
- const p = deviceDocPath(device);
153
- let raw;
154
- try {
155
- raw = fs.readFileSync(p, 'utf-8');
156
- }
157
- catch (err) {
158
- if (err && err.code === 'ENOENT')
159
- return null;
160
- throw err;
161
- }
162
- const corrupted = (detail) => new Error(`Device config corrupted at ${p}: ${detail}. Inspect and restore from backup.`);
163
- let parsed;
265
+ export function ensureDeviceConfigMigrated() {
266
+ if (migrationDone || process.env.AGENTS_SKIP_MIGRATION === '1')
267
+ return;
164
268
  try {
165
- parsed = yaml.parse(raw);
269
+ migrateDeviceConfigToCentral();
270
+ migrationDone = true;
166
271
  }
167
272
  catch (err) {
168
- throw corrupted(err?.message ?? String(err));
169
- }
170
- if (parsed === null || parsed === undefined)
171
- return {};
172
- if (typeof parsed !== 'object' || Array.isArray(parsed)) {
173
- throw corrupted(`expected a YAML map, got ${Array.isArray(parsed) ? 'a list' : JSON.stringify(parsed)}`);
273
+ console.error(`device config migration failed (${err?.message ?? err}); a later run retries`);
174
274
  }
175
- return parsed;
176
- }
177
- /** Write a device doc in place (atomic). Only ever holds device-local fields. */
178
- function writeDeviceDoc(device, doc) {
179
- const p = deviceDocPath(device);
180
- fs.mkdirSync(path.dirname(p), { recursive: true });
181
- const body = Object.keys(doc).length > 0 ? doc : { agents: {} };
182
- atomicWriteFileSync(p, META_HEADER + yaml.stringify(body));
183
275
  }
184
276
  // ─── Reads ────────────────────────────────────────────────────────────────────
185
- function entryFromMeta(spec, meta) {
186
- if (spec.field === 'defaultBrowserProfile') {
187
- const value = meta.defaultBrowserProfile;
188
- return { spec, value, layer: value !== undefined ? 'device' : undefined };
189
- }
190
- if (spec.scope === 'user') {
191
- const value = meta.config?.[spec.yamlKey];
192
- return { spec, value, layer: value !== undefined ? 'user' : undefined };
193
- }
194
- const value = meta.deviceConfig?.[spec.yamlKey];
195
- return { spec, value, layer: value !== undefined ? 'device' : undefined };
277
+ /**
278
+ * The raw device-scope config block for `device` from the central
279
+ * `fleet.devices.<name>.config` map ({} when unset). This is the single read
280
+ * path post-migration the profile resolver (`lib/devices/resolve-profile.ts`)
281
+ * goes through here. Deliberately does NOT auto-trigger the migration: it
282
+ * serves the hot dial/render paths, and the keys it resolves (ssh.*, platform)
283
+ * are new — they never existed in the legacy stores. Keys with legacy data are
284
+ * read through the public API below, which triggers the fold.
285
+ */
286
+ export function readDeviceConfigValues(device) {
287
+ const devices = readMeta().fleet?.devices;
288
+ if (!devices || devices === 'all')
289
+ return {};
290
+ const config = devices[device]?.config;
291
+ return config && typeof config === 'object' && !Array.isArray(config) ? config : {};
292
+ }
293
+ /** The device a targeted read/write applies to (default: this machine). */
294
+ function targetDevice(opts) {
295
+ return opts?.device ?? machineId();
196
296
  }
197
- /** True when `device` names this machine (case-insensitive, mirroring
198
- * `isLocalDevice` in teams/scheduler.ts) `configure ZION` on host zion must
199
- * take the self path (readMeta/updateMeta funnel), not the peer-doc path. */
200
- function isSelfDevice(device) {
201
- return device.toLowerCase() === machineId();
297
+ /**
298
+ * A machine-visibility key is only ever readable for THIS box, because it lives
299
+ * in this box's own gitignored doc. Asking for a peer's value is a mistake with a
300
+ * concrete fix, so say so rather than silently returning this machine's answer
301
+ * for another machine — that would make `agents devices config <peer>
302
+ * browser.remote-control` look like it reported the peer's consent state.
303
+ */
304
+ function assertLocalTarget(spec, device) {
305
+ if (spec.scope !== 'device' || spec.visibility !== 'machine')
306
+ return;
307
+ if (device === machineId())
308
+ return;
309
+ throw new Error(`${spec.name} is machine-local, so it can only be read or set on the device itself.\n` +
310
+ `Run it on ${device}, e.g.: agents ssh ${device} 'agents config ${spec.name} <value>'`);
202
311
  }
203
312
  /** Get one config key's value and the layer that set it. */
204
313
  export function getConfigValue(name, opts) {
205
314
  const spec = configKeySpec(name);
206
- if (spec.scope === 'device' && opts?.device && !isSelfDevice(opts.device)) {
207
- const doc = readDeviceDoc(opts.device) ?? {};
208
- return entryFromMeta(spec, { deviceConfig: doc.config, defaultBrowserProfile: doc.defaultBrowserProfile });
315
+ if (spec.scope === 'user') {
316
+ const value = readMeta().config?.[spec.yamlKey];
317
+ return { spec, value, layer: value !== undefined ? 'user' : undefined };
318
+ }
319
+ const device = targetDevice(opts);
320
+ assertLocalTarget(spec, device);
321
+ if (spec.visibility === 'machine') {
322
+ // This machine's own doc, never the synced file. Fall back to the central
323
+ // block so a value written by an older CLI is still honored until the
324
+ // operator prunes it (the migration is additive and leaves it in place).
325
+ const local = readMeta().deviceConfig?.[spec.yamlKey];
326
+ const value = local !== undefined ? local : readDeviceConfigValues(device)[spec.yamlKey];
327
+ return { spec, value, layer: value !== undefined ? 'device' : undefined };
209
328
  }
210
- return entryFromMeta(spec, readMeta());
329
+ const value = readDeviceConfigValues(device)[spec.yamlKey];
330
+ return { spec, value, layer: value !== undefined ? 'device' : undefined };
211
331
  }
212
- /** List every known key with its value and the layer that set it. */
332
+ /**
333
+ * List every known key with its value and the layer that set it.
334
+ *
335
+ * Listing a PEER omits its machine-local keys rather than throwing. Their values
336
+ * live in that box's own doc and are genuinely unknowable from here, but a bulk
337
+ * listing must not hard-fail because one key in the registry is unreadable —
338
+ * `agents devices config <peer>` should still show everything it CAN resolve.
339
+ * Asking for such a key by name still errors, with the `agents ssh` fix named.
340
+ */
213
341
  export function listConfig(opts) {
214
- return CONFIG_KEYS.map((spec) => getConfigValue(spec.name, opts));
342
+ const isPeer = targetDevice(opts) !== machineId();
343
+ const visible = isPeer
344
+ ? CONFIG_KEYS.filter((spec) => spec.scope !== 'device' || spec.visibility !== 'machine')
345
+ : CONFIG_KEYS;
346
+ return visible.map((spec) => getConfigValue(spec.name, opts));
347
+ }
348
+ /** List user-scope config keys with their values. Used to show inherited settings
349
+ * in per-device views without implying those keys are device-local. */
350
+ export function listUserConfig() {
351
+ return CONFIG_KEYS.filter((spec) => spec.scope === 'user').map((spec) => getConfigValue(spec.name));
352
+ }
353
+ /** Resolve the explicit usage host, falling back to the user's interactive host. */
354
+ export function resolveUsagePrimaryHost() {
355
+ return getConfigValue('usage.primary-host').value
356
+ ?? getConfigValue('interactive.host').value
357
+ ?? null;
215
358
  }
216
359
  // ─── Writes ───────────────────────────────────────────────────────────────────
217
- function setInMeta(spec, value) {
360
+ function setInCentralBlock(device, spec, value) {
218
361
  updateMeta((m) => {
219
- if (spec.field === 'defaultBrowserProfile') {
220
- return { ...m, defaultBrowserProfile: value };
221
- }
222
- if (spec.scope === 'user') {
223
- return { ...m, config: { ...m.config, [spec.yamlKey]: value } };
224
- }
225
- return { ...m, deviceConfig: { ...m.deviceConfig, [spec.yamlKey]: value } };
362
+ const devices = fleetDevicesMapForWrite(m.fleet);
363
+ const prev = devices[device] ?? {};
364
+ devices[device] = { ...prev, config: { ...prev.config, [spec.yamlKey]: value } };
365
+ return { ...m, fleet: { ...m.fleet, devices } };
226
366
  });
227
367
  }
228
- function unsetInMeta(spec) {
368
+ function unsetInCentralBlock(device, spec) {
229
369
  updateMeta((m) => {
230
- if (spec.field === 'defaultBrowserProfile') {
231
- const { defaultBrowserProfile, ...rest } = m;
232
- void defaultBrowserProfile;
370
+ const stored = m.fleet?.devices;
371
+ if (!stored || stored === 'all')
372
+ return m; // nothing stored — unset is a no-op (never upgrade 'all' for one)
373
+ const prev = stored[device];
374
+ if (!prev?.config || !(spec.yamlKey in prev.config))
375
+ return m; // key not present — no write needed
376
+ const config = { ...prev.config };
377
+ delete config[spec.yamlKey];
378
+ const override = { ...prev };
379
+ if (Object.keys(config).length > 0)
380
+ override.config = config;
381
+ else
382
+ delete override.config;
383
+ const devices = { ...stored };
384
+ if (Object.keys(override).length > 0)
385
+ devices[device] = override;
386
+ else
387
+ delete devices[device];
388
+ const fleet = { ...m.fleet, devices };
389
+ // Drop the fleet block entirely when the unset emptied a block that holds
390
+ // nothing else — don't leave a vestigial `fleet: {devices: {}}` behind.
391
+ if (Object.keys(devices).length === 0 && !fleet.defaults && !fleet.secrets && !fleet.routines) {
392
+ const { fleet: _, ...rest } = m;
393
+ void _;
233
394
  return rest;
234
395
  }
235
- const block = spec.scope === 'user' ? m.config : m.deviceConfig;
236
- if (!block || !(spec.yamlKey in block))
237
- return m;
238
- const next = { ...block };
239
- delete next[spec.yamlKey];
240
- const cleaned = Object.keys(next).length > 0 ? next : undefined;
241
- return spec.scope === 'user' ? { ...m, config: cleaned } : { ...m, deviceConfig: cleaned };
396
+ return { ...m, fleet };
242
397
  });
243
398
  }
244
- function setInDeviceDoc(device, spec, value) {
245
- const doc = readDeviceDoc(device) ?? {};
246
- if (spec.field === 'defaultBrowserProfile') {
247
- doc.defaultBrowserProfile = value;
248
- }
249
- else {
250
- doc.config = { ...doc.config, [spec.yamlKey]: value };
251
- }
252
- writeDeviceDoc(device, doc);
253
- }
254
- function unsetInDeviceDoc(device, spec) {
255
- const doc = readDeviceDoc(device);
256
- if (!doc)
257
- return; // nothing stored — unset is a no-op
258
- if (spec.field === 'defaultBrowserProfile') {
259
- delete doc.defaultBrowserProfile;
260
- }
261
- else if (doc.config && spec.yamlKey in doc.config) {
262
- delete doc.config[spec.yamlKey];
263
- if (Object.keys(doc.config).length === 0)
264
- delete doc.config;
265
- }
266
- else {
267
- return; // key not present — no write needed
268
- }
269
- writeDeviceDoc(device, doc);
270
- }
271
399
  /** Set a config key (validated). Device-scope keys target this machine unless `opts.device` names a peer. */
272
400
  export function setConfigValue(name, value, opts) {
273
401
  const spec = configKeySpec(name);
274
402
  assertValidValue(spec, value);
275
- if (spec.scope === 'device' && opts?.device && !isSelfDevice(opts.device)) {
276
- setInDeviceDoc(opts.device, spec, value);
403
+ if (spec.scope === 'user') {
404
+ updateMeta((m) => ({ ...m, config: { ...m.config, [spec.yamlKey]: value } }));
405
+ return;
406
+ }
407
+ const device = targetDevice(opts);
408
+ assertLocalTarget(spec, device);
409
+ if (spec.visibility === 'machine') {
410
+ updateMeta((m) => ({ ...m, deviceConfig: { ...m.deviceConfig, [spec.yamlKey]: value } }));
277
411
  return;
278
412
  }
279
- setInMeta(spec, value);
413
+ setInCentralBlock(device, spec, value);
280
414
  }
281
415
  /** Unset a config key — restores default behavior. No-op when already unset. */
282
416
  export function unsetConfigValue(name, opts) {
283
417
  const spec = configKeySpec(name);
284
- if (spec.scope === 'device' && opts?.device && !isSelfDevice(opts.device)) {
285
- unsetInDeviceDoc(opts.device, spec);
418
+ if (spec.scope === 'user') {
419
+ updateMeta((m) => {
420
+ if (!m.config || !(spec.yamlKey in m.config))
421
+ return m;
422
+ const next = { ...m.config };
423
+ delete next[spec.yamlKey];
424
+ return { ...m, config: Object.keys(next).length > 0 ? next : undefined };
425
+ });
426
+ return;
427
+ }
428
+ const device = targetDevice(opts);
429
+ assertLocalTarget(spec, device);
430
+ if (spec.visibility === 'machine') {
431
+ updateMeta((m) => {
432
+ if (!m.deviceConfig || !(spec.yamlKey in m.deviceConfig))
433
+ return m;
434
+ const next = { ...m.deviceConfig };
435
+ delete next[spec.yamlKey];
436
+ return { ...m, deviceConfig: Object.keys(next).length > 0 ? next : undefined };
437
+ });
438
+ // Also clear any copy an older CLI left centrally, so the unset is not
439
+ // shadowed by the fallback read above.
440
+ unsetInCentralBlock(device, spec);
286
441
  return;
287
442
  }
288
- unsetInMeta(spec);
443
+ unsetInCentralBlock(device, spec);
444
+ }
445
+ /** True if the device is enabled for auto-launch. Unset defaults to true. */
446
+ export function isAutoLaunchEnabled(name) {
447
+ assertValidDeviceName(name);
448
+ return getConfigValue('auto-launch.enabled', { device: name }).value !== false;
449
+ }
450
+ /** Set whether a device is enabled for auto-launch. Setting the default
451
+ * (enabled) removes the key to keep the block minimal. */
452
+ export function setAutoLaunchEnabled(name, enabled) {
453
+ assertValidDeviceName(name);
454
+ if (enabled)
455
+ unsetConfigValue('auto-launch.enabled', { device: name });
456
+ else
457
+ setConfigValue('auto-launch.enabled', false, { device: name });
458
+ }
459
+ /** True if the device is preferred for auto-launch ranking. */
460
+ export function isAutoLaunchPreferred(name) {
461
+ assertValidDeviceName(name);
462
+ return getConfigValue('auto-launch.preferred', { device: name }).value === true;
463
+ }
464
+ /** Set whether a device is preferred for auto-launch. Setting the default
465
+ * (not preferred) removes the key to keep the block minimal. */
466
+ export function setAutoLaunchPreferred(name, preferred) {
467
+ assertValidDeviceName(name);
468
+ if (preferred)
469
+ setConfigValue('auto-launch.preferred', true, { device: name });
470
+ else
471
+ unsetConfigValue('auto-launch.preferred', { device: name });
472
+ }
473
+ /** Every device's auto-launch flags, keyed by device name (set flags only) —
474
+ * the shape the ext's launch ranking consumes. */
475
+ export function loadAutoLaunchPreferences() {
476
+ ensureDeviceConfigMigrated();
477
+ const devices = readMeta().fleet?.devices;
478
+ const out = {};
479
+ if (!devices || devices === 'all')
480
+ return out;
481
+ for (const [name, override] of Object.entries(devices)) {
482
+ const config = override?.config;
483
+ if (!config)
484
+ continue;
485
+ const pref = {};
486
+ if (config.autoLaunchEnabled === false)
487
+ pref.enabled = false;
488
+ if (config.autoLaunchPreferred === true)
489
+ pref.preferred = true;
490
+ if (pref.enabled !== undefined || pref.preferred !== undefined)
491
+ out[name] = pref;
492
+ }
493
+ return out;
289
494
  }
290
495
  // ─── Consumers' helpers ───────────────────────────────────────────────────────
291
- /** True unless this machine's device doc disables the routines scheduler. */
496
+ /** True unless this machine's config disables the routines scheduler. */
292
497
  export function isSchedulerEnabled() {
293
498
  return getConfigValue('scheduler.enabled').value !== false;
294
499
  }
@@ -301,10 +506,10 @@ export function isSchedulerEnabled() {
301
506
  export function assertSchedulerEnabled() {
302
507
  if (isSchedulerEnabled())
303
508
  return;
304
- throw new Error(`The routines scheduler is disabled on this device (scheduler.enabled=false in ~/.agents/devices/${machineId()}/agents.yaml). ` +
305
- `Re-enable with: agents devices configure ${machineId()} --scheduler on`);
509
+ throw new Error(`The routines scheduler is disabled on this device (scheduler.enabled=false in ~/.agents/agents.yaml fleet.devices.${machineId()}.config). ` +
510
+ `Re-enable with: agents devices config ${machineId()} scheduler.enabled on`);
306
511
  }
307
- /** True unless this machine's device doc disables the daemon outright (top-level kill switch). */
512
+ /** True unless this machine's config disables the daemon outright (top-level kill switch). */
308
513
  export function isDaemonEnabled() {
309
514
  return getConfigValue('daemon.enabled').value !== false;
310
515
  }
@@ -318,12 +523,12 @@ export function isDaemonEnabled() {
318
523
  export function assertDaemonEnabled() {
319
524
  if (isDaemonEnabled())
320
525
  return;
321
- throw new Error(`The daemon is disabled on this device (daemon.enabled=false in ~/.agents/devices/${machineId()}/agents.yaml). ` +
526
+ throw new Error(`The daemon is disabled on this device (daemon.enabled=false in ~/.agents/agents.yaml fleet.devices.${machineId()}.config). ` +
322
527
  `Re-enable with: agents daemon enable`);
323
528
  }
324
529
  /**
325
- * Read the `agents.max-concurrent` cap for each named device from its synced
326
- * device doc (no SSH). Devices without a cap are omitted — uncapped is the
530
+ * Read the `agents.max-concurrent` cap for each named device from the central
531
+ * config block (no SSH). Devices without a cap are omitted — uncapped is the
327
532
  * default. Used as an input to host ranking (teams placement, Factory
328
533
  * auto-launch), never as a remote probe.
329
534
  */