@phnx-labs/agents-cli 1.22.39 → 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 +294 -0
  2. package/README.md +111 -70
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +45 -26
  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 +16 -3
  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 +160 -215
  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 +186 -64
  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 +2 -1
  191. package/dist/lib/config-keys.js +8 -4
  192. package/dist/lib/config-machine-keys.d.ts +4 -2
  193. package/dist/lib/config-machine-keys.js +5 -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 +85 -75
  206. package/dist/lib/device-config.js +279 -141
  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 +10 -5
  218. package/dist/lib/devices/pool.js +5 -7
  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 +4 -4
  239. package/dist/lib/exec.js +11 -11
  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} +13 -1
  304. package/dist/lib/{migrate.js → installations/migrate.js} +160 -40
  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 +4 -4
  474. package/dist/lib/smart-launch.js +6 -4
  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,8 +7,8 @@ import { select, checkbox } from '@inquirer/prompts';
7
7
  import { AGENTS, resolveAgentName, formatAgentError, agentLabel, } from '../lib/agents.js';
8
8
  import { capableAgents } from '../lib/capabilities.js';
9
9
  import { cloneRepo } from '../lib/git.js';
10
- import { discoverSkillsFromRepo, installSkillCentrally, listInstalledSkills, listInstalledSkillsWithScope, getSkillInfo, getSkillRules, getSkillsDir, countSkillFiles, tryParseSkillMetadata, diffVersionSkills, iterSkillsCapableVersions, removeSkillFromVersion, } from '../lib/skills.js';
11
- import { getGlobalDefault, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, } from '../lib/versions.js';
10
+ import { discoverSkillsFromRepo, installSkillCentrally, listInstalledSkills, listInstalledSkillsWithScope, getSkillInfo, getSkillRules, getSkillsDir, countSkillFiles, tryParseSkillMetadata, diffVersionSkills, iterSkillsCapableVersions, removeSkillFromVersion, } from '../lib/plugins/skills.js';
11
+ import { getGlobalDefault, syncResourcesToVersion, promptAgentVersionSelection, getVersionHomePath, } from '../lib/installations/versions.js';
12
12
  import { recordVersionResources } from '../lib/state.js';
13
13
  import { isPromptCancelled, isInteractiveTerminal, parseCommaSeparatedList, printWithPager, requireInteractiveSelection, resolveAgentTargetsAutoInstalling, promptRemovalTargets, resolveListFilterOrExit, } from './utils.js';
14
14
  import { showResourceList, buildTargetsSection, } from './resource-view.js';
@@ -180,7 +180,7 @@ Examples:
180
180
  const skillMdPath = path.join(localPath, 'SKILL.md');
