@phnx-labs/agents-cli 1.22.38 → 1.22.40

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 (554) hide show
  1. package/CHANGELOG.md +302 -0
  2. package/README.md +111 -70
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +46 -27
  5. package/dist/browser.js +2 -2
  6. package/dist/cli/command-registry.d.ts +135 -0
  7. package/dist/cli/command-registry.js +260 -0
  8. package/dist/commands/accounts.d.ts +20 -0
  9. package/dist/commands/accounts.js +186 -25
  10. package/dist/commands/apply.d.ts +3 -3
  11. package/dist/commands/apply.js +20 -63
  12. package/dist/commands/browser.js +206 -94
  13. package/dist/commands/budget.d.ts +7 -6
  14. package/dist/commands/budget.js +8 -7
  15. package/dist/commands/cloud.js +17 -20
  16. package/dist/commands/commands.js +1 -1
  17. package/dist/commands/computer-actions.d.ts +1 -35
  18. package/dist/commands/computer-actions.js +13 -181
  19. package/dist/commands/computer.d.ts +28 -3
  20. package/dist/commands/computer.js +93 -65
  21. package/dist/commands/config.js +47 -4
  22. package/dist/commands/cost.d.ts +2 -1
  23. package/dist/commands/cost.js +7 -6
  24. package/dist/commands/daemon.js +151 -4
  25. package/dist/commands/detach.js +1 -1
  26. package/dist/commands/doctor.js +19 -11
  27. package/dist/commands/events.js +1 -1
  28. package/dist/commands/exec.d.ts +2 -50
  29. package/dist/commands/exec.js +161 -216
  30. package/dist/commands/factory.js +1 -1
  31. package/dist/commands/feed.d.ts +2 -2
  32. package/dist/commands/feed.js +9 -12
  33. package/dist/commands/fleet-capture.js +25 -27
  34. package/dist/commands/focus.d.ts +2 -3
  35. package/dist/commands/focus.js +34 -9
  36. package/dist/commands/go.js +15 -5
  37. package/dist/commands/harness.d.ts +3 -3
  38. package/dist/commands/harness.js +53 -5
  39. package/dist/commands/hooks.js +1 -1
  40. package/dist/commands/import.js +2 -2
  41. package/dist/commands/insights.d.ts +5 -5
  42. package/dist/commands/insights.js +15 -9
  43. package/dist/commands/inspect.d.ts +2 -3
  44. package/dist/commands/inspect.js +4 -16
  45. package/dist/commands/logs.d.ts +2 -2
  46. package/dist/commands/logs.js +9 -9
  47. package/dist/commands/mcp.js +2 -2
  48. package/dist/commands/memory.js +1 -1
  49. package/dist/commands/message.d.ts +1 -1
  50. package/dist/commands/message.js +7 -7
  51. package/dist/commands/mine.d.ts +11 -8
  52. package/dist/commands/mine.js +11 -10
  53. package/dist/commands/models.js +1 -1
  54. package/dist/commands/modes.js +1 -1
  55. package/dist/commands/monitors.js +23 -6
  56. package/dist/commands/output.d.ts +7 -6
  57. package/dist/commands/output.js +11 -10
  58. package/dist/commands/packages.js +4 -4
  59. package/dist/commands/perf.js +1 -1
  60. package/dist/commands/permissions.js +49 -32
  61. package/dist/commands/plugins.d.ts +1 -1
  62. package/dist/commands/plugins.js +3 -3
  63. package/dist/commands/profiles.d.ts +6 -9
  64. package/dist/commands/profiles.js +8 -321
  65. package/dist/commands/projects.d.ts +9 -0
  66. package/dist/commands/projects.js +140 -8
  67. package/dist/commands/prune.js +5 -13
  68. package/dist/commands/refresh-rules.js +1 -1
  69. package/dist/commands/repo.d.ts +5 -7
  70. package/dist/commands/repo.js +34 -18
  71. package/dist/commands/resource-view.js +4 -0
  72. package/dist/commands/resume.d.ts +11 -7
  73. package/dist/commands/resume.js +82 -98
  74. package/dist/commands/route.d.ts +12 -0
  75. package/dist/commands/route.js +261 -0
  76. package/dist/commands/routines.d.ts +2 -3
  77. package/dist/commands/routines.js +120 -145
  78. package/dist/commands/rules.js +1 -1
  79. package/dist/commands/run-account-picker.d.ts +1 -1
  80. package/dist/commands/run-account-picker.js +2 -2
  81. package/dist/commands/run-broadcast.d.ts +21 -0
  82. package/dist/commands/run-broadcast.js +89 -0
  83. package/dist/commands/run-cloud.js +1 -1
  84. package/dist/commands/secrets-vault.d.ts +10 -0
  85. package/dist/commands/{login.js → secrets-vault.js} +34 -14
  86. package/dist/commands/secrets.d.ts +4 -4
  87. package/dist/commands/secrets.js +72 -63
  88. package/dist/commands/sessions-backfill.js +1 -1
  89. package/dist/commands/sessions-browser.d.ts +1 -1
  90. package/dist/commands/sessions-browser.js +9 -5
  91. package/dist/commands/sessions-export.js +2 -2
  92. package/dist/commands/sessions-inject.js +4 -5
  93. package/dist/commands/sessions-migrate.js +16 -27
  94. package/dist/commands/sessions-picker.d.ts +13 -0
  95. package/dist/commands/sessions-picker.js +182 -8
  96. package/dist/commands/sessions-resume.d.ts +7 -3
  97. package/dist/commands/sessions-resume.js +81 -33
  98. package/dist/commands/sessions-stats.js +2 -2
  99. package/dist/commands/sessions.d.ts +75 -68
  100. package/dist/commands/sessions.js +142 -180
  101. package/dist/commands/setup-computer.js +1 -1
  102. package/dist/commands/setup-fleet.js +3 -0
  103. package/dist/commands/setup-mine.d.ts +7 -3
  104. package/dist/commands/setup-mine.js +13 -8
  105. package/dist/commands/setup-secrets.js +2 -2
  106. package/dist/commands/setup-watchdog.js +2 -2
  107. package/dist/commands/setup.js +7 -2
  108. package/dist/commands/share.d.ts +65 -0
  109. package/dist/commands/share.js +253 -20
  110. package/dist/commands/skills.js +3 -3
  111. package/dist/commands/snapshot.d.ts +2 -2
  112. package/dist/commands/snapshot.js +9 -9
  113. package/dist/commands/ssh.d.ts +1 -1
  114. package/dist/commands/ssh.js +318 -48
  115. package/dist/commands/subagents.js +1 -1
  116. package/dist/commands/sync.js +24 -9
  117. package/dist/commands/teams.d.ts +2 -2
  118. package/dist/commands/teams.js +9 -18
  119. package/dist/commands/tmux.js +5 -1
  120. package/dist/commands/trash.js +1 -1
  121. package/dist/commands/usage.d.ts +1 -1
  122. package/dist/commands/usage.js +2 -2
  123. package/dist/commands/utils.d.ts +4 -14
  124. package/dist/commands/utils.js +6 -27
  125. package/dist/commands/versions.js +2 -2
  126. package/dist/commands/view.d.ts +9 -77
  127. package/dist/commands/view.js +23 -8
  128. package/dist/commands/watchdog.js +1 -1
  129. package/dist/commands/webhook.js +11 -25
  130. package/dist/commands/workflows.js +1 -1
  131. package/dist/index.js +1 -1
  132. package/dist/lib/account-capabilities.d.ts +39 -0
  133. package/dist/lib/account-capabilities.js +59 -0
  134. package/dist/lib/account-catalog.js +1 -1
  135. package/dist/lib/account-registry.d.ts +66 -0
  136. package/dist/lib/account-registry.js +151 -5
  137. package/dist/lib/{rotate.d.ts → accounting/rotate.d.ts} +4 -4
  138. package/dist/lib/{rotate.js → accounting/rotate.js} +8 -8
  139. package/dist/lib/{usage.d.ts → accounting/usage.d.ts} +4 -4
  140. package/dist/lib/{usage.js → accounting/usage.js} +11 -11
  141. package/dist/lib/agent-spec/provider.js +1 -1
  142. package/dist/lib/agents.d.ts +72 -4
  143. package/dist/lib/agents.js +231 -199
  144. package/dist/lib/answer-router.d.ts +2 -2
  145. package/dist/lib/ask-classifier.d.ts +1 -1
  146. package/dist/lib/ask-classifier.js +1 -1
  147. package/dist/lib/audit/log.js +1 -1
  148. package/dist/lib/auth-health.d.ts +1 -1
  149. package/dist/lib/auth-health.js +2 -2
  150. package/dist/lib/brand.js +1 -1
  151. package/dist/lib/browser/caller-identity.d.ts +28 -0
  152. package/dist/lib/browser/caller-identity.js +156 -0
  153. package/dist/lib/browser/cdp.js +1 -1
  154. package/dist/lib/browser/drivers/ssh.d.ts +1 -1
  155. package/dist/lib/browser/drivers/ssh.js +2 -2
  156. package/dist/lib/browser/hygiene.d.ts +10 -2
  157. package/dist/lib/browser/hygiene.js +7 -4
  158. package/dist/lib/browser/ipc.d.ts +22 -2
  159. package/dist/lib/browser/ipc.js +185 -21
  160. package/dist/lib/browser/profiles.d.ts +67 -3
  161. package/dist/lib/browser/profiles.js +129 -7
  162. package/dist/lib/browser/remote-control.d.ts +2 -2
  163. package/dist/lib/browser/remote-control.js +3 -3
  164. package/dist/lib/browser/runtime-state.d.ts +79 -0
  165. package/dist/lib/browser/runtime-state.js +119 -1
  166. package/dist/lib/browser/service.d.ts +113 -1
  167. package/dist/lib/browser/service.js +454 -40
  168. package/dist/lib/browser/sessions-list.d.ts +2 -1
  169. package/dist/lib/browser/sessions-list.js +4 -13
  170. package/dist/lib/browser/types.d.ts +18 -0
  171. package/dist/lib/budget/config.js +1 -1
  172. package/dist/lib/budget/ledger.js +1 -1
  173. package/dist/lib/byok-usage.js +1 -1
  174. package/dist/lib/capabilities.js +3 -15
  175. package/dist/lib/catchup.d.ts +1 -1
  176. package/dist/lib/catchup.js +1 -1
  177. package/dist/lib/cloud/dispatch.js +1 -1
  178. package/dist/lib/cloud/host.d.ts +3 -3
  179. package/dist/lib/cloud/host.js +5 -5
  180. package/dist/lib/cloud/rush.d.ts +9 -21
  181. package/dist/lib/cloud/rush.js +33 -120
  182. package/dist/lib/cloud/types.d.ts +2 -2
  183. package/dist/lib/commands.js +3 -13
  184. package/dist/lib/computer/actions.d.ts +36 -0
  185. package/dist/lib/computer/actions.js +162 -0
  186. package/dist/lib/computer/dispatch.d.ts +2 -2
  187. package/dist/lib/computer/dispatch.js +2 -2
  188. package/dist/lib/computer/sessions-list.d.ts +3 -3
  189. package/dist/lib/computer/sessions-list.js +2 -2
  190. package/dist/lib/config-keys.d.ts +12 -3
  191. package/dist/lib/config-keys.js +29 -6
  192. package/dist/lib/config-machine-keys.d.ts +4 -2
  193. package/dist/lib/config-machine-keys.js +6 -2
  194. package/dist/lib/crabbox/lease.js +9 -1
  195. package/dist/lib/crabbox/runtimes.d.ts +32 -7
  196. package/dist/lib/crabbox/runtimes.js +72 -30
  197. package/dist/lib/{daemon.d.ts → daemon/daemon.d.ts} +59 -1
  198. package/dist/lib/{daemon.js → daemon/daemon.js} +237 -49
  199. package/dist/lib/daemon-services.d.ts +1 -1
  200. package/dist/lib/daemon-services.js +5 -0
  201. package/dist/lib/daemon-ticks.d.ts +25 -0
  202. package/dist/lib/daemon-ticks.js +31 -1
  203. package/dist/lib/daemon-webhooks.d.ts +102 -0
  204. package/dist/lib/daemon-webhooks.js +210 -0
  205. package/dist/lib/device-config.d.ts +116 -72
  206. package/dist/lib/device-config.js +366 -132
  207. package/dist/lib/devices/config-migration.d.ts +29 -34
  208. package/dist/lib/devices/config-migration.js +209 -130
  209. package/dist/lib/devices/connect.d.ts +2 -2
  210. package/dist/lib/devices/connect.js +2 -2
  211. package/dist/lib/devices/discovery-policy.d.ts +30 -0
  212. package/dist/lib/devices/discovery-policy.js +101 -0
  213. package/dist/lib/devices/fleet-inventory.js +8 -3
  214. package/dist/lib/devices/harness-inventory.d.ts +1 -1
  215. package/dist/lib/devices/harness-inventory.js +12 -3
  216. package/dist/lib/devices/known-hosts.js +1 -1
  217. package/dist/lib/devices/pool.d.ts +61 -0
  218. package/dist/lib/devices/pool.js +83 -0
  219. package/dist/lib/devices/registry.d.ts +1 -1
  220. package/dist/lib/devices/registry.js +1 -1
  221. package/dist/lib/devices/resolve-profile.d.ts +2 -2
  222. package/dist/lib/devices/resolve-profile.js +2 -2
  223. package/dist/lib/devices/resolve-target.d.ts +1 -1
  224. package/dist/lib/devices/resolve-target.js +4 -4
  225. package/dist/lib/devices/self-host.d.ts +1 -1
  226. package/dist/lib/devices/self-host.js +3 -3
  227. package/dist/lib/devices/ssh-config.d.ts +1 -1
  228. package/dist/lib/devices/stats-cache.js +1 -1
  229. package/dist/lib/devices/sync.d.ts +3 -1
  230. package/dist/lib/devices/sync.js +3 -3
  231. package/dist/lib/doctor-diff.js +4 -4
  232. package/dist/lib/drift-sync.js +2 -2
  233. package/dist/lib/drift.js +2 -2
  234. package/dist/lib/event-families.d.ts +1 -1
  235. package/dist/lib/event-stream.d.ts +1 -1
  236. package/dist/lib/event-stream.js +2 -2
  237. package/dist/lib/events-ingest.js +2 -2
  238. package/dist/lib/exec.d.ts +8 -5
  239. package/dist/lib/exec.js +19 -13
  240. package/dist/lib/factory/snapshot.d.ts +1 -1
  241. package/dist/lib/factory/snapshot.js +1 -1
  242. package/dist/lib/{activity.d.ts → feed/activity.d.ts} +1 -1
  243. package/dist/lib/{activity.js → feed/activity.js} +7 -7
  244. package/dist/lib/{events.d.ts → feed/events.d.ts} +2 -2
  245. package/dist/lib/{events.js → feed/events.js} +5 -5
  246. package/dist/lib/{feed.js → feed/feed.js} +4 -4
  247. package/dist/lib/feed-outcome.d.ts +1 -1
  248. package/dist/lib/feed-policy.d.ts +1 -1
  249. package/dist/lib/feed-policy.js +1 -1
  250. package/dist/lib/feed-post.d.ts +1 -1
  251. package/dist/lib/feed-post.js +1 -1
  252. package/dist/lib/feed-ranking.d.ts +1 -1
  253. package/dist/lib/fleet/apply.d.ts +0 -6
  254. package/dist/lib/fleet/apply.js +18 -45
  255. package/dist/lib/fleet/auth-sync.d.ts +16 -35
  256. package/dist/lib/fleet/auth-sync.js +16 -75
  257. package/dist/lib/fleet/capture.js +8 -6
  258. package/dist/lib/fleet/manifest.js +23 -11
  259. package/dist/lib/fleet/types.d.ts +19 -7
  260. package/dist/lib/fleet-cache.d.ts +1 -1
  261. package/dist/lib/fleet-cache.js +1 -1
  262. package/dist/lib/format.d.ts +19 -0
  263. package/dist/lib/format.js +44 -1
  264. package/dist/lib/friction-heuristics.d.ts +1 -1
  265. package/dist/lib/git.d.ts +24 -1
  266. package/dist/lib/git.js +82 -38
  267. package/dist/lib/heal.js +3 -3
  268. package/dist/lib/hooks.d.ts +18 -0
  269. package/dist/lib/hooks.js +113 -1
  270. package/dist/lib/hosts/credentials.d.ts +30 -10
  271. package/dist/lib/hosts/credentials.js +38 -26
  272. package/dist/lib/hosts/dispatch.d.ts +3 -3
  273. package/dist/lib/hosts/dispatch.js +3 -3
  274. package/dist/lib/hosts/option.d.ts +3 -3
  275. package/dist/lib/hosts/option.js +7 -8
  276. package/dist/lib/hosts/passthrough.d.ts +17 -17
  277. package/dist/lib/hosts/passthrough.js +67 -50
  278. package/dist/lib/hosts/providers/devices.d.ts +1 -1
  279. package/dist/lib/hosts/providers/devices.js +1 -1
  280. package/dist/lib/hosts/reconcile.d.ts +1 -1
  281. package/dist/lib/hosts/reconcile.js +1 -1
  282. package/dist/lib/hosts/reconnect.d.ts +1 -1
  283. package/dist/lib/hosts/reconnect.js +2 -2
  284. package/dist/lib/hosts/registry.d.ts +5 -5
  285. package/dist/lib/hosts/registry.js +5 -5
  286. package/dist/lib/hosts/remote-cmd.d.ts +10 -10
  287. package/dist/lib/hosts/remote-cmd.js +25 -18
  288. package/dist/lib/hosts/remote-os.d.ts +4 -4
  289. package/dist/lib/hosts/remote-os.js +4 -4
  290. package/dist/lib/hosts/remote-session-id.d.ts +2 -2
  291. package/dist/lib/hosts/remote-session-id.js +2 -2
  292. package/dist/lib/hosts/routing-flag.d.ts +3 -3
  293. package/dist/lib/hosts/routing-flag.js +4 -5
  294. package/dist/lib/hosts/run-target.d.ts +4 -4
  295. package/dist/lib/hosts/run-target.js +4 -4
  296. package/dist/lib/hosts/session-index.d.ts +2 -2
  297. package/dist/lib/hosts/session-index.js +1 -1
  298. package/dist/lib/hosts/session-marker.d.ts +1 -1
  299. package/dist/lib/hosts/session-marker.js +1 -1
  300. package/dist/lib/hosts/types.d.ts +2 -2
  301. package/dist/lib/hosts/types.js +2 -2
  302. package/dist/lib/import.js +1 -1
  303. package/dist/lib/{migrate.d.ts → installations/migrate.d.ts} +49 -1
  304. package/dist/lib/{migrate.js → installations/migrate.js} +265 -38
  305. package/dist/lib/installations/resolve.js +1 -1
  306. package/dist/lib/installations/strategies.js +1 -1
  307. package/dist/lib/installations/update.js +2 -2
  308. package/dist/lib/{versions.d.ts → installations/versions.d.ts} +12 -3
  309. package/dist/lib/{versions.js → installations/versions.js} +51 -31
  310. package/dist/lib/isolation-boundary-report.js +1 -1
  311. package/dist/lib/linear-projects.d.ts +28 -0
  312. package/dist/lib/linear-projects.js +30 -0
  313. package/dist/lib/loop.js +1 -1
  314. package/dist/lib/mailbox-gc.js +1 -1
  315. package/dist/lib/mailbox.js +1 -1
  316. package/dist/lib/mcp-registry.d.ts +62 -0
  317. package/dist/lib/mcp-registry.js +177 -0
  318. package/dist/lib/mcp.d.ts +5 -0
  319. package/dist/lib/mcp.js +124 -307
  320. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  321. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  322. package/dist/lib/menubar/install-menubar.d.ts +7 -0
  323. package/dist/lib/menubar/install-menubar.js +24 -6
  324. package/dist/lib/menubar/snapshot.d.ts +7 -0
  325. package/dist/lib/menubar/snapshot.js +8 -6
  326. package/dist/lib/models.js +1 -1
  327. package/dist/lib/monitors/config.d.ts +12 -0
  328. package/dist/lib/monitors/config.js +3 -0
  329. package/dist/lib/monitors/dispatch.js +26 -5
  330. package/dist/lib/monitors/engine.js +10 -0
  331. package/dist/lib/monitors/sources/webhook.d.ts +1 -1
  332. package/dist/lib/monitors/state.d.ts +42 -0
  333. package/dist/lib/monitors/state.js +30 -0
  334. package/dist/lib/notify.d.ts +1 -1
  335. package/dist/lib/observe-aliases.d.ts +2 -2
  336. package/dist/lib/observe-aliases.js +2 -11
  337. package/dist/lib/output/git-output.js +2 -2
  338. package/dist/lib/overdue.d.ts +1 -1
  339. package/dist/lib/overdue.js +1 -1
  340. package/dist/lib/permissions-registry.d.ts +65 -0
  341. package/dist/lib/permissions-registry.js +599 -0
  342. package/dist/lib/permissions.d.ts +24 -13
  343. package/dist/lib/permissions.js +52 -271
  344. package/dist/lib/picker.d.ts +16 -0
  345. package/dist/lib/picker.js +33 -3
  346. package/dist/lib/placement.d.ts +1 -1
  347. package/dist/lib/placement.js +4 -4
  348. package/dist/lib/platform/paths.d.ts +8 -0
  349. package/dist/lib/platform/paths.js +11 -0
  350. package/dist/lib/platform/posixpath.js +3 -3
  351. package/dist/lib/{plugin-marketplace.d.ts → plugins/plugin-marketplace.d.ts} +1 -1
  352. package/dist/lib/{plugin-marketplace.js → plugins/plugin-marketplace.js} +2 -2
  353. package/dist/lib/{plugins.d.ts → plugins/plugins.d.ts} +1 -1
  354. package/dist/lib/{plugins.js → plugins/plugins.js} +7 -7
  355. package/dist/lib/{skills.d.ts → plugins/skills.d.ts} +1 -1
  356. package/dist/lib/{skills.js → plugins/skills.js} +7 -7
  357. package/dist/lib/pricing/cost.d.ts +1 -1
  358. package/dist/lib/pricing/cost.js +1 -1
  359. package/dist/lib/profiles-presets.d.ts +1 -1
  360. package/dist/lib/profiles-presets.js +1 -1
  361. package/dist/lib/profiles.js +2 -2
  362. package/dist/lib/project-import.js +4 -1
  363. package/dist/lib/project-launch.d.ts +1 -1
  364. package/dist/lib/project-launch.js +3 -3
  365. package/dist/lib/project-pull.d.ts +128 -0
  366. package/dist/lib/project-pull.js +384 -0
  367. package/dist/lib/project-root.d.ts +2 -2
  368. package/dist/lib/project-root.js +2 -2
  369. package/dist/lib/project-status.js +1 -1
  370. package/dist/lib/projects.d.ts +23 -0
  371. package/dist/lib/projects.js +29 -6
  372. package/dist/lib/refresh.d.ts +12 -1
  373. package/dist/lib/refresh.js +16 -9
  374. package/dist/lib/registry.d.ts +9 -2
  375. package/dist/lib/registry.js +11 -4
  376. package/dist/lib/resources.d.ts +2 -2
  377. package/dist/lib/resources.js +2 -2
  378. package/dist/lib/routers.d.ts +81 -0
  379. package/dist/lib/routers.js +153 -0
  380. package/dist/lib/routine-context.d.ts +1 -0
  381. package/dist/lib/routine-context.js +7 -2
  382. package/dist/lib/routine-notify-owner.d.ts +1 -1
  383. package/dist/lib/routine-notify.d.ts +1 -1
  384. package/dist/lib/routine-notify.js +1 -1
  385. package/dist/lib/routine-process-cleanup.d.ts +1 -1
  386. package/dist/lib/routine-readiness.d.ts +1 -1
  387. package/dist/lib/routine-readiness.js +11 -4
  388. package/dist/lib/routines-placement.d.ts +12 -2
  389. package/dist/lib/routines-placement.js +20 -3
  390. package/dist/lib/routines-project.d.ts +1 -1
  391. package/dist/lib/routines-project.js +1 -1
  392. package/dist/lib/rules/compile.d.ts +1 -0
  393. package/dist/lib/rules/compile.js +10 -2
  394. package/dist/lib/rules/rules.js +1 -1
  395. package/dist/lib/run-notify.js +1 -1
  396. package/dist/lib/runner.d.ts +80 -2
  397. package/dist/lib/runner.js +241 -62
  398. package/dist/lib/sandbox.d.ts +1 -1
  399. package/dist/lib/scheduler.d.ts +1 -1
  400. package/dist/lib/scheduler.js +1 -1
  401. package/dist/lib/{routines.d.ts → scheduling/routines.d.ts} +54 -9
  402. package/dist/lib/{routines.js → scheduling/routines.js} +173 -14
  403. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  404. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  405. package/dist/lib/secrets/agent.js +2 -2
  406. package/dist/lib/secrets/audit.js +1 -1
  407. package/dist/lib/secrets/bundles.d.ts +3 -3
  408. package/dist/lib/secrets/bundles.js +7 -7
  409. package/dist/lib/secrets/index.js +1 -1
  410. package/dist/lib/secrets/list-filter.d.ts +1 -1
  411. package/dist/lib/secrets/list-filter.js +2 -2
  412. package/dist/lib/secrets/push.d.ts +1 -1
  413. package/dist/lib/secrets/push.js +10 -12
  414. package/dist/lib/secrets/remote.d.ts +12 -10
  415. package/dist/lib/secrets/remote.js +21 -14
  416. package/dist/lib/secrets/vault.js +2 -2
  417. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  418. package/dist/lib/self-heal/checks/shims.js +1 -1
  419. package/dist/lib/self-update.d.ts +39 -4
  420. package/dist/lib/self-update.js +78 -25
  421. package/dist/lib/serve/control.d.ts +1 -1
  422. package/dist/lib/serve/control.js +4 -4
  423. package/dist/lib/serve/data.d.ts +1 -1
  424. package/dist/lib/serve/data.js +1 -1
  425. package/dist/lib/serve/stream.js +1 -1
  426. package/dist/lib/service-manifest.d.ts +29 -0
  427. package/dist/lib/service-manifest.js +80 -0
  428. package/dist/lib/session/active.d.ts +59 -7
  429. package/dist/lib/session/active.js +158 -17
  430. package/dist/lib/session/bash-command.js +1 -1
  431. package/dist/lib/session/claude-accounts.d.ts +1 -1
  432. package/dist/lib/session/claude-accounts.js +1 -1
  433. package/dist/lib/session/db.d.ts +10 -2
  434. package/dist/lib/session/db.js +25 -6
  435. package/dist/lib/session/discover.d.ts +77 -0
  436. package/dist/lib/session/discover.js +130 -25
  437. package/dist/lib/session/fork.js +1 -1
  438. package/dist/lib/session/inject.d.ts +1 -1
  439. package/dist/lib/session/insights.d.ts +1 -1
  440. package/dist/lib/session/insights.js +1 -1
  441. package/dist/lib/session/live-metadata.d.ts +15 -0
  442. package/dist/lib/session/live-metadata.js +76 -0
  443. package/dist/lib/session/migrate-targets.d.ts +1 -1
  444. package/dist/lib/session/recovery.d.ts +1 -1
  445. package/dist/lib/session/recovery.js +2 -2
  446. package/dist/lib/session/remote-active.d.ts +10 -1
  447. package/dist/lib/session/remote-active.js +8 -3
  448. package/dist/lib/session/remote-bundle.d.ts +1 -1
  449. package/dist/lib/session/remote-bundle.js +2 -2
  450. package/dist/lib/session/remote-list.d.ts +15 -4
  451. package/dist/lib/session/remote-list.js +40 -3
  452. package/dist/lib/session/remote.d.ts +5 -5
  453. package/dist/lib/session/remote.js +13 -17
  454. package/dist/lib/session/resume-command.d.ts +3 -2
  455. package/dist/lib/session/resume-command.js +4 -3
  456. package/dist/lib/session/resume-owner.d.ts +3 -3
  457. package/dist/lib/session/resume-owner.js +3 -3
  458. package/dist/lib/session/session-cache.d.ts +12 -0
  459. package/dist/lib/session/session-cache.js +2 -0
  460. package/dist/lib/session/shell-programs.js +1 -1
  461. package/dist/lib/session/state.js +5 -5
  462. package/dist/lib/session/team-filter.d.ts +1 -1
  463. package/dist/lib/session/team-filter.js +1 -1
  464. package/dist/lib/session/types.d.ts +3 -3
  465. package/dist/lib/session/width.d.ts +2 -2
  466. package/dist/lib/session/width.js +2 -2
  467. package/dist/lib/share/delete.d.ts +21 -0
  468. package/dist/lib/share/delete.js +42 -0
  469. package/dist/lib/share/publish.d.ts +82 -0
  470. package/dist/lib/share/publish.js +170 -18
  471. package/dist/lib/share/worker-template.js +172 -9
  472. package/dist/lib/shims.js +35 -7
  473. package/dist/lib/smart-launch.d.ts +36 -6
  474. package/dist/lib/smart-launch.js +65 -8
  475. package/dist/lib/snapshot.d.ts +4 -4
  476. package/dist/lib/snapshot.js +2 -2
  477. package/dist/lib/ssh-exec.d.ts +1 -1
  478. package/dist/lib/ssh-exec.js +2 -2
  479. package/dist/lib/ssh-tunnel.d.ts +10 -10
  480. package/dist/lib/ssh-tunnel.js +12 -12
  481. package/dist/lib/staleness/checkers/hooks.d.ts +1 -1
  482. package/dist/lib/staleness/checkers/hooks.js +1 -1
  483. package/dist/lib/staleness/detectors/permissions.js +0 -23
  484. package/dist/lib/staleness/detectors/plugins.js +1 -1
  485. package/dist/lib/staleness/fingerprint.js +1 -1
  486. package/dist/lib/staleness/layers.d.ts +1 -1
  487. package/dist/lib/staleness/layers.js +1 -1
  488. package/dist/lib/staleness/writers/mcp.js +3 -1
  489. package/dist/lib/staleness/writers/plugins.js +1 -1
  490. package/dist/lib/staleness/writers/types.d.ts +8 -0
  491. package/dist/lib/startup/command-registry.d.ts +5 -147
  492. package/dist/lib/startup/command-registry.js +38 -303
  493. package/dist/lib/startup/dev-build.d.ts +0 -21
  494. package/dist/lib/startup/dev-build.js +29 -8
  495. package/dist/lib/state.d.ts +19 -1
  496. package/dist/lib/state.js +120 -51
  497. package/dist/lib/subagents.js +1 -1
  498. package/dist/lib/sync-status.js +1 -1
  499. package/dist/lib/sync-umbrella.d.ts +6 -1
  500. package/dist/lib/sync-umbrella.js +9 -4
  501. package/dist/lib/teams/agents.js +2 -2
  502. package/dist/lib/teams/registry.js +1 -1
  503. package/dist/lib/terminal/backends/vscodium-agent.js +1 -1
  504. package/dist/lib/terminal/engine.js +1 -1
  505. package/dist/lib/terminal/index.d.ts +4 -0
  506. package/dist/lib/terminal/index.js +3 -0
  507. package/dist/lib/terminal/inject.d.ts +2 -2
  508. package/dist/lib/terminal/inject.js +2 -2
  509. package/dist/lib/terminal/transport.js +1 -1
  510. package/dist/lib/tmux/index.d.ts +1 -1
  511. package/dist/lib/tmux/index.js +1 -1
  512. package/dist/lib/tmux/session.d.ts +21 -5
  513. package/dist/lib/tmux/session.js +76 -22
  514. package/dist/lib/triggers/handlers.d.ts +1 -1
  515. package/dist/lib/triggers/handlers.js +2 -2
  516. package/dist/lib/triggers/webhook.d.ts +36 -2
  517. package/dist/lib/triggers/webhook.js +97 -42
  518. package/dist/lib/types.d.ts +18 -6
  519. package/dist/lib/usage-fleet.d.ts +1 -1
  520. package/dist/lib/usage-fleet.js +1 -1
  521. package/dist/lib/usage-refresh.d.ts +1 -1
  522. package/dist/lib/usage-refresh.js +3 -3
  523. package/dist/lib/version-duplicates.js +2 -2
  524. package/dist/lib/view-types.d.ts +56 -0
  525. package/dist/lib/view-types.js +1 -0
  526. package/dist/lib/watchdog/rotate.d.ts +2 -2
  527. package/dist/lib/watchdog/rotate.js +3 -3
  528. package/dist/lib/watchdog/runner.d.ts +2 -3
  529. package/dist/lib/watchdog/runner.js +3 -4
  530. package/dist/lib/workflows.js +1 -1
  531. package/package.json +2 -1
  532. package/scripts/postinstall.js +2 -2
  533. package/dist/commands/bench.d.ts +0 -2
  534. package/dist/commands/bench.js +0 -101
  535. package/dist/commands/cp.d.ts +0 -84
  536. package/dist/commands/cp.js +0 -231
  537. package/dist/commands/login.d.ts +0 -2
  538. package/dist/lib/resources/commands.d.ts +0 -46
  539. package/dist/lib/resources/commands.js +0 -211
  540. package/dist/lib/resources/hooks.d.ts +0 -16
  541. package/dist/lib/resources/hooks.js +0 -153
  542. package/dist/lib/resources/mcp.d.ts +0 -34
  543. package/dist/lib/resources/mcp.js +0 -250
  544. package/dist/lib/resources/memory.d.ts +0 -15
  545. package/dist/lib/resources/memory.js +0 -46
  546. package/dist/lib/resources/permissions.d.ts +0 -13
  547. package/dist/lib/resources/permissions.js +0 -202
  548. package/dist/lib/resources/rules.d.ts +0 -46
  549. package/dist/lib/resources/rules.js +0 -179
  550. package/dist/lib/resources/skills.d.ts +0 -37
  551. package/dist/lib/resources/skills.js +0 -247
  552. package/dist/lib/resources/subagents.d.ts +0 -46
  553. package/dist/lib/resources/subagents.js +0 -202
  554. /package/dist/lib/{feed.d.ts → feed/feed.d.ts} +0 -0
