@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
package/dist/lib/mcp.js CHANGED
@@ -14,9 +14,10 @@ import * as TOML from 'smol-toml';
14
14
  import { execFileSync } from 'child_process';
15
15
  import * as os from 'os';
16
16
  import { getMcpDir, getUserMcpDir, getProjectAgentsDir, getVersionsDir, getUserAgentsDir } from './state.js';
17
- import { getBinaryPath, getVersionHomePath } from './versions.js';
17
+ import { getBinaryPath, getVersionHomePath } from './installations/versions.js';
18
18
  import { IS_WINDOWS, execFileShellSpec } from './platform/index.js';
19
- import { AGENTS, getMcpConfigPathForHome, getProjectMcpConfigPath } from './agents.js';
19
+ import { AGENTS, getMcpConfigPathForHome, getProjectMcpConfigPath, stripJsonComments } from './agents.js';
20
+ import { MCP_TARGETS, mcpWriteUnsupportedReason } from './mcp-registry.js';
20
21
  import { isCapable } from './capabilities.js';
21
22
  /**
22
23
  * Parse an MCP server config from a YAML file.
@@ -420,18 +421,15 @@ function registerMcpCommand(agentId, name, commandSpec, scope, transport, option
420
421
  try {
421
422
  validateMcpServerName(name);
422
423
  if (agentId === 'hermes') {
423
- const server = {
424
- name,
425
- path: '',
426
- config: {
424
+ // Hermes has no `mcp add` CLI; write its YAML config directly.
425
+ const home = options.home || os.homedir();
426
+ writeMcpConfig(agentId, getMcpConfigPathForHome(agentId, home), [{
427
427
  name,
428
428
  transport: transport === 'http' ? 'http' : 'stdio',
429
429
  ...(transport === 'http'
430
430
  ? { url: commandSpec.command }
431
431
  : { command: commandSpec.command, args: commandSpec.args }),
432
- },
433
- };
434
- installMcpToHermesConfig(server, options.home || os.homedir());
432
+ }], 'merge');
435
433
  return { success: true };
436
434
  }
437
435
  const bin = options.binary || AGENTS[agentId].cliCommand;
@@ -449,181 +447,71 @@ function registerMcpCommand(agentId, name, commandSpec, scope, transport, option
449
447
  return { success: false, error: err.message };
450
448
  }
451
449
  }
452
- /**
453
- * Install MCP server to Cursor config file.
454
- */
455
- function installMcpToCursorConfig(server, versionHome) {
456
- const configPath = path.join(versionHome, '.cursor', 'mcp.json');
457
- let config = {};
458
- if (fs.existsSync(configPath)) {
459
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
460
- }
461
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
462
- config.mcpServers = {};
463
- }
464
- const mcpServers = config.mcpServers;
465
- if (server.config.transport === 'stdio') {
466
- mcpServers[server.name] = {
467
- command: server.config.command,
468
- args: server.config.args || [],
469
- env: server.config.env || {},
470
- };
471
- }
472
- else {
473
- mcpServers[server.name] = {
474
- url: server.config.url,
475
- };
476
- }
477
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
478
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
479
- }
480
- /**
481
- * Install MCP server to OpenCode config file.
482
- */
483
- function installMcpToKimiConfig(server, versionHome) {
484
- const configPath = path.join(versionHome, '.kimi-code', 'mcp.json');
485
- let config = {};
486
- if (fs.existsSync(configPath)) {
487
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
488
- }
489
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
490
- config.mcpServers = {};
491
- }
492
- const mcpServers = config.mcpServers;
493
- if (server.config.transport === 'stdio') {
494
- mcpServers[server.name] = {
495
- command: server.config.command,
496
- args: server.config.args || [],
497
- env: server.config.env || {},
498
- };
499
- }
500
- else {
501
- mcpServers[server.name] = {
502
- url: server.config.url,
503
- };
504
- }
505
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
506
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
450
+ /** Project a discovered MCP server config into the writer's input shape. */
451
+ function toWritableServer(server) {
452
+ return {
453
+ name: server.config.name,
454
+ transport: server.config.transport,
455
+ command: server.config.command,
456
+ args: server.config.args,
457
+ env: server.config.env,
458
+ url: server.config.url,
459
+ };
507
460
  }