181
181
  if (fs.existsSync(skillMdPath)) {
182
182
  const skillName = path.basename(localPath);
183
- const { validateSkillMetadata, countSkillRules } = await import('../lib/skills.js');
183
+ const { validateSkillMetadata, countSkillRules } = await import('../lib/plugins/skills.js');
184
184
  const parseResult = tryParseSkillMetadata(localPath);
185
185
  const validation = validateSkillMetadata(parseResult.metadata, skillName);
186
186
  // Warn if YAML is invalid
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `agents snapshot` — one-process consumer snapshot for pollers.
2
+ * `agents devices snapshot` — one-process consumer snapshot for pollers.
3
3
  *
4
4
  * Replaces the N× `view --json` + `sessions --active --json` (+ optional feed)
5
5
  * fork storm with a single command. Does NOT replace `agents status`, which
@@ -8,4 +8,4 @@
8
8
  * JSON shape: {@link FleetSnapshot} in `lib/snapshot.ts` (version: 1).
9
9
  */
10
10
  import type { Command } from 'commander';
11
- export declare function registerSnapshotCommand(program: Command): void;
11
+ export declare function registerSnapshotCommand(devicesCmd: Command): void;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `agents snapshot` — one-process consumer snapshot for pollers.
2
+ * `agents devices snapshot` — one-process consumer snapshot for pollers.
3
3
  *
4
4
  * Replaces the N× `view --json` + `sessions --active --json` (+ optional feed)
5
5
  * fork storm with a single command. Does NOT replace `agents status`, which
@@ -59,11 +59,11 @@ function renderHuman(snap) {
59
59
  : 'system ok';
60
60
  console.log(` ${'Sync'.padEnd(12)} ${sys} · ${need} version${need === 1 ? '' : 's'} need sync`);
61
61
  }
62
- console.log(chalk.gray('\n Machine-readable: agents snapshot --json\n' +
62
+ console.log(chalk.gray('\n Machine-readable: agents devices snapshot --json\n' +
63
63
  ' Sync-only (unchanged): agents status --json'));
64
64
  }
65
- export function registerSnapshotCommand(program) {
66
- const cmd = addHostOption(program
65
+ export function registerSnapshotCommand(devicesCmd) {
66
+ const cmd = addHostOption(devicesCmd
67
67
  .command('snapshot')
68
68
  .description('One-process poll snapshot: install inventory + active sessions (optional feed/sync). Not the sync-status command — use `agents status` for drift.'))
69
69
  .option('--json', 'Emit the machine-readable FleetSnapshot contract (version 1)')
@@ -74,19 +74,19 @@ export function registerSnapshotCommand(program) {
74
74
  setHelpSections(cmd, {
75
75
  examples: `
76
76
  # One-shot inventory + local active sessions (JSON)
77
- agents snapshot --json
77
+ agents devices snapshot --json
78
78
 
79
79
  # Same, plus open feed blocks for needs-you polls
80
- agents snapshot --json --with-feed
80
+ agents devices snapshot --json --with-feed
81
81
 
82
82
  # Fleet-wide active sessions (matches sessions --active scope)
83
- agents snapshot --json --all-hosts
83
+ agents devices snapshot --json --all-hosts
84
84
 
85
85
  # Inventory for one harness only (an AGI EXT-style usage poll)
86
- agents snapshot --json --agent claude
86
+ agents devices snapshot --json --agent claude
87
87
 
88
88
  # Run the whole snapshot on another device
89
- agents snapshot --json --host yosemite-s0
89
+ agents devices snapshot --json --device yosemite-s0
90
90
  `,
91
91
  });
92
92
  cmd.action(async (opts, command) => {
@@ -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 type { Command } from 'commander';
13
13
  import { type FanOutDeviceTarget } from '../lib/devices/fleet.js';
@@ -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,6 +55,7 @@ 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
61
  import { getConfigValue, listConfig, setConfigValue, unsetConfigValue, configKeySpec, autoPoolMode, configuredDeviceRole, listConfiguredDeviceRoles, setConfiguredDeviceRole, } from '../lib/device-config.js';
@@ -62,7 +64,7 @@ import { registerCommandGroups, setHelpSections } from '../lib/help.js';
62
64
  /** One-line summary of a device for `list`. `isSelf` marks the machine this
63
65
  * command is running on so it stands out from the rest of the tailnet.
64
66
  * `isInteractive` marks the configured interactive host (`devices config <name> interactive.host`). */
65
- function deviceSummary(d, isSelf = false, stats, isInteractive = false) {
67
+ function deviceSummary(d, isSelf = false, stats, isInteractive = false, roles) {
66
68
  d = resolveDeviceProfile(d);
67
69
  const addr = hostNameFor(d) ?? chalk.gray('no address');
68
70
  // Prefer a fresh live verdict (this run's probe, else the written-back
@@ -78,7 +80,9 @@ function deviceSummary(d, isSelf = false, stats, isInteractive = false) {
78
80
  const name = isSelf ? chalk.bold.cyan(d.name.padEnd(16)) : chalk.bold(d.name.padEnd(16));
79
81
  const here = isSelf ? chalk.cyan(' ← this machine') : '';
80
82
  const interactive = isInteractive ? chalk.yellow(' ★ interactive') : '';
81
- const role = roleTag(d.name, listConfiguredDeviceRoles());
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]));
82
86
  return `${marker}${name} ${String(d.platform).padEnd(8)} ${(d.user ? d.user + '@' : '') + addr} ${online}${reach}${here}${interactive}${role}`;
83
87
  }
84
88
  /** The fleet-wide role mark, rendered for a device row. Empty when unmarked —
@@ -119,9 +123,11 @@ function pctCell(v, width) {
119
123
  * capacity summary is appended whenever stats were gathered.
120
124
  */
121
125
  function renderDeviceTable(reg, names, self, statsMap, full = false, interactiveHost) {
122
- if (!statsMap)
123
- return names.map((n) => deviceSummary(reg[n], n === self, undefined, n === interactiveHost));
124
- const deviceRoles = listConfiguredDeviceRoles();
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);
125
131
  const lines = [];
126
132
  const head = ' ' +
127
133
  chalk.gray('device'.padEnd(16)) +
@@ -319,13 +325,16 @@ async function runInteractiveDeviceSync() {
319
325
  for (const name of plan.toRegister) {
320
326
  const input = withDefaultUser(nodeToDeviceInput(byName.get(name)), reg[name]?.user, localUser);
321
327
  await upsertDevice(name, input);
328
+ setDeviceDiscoveryStatus(name, 'approved');
322
329
  }
323
330
  for (const name of plan.toUnignore)
324
331
  await removeIgnored(name);
325
332
  for (const name of plan.toRemove)
326
333
  await removeDevice(name);
327
- for (const name of plan.toIgnore)
334
+ for (const name of plan.toIgnore) {
328
335
  await addIgnored(name);
336
+ setDeviceDiscoveryStatus(name, 'ignored');
337
+ }
329
338
  const parts = [
330
339
  chalk.green(`${plan.toRegister.length} registered`),
331
340
  plan.toRemove.length ? chalk.yellow(`${plan.toRemove.length} removed`) : null,
@@ -435,11 +444,14 @@ async function probeRemoteHealth(target) {
435
444
  inventory: parsed.fleet,
436
445
  };
437
446
  }
438
- /** Effective device-scoped config, keyed by the canonical YAML key. */
447
+ /** Device-layer config only (not fleet defaults), keyed by the canonical YAML key. */
439
448
  function deviceConfigJson(name) {
440
449
  const config = {};
441
450
  for (const entry of listConfig({ device: name })) {
442
- 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')
443
455
  continue;
444
456
  config[entry.spec.yamlKey] = entry.value;
445
457
  }
@@ -982,9 +994,10 @@ function registerDevicesCommands(program) {
982
994
  notes: '`agents fleet` is an alias for `agents devices` — same subcommands.',
983
995
  });
984
996
  registerLeaseCommand(devicesCmd);
997
+ registerSnapshotCommand(devicesCmd);
985
998
  registerCommandGroups(devicesCmd, [
986
999
  { title: 'Discover & register', names: ['sync', 'register', 'add', 'ignore', 'unignore', 'rm'] },
987
- { title: 'Inspect', names: ['list', 'show', 'status', 'ping', 'harnesses', 'accounts'] },
1000
+ { title: 'Inspect', names: ['list', 'show', 'status', 'ping', 'harnesses', 'accounts', 'snapshot'] },
988
1001
  { title: 'Disposable devices', names: ['lease'] },
989
1002
  { title: 'Configure a device', names: ['config', 'render'] },
990
1003
  { title: 'Fleet operations', names: ['update', 'run', 'login', 'pair-ios', 'capture', 'apply'] },
@@ -1001,6 +1014,8 @@ function registerDevicesCommands(program) {
1001
1014
  const spinner = ora('Reading tailscale status...').start();
1002
1015
  try {
1003
1016
  const res = await runDeviceSync();
1017
+ for (const name of res.syncedNames)
1018
+ setDeviceDiscoveryStatus(name, 'approved');
1004
1019
  const extra = res.pending.length ? chalk.gray(` (${res.pending.length} new)`) : '';
1005
1020
  spinner.succeed(`Synced ${res.synced} device${res.synced === 1 ? '' : 's'} from Tailscale${extra}`);
1006
1021
  }
@@ -1016,7 +1031,7 @@ function registerDevicesCommands(program) {
1016
1031
  registerFleetApplyAlias(devicesCmd);
1017
1032
  devicesCmd
1018
1033
  .command('register <name>')
1019
- .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.')
1020
1035
  .action(async (name) => {
1021
1036
  try {
1022
1037
  const nodes = parseTailscaleStatus(tailscaleStatusJson());
@@ -1027,6 +1042,7 @@ function registerDevicesCommands(program) {
1027
1042
  }
1028
1043
  await removeIgnored(name); // a re-registered node is no longer dismissed
1029
1044
  const d = await upsertDevice(name, nodeToDeviceInput(node));
1045
+ setDeviceDiscoveryStatus(name, 'approved');
1030
1046
  clearPendingSentinel(name); // drop the notification immediately
1031
1047
  console.log(chalk.green(`Registered '${name}'`) + chalk.gray(` (${d.platform})`));
1032
1048
  }
@@ -1037,11 +1053,12 @@ function registerDevicesCommands(program) {
1037
1053
  });
1038
1054
  devicesCmd
1039
1055
  .command('ignore <name>')
1040
- .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).')
1041
1057
  .action(async (name) => {
1042
1058
  try {
1043
1059
  await removeDevice(name);
1044
1060
  await addIgnored(name);
1061
+ setDeviceDiscoveryStatus(name, 'ignored');
1045
1062
  clearPendingSentinel(name); // drop the notification immediately
1046
1063
  console.log(chalk.green(`Ignored '${name}'`) + chalk.gray(" — it won't be suggested again. Undo with `agents devices unignore`."));
1047
1064
  }
@@ -1054,11 +1071,13 @@ function registerDevicesCommands(program) {
1054
1071
  .command('unignore <name>')
1055
1072
  .description('Undo `ignore`: allow a node to be discovered and registered again.')
1056
1073
  .action(async (name) => {
1074
+ const portableWasIgnored = getDeviceDiscoveryStatus(name) === 'ignored';
1057
1075
  const ok = await removeIgnored(name);
1058
- if (!ok) {
1076
+ if (!ok && !portableWasIgnored) {
1059
1077
  console.error(chalk.gray(`'${name}' was not ignored.`));
1060
1078
  return;
1061
1079
  }
1080
+ setDeviceDiscoveryStatus(name, undefined);
1062
1081
  console.log(chalk.green(`No longer ignoring '${name}'`) + chalk.gray(' — run `agents devices sync` to register it.'));
1063
1082
  });
1064
1083
  // ─── devices config (unified settings surface) ────────────────────────────
@@ -1094,18 +1113,39 @@ function registerDevicesCommands(program) {
1094
1113
  };
1095
1114
  /** The device-scope config entries for `name` (what the config surface edits). */
1096
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
+ };
1097
1123
  /** Print the full resolved config for a device (bare invocation, non-menu). */
1098
1124
  const printDevicesConfig = (name, json) => {
1099
1125
  const entries = deviceConfigEntries(name);
1100
1126
  if (json) {
1101
1127
  const config = {};
1102
1128
  for (const e of entries)
1103
- if (e.value !== undefined)
1104
- config[e.spec.name] = e.value;
1129
+ config[e.spec.name] = { value: e.value ?? null, source: e.source };
1105
1130
  writeJson({ device: name, config });
1106
1131
  return;
1107
1132
  }
1108
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)'));
1109
1149
  for (const e of entries) {
1110
1150
  const value = e.value === undefined ? chalk.gray('— (default)') : chalk.cyan(JSON.stringify(e.value));
1111
1151
  console.log(` ${e.spec.name.padEnd(24)} ${value}${chalk.gray(` ${e.spec.description}`)}`);
@@ -1114,11 +1154,60 @@ function registerDevicesCommands(program) {
1114
1154
  /**
1115
1155
  * The `devices config` engine — shared by the config command's action and
1116
1156
  * every tombstone. `quiet` performs the write with no output (a tombstone
1117
- * that prints its own legacy shape). Throws on a bad key/value; callers map
1118
- * 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.
1119
1160
  */
1120
1161
  const runDevicesConfig = async (name, key, valueParts, opts) => {
1121
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
+ }
1122
1211
  // User-scope keys (interactive.host) are stored centrally — the device name
1123
1212
  // is syntax only, so an unregistered name is not an error for them.
1124
1213
  if (!spec || spec.scope === 'device')
@@ -1130,9 +1219,9 @@ function registerDevicesCommands(program) {
1130
1219
  if (opts.quiet)
1131
1220
  return;
1132
1221
  if (opts.json)
1133
- writeJson({ device: name, key: spec.name, value: null });
1222
+ writeJson({ device: name, key: spec.name, value: null, source: 'default' });
1134
1223
  else
1135
- 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.`));
1136
1225
  return;
1137
1226
  }
1138
1227
  if (spec && valueParts.length > 0) {
@@ -1149,7 +1238,7 @@ function registerDevicesCommands(program) {
1149
1238
  if (opts.quiet)
1150
1239
  return;
1151
1240
  if (opts.json)
1152
- writeJson({ device: name, key: spec.name, value });
1241
+ writeJson({ device: name, key: spec.name, value, source: 'device' });
1153
1242
  else
1154
1243
  console.log(chalk.green(`Set ${spec.name} = ${JSON.stringify(value)}`) + chalk.gray(` on '${name}'.`));
1155
1244
  return;
@@ -1159,13 +1248,10 @@ function registerDevicesCommands(program) {
1159
1248
  if (opts.quiet)
1160
1249
  return;
1161
1250
  if (opts.json) {
1162
- writeJson({ device: name, key: spec.name, value: entry.value ?? null });
1163
- }
1164
- else if (entry.value === undefined) {
1165
- 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 });
1166
1252
  }
1167
1253
  else {
1168
- 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}`)}`);
1169
1255
  }
1170
1256
  return;
1171
1257
  }
@@ -1180,22 +1266,26 @@ function registerDevicesCommands(program) {
1180
1266
  * The `devices role` engine — read or write the fleet-wide role mark, and say
1181
1267
  * what it does to automatic placement.
1182
1268
  *
1183
- * A role written here lands in the SHARED block (`fleet.devices.<name>.config.role`)
1184
- * because every box has to agree on it. The vocabulary is deliberately
1185
- * `worker | personal` only: a paired cockpit's `control` role lives in the
1186
- * per-machine device registry, is written by `agents devices pair-ios`, and is
1187
- * what the existing dial-exclusion filters (`isControlDevice`) read. Accepting
1188
- * `control` here too would promise a fleet-wide dial exclusion this key cannot
1189
- * deliver those filters read each box's own registry, so the mark would only
1190
- * hold on the machine that ran the command.
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.
1191
1278
  */
1192
1279
  const runDevicesRole = async (name, role, opts) => {
1193
1280
  if (!name) {
1194
1281
  if (role)
1195
1282
  throw new Error('Name a device: agents devices role <name> <worker|personal>');
1196
- const roles = listConfiguredDeviceRoles();
1197
- const mode = autoPoolMode();
1198
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();
1199
1289
  const online = Object.entries(reg)
1200
1290
  .filter(([, d]) => d?.tailscale?.online !== false)
1201
1291
  .map(([n]) => n);
@@ -1240,12 +1330,17 @@ function registerDevicesCommands(program) {
1240
1330
  // configuredDeviceRole's key spec validates the value; a bad one throws with
1241
1331
  // the accepted list, which the command's catch turns into exit 1.
1242
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()));
1243
1338
  if (opts.json) {
1244
- writeJson({ device: name, role, autoPoolWorkers: listWorkerDevices() });
1339
+ writeJson({ device: name, role, autoPoolWorkers: listWorkerDevices({ roles }) });
1245
1340
  return;
1246
1341
  }
1247
1342
  console.log(chalk.green(`Marked '${name}' role=${role}.`));
1248
- const workers = listWorkerDevices();
1343
+ const workers = listWorkerDevices({ roles });
1249
1344
  if (workers.length > 0) {
1250
1345
  console.log(chalk.gray(`\`--device auto\` now picks only from: ${workers.join(', ')}`));
1251
1346
  }
@@ -1254,7 +1349,9 @@ function registerDevicesCommands(program) {
1254
1349
  }
1255
1350
  console.log(chalk.gray('Sync it to the fleet with `agents repo push`.'));
1256
1351
  };
1257
- /** The interactive settings menu: pick a key, edit it, repeat. TTY-only. */
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. */
1258
1355
  const runDevicesConfigMenu = async (name) => {
1259
1356
  const { select, input, confirm } = await import('@inquirer/prompts');
1260
1357
  const DONE = '__done__';
@@ -1262,12 +1359,12 @@ function registerDevicesCommands(program) {
1262
1359
  for (;;) {
1263
1360
  const entries = deviceConfigEntries(name);
1264
1361
  const picked = await select({
1265
- message: `Config for '${name}' — pick a key to edit:`,
1362
+ message: `Config for '${name}' — pick a key to edit (writes the device layer):`,
1266
1363
  pageSize: Math.min(entries.length + 1, 20),
1267
1364
  choices: [
1268
1365
  ...entries.map((e) => {
1269
- const value = e.value !== undefined
1270
- ? chalk.cyan(JSON.stringify(e.value))
1366
+ const value = e.source !== 'default'
1367
+ ? entryValueText(e)
1271
1368
  : chalk.gray(e.spec.defaultValue !== undefined
1272
1369
  ? `default: ${JSON.stringify(e.spec.defaultValue)}`
1273
1370
  : 'unset (default)');
@@ -1317,14 +1414,25 @@ function registerDevicesCommands(program) {
1317
1414
  }
1318
1415
  };
1319
1416
  const configCmd = devicesCmd
1320
- .command('config <name> [key] [value...]')
1417
+ .command('config [name] [key] [value...]')
1321
1418
  .description('Get, set, or unset a device’s settings (scheduler, agent cap, ssh overrides, auto-launch, notes). ' +
1322
1419
  'Bare opens an interactive settings menu (TTY) or prints the resolved config (piped). ' +
1323
- 'Stored centrally in ~/.agents/agents.yaml under fleet.devices.<name>.config synced, so any box can configure any device.')
1324
- .option('--unset', 'reset the key to its default (removes the stored value)')
1325
- .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)')
1326
1425
  .action(async (name, key, valueParts, opts) => {
1327
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
+ }
1328
1436
  await runDevicesConfig(name, key, valueParts ?? [], opts);
1329
1437
  }
1330
1438
  catch (err) {
@@ -1335,10 +1443,13 @@ function registerDevicesCommands(program) {
1335
1443
  setHelpSections(configCmd, {
1336
1444
  examples: `
1337
1445
  agents devices config mac-mini # settings menu (TTY) / print config (piped)
1338
- 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
1339
1447
  agents devices config mac-mini scheduler.enabled off # no routines firing there
1340
- agents devices config mac-mini scheduler.enabled # read one key back
1341
- 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
1342
1453
  agents devices config mac-mini notes "runs the releases" # append an operator note
1343
1454
  agents devices config win-mini ssh.auth password # password auth…
1344
1455
  agents devices config win-mini ssh.bundle muqsit # …from this secrets bundle
@@ -1347,26 +1458,33 @@ function registerDevicesCommands(program) {
1347
1458
  agents devices config mac-mini auto-launch.enabled off # exclude from AGI EXT auto-launch
1348
1459
  agents devices config mac-mini auto-launch.preferred on # boost in auto-launch ranking
1349
1460
  agents devices config zion interactive.host zion # user scope: where agents show YOU artifacts
1350
- agents devices config mac-mini --json # machine-readable
1461
+ agents devices config mac-mini --json # machine-readable, per-key source
1351
1462
  `,
1352
1463
  notes: `
1353
1464
  Keys: role (worker|personal), see 'agents devices role',
1354
1465
  agents.max-concurrent, scheduler.enabled, daemon.enabled,
1355
- watchdog.enabled, tmux.enabled, browser.remote-control, browser.profile,
1466
+ watchdog.enabled, tmux.enabled, browser.remote-control,
1467
+ browser.task-idle-minutes, browser.profile,
1356
1468
  notes, ssh.user, ssh.auth (key|password), ssh.bundle, ssh.bundle-key,
1357
1469
  ssh.identity-file, platform (windows|linux|macos|unknown),
1358
1470
  auto-launch.enabled, auto-launch.preferred — plus the user-scope
1359
1471
  interactive.host (stored centrally; the device name is syntax only).
1360
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
+
1361
1480
  Booleans take on/off (or true/false). 'notes' appends one entry per
1362
- invocation. Values a PEER reads land in ~/.agents/agents.yaml under
1363
- fleet.devices.<name>.config and sync with 'agents repo push/pull'. The
1364
- keys only the owning box reads scheduler.enabled, daemon.enabled,
1365
- tmux.enabled, browser.remote-control, browser.profile — stay in that
1366
- machine's own doc, never sync, and can only be set on the device itself.
1367
- ssh.* / platform / user overlay the discovered registry profile at dial
1368
- time. scheduler.enabled / daemon.enabled take effect when the daemon
1369
- 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.
1370
1488
 
1371
1489
  The retired subcommands still work and forward here: configure, note,
1372
1490
  set, set-interactive, enable, disable, prefer, unprefer.
@@ -1397,9 +1515,10 @@ function registerDevicesCommands(program) {
1397
1515
  agents devices role --json # machine-readable
1398
1516
  `,
1399
1517
  notes: `
1400
- Roles are stored fleet-wide in ~/.agents/agents.yaml under
1401
- fleet.devices.<name>.config.role and travel with 'agents repo push/pull',
1402
- so a mark set on one box is the whole fleet's answer.
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.
1403
1522
 
1404
1523
  Effect on '--device auto' (agents run, teams, agents ssh auto, and the AGI
1405
1524
  EXT launch commands, which all resolve placement through the CLI):
@@ -1634,7 +1753,7 @@ function registerDevicesCommands(program) {
1634
1753
  await writeReachability(collectReachabilityWriteBacks(reg, statsMap)).catch(() => { });
1635
1754
  }
1636
1755
  if (opts.json) {
1637
- const jsonRoles = listConfiguredDeviceRoles();
1756
+ const jsonRoles = listConfiguredDeviceRoles(names);
1638
1757
  const autoPool = new Set(filterAutoPool(names, { roles: jsonRoles }));
1639
1758
  process.stdout.write(JSON.stringify(names.map((name) => {
1640
1759
  const config = deviceConfigJson(name);
@@ -1817,6 +1936,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
1817
1936
  user,
1818
1937
  address: { via: 'manual', dnsName: isIp ? undefined : host, ip: isIp ? host : undefined },
1819
1938
  });
1939
+ setDeviceDiscoveryStatus(name, 'approved');
1820
1940
  console.log(chalk.green(`Added device '${name}'`) + chalk.gray(` (${d.platform}, ${user ? user + '@' : ''}${host})`));
1821
1941
  }
1822
1942
  catch (err) {
@@ -1888,6 +2008,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
1888
2008
  const existing = await getDevice(name);
1889
2009
  if (existing) {
1890
2010
  await upsertDevice(name, { role: 'control' });
2011
+ setDeviceDiscoveryStatus(name, 'approved');
1891
2012
  marked = true;
1892
2013
  }
1893
2014
  else {
@@ -1922,6 +2043,7 @@ email) into a single row. Use \`agents devices harnesses\` for the per-install v
1922
2043
  console.error(chalk.red(`Unknown device '${name}'.`));
1923
2044
  process.exit(1);
1924
2045
  }
2046
+ setDeviceDiscoveryStatus(name, undefined);
1925
2047
  console.log(chalk.green(`Removed device '${name}'`));
1926
2048
  });
1927
2049
  devicesCmd
@@ -2097,7 +2219,7 @@ is refused with a clear message instead of self-dialing.
2097
2219
  An interactive login with no command mirrors the home-relative directory you
2098
2220
  launched from — 'agents ssh yosemite-s0' from ~/src/app lands in ~/src/app on
2099
2221
  the target when it exists, else the remote home. Same portable-cwd rule as
2100
- 'agents run --host'. Passing a command keeps the remote home.
2222
+ 'agents run --device'. Passing a command keeps the remote home.
2101
2223
  `)
2102
2224
  .action(async (name, cmd) => {
2103
2225
  // Hidden askpass bridge: ssh execs the shim, which re-invokes us here.
@@ -2160,7 +2282,7 @@ the target when it exists, else the remote home. Same portable-cwd rule as
2160
2282
  const pinned = addr ? isHostPinned(addr) : false;
2161
2283
  // Interactive login (no cmd): mirror the caller's project directory on
2162
2284
  // the target when the same home-relative checkout exists there, matching
2163
- // `agents run --host` (deriveMirroredCwd). Best-effort — a missing dir
2285
+ // `agents run --device` (deriveMirroredCwd). Best-effort — a missing dir
2164
2286
  // falls back to the remote home. An explicit `cmd` keeps its cwd (RUSH-2412).
2165
2287
  const mirrorCwd = cmd.length === 0 ? deriveMirroredCwd(process.cwd()) : undefined;
2166
2288
  const { args, env } = buildSshInvocation(device, cmd, shim, { pinned }, { interactiveCwd: mirrorCwd });