@@ -7,7 +7,7 @@
7
7
  * (offline → fail fast instead of a 2-minute hang), platform-aware exec
8
8
  * (PowerShell on Windows), and password-from-bundle auth via an askpass shim.
9
9
  * Rendering the registry to an ssh_config include also lets plain ssh / scp /
10
- * rsync / `agents sessions --host` resolve the same logical names.
10
+ * rsync / `agents sessions --device` resolve the same logical names.
11
11
  */
12
12
  import { spawnSync } from 'child_process';
13
13
  import * as fs from 'fs';
@@ -31,6 +31,7 @@ import { defaultPickerChecked, localLoginUser, planDeviceReconciliation, runDevi
31
31
  import { resolveDeviceTarget, splitUserHost } from '../lib/devices/resolve-target.js';
32
32
  import { deriveMirroredCwd } from '../lib/project-root.js';
33
33
  import { clearPendingSentinel } from '../lib/devices/pending.js';
34
+ import { getDeviceDiscoveryStatus, setDeviceDiscoveryStatus } from '../lib/devices/discovery-policy.js';
34
35
  import { isInteractiveTerminal, isPromptCancelled } from './utils.js';
35
36
  import { hostNameFor, renderSshConfig } from '../lib/devices/ssh-config.js';
36
37
  import { ASKPASS_BUNDLE_ENV, ASKPASS_KEY_ENV, buildSshInvocation, deviceIdentityArgs, fleetDialTarget, writeAskpassShim, } from '../lib/devices/connect.js';
@@ -54,14 +55,16 @@ import { ALL_AGENT_IDS } from '../lib/agents.js';
54
55
  import { collectLocalHarnessInventory, groupByAccount, renderAccountsMatrix, renderHarnessMatrix, } from '../lib/devices/harness-inventory.js';
55
56
  import { crabboxList, crabboxFind, crabboxSshArgv } from '../lib/crabbox/cli.js';
56
57
  import { boxAddress, boxStatus, fmtIdleShort, fmtExpiresShort, registerLeaseCommand } from './lease.js';
58
+ import { registerSnapshotCommand } from './snapshot.js';
57
59
  import { authCellColor, formatCheckedAge, isDeadVerdict, readAuthHealthCache, summarizeHostAuth, summarizeVerdicts, verdictColor, verdictLabel, writeFleetAuthRows, } from '../lib/auth-health.js';
58
60
  import { runFleetLogin } from '../lib/fleet/remote-login.js';
59
- import { getConfigValue, listConfig, setConfigValue, unsetConfigValue, configKeySpec } from '../lib/device-config.js';
61
+ import { getConfigValue, listConfig, setConfigValue, unsetConfigValue, configKeySpec, autoPoolMode, configuredDeviceRole, listConfiguredDeviceRoles, setConfiguredDeviceRole, } from '../lib/device-config.js';
62
+ import { filterAutoPool, listWorkerDevices } from '../lib/devices/pool.js';
60
63
  import { registerCommandGroups, setHelpSections } from '../lib/help.js';
61
64
  /** One-line summary of a device for `list`. `isSelf` marks the machine this
62
65
  * command is running on so it stands out from the rest of the tailnet.
63
66
  * `isInteractive` marks the configured interactive host (`devices config <name> interactive.host`). */
64
- function deviceSummary(d, isSelf = false, stats, isInteractive = false) {
67
+ function deviceSummary(d, isSelf = false, stats, isInteractive = false, roles) {
65
68
  d = resolveDeviceProfile(d);
66
69
  const addr = hostNameFor(d) ?? chalk.gray('no address');
67
70
  // Prefer a fresh live verdict (this run's probe, else the written-back
@@ -77,7 +80,22 @@ function deviceSummary(d, isSelf = false, stats, isInteractive = false) {
77
80
  const name = isSelf ? chalk.bold.cyan(d.name.padEnd(16)) : chalk.bold(d.name.padEnd(16));
78
81
  const here = isSelf ? chalk.cyan(' ← this machine') : '';
79
82
  const interactive = isInteractive ? chalk.yellow(' ★ interactive') : '';
80
- return `${marker}${name} ${String(d.platform).padEnd(8)} ${(d.user ? d.user + '@' : '') + addr} ${online}${reach}${here}${interactive}`;
83
+ // `roles` defaults to a single-device roster so a fleet-wide `role` default
84
+ // still reaches this device even when it has no per-device doc of its own.
85
+ const role = roleTag(d.name, roles ?? listConfiguredDeviceRoles([d.name]));
86
+ return `${marker}${name} ${String(d.platform).padEnd(8)} ${(d.user ? d.user + '@' : '') + addr} ${online}${reach}${here}${interactive}${role}`;
87
+ }
88
+ /** The fleet-wide role mark, rendered for a device row. Empty when unmarked —
89
+ * an unmarked device is the common case and must not add a column of noise. */
90
+ function roleTag(name, roles) {
91
+ const role = roles[name];
92
+ if (!role)
93
+ return '';
94
+ if (role === 'worker')
95
+ return chalk.green(' worker');
96
+ if (role === 'personal')
97
+ return chalk.yellow(' personal');
98
+ return chalk.gray(' control');
81
99
  }
82
100
  const HEADROOM_BADGE = {
83
101
  idle: chalk.green('○ idle'),
@@ -105,8 +123,11 @@ function pctCell(v, width) {
105
123
  * capacity summary is appended whenever stats were gathered.
106
124
  */
107
125
  function renderDeviceTable(reg, names, self, statsMap, full = false, interactiveHost) {
108
- if (!statsMap)
109
- return names.map((n) => deviceSummary(reg[n], n === self, undefined, n === interactiveHost));
126
+ if (!statsMap) {
127
+ const roles = listConfiguredDeviceRoles(names);
128
+ return names.map((n) => deviceSummary(reg[n], n === self, undefined, n === interactiveHost, roles));
129
+ }
130
+ const deviceRoles = listConfiguredDeviceRoles(names);
110
131
  const lines = [];
111
132
  const head = ' ' +
112
133
  chalk.gray('device'.padEnd(16)) +
@@ -149,7 +170,7 @@ function renderDeviceTable(reg, names, self, statsMap, full = false, interactive
149
170
  const badge = HEADROOM_BADGE[headroom(stats)];
150
171
  const here = isSelf ? chalk.cyan(' ← this machine') : '';
151
172
  const interactive = name === interactiveHost ? chalk.yellow(' ★ interactive') : '';
152
- lines.push(`${marker}${label}${plat} ${cores}${load}${mem}${freeTotal} ${badge}${relay}${here}${interactive}`);
173
+ lines.push(`${marker}${label}${plat} ${cores}${load}${mem}${freeTotal} ${badge}${relay}${here}${interactive}${roleTag(name, deviceRoles)}`);
153
174
  }
154
175
  // Fleet capacity summary — total cores + how much RAM is free right now.
155
176
  const cap = fleetCapacity(statsMap.values());
@@ -304,13 +325,16 @@ async function runInteractiveDeviceSync() {
304
325
  for (const name of plan.toRegister) {
305
326
  const input = withDefaultUser(nodeToDeviceInput(byName.get(name)), reg[name]?.user, localUser);
306
327
  await upsertDevice(name, input);
328
+ setDeviceDiscoveryStatus(name, 'approved');
307
329
  }
308
330
  for (const name of plan.toUnignore)
309
331
  await removeIgnored(name);
310
332
  for (const name of plan.toRemove)
311
333
  await removeDevice(name);
312
- for (const name of plan.toIgnore)
334
+ for (const name of plan.toIgnore) {
313
335
  await addIgnored(name);
336
+ setDeviceDiscoveryStatus(name, 'ignored');
337
+ }
314
338
  const parts = [
315
339
  chalk.green(`${plan.toRegister.length} registered`),
316
340
  plan.toRemove.length ? chalk.yellow(`${plan.toRemove.length} removed`) : null,
@@ -420,11 +444,14 @@ async function probeRemoteHealth(target) {
420
444
  inventory: parsed.fleet,
421
445
  };
422
446
  }
423
- /** Effective device-scoped config, keyed by the canonical YAML key. */
447
+ /** Device-layer config only (not fleet defaults), keyed by the canonical YAML key. */
424
448
  function deviceConfigJson(name) {
425
449
  const config = {};
426
450
  for (const entry of listConfig({ device: name })) {
427
- if (entry.spec.scope !== 'device' || entry.value === undefined)
451
+ // The device's OWN layer only — a fleet-default value is not this
452
+ // device's setting (the effective profile fields already carry the
453
+ // merged view via resolveDeviceProfile).
454
+ if (entry.source !== 'device')
428
455
  continue;
429
456
  config[entry.spec.yamlKey] = entry.value;
430
457
  }
@@ -967,9 +994,10 @@ function registerDevicesCommands(program) {
967
994
  notes: '`agents fleet` is an alias for `agents devices` — same subcommands.',
968
995
  });
969
996
  registerLeaseCommand(devicesCmd);
997
+ registerSnapshotCommand(devicesCmd);
970
998
  registerCommandGroups(devicesCmd, [
971
999
  { title: 'Discover & register', names: ['sync', 'register', 'add', 'ignore', 'unignore', 'rm'] },
972
- { title: 'Inspect', names: ['list', 'show', 'status', 'ping', 'harnesses', 'accounts'] },
1000
+ { title: 'Inspect', names: ['list', 'show', 'status', 'ping', 'harnesses', 'accounts', 'snapshot'] },
973
1001
  { title: 'Disposable devices', names: ['lease'] },
974
1002
  { title: 'Configure a device', names: ['config', 'render'] },
975
1003
  { title: 'Fleet operations', names: ['update', 'run', 'login', 'pair-ios', 'capture', 'apply'] },
@@ -986,6 +1014,8 @@ function registerDevicesCommands(program) {
986
1014
  const spinner = ora('Reading tailscale status...').start();
987
1015
  try {
988
1016
  const res = await runDeviceSync();
1017
+ for (const name of res.syncedNames)
1018
+ setDeviceDiscoveryStatus(name, 'approved');
989
1019
  const extra = res.pending.length ? chalk.gray(` (${res.pending.length} new)`) : '';
990
1020
  spinner.succeed(`Synced ${res.synced} device${res.synced === 1 ? '' : 's'} from Tailscale${extra}`);
991
1021
  }
@@ -1001,7 +1031,7 @@ function registerDevicesCommands(program) {
1001
1031
  registerFleetApplyAlias(devicesCmd);
1002
1032
  devicesCmd
1003
1033
  .command('register <name>')
1004
- .description('Register a discovered (pending) node by name — used by the menu-bar "NEW DEVICES → Register" action.')
1034
+ .description('Register a discovered node and sync the approval through agents.yaml fleet.discovery.')
1005
1035
  .action(async (name) => {
1006
1036
  try {
1007
1037
  const nodes = parseTailscaleStatus(tailscaleStatusJson());
@@ -1012,6 +1042,7 @@ function registerDevicesCommands(program) {
1012
1042
  }
1013
1043
  await removeIgnored(name); // a re-registered node is no longer dismissed
1014
1044
  const d = await upsertDevice(name, nodeToDeviceInput(node));
1045
+ setDeviceDiscoveryStatus(name, 'approved');
1015
1046
  clearPendingSentinel(name); // drop the notification immediately
1016
1047
  console.log(chalk.green(`Registered '${name}'`) + chalk.gray(` (${d.platform})`));
1017
1048
  }
@@ -1022,11 +1053,12 @@ function registerDevicesCommands(program) {
1022
1053
  });
1023
1054
  devicesCmd
1024
1055
  .command('ignore <name>')
1025
- .description('Dismiss a node from auto-discovery so it is never re-suggested (and remove it from the registry if present).')
1056
+ .description('Dismiss a node and sync the decision through agents.yaml fleet.discovery (also removes it locally).')
1026
1057
  .action(async (name) => {
1027
1058
  try {
1028
1059
  await removeDevice(name);
1029
1060
  await addIgnored(name);
1061
+ setDeviceDiscoveryStatus(name, 'ignored');
1030
1062
  clearPendingSentinel(name); // drop the notification immediately
1031
1063
  console.log(chalk.green(`Ignored '${name}'`) + chalk.gray(" — it won't be suggested again. Undo with `agents devices unignore`."));
1032
1064
  }
@@ -1039,11 +1071,13 @@ function registerDevicesCommands(program) {
1039
1071
  .command('unignore <name>')
1040
1072
  .description('Undo `ignore`: allow a node to be discovered and registered again.')
1041
1073
  .action(async (name) => {
1074
+ const portableWasIgnored = getDeviceDiscoveryStatus(name) === 'ignored';
1042
1075
  const ok = await removeIgnored(name);
1043
- if (!ok) {
1076
+ if (!ok && !portableWasIgnored) {
1044
1077
  console.error(chalk.gray(`'${name}' was not ignored.`));
1045
1078
  return;
1046
1079
  }
1080
+ setDeviceDiscoveryStatus(name, undefined);
1047
1081
  console.log(chalk.green(`No longer ignoring '${name}'`) + chalk.gray(' — run `agents devices sync` to register it.'));
1048
1082
  });
1049
1083
  // ─── devices config (unified settings surface) ────────────────────────────
@@ -1079,18 +1113,39 @@ function registerDevicesCommands(program) {
1079
1113
  };
1080
1114
  /** The device-scope config entries for `name` (what the config surface edits). */
1081
1115
  const deviceConfigEntries = (name) => listConfig({ device: name }).filter((e) => e.spec.scope === 'device');
1116
+ /** Render one entry's effective value with its layer tag. */
1117
+ const entryValueText = (e) => {
1118
+ if (e.source === 'default')
1119
+ return chalk.gray('— (default)');
1120
+ const tag = e.source === 'fleet' ? chalk.yellow(' (fleet default)') : e.source === 'user' ? chalk.gray(' (user scope)') : '';
1121
+ return chalk.cyan(JSON.stringify(e.value)) + tag;
1122
+ };
1082
1123
  /** Print the full resolved config for a device (bare invocation, non-menu). */
1083
1124
  const printDevicesConfig = (name, json) => {
1084
1125
  const entries = deviceConfigEntries(name);
1085
1126
  if (json) {
1086
1127
  const config = {};
1087
1128
  for (const e of entries)
1088
- if (e.value !== undefined)
1089
- config[e.spec.name] = e.value;
1129
+ config[e.spec.name] = { value: e.value ?? null, source: e.source };
1090
1130
  writeJson({ device: name, config });
1091
1131
  return;
1092
1132
  }
1093
1133
  console.log(chalk.bold(`Config for '${name}'`));
1134
+ for (const e of entries) {
1135
+ console.log(` ${e.spec.name.padEnd(24)} ${entryValueText(e)}${chalk.gray(` ${e.spec.description}`)}`);
1136
+ }
1137
+ };
1138
+ /** Print the fleet-wide defaults layer (`config --fleet`, bare). */
1139
+ const printFleetConfig = (json) => {
1140
+ const entries = listConfig({ fleet: true }).filter((e) => e.spec.scope === 'device');
1141
+ if (json) {
1142
+ const config = {};
1143
+ for (const e of entries)
1144
+ config[e.spec.name] = { value: e.value ?? null, source: e.source };
1145
+ writeJson({ fleet: true, config });
1146
+ return;
1147
+ }
1148
+ console.log(chalk.bold('Fleet-wide config defaults') + chalk.gray(' (every device inherits these unless it overrides the key)'));
1094
1149
  for (const e of entries) {
1095
1150
  const value = e.value === undefined ? chalk.gray('— (default)') : chalk.cyan(JSON.stringify(e.value));
1096
1151
  console.log(` ${e.spec.name.padEnd(24)} ${value}${chalk.gray(` ${e.spec.description}`)}`);
@@ -1099,11 +1154,60 @@ function registerDevicesCommands(program) {
1099
1154
  /**
1100
1155
  * The `devices config` engine — shared by the config command's action and
1101
1156
  * every tombstone. `quiet` performs the write with no output (a tombstone
1102
- * that prints its own legacy shape). Throws on a bad key/value; callers map
1103
- * that to exit 1.
1157
+ * that prints its own legacy shape). `fleet` targets the fleet-wide defaults
1158
+ * layer instead of a device (`name` is then unused). Throws on a bad
1159
+ * key/value; callers map that to exit 1.
1104
1160
  */
1105
1161
  const runDevicesConfig = async (name, key, valueParts, opts) => {
1106
1162
  const spec = key ? configKeySpec(key) : undefined; // unknown key → throw listing the valid keys
1163
+ // ── Fleet-defaults layer (`--fleet`): no device involved.
1164
+ if (opts.fleet) {
1165
+ if (spec && spec.scope === 'user') {
1166
+ throw new Error(`Config key '${spec.name}' is user-scope (already fleet-wide) — --fleet does not apply.`);
1167
+ }
1168
+ if (opts.unset) {
1169
+ if (!spec)
1170
+ throw new Error('--unset needs a key: agents devices config --fleet <key> --unset');
1171
+ unsetConfigValue(spec.name, { fleet: true });
1172
+ if (opts.quiet)
1173
+ return;
1174
+ if (opts.json)
1175
+ writeJson({ fleet: true, key: spec.name, value: null, source: 'default' });
1176
+ else
1177
+ console.log(chalk.green(`Unset ${spec.name}`) + chalk.gray(' in the fleet defaults.'));
1178
+ return;
1179
+ }
1180
+ if (spec && valueParts.length > 0) {
1181
+ let value;
1182
+ if (spec.type === 'string-list') {
1183
+ const existing = getConfigValue(spec.name, { fleet: true }).value ?? [];
1184
+ value = [...existing, valueParts.join(' ')];
1185
+ }
1186
+ else {
1187
+ value = parseConfigValueInput(spec, valueParts.join(' '));
1188
+ }
1189
+ setConfigValue(spec.name, value, { fleet: true });
1190
+ if (opts.quiet)
1191
+ return;
1192
+ if (opts.json)
1193
+ writeJson({ fleet: true, key: spec.name, value, source: 'fleet' });
1194
+ else
1195
+ console.log(chalk.green(`Set ${spec.name} = ${JSON.stringify(value)}`) + chalk.gray(' as the fleet-wide default.'));
1196
+ return;
1197
+ }
1198
+ if (spec) {
1199
+ const entry = getConfigValue(spec.name, { fleet: true });
1200
+ if (opts.quiet)
1201
+ return;
1202
+ if (opts.json)
1203
+ writeJson({ fleet: true, key: spec.name, value: entry.value ?? null, source: entry.source });
1204
+ else
1205
+ console.log(` ${spec.name.padEnd(24)} ${entryValueText(entry)}${chalk.gray(` ${spec.description}`)}`);
1206
+ return;
1207
+ }
1208
+ printFleetConfig(Boolean(opts.json));
1209
+ return;
1210
+ }
1107
1211
  // User-scope keys (interactive.host) are stored centrally — the device name
1108
1212
  // is syntax only, so an unregistered name is not an error for them.
1109
1213
  if (!spec || spec.scope === 'device')
@@ -1115,9 +1219,9 @@ function registerDevicesCommands(program) {
1115
1219
  if (opts.quiet)
1116
1220
  return;
1117
1221
  if (opts.json)
1118
- writeJson({ device: name, key: spec.name, value: null });
1222
+ writeJson({ device: name, key: spec.name, value: null, source: 'default' });
1119
1223
  else
1120
- console.log(chalk.green(`Unset ${spec.name}`) + chalk.gray(` on '${name}' — back to the default.`));
1224
+ console.log(chalk.green(`Unset ${spec.name}`) + chalk.gray(` on '${name}' — falls back to the fleet default / built-in behavior.`));
1121
1225
  return;
1122
1226
  }
1123
1227
  if (spec && valueParts.length > 0) {
@@ -1134,7 +1238,7 @@ function registerDevicesCommands(program) {
1134
1238
  if (opts.quiet)
1135
1239
  return;
1136
1240
  if (opts.json)
1137
- writeJson({ device: name, key: spec.name, value });
1241
+ writeJson({ device: name, key: spec.name, value, source: 'device' });
1138
1242
  else
1139
1243
  console.log(chalk.green(`Set ${spec.name} = ${JSON.stringify(value)}`) + chalk.gray(` on '${name}'.`));
1140
1244
  return;
@@ -1144,13 +1248,10 @@ function registerDevicesCommands(program) {
1144
1248
  if (opts.quiet)
1145
1249
  return;
1146
1250
  if (opts.json) {
1147
- writeJson({ device: name, key: spec.name, value: entry.value ?? null });
1148
- }
1149
- else if (entry.value === undefined) {
1150
- console.log(` ${spec.name.padEnd(24)} ${chalk.gray('— (default)')}${chalk.gray(` ${spec.description}`)}`);
1251
+ writeJson({ device: name, key: spec.name, value: entry.value ?? null, source: entry.source });
1151
1252
  }
1152
1253
  else {
1153
- console.log(` ${spec.name.padEnd(24)} ${chalk.cyan(JSON.stringify(entry.value))}${chalk.gray(` ${spec.description}`)}`);
1254
+ console.log(` ${spec.name.padEnd(24)} ${entryValueText(entry)}${chalk.gray(` ${spec.description}`)}`);
1154
1255
  }
1155
1256
  return;
1156
1257
  }
@@ -1161,7 +1262,96 @@ function registerDevicesCommands(program) {
1161
1262
  }
1162
1263
  await runDevicesConfigMenu(name);
1163
1264
  };
1164
- /** The interactive settings menu: pick a key, edit it, repeat. TTY-only. */
1265
+ /**
1266
+ * The `devices role` engine — read or write the fleet-wide role mark, and say
1267
+ * what it does to automatic placement.
1268
+ *
1269
+ * A role written here lands in that device's tracked per-device doc
1270
+ * (`devices/<name>/agents.yaml` `config.role`) and syncs with repo
1271
+ * push/pull. The vocabulary is deliberately `worker | personal` only: a
1272
+ * paired cockpit's `control` role lives in the per-machine device registry,
1273
+ * is written by `agents devices pair-ios`, and is what the existing
1274
+ * dial-exclusion filters (`isControlDevice`) read. Accepting `control` here
1275
+ * too would promise a fleet-wide dial exclusion this key cannot deliver —
1276
+ * those filters read each box's own registry, so the mark would only hold
1277
+ * on the machine that ran the command.
1278
+ */
1279
+ const runDevicesRole = async (name, role, opts) => {
1280
+ if (!name) {
1281
+ if (role)
1282
+ throw new Error('Name a device: agents devices role <name> <worker|personal>');
1283
+ const reg = await loadDevices();
1284
+ // The full registered roster, not just online — a fleet-wide `role`
1285
+ // default must reach a registered device even when it has no per-device
1286
+ // doc of its own, or it silently falls out of the worker allowlist.
1287
+ const roles = listConfiguredDeviceRoles(Object.keys(reg));
1288
+ const mode = autoPoolMode();
1289
+ const online = Object.entries(reg)
1290
+ .filter(([, d]) => d?.tailscale?.online !== false)
1291
+ .map(([n]) => n);
1292
+ const pool = filterAutoPool(online, { mode, roles });
1293
+ if (opts.json) {
1294
+ writeJson({ mode, roles, autoPool: pool });
1295
+ return;
1296
+ }
1297
+ const marked = Object.entries(roles);
1298
+ if (marked.length === 0) {
1299
+ console.log(chalk.gray('No device is marked. `--device auto` considers every online device.'));
1300
+ }
1301
+ else {
1302
+ for (const [device, r] of marked) {
1303
+ const tint = r === 'worker' ? chalk.green : r === 'personal' ? chalk.yellow : chalk.gray;
1304
+ console.log(` ${device.padEnd(20)} ${tint(r)}`);
1305
+ }
1306
+ }
1307
+ console.log();
1308
+ console.log(chalk.bold('--device auto picks from: ') + (pool.length > 0 ? pool.join(', ') : chalk.red('nothing — no eligible device')));
1309
+ if (mode === 'all')
1310
+ console.log(chalk.gray('auto.pool=all — worker marks are ignored (a personal device is still excluded).'));
1311
+ return;
1312
+ }
1313
+ await mustGetDevice(name);
1314
+ if (opts.clear || role === 'none') {
1315
+ setConfiguredDeviceRole(name, undefined);
1316
+ if (opts.json)
1317
+ writeJson({ device: name, role: null });
1318
+ else
1319
+ console.log(chalk.green(`Cleared the role on '${name}'.`));
1320
+ return;
1321
+ }
1322
+ if (!role) {
1323
+ const current = configuredDeviceRole(name);
1324
+ if (opts.json)
1325
+ writeJson({ device: name, role: current ?? null });
1326
+ else
1327
+ console.log(` ${name.padEnd(20)} ${current ? chalk.cyan(current) : chalk.gray('— (unmarked)')}`);
1328
+ return;
1329
+ }
1330
+ // configuredDeviceRole's key spec validates the value; a bad one throws with
1331
+ // the accepted list, which the command's catch turns into exit 1.
1332
+ setConfiguredDeviceRole(name, role);
1333
+ // Full registered roster, mirroring the bare-listing branch above — a
1334
+ // fleet-wide `role` default must reach a doc-less registered device here
1335
+ // too, or `autoPoolWorkers` under-reports the allowlist right after this
1336
+ // write changed it.
1337
+ const roles = listConfiguredDeviceRoles(Object.keys(await loadDevices()));
1338
+ if (opts.json) {
1339
+ writeJson({ device: name, role, autoPoolWorkers: listWorkerDevices({ roles }) });
1340
+ return;
1341
+ }
1342
+ console.log(chalk.green(`Marked '${name}' role=${role}.`));
1343
+ const workers = listWorkerDevices({ roles });
1344
+ if (workers.length > 0) {
1345
+ console.log(chalk.gray(`\`--device auto\` now picks only from: ${workers.join(', ')}`));
1346
+ }
1347
+ else {
1348
+ console.log(chalk.gray('No device is marked worker, so `--device auto` still considers every online device.'));
1349
+ }
1350
+ console.log(chalk.gray('Sync it to the fleet with `agents repo push`.'));
1351
+ };
1352
+ /** The interactive settings menu: pick a key, edit it, repeat. TTY-only.
1353
+ * Shows EFFECTIVE values (with a fleet tag when inherited); edits always
1354
+ * write the device layer. */
1165
1355
  const runDevicesConfigMenu = async (name) => {
1166
1356
  const { select, input, confirm } = await import('@inquirer/prompts');
1167
1357
  const DONE = '__done__';
@@ -1169,12 +1359,12 @@ function registerDevicesCommands(program) {
1169
1359
  for (;;) {
1170
1360
  const entries = deviceConfigEntries(name);
1171
1361
  const picked = await select({
1172
- message: `Config for '${name}' — pick a key to edit:`,
1362
+ message: `Config for '${name}' — pick a key to edit (writes the device layer):`,
1173
1363
  pageSize: Math.min(entries.length + 1, 20),
1174
1364
  choices: [
1175
1365
  ...entries.map((e) => {
1176
- const value = e.value !== undefined
1177
- ? chalk.cyan(JSON.stringify(e.value))
1366
+ const value = e.source !== 'default'
1367
+ ? entryValueText(e)
1178
1368
  : chalk.gray(e.spec.defaultValue !== undefined
1179
1369
  ? `default: ${JSON.stringify(e.spec.defaultValue)}`
1180
1370
  : 'unset (default)');
@@ -1224,14 +1414,25 @@ function registerDevicesCommands(program) {
1224
1414
  }
1225
1415
  };
1226
1416
  const configCmd = devicesCmd
1227
- .command('config <name> [key] [value...]')
1417
+ .command('config [name] [key] [value...]')
1228
1418
  .description('Get, set, or unset a device’s settings (scheduler, agent cap, ssh overrides, auto-launch, notes). ' +
1229
1419
  'Bare opens an interactive settings menu (TTY) or prints the resolved config (piped). ' +
1230
- 'Stored centrally in ~/.agents/agents.yaml under fleet.devices.<name>.config synced, so any box can configure any device.')
1231
- .option('--unset', 'reset the key to its default (removes the stored value)')
1232
- .option('--json', 'output machine-readable JSON')
1420
+ 'Per-device values live in the tracked devices/<name>/agents.yaml config: block; --fleet targets the ' +
1421
+ 'fleet-wide defaults (central fleet.defaults.config) every device inherits unless it overrides the key.')
1422
+ .option('--fleet', 'target the fleet-wide defaults layer instead of a device (first positional is the key)')
1423
+ .option('--unset', 'reset the key at that layer (a device key then inherits the fleet default)')
1424
+ .option('--json', 'output machine-readable JSON (each key carries its source: device | fleet | default)')
1233
1425
  .action(async (name, key, valueParts, opts) => {
1234
1426
  try {
1427
+ if (opts.fleet) {
1428
+ // Positionals shift left: the first one is the key, the rest the value.
1429
+ const fleetValue = [key, ...(valueParts ?? [])].filter((v) => v !== undefined);
1430
+ await runDevicesConfig(undefined, name, fleetValue, opts);
1431
+ return;
1432
+ }
1433
+ if (!name) {
1434
+ throw new Error('Missing device name. Usage: agents devices config <name> [key] [value] — or --fleet <key> <value> for the fleet-wide defaults.');
1435
+ }
1235
1436
  await runDevicesConfig(name, key, valueParts ?? [], opts);
1236
1437
  }
1237
1438
  catch (err) {
@@ -1242,38 +1443,97 @@ function registerDevicesCommands(program) {
1242
1443
  setHelpSections(configCmd, {
1243
1444
  examples: `
1244
1445
  agents devices config mac-mini # settings menu (TTY) / print config (piped)
1245
- agents devices config mac-mini agents.max-concurrent 4 # cap concurrent agents
1446
+ agents devices config mac-mini agents.max-concurrent 4 # cap concurrent agents on mac-mini
1246
1447
  agents devices config mac-mini scheduler.enabled off # no routines firing there
1247
- agents devices config mac-mini scheduler.enabled # read one key back
1248
- agents devices config mac-mini scheduler.enabled --unset # back to the default
1448
+ agents devices config mac-mini scheduler.enabled # read the effective value back
1449
+ agents devices config mac-mini scheduler.enabled --unset # inherit the fleet default again
1450
+ agents devices config --fleet scheduler.enabled off # fleet-wide default (all devices)
1451
+ agents devices config --fleet agents.max-concurrent 2 # every box caps at 2 unless it overrides
1452
+ agents devices config --fleet # print the fleet defaults layer
1249
1453
  agents devices config mac-mini notes "runs the releases" # append an operator note
1250
1454
  agents devices config win-mini ssh.auth password # password auth…
1251
1455
  agents devices config win-mini ssh.bundle muqsit # …from this secrets bundle
1252
1456
  agents devices config worker ssh.identity-file ~/.ssh/worker_ed25519
1457
+ agents devices config mac-mini role worker # same as \`agents devices role mac-mini worker\`
1253
1458
  agents devices config mac-mini auto-launch.enabled off # exclude from AGI EXT auto-launch
1254
1459
  agents devices config mac-mini auto-launch.preferred on # boost in auto-launch ranking
1255
1460
  agents devices config zion interactive.host zion # user scope: where agents show YOU artifacts
1256
- agents devices config mac-mini --json # machine-readable
1461
+ agents devices config mac-mini --json # machine-readable, per-key source
1257
1462
  `,
1258
1463
  notes: `
1259
- Keys: agents.max-concurrent, scheduler.enabled, daemon.enabled,
1260
- watchdog.enabled, browser.remote-control, browser.profile, notes,
1261
- ssh.user, ssh.auth (key|password), ssh.bundle, ssh.bundle-key,
1464
+ Keys: role (worker|personal), see 'agents devices role',
1465
+ agents.max-concurrent, scheduler.enabled, daemon.enabled,
1466
+ watchdog.enabled, tmux.enabled, browser.remote-control,
1467
+ browser.task-idle-minutes, browser.profile,
1468
+ notes, ssh.user, ssh.auth (key|password), ssh.bundle, ssh.bundle-key,
1262
1469
  ssh.identity-file, platform (windows|linux|macos|unknown),
1263
1470
  auto-launch.enabled, auto-launch.preferred — plus the user-scope
1264
1471
  interactive.host (stored centrally; the device name is syntax only).
1265
1472
 
1473
+ Three layers, read in order — built-in default < fleet default
1474
+ (--fleet, central fleet.defaults.config) < per-device value
1475
+ (devices/<name>/agents.yaml config:). Both files are tracked and sync
1476
+ with 'agents repo push/pull'; per-device files are conflict-free because
1477
+ each machine writes only its own folder. --unset removes the value at
1478
+ the targeted layer, so a device key falls back to the fleet default.
1479
+
1266
1480
  Booleans take on/off (or true/false). 'notes' appends one entry per
1267
- invocation. Values land in ~/.agents/agents.yaml under
1268
- fleet.devices.<name>.config and sync with 'agents repo push/pull'.
1269
- ssh.* / platform / user overlay the discovered registry profile at dial
1270
- time. scheduler.enabled / daemon.enabled take effect when the daemon
1271
- reloads or restarts on that device.
1481
+ invocation. ssh.* / platform / user overlay the discovered registry
1482
+ profile at dial time. scheduler.enabled / daemon.enabled take effect
1483
+ when the daemon reloads or restarts on that device. Machine-local keys
1484
+ (scheduler.enabled, daemon.enabled, tmux.enabled, browser.remote-control,
1485
+ browser.task-idle-minutes, browser.profile) can only be read or set on
1486
+ the device itself; --fleet still writes a fleet-wide default those boxes
1487
+ inherit until they override.
1272
1488
 
1273
1489
  The retired subcommands still work and forward here: configure, note,
1274
1490
  set, set-interactive, enable, disable, prefer, unprefer.
1275
1491
  `,
1276
1492
  });
1493
+ const roleCmd = devicesCmd
1494
+ .command('role [name] [role]')
1495
+ .description('Show or set what a device is for: worker (agents run here) or personal (you sit here — never picked automatically). ' +
1496
+ 'Marking any device worker makes `--device auto` an allowlist over the marked workers.')
1497
+ .option('--clear', 'remove the mark, returning the device to unmarked')
1498
+ .option('--json', 'output machine-readable JSON')
1499
+ .action(async (name, role, opts) => {
1500
+ try {
1501
+ await runDevicesRole(name, role, opts);
1502
+ }
1503
+ catch (err) {
1504
+ console.error(chalk.red(err.message));
1505
+ process.exit(1);
1506
+ }
1507
+ });
1508
+ setHelpSections(roleCmd, {
1509
+ examples: `
1510
+ agents devices role # who is marked what, and what --device auto would pick
1511
+ agents devices role yosemite-s0 worker # agents spin up here
1512
+ agents devices role yosemite-s1 worker # …and here; auto now rotates over these two only
1513
+ agents devices role zion personal # your laptop — keep automatic placement off it
1514
+ agents devices role yosemite-s0 --clear # unmark
1515
+ agents devices role --json # machine-readable
1516
+ `,
1517
+ notes: `
1518
+ Roles live in that device's tracked per-device doc
1519
+ (devices/<name>/agents.yaml config.role) and travel with
1520
+ 'agents repo push/pull', so a mark set on one box is the whole fleet's
1521
+ answer.
1522
+
1523
+ Effect on '--device auto' (agents run, teams, agents ssh auto, and the AGI
1524
+ EXT launch commands, which all resolve placement through the CLI):
1525
+ no device marked -> every online device, as before
1526
+ any worker marked -> ONLY the marked workers
1527
+ personal -> never picked, under either state
1528
+
1529
+ Turn the allowlist off with 'agents config set auto.pool all'; a personal
1530
+ box stays excluded, since that is what the mark is for.
1531
+
1532
+ A paired iPhone/iPad cockpit is a separate role: 'agents devices pair-ios'
1533
+ marks it control in that box's device registry, and the fleet never dials
1534
+ it — including for placement. This command does not set that role.
1535
+ `,
1536
+ });
1277
1537
  /** Deprecation notice for a retired subcommand — STDERR only, so a --json consumer's stdout stays parseable. */
1278
1538
  const configTombstoneNotice = (retired, replacement) => {
1279
1539
  console.error(chalk.yellow(`Deprecated: "agents devices ${retired}" is now "agents devices ${replacement}". Running that for you.\n`));
@@ -1493,12 +1753,19 @@ function registerDevicesCommands(program) {
1493
1753
  await writeReachability(collectReachabilityWriteBacks(reg, statsMap)).catch(() => { });
1494
1754
  }
1495
1755
  if (opts.json) {
1756
+ const jsonRoles = listConfiguredDeviceRoles(names);
1757
+ const autoPool = new Set(filterAutoPool(names, { roles: jsonRoles }));
1496
1758
  process.stdout.write(JSON.stringify(names.map((name) => {
1497
1759
  const config = deviceConfigJson(name);
1498
1760
  const health = statsMap?.get(name);
1499
1761
  return {
1500
1762
  ...resolveDeviceProfile(reg[name]),
1501
1763
  interactive: name === interactiveHost,
1764
+ // Roles as machine-readable fields: `role` is what the operator
1765
+ // marked (absent when unmarked), `autoPool` is the answer that
1766
+ // matters to a caller — may `--device auto` pick this box.
1767
+ ...(jsonRoles[name] ? { role: jsonRoles[name] } : {}),
1768
+ autoPool: autoPool.has(name),
1502
1769
  ...(config ? { config } : {}),
1503
1770
  ...(health ? { health: { ...health, headroom: headroom(health) } } : {}),
1504
1771
  };
@@ -1669,6 +1936,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
1669
1936
  user,
1670
1937
  address: { via: 'manual', dnsName: isIp ? undefined : host, ip: isIp ? host : undefined },
1671
1938
  });
1939
+ setDeviceDiscoveryStatus(name, 'approved');
1672
1940
  console.log(chalk.green(`Added device '${name}'`) + chalk.gray(` (${d.platform}, ${user ? user + '@' : ''}${host})`));
1673
1941
  }
1674
1942
  catch (err) {
@@ -1740,6 +2008,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
1740
2008
  const existing = await getDevice(name);
1741
2009
  if (existing) {
1742
2010
  await upsertDevice(name, { role: 'control' });
2011
+ setDeviceDiscoveryStatus(name, 'approved');
1743
2012
  marked = true;
1744
2013
  }
1745
2014
  else {
@@ -1774,6 +2043,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
1774
2043
  console.error(chalk.red(`Unknown device '${name}'.`));
1775
2044
  process.exit(1);
1776
2045
  }
2046
+ setDeviceDiscoveryStatus(name, undefined);
1777
2047
  console.log(chalk.green(`Removed device '${name}'`));
1778
2048
  });
1779
2049
  devicesCmd
@@ -1949,7 +2219,7 @@ is refused with a clear message instead of self-dialing.
1949
2219
  An interactive login with no command mirrors the home-relative directory you
1950
2220
  launched from — 'agents ssh yosemite-s0' from ~/src/app lands in ~/src/app on
1951
2221
  the target when it exists, else the remote home. Same portable-cwd rule as
1952
- 'agents run --host'. Passing a command keeps the remote home.
2222
+ 'agents run --device'. Passing a command keeps the remote home.
1953
2223
  `)
1954
2224
  .action(async (name, cmd) => {
1955
2225
  // Hidden askpass bridge: ssh execs the shim, which re-invokes us here.
@@ -2012,7 +2282,7 @@ the target when it exists, else the remote home. Same portable-cwd rule as
2012
2282
  const pinned = addr ? isHostPinned(addr) : false;
2013
2283
  // Interactive login (no cmd): mirror the caller's project directory on
2014
2284
  // the target when the same home-relative checkout exists there, matching
2015
- // `agents run --host` (deriveMirroredCwd). Best-effort — a missing dir
2285
+ // `agents run --device` (deriveMirroredCwd). Best-effort — a missing dir
2016
2286
  // falls back to the remote home. An explicit `cmd` keeps its cwd (RUSH-2412).
2017
2287
  const mirrorCwd = cmd.length === 0 ? deriveMirroredCwd(process.cwd()) : undefined;
2018
2288
  const { args, env } = buildSshInvocation(device, cmd, shim, { pinned }, { interactiveCwd: mirrorCwd });
@@ -14,7 +14,7 @@ import { homeDir } from '../lib/platform/index.js';
14
14
  import { capableAgents } from '../lib/capabilities.js';
15
15
  import { cloneRepo } from '../lib/git.js';
16
16
  import { discoverSubagentsFromRepo, installSubagentCentrally, listInstalledSubagents, getInstalledSubagent, listSubagentsForAgent, iterSubagentsCapableVersions, removeSubagentFromVersion, } from '../lib/subagents.js';
17
- import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection, } from '../lib/versions.js';
17
+ import { listInstalledVersions, syncResourcesToVersion, getGlobalDefault, getVersionHomePath, promptAgentVersionSelection, } from '../lib/installations/versions.js';
18
18
  import { getSubagentsDir, recordVersionResources } from '../lib/state.js';
19
19
  import { requireDestructiveArg, promptRemovalTargets, parseCommaSeparatedList, resolveAgentTargetsAutoInstalling, } from './utils.js';
20
20
  import { showResourceList, buildTargetsSection, } from './resource-view.js';