508
461
  /**
509
- * Install MCP server to Factory AI Droid config (`~/.factory/mcp.json`).
510
- * Droid uses the standard `mcpServers` JSON shape, same as Kimi/Claude.
462
+ * Read an existing agent config, or `{}` when it does not exist yet.
463
+ *
464
+ * A file that exists but does not parse **throws** rather than resetting to
465
+ * `{}`: these configs hold far more than MCP (hermes' whole `config.yaml`,
466
+ * openclaw's `openclaw.json`, opencode's `opencode.jsonc`), so silently
467
+ * rewriting one from scratch destroys everything else in it. The five per-agent
468
+ * installers this replaced parsed unguarded for exactly that reason -- the throw
469
+ * surfaced as a reported error and left the file intact, which is the behavior
470
+ * preserved here.
511
471
  */
512
- function installMcpToFactoryConfig(server, versionHome) {
513
- const configPath = path.join(versionHome, '.factory', 'mcp.json');
514
- let config = {};
515
- if (fs.existsSync(configPath)) {
516
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
517
- }
518
- if (!config.mcpServers || typeof config.mcpServers !== 'object') {
519
- config.mcpServers = {};
520
- }
521
- const mcpServers = config.mcpServers;
522
- if (server.config.transport === 'stdio') {
523
- mcpServers[server.name] = {
524
- command: server.config.command,
525
- args: server.config.args || [],
526
- env: server.config.env || {},
527
- };
528
- }
529
- else {
530
- mcpServers[server.name] = {
531
- url: server.config.url,
532
- };
533
- }
534
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
535
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
536
- }
537
- function installMcpToHermesConfig(server, versionHome) {
538
- const configPath = path.join(versionHome, '.hermes', 'config.yaml');
539
- let config = {};
540
- if (fs.existsSync(configPath)) {
541
- const parsed = yaml.parse(fs.readFileSync(configPath, 'utf-8'));
542
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
543
- config = parsed;
544
- }
545
- }
546
- if (!config.mcp_servers || typeof config.mcp_servers !== 'object' || Array.isArray(config.mcp_servers)) {
547
- config.mcp_servers = {};
548
- }
549
- const mcpServers = config.mcp_servers;
550
- if (server.config.transport === 'stdio') {
551
- mcpServers[server.name] = {
552
- command: server.config.command,
553
- args: server.config.args || [],
554
- ...(server.config.env && { env: server.config.env }),
555
- };
556
- }
557
- else {
558
- mcpServers[server.name] = {
559
- url: server.config.url,
560
- };
561
- }
562
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
563
- fs.writeFileSync(configPath, yaml.stringify(config), 'utf-8');
564
- }
565
- function installMcpToOpenCodeConfig(server, versionHome) {
566
- const configPath = path.join(versionHome, '.config', 'opencode', 'opencode.jsonc');
567
- let config = {};
568
- if (fs.existsSync(configPath)) {
569
- const content = fs.readFileSync(configPath, 'utf-8');
570
- // Strip JSONC comments
571
- const jsonContent = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
572
- try {
573
- config = JSON.parse(jsonContent);
574
- }
575
- catch {
576
- config = {};
577
- }
578
- }
579
- if (!config.mcp || typeof config.mcp !== 'object') {
580
- config.mcp = {};
472
+ function readExistingConfig(configPath, parse) {
473
+ if (!fs.existsSync(configPath))
474
+ return {};
475
+ const raw = fs.readFileSync(configPath, 'utf-8');
476
+ // An empty (or whitespace-only) file is "nothing recorded yet", not corruption
477
+ // -- a touched file or an interrupted write. `JSON.parse('')` throws, so
478
+ // without this an empty ~/.factory/mcp.json would fail the whole sync.
479
+ if (raw.trim() === '')
480
+ return {};
481
+ let parsed;
482
+ try {
483
+ parsed = parse(raw);
581
484
  }
582
- const mcpServers = config.mcp;
583
- if (server.config.transport === 'stdio') {
584
- // OpenCode uses command as array
585
- const commandArray = [server.config.command, ...(server.config.args || [])];
586
- mcpServers[server.name] = {
587
- type: 'local',
588
- command: commandArray,
589
- ...(server.config.env && { env: server.config.env }),
590
- };
485
+ catch (err) {
486
+ throw new Error(`existing config at ${configPath} is not valid: ${err.message}`);
591
487
  }
592
- else {
593
- mcpServers[server.name] = {
594
- type: 'remote',
595
- url: server.config.url,
596
- };
488
+ if (parsed === null || parsed === undefined)
489
+ return {};
490
+ if (typeof parsed !== 'object' || Array.isArray(parsed)) {
491
+ throw new Error(`existing config at ${configPath} is not an object`);
597
492
  }
598
- fs.mkdirSync(path.dirname(configPath), { recursive: true });
599
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
493
+ return parsed;
600
494
  }
601
495
  /**
602
- * Agents whose config file format is implemented by `writeMcpConfig`.
603
- * Others are intentionally skipped until their schema is added.
496
+ * Parse a JSONC config.
497
+ *
498
+ * Uses the shared string-literal-aware `stripJsonComments` — the same one the
499
+ * read path uses on this very file. A regex that blanks `//` to end-of-line
500
+ * destroys `"$schema": "https://opencode.ai/config.json"`, which every
501
+ * opencode-generated config carries, and would make the writer disagree with
502
+ * the reader about the same bytes.
604
503
  */
605
- function writeMcpConfigSupportsAgent(agentId) {
606
- switch (agentId) {
607
- case 'claude':
608
- case 'cursor':
609
- case 'kimi':
610
- case 'droid':
611
- case 'openclaw':
612
- case 'codex':
613
- case 'grok':
614
- case 'opencode':
615
- case 'hermes':
616
- case 'pi':
617
- case 'muse':
618
- case 'warp':
619
- return true;
620
- default:
621
- return false;
622
- }
504
+ function parseJsonc(raw) {
505
+ return JSON.parse(stripJsonComments(raw));
623
506
  }
624
507
  /**
625
508
  * Serialize MCP servers into an agent-specific config file.
626
509
  *
510
+ * The format comes from `MCP_TARGETS` (lib/mcp-registry.ts), so a harness whose
511
+ * schema is not implemented **throws** here rather than falling through the
512
+ * switch and returning as if it had written something. `installMcpServers`
513
+ * catches that and reports it as an error, never as a silent success.
514
+ *
627
515
  * `mode: 'overwrite'` replaces the whole MCP section (used for tool-managed
628
516
  * version-home configs). `mode: 'merge'` updates/adds the provided server
629
517
  * entries while preserving existing entries (used for project-level configs
@@ -633,27 +521,19 @@ export function writeMcpConfig(agentId, configPath, servers, mode = 'overwrite')
633
521
  if (servers.length === 0) {
634
522
  return;
635
523
  }
636
- switch (agentId) {
637
- case 'claude':
638
- case 'cursor':
639
- case 'kimi':
640
- case 'droid':
641
- // omp reads the same Claude `{ "mcpServers": {...} }` schema from .mcp.json
642
- // (stdio: command/args/env; http/sse: url/headers — transport inferred from
643
- // command/url presence).
644
- case 'pi':
645
- // Oz reads the same Claude `{ "mcpServers": {...} }` schema from
646
- // `.warp/.mcp.json` (stdio + http with headers).
647
- case 'warp': {
648
- let config = {};
649
- if (fs.existsSync(configPath)) {
650
- try {
651
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
652
- }
653
- catch {
654
- config = {};
655
- }
656
- }
524
+ // Narrowed, not asserted: this is what lets the `never` guard on the default
525
+ // arm below be a real compile-time check rather than a cosmetic one.
526
+ const target = MCP_TARGETS[agentId];
527
+ if (!target || target.format === null) {
528
+ throw new Error(`cannot write MCP config: ${mcpWriteUnsupportedReason(agentId)}`);
529
+ }
530
+ const format = target.format;
531
+ switch (format) {
532
+ // Claude's `{ "mcpServers": {...} }` schema, shared by cursor, kimi, droid,
533
+ // omp (.mcp.json) and Oz (.warp/.mcp.json): stdio carries command/args/env,
534
+ // remote carries url + optional headers.
535
+ case 'claude-json': {
536
+ const config = readExistingConfig(configPath, JSON.parse);
657
537
  const mcpServers = mode === 'merge' && config.mcpServers && typeof config.mcpServers === 'object'
658
538
  ? { ...config.mcpServers }
659
539
  : {};
@@ -677,16 +557,33 @@ export function writeMcpConfig(agentId, configPath, servers, mode = 'overwrite')
677
557
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
678
558
  break;
679
559
  }
680
- case 'openclaw': {
681
- let config = {};
682
- if (fs.existsSync(configPath)) {
683
- try {
684
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
560
+ case 'antigravity-json': {
561
+ // agy reads ~/.gemini/config/mcp_config.json. Same `mcpServers` map as
562
+ // Claude for stdio, but a remote server is keyed `serverUrl` (SSE) and
563
+ // carries no headers — see agy's bundled docs/mcp_servers.md.
564
+ const config = readExistingConfig(configPath, JSON.parse);
565
+ const mcpServers = mode === 'merge' && config.mcpServers && typeof config.mcpServers === 'object'
566
+ ? { ...config.mcpServers }
567
+ : {};
568
+ for (const server of servers) {
569
+ if (server.transport === 'stdio') {
570
+ mcpServers[server.name] = {
571
+ command: server.command,
572
+ args: server.args || [],
573
+ env: server.env || {},
574
+ };
685
575
  }
686
- catch {
687
- config = {};
576
+ else {
577
+ mcpServers[server.name] = { serverUrl: server.url };
688
578
  }
689
579
  }
580
+ config.mcpServers = mcpServers;
581
+ fs.mkdirSync(path.dirname(configPath), { recursive: true });
582
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
583
+ break;
584
+ }
585
+ case 'openclaw-json': {
586
+ const config = readExistingConfig(configPath, JSON.parse);
690
587
  if (!config.mcp || typeof config.mcp !== 'object') {
691
588
  config.mcp = {};
692
589
  }
@@ -716,17 +613,8 @@ export function writeMcpConfig(agentId, configPath, servers, mode = 'overwrite')
716
613
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
717
614
  break;
718
615
  }
719
- case 'codex':
720
- case 'grok': {
721
- let config = {};
722
- if (fs.existsSync(configPath)) {
723
- try {
724
- config = TOML.parse(fs.readFileSync(configPath, 'utf-8'));
725
- }
726
- catch {
727
- config = {};
728
- }
729
- }
616
+ case 'toml': {
617
+ const config = readExistingConfig(configPath, (raw) => TOML.parse(raw));
730
618
  const mcpServers = mode === 'merge' && config.mcp_servers && typeof config.mcp_servers === 'object'
731
619
  ? { ...config.mcp_servers }
732
620
  : {};
@@ -750,18 +638,8 @@ export function writeMcpConfig(agentId, configPath, servers, mode = 'overwrite')
750
638
  fs.writeFileSync(configPath, TOML.stringify(config), 'utf-8');
751
639
  break;
752
640
  }
753
- case 'opencode': {
754
- let config = {};
755
- if (fs.existsSync(configPath)) {
756
- try {
757
- const content = fs.readFileSync(configPath, 'utf-8');
758
- const jsonContent = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
759
- config = JSON.parse(jsonContent);
760
- }
761
- catch {
762
- config = {};
763
- }
764
- }
641
+ case 'opencode-jsonc': {
642
+ const config = readExistingConfig(configPath, parseJsonc);
765
643
  const mcp = mode === 'merge' && config.mcp && typeof config.mcp === 'object'
766
644
  ? { ...config.mcp }
767
645
  : {};
@@ -786,19 +664,8 @@ export function writeMcpConfig(agentId, configPath, servers, mode = 'overwrite')
786
664
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
787
665
  break;
788
666
  }
789
- case 'hermes': {
790
- let config = {};
791
- if (fs.existsSync(configPath)) {
792
- try {
793
- const parsed = yaml.parse(fs.readFileSync(configPath, 'utf-8'));
794
- if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
795
- config = parsed;
796
- }
797
- }
798
- catch {
799
- config = {};
800
- }
801
- }
667
+ case 'yaml': {
668
+ const config = readExistingConfig(configPath, (raw) => yaml.parse(raw));
802
669
  const mcpServers = mode === 'merge' && config.mcp_servers && typeof config.mcp_servers === 'object' && !Array.isArray(config.mcp_servers)
803
670
  ? { ...config.mcp_servers }
804
671
  : {};
@@ -821,19 +688,11 @@ export function writeMcpConfig(agentId, configPath, servers, mode = 'overwrite')
821
688
  fs.writeFileSync(configPath, yaml.stringify(config), 'utf-8');
822
689
  break;
823
690
  }
824
- case 'muse': {
691
+ case 'muse-json': {
825
692
  // Muse Code settings.json: requires schema_version: 1; MCP lives under
826
693
  // mcp_servers with an explicit transport (stdio | streamable_http).
827
694
  // See https://dev.meta.ai/docs/muse-code/extending#mcp
828
- let config = {};
829
- if (fs.existsSync(configPath)) {
830
- try {
831
- config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
832
- }
833
- catch {
834
- config = {};
835
- }
836
- }
695
+ const config = readExistingConfig(configPath, JSON.parse);
837
696
  if (config.schema_version === undefined) {
838
697
  config.schema_version = 1;
839
698
  }
@@ -864,6 +723,14 @@ export function writeMcpConfig(agentId, configPath, servers, mode = 'overwrite')
864
723
  fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8');
865
724
  break;
866
725
  }
726
+ default: {
727
+ // Unreachable: mcpWriteUnsupportedReason above rejects a null format and
728
+ // every McpFormat has an arm. The assignment is deliberately NOT cast —
729
+ // `as never` would make it unfailable and the guard cosmetic. Adding an
730
+ // McpFormat without an arm above is a compile error here.
731
+ const unhandled = format;
732
+ throw new Error(`unhandled MCP config format: ${String(unhandled)}`);
733
+ }
867
734
  }
868
735
  }
869
736
  /**
@@ -892,79 +759,29 @@ export function installMcpServers(agentId, version, versionHome, mcpNames, optio
892
759
  for (const server of servers) {
893
760
  let handled = false;
894
761
  try {
895
- if (agentId === 'claude') {
762
+ const target = MCP_TARGETS[agentId];
763
+ if (target?.cli === 'claude') {
896
764
  installMcpViaClaude(binaryPath, server, versionHome);
897
765
  handled = true;
898
766
  }
899
- else if (agentId === 'codex') {
767
+ else if (target?.cli === 'codex') {
900
768
  installMcpViaCodex(binaryPath, server, versionHome);
901
769
  handled = true;
902
770
  }
903
- else if (agentId === 'cursor') {
904
- installMcpToCursorConfig(server, versionHome);
905
- handled = true;
906
- }
907
- else if (agentId === 'opencode') {
908
- installMcpToOpenCodeConfig(server, versionHome);
909
- handled = true;
910
- }
911
- else if (agentId === 'openclaw') {
912
- // OpenClaw has no install CLI; write the JSON config directly.
913
- // Use merge because this loop runs once per server.
914
- const userConfigPath = getMcpConfigPathForHome(agentId, versionHome);
915
- const writableServer = {
916
- name: server.config.name,
917
- transport: server.config.transport,
918
- command: server.config.command,
919
- args: server.config.args,
920
- env: server.config.env,
921
- url: server.config.url,
922
- };
923
- writeMcpConfig(agentId, userConfigPath, [writableServer], 'merge');
924
- handled = true;
925
- }
926
- else if (agentId === 'grok') {
927
- // Grok has no working `grok mcp add` CLI, so write the TOML config
928
- // directly into the version-home directory for all scopes.
929
- // Use merge because this loop runs once per server.
930
- const userConfigPath = getMcpConfigPathForHome(agentId, versionHome);
931
- const writableServer = {
932
- name: server.config.name,
933
- transport: server.config.transport,
934
- command: server.config.command,
935
- args: server.config.args,
936
- env: server.config.env,
937
- url: server.config.url,
938
- };
939
- writeMcpConfig(agentId, userConfigPath, [writableServer], 'merge');
940
- handled = true;
941
- }
942
- else if (agentId === 'kimi') {
943
- installMcpToKimiConfig(server, versionHome);
944
- handled = true;
945
- }
946
- else if (agentId === 'droid') {
947
- installMcpToFactoryConfig(server, versionHome);
948
- handled = true;
949
- }
950
- else if (agentId === 'hermes') {
951
- installMcpToHermesConfig(server, versionHome);
771
+ else {
772
+ // No harness CLI for this agent (or none that works — `grok mcp add`
773
+ // does not register into the version home), so write its config file
774
+ // directly. `writeMcpConfig` throws for a harness whose format is not
775
+ // implemented, which the catch below turns into a reported error rather
776
+ // than a silent success. Merge, because this loop runs once per server.
777
+ writeMcpConfig(agentId, getMcpConfigPathForHome(agentId, versionHome), [toWritableServer(server)], 'merge');
952
778
  handled = true;
953
779
  }
954
780
  // Project-layer servers also get merged into the agent's project-level
955
781
  // config (e.g., .mcp.json, .codex/config.toml) so the CLI discovers them
956
782
  // when run inside the repo.
957
- if (server.scope === 'project' && options.cwd && writeMcpConfigSupportsAgent(agentId)) {
958
- const projectConfigPath = getProjectMcpConfigPath(agentId, options.cwd);
959
- const writableServer = {
960
- name: server.config.name,
961
- transport: server.config.transport,
962
- command: server.config.command,
963
- args: server.config.args,
964
- env: server.config.env,
965
- url: server.config.url,
966
- };
967
- writeMcpConfig(agentId, projectConfigPath, [writableServer], 'merge');
783
+ if (server.scope === 'project' && options.cwd) {
784
+ writeMcpConfig(agentId, getProjectMcpConfigPath(agentId, options.cwd), [toWritableServer(server)], 'merge');
968
785
  handled = true;
969
786
  }
970
787
  if (handled) {
@@ -14,6 +14,13 @@
14
14
  * migration (`installMenubarLaunchAgent` in migrate.ts) honors, so a disabled
15
15
  * menu bar never silently comes back on the next release.
16
16
  */
17
+ /**
18
+ * launchd Label for this process's helper — the production identifier for a
19
+ * real invocation, namespaced under a redirected HOME (RUSH-2639). launchd
20
+ * routes bootout/bootstrap/kickstart by identifier alone, so without this a
21
+ * hermetic test fork's own teardown boots out the operator's live helper.
22
+ */
23
+ export declare function serviceLabel(): string;
17
24
  /**
18
25
  * Absolute path to the installed MenubarHelper executable if it exists on disk,
19
26
  * else null. The desktop notifier (notify-desktop.ts) routes daemon
@@ -24,9 +24,19 @@ import { getRuntimeStateDir, getHelpersDir } from '../state.js';
24
24
  import { getCliVersion, resolveAgentsBin, resolveInstalledLayout } from '../version.js';
25
25
  import { copyAppBundle, withInstallLock } from '../app-bundle-install.js';
26
26
  import { compareVersions } from '../agent-spec/primitives.js';
27
+ import { namespacedServiceLabel, serviceManifestHomeEnv } from '../service-manifest.js';
27
28
  const APP_BUNDLE_NAME = 'MenubarHelper.app';
28
29
  const INSTALL_DIR_NAME = 'agents-cli';
29
- const SERVICE_LABEL = 'com.phnx-labs.agents-menubar';
30
+ const SERVICE_LABEL_BASE = 'com.phnx-labs.agents-menubar';
31
+ /**
32
+ * launchd Label for this process's helper — the production identifier for a
33
+ * real invocation, namespaced under a redirected HOME (RUSH-2639). launchd
34
+ * routes bootout/bootstrap/kickstart by identifier alone, so without this a
35
+ * hermetic test fork's own teardown boots out the operator's live helper.
36
+ */
37
+ export function serviceLabel() {
38
+ return namespacedServiceLabel(SERVICE_LABEL_BASE);
39
+ }
30
40
  /**
31
41
  * Minimum seconds between launchd restarts of the helper (`ThrottleInterval`).
32
42
  *
@@ -91,7 +101,7 @@ export function resolveInstalledMenubarExecutable() {
91
101
  }
92
102
  /** ~/Library/LaunchAgents/com.phnx-labs.agents-menubar.plist */
93
103
  function servicePlistPath() {
94
- return path.join(os.homedir(), 'Library', 'LaunchAgents', `${SERVICE_LABEL}.plist`);
104
+ return path.join(os.homedir(), 'Library', 'LaunchAgents', `${serviceLabel()}.plist`);
95
105
  }
96
106
  /** Sticky opt-out marker written by `agents menubar disable`. */
97
107
  function disabledSentinelPath() {
@@ -261,8 +271,16 @@ export function generateServicePlist(execPath) {
261
271
  // Bake interpreter + entry + bin so the GUI helper can reach the CLI with no
262
272
  // login PATH. AgentsCLI.swift prefers [AGENTS_NODE, AGENTS_ENTRY] when both
263
273
  // exist, else falls back to AGENTS_BIN, else probes well-known paths.
274
+ //
275
+ // HOME is baked for the same reason (RUSH-2639, see service-manifest.ts):
276
+ // launchd applies this dict on top of the LOGIN SESSION's environment, not the
277
+ // environment of whoever called `launchctl bootstrap`. Without the key the
278
+ // helper resolves the account home and every `agents` call it makes bootstraps
279
+ // that home's `~/.agents` — which is how a hermetic test fork's helper wrote
280
+ // into the runner's real home.
264
281
  const env = {
265
282
  PATH: `/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:${path.dirname(process.execPath)}:${home}/.local/bin`,
283
+ ...serviceManifestHomeEnv(),
266
284
  };
267
285
  const node = process.execPath;
268
286
  const entry = resolveCliEntry();
@@ -281,7 +299,7 @@ export function generateServicePlist(execPath) {
281
299
  <plist version="1.0">
282
300
  <dict>
283
301
  <key>Label</key>
284
- <string>${SERVICE_LABEL}</string>
302
+ <string>${serviceLabel()}</string>
285
303
  <key>ProgramArguments</key>
286
304
  <array>
287
305
  <string>${xmlEscape(execPath)}</string>
@@ -315,7 +333,7 @@ ${envXml}
315
333
  * is the only sequence that reliably re-attaches the status item.
316
334
  */
317
335
  export function restartMenubarLaunchAgent(uid, plist, exec = execFileSync) {
318
- const serviceTarget = `gui/${uid}/${SERVICE_LABEL}`;
336
+ const serviceTarget = `gui/${uid}/${serviceLabel()}`;
319
337
  const opts = { stdio: ['ignore', 'ignore', 'ignore'] };
320
338
  try {
321
339
  exec('launchctl', ['bootout', serviceTarget], opts);
@@ -451,7 +469,7 @@ export function disableMenubarService() {
451
469
  const plist = servicePlistPath();
452
470
  const uid = process.getuid?.() ?? 0;
453
471
  try {
454
- execFileSync('launchctl', ['bootout', `gui/${uid}/${SERVICE_LABEL}`], { stdio: ['ignore', 'ignore', 'ignore'] });
472
+ execFileSync('launchctl', ['bootout', `gui/${uid}/${serviceLabel()}`], { stdio: ['ignore', 'ignore', 'ignore'] });
455
473
  }
456
474
  catch {
457
475
  try {
@@ -727,7 +745,7 @@ export function runMenubarSetup() {
727
745
  // menu bar, so a stale `menubar disable` must not silently win.
728
746
  clearMenubarOptOut();
729
747
  installAndStartService(exec);
730
- step('login item', before.serviceInstalled ? 'ok' : 'changed', `${SERVICE_LABEL} — starts at login, restarts if it dies`);
748
+ step('login item', before.serviceInstalled ? 'ok' : 'changed', `${serviceLabel()} — starts at login, restarts if it dies`);
731
749
  // launchd's bootstrap+kickstart is asynchronous; give the status item a beat
732
750
  // to claim the lock before counting instances, or `setup` reports zero on a
733
751
  // machine that is in fact coming up correctly.
@@ -18,6 +18,13 @@ export interface MenubarDevice {
18
18
  export interface MenubarSnapshot {
19
19
  version: 1;
20
20
  capturedAt: string;
21
+ /**
22
+ * The installed CLI version that produced this snapshot — the same string
23
+ * `agents --version` prints (RUSH-2688). The snapshot is emitted by whatever
24
+ * `agents` binary is on PATH, so this is resolved at runtime, letting the menu
25
+ * bar show its own version in the header and making a stale menu bar visible.
26
+ */
27
+ cliVersion: string;
21
28
  routines: Record<string, unknown>[];
22
29
  recentSessions: Record<string, unknown>[];
23
30
  activeSessions: Record<string, unknown>[];