@swarmify/agents-cli 1.13.4 → 1.14.0

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 (567) hide show
  1. package/README.md +2 -319
  2. package/bin/agents.js +2 -0
  3. package/package.json +13 -79
  4. package/scripts/postinstall.js +4 -71
  5. package/CHANGELOG.md +0 -316
  6. package/LICENSE +0 -21
  7. package/dist/commands/__tests__/sessions-tail.test.d.ts +0 -2
  8. package/dist/commands/__tests__/sessions-tail.test.d.ts.map +0 -1
  9. package/dist/commands/__tests__/sessions-tail.test.js +0 -108
  10. package/dist/commands/__tests__/sessions-tail.test.js.map +0 -1
  11. package/dist/commands/__tests__/sessions.test.d.ts +0 -2
  12. package/dist/commands/__tests__/sessions.test.d.ts.map +0 -1
  13. package/dist/commands/__tests__/sessions.test.js +0 -636
  14. package/dist/commands/__tests__/sessions.test.js.map +0 -1
  15. package/dist/commands/cloud.d.ts +0 -11
  16. package/dist/commands/cloud.d.ts.map +0 -1
  17. package/dist/commands/cloud.js +0 -363
  18. package/dist/commands/cloud.js.map +0 -1
  19. package/dist/commands/commands.d.ts +0 -12
  20. package/dist/commands/commands.d.ts.map +0 -1
  21. package/dist/commands/commands.js +0 -629
  22. package/dist/commands/commands.js.map +0 -1
  23. package/dist/commands/daemon.d.ts +0 -11
  24. package/dist/commands/daemon.d.ts.map +0 -1
  25. package/dist/commands/daemon.js +0 -119
  26. package/dist/commands/daemon.js.map +0 -1
  27. package/dist/commands/drive.d.ts +0 -11
  28. package/dist/commands/drive.d.ts.map +0 -1
  29. package/dist/commands/drive.js +0 -175
  30. package/dist/commands/drive.js.map +0 -1
  31. package/dist/commands/exec.d.ts +0 -11
  32. package/dist/commands/exec.d.ts.map +0 -1
  33. package/dist/commands/exec.js +0 -251
  34. package/dist/commands/exec.js.map +0 -1
  35. package/dist/commands/factory.d.ts +0 -11
  36. package/dist/commands/factory.d.ts.map +0 -1
  37. package/dist/commands/factory.js +0 -445
  38. package/dist/commands/factory.js.map +0 -1
  39. package/dist/commands/fork.d.ts +0 -11
  40. package/dist/commands/fork.d.ts.map +0 -1
  41. package/dist/commands/fork.js +0 -147
  42. package/dist/commands/fork.js.map +0 -1
  43. package/dist/commands/hooks.d.ts +0 -12
  44. package/dist/commands/hooks.d.ts.map +0 -1
  45. package/dist/commands/hooks.js +0 -690
  46. package/dist/commands/hooks.js.map +0 -1
  47. package/dist/commands/init.d.ts +0 -15
  48. package/dist/commands/init.d.ts.map +0 -1
  49. package/dist/commands/init.js +0 -137
  50. package/dist/commands/init.js.map +0 -1
  51. package/dist/commands/mcp.d.ts +0 -12
  52. package/dist/commands/mcp.d.ts.map +0 -1
  53. package/dist/commands/mcp.js +0 -583
  54. package/dist/commands/mcp.js.map +0 -1
  55. package/dist/commands/models.d.ts +0 -11
  56. package/dist/commands/models.d.ts.map +0 -1
  57. package/dist/commands/models.js +0 -170
  58. package/dist/commands/models.js.map +0 -1
  59. package/dist/commands/packages.d.ts +0 -11
  60. package/dist/commands/packages.d.ts.map +0 -1
  61. package/dist/commands/packages.js +0 -551
  62. package/dist/commands/packages.js.map +0 -1
  63. package/dist/commands/permissions.d.ts +0 -12
  64. package/dist/commands/permissions.d.ts.map +0 -1
  65. package/dist/commands/permissions.js +0 -724
  66. package/dist/commands/permissions.js.map +0 -1
  67. package/dist/commands/plugins.d.ts +0 -11
  68. package/dist/commands/plugins.d.ts.map +0 -1
  69. package/dist/commands/plugins.js +0 -393
  70. package/dist/commands/plugins.js.map +0 -1
  71. package/dist/commands/profiles.d.ts +0 -12
  72. package/dist/commands/profiles.d.ts.map +0 -1
  73. package/dist/commands/profiles.js +0 -255
  74. package/dist/commands/profiles.js.map +0 -1
  75. package/dist/commands/pty.d.ts +0 -21
  76. package/dist/commands/pty.d.ts.map +0 -1
  77. package/dist/commands/pty.js +0 -391
  78. package/dist/commands/pty.js.map +0 -1
  79. package/dist/commands/pull.d.ts +0 -11
  80. package/dist/commands/pull.d.ts.map +0 -1
  81. package/dist/commands/pull.js +0 -456
  82. package/dist/commands/pull.js.map +0 -1
  83. package/dist/commands/push.d.ts +0 -11
  84. package/dist/commands/push.d.ts.map +0 -1
  85. package/dist/commands/push.js +0 -188
  86. package/dist/commands/push.js.map +0 -1
  87. package/dist/commands/refresh-memory.d.ts +0 -16
  88. package/dist/commands/refresh-memory.d.ts.map +0 -1
  89. package/dist/commands/refresh-memory.js +0 -52
  90. package/dist/commands/refresh-memory.js.map +0 -1
  91. package/dist/commands/resource-view.d.ts +0 -39
  92. package/dist/commands/resource-view.d.ts.map +0 -1
  93. package/dist/commands/resource-view.js +0 -197
  94. package/dist/commands/resource-view.js.map +0 -1
  95. package/dist/commands/routines.d.ts +0 -11
  96. package/dist/commands/routines.d.ts.map +0 -1
  97. package/dist/commands/routines.js +0 -590
  98. package/dist/commands/routines.js.map +0 -1
  99. package/dist/commands/rules.d.ts +0 -12
  100. package/dist/commands/rules.d.ts.map +0 -1
  101. package/dist/commands/rules.js +0 -489
  102. package/dist/commands/rules.js.map +0 -1
  103. package/dist/commands/secrets.d.ts +0 -11
  104. package/dist/commands/secrets.d.ts.map +0 -1
  105. package/dist/commands/secrets.js +0 -352
  106. package/dist/commands/secrets.js.map +0 -1
  107. package/dist/commands/sessions-picker.d.ts +0 -18
  108. package/dist/commands/sessions-picker.d.ts.map +0 -1
  109. package/dist/commands/sessions-picker.js +0 -265
  110. package/dist/commands/sessions-picker.js.map +0 -1
  111. package/dist/commands/sessions-tail.d.ts +0 -20
  112. package/dist/commands/sessions-tail.d.ts.map +0 -1
  113. package/dist/commands/sessions-tail.js +0 -236
  114. package/dist/commands/sessions-tail.js.map +0 -1
  115. package/dist/commands/sessions.d.ts +0 -18
  116. package/dist/commands/sessions.d.ts.map +0 -1
  117. package/dist/commands/sessions.js +0 -1173
  118. package/dist/commands/sessions.js.map +0 -1
  119. package/dist/commands/skills.d.ts +0 -12
  120. package/dist/commands/skills.d.ts.map +0 -1
  121. package/dist/commands/skills.js +0 -717
  122. package/dist/commands/skills.js.map +0 -1
  123. package/dist/commands/status.d.ts +0 -10
  124. package/dist/commands/status.d.ts.map +0 -1
  125. package/dist/commands/status.js +0 -26
  126. package/dist/commands/status.js.map +0 -1
  127. package/dist/commands/subagents.d.ts +0 -11
  128. package/dist/commands/subagents.d.ts.map +0 -1
  129. package/dist/commands/subagents.js +0 -361
  130. package/dist/commands/subagents.js.map +0 -1
  131. package/dist/commands/sync.d.ts +0 -11
  132. package/dist/commands/sync.d.ts.map +0 -1
  133. package/dist/commands/sync.js +0 -70
  134. package/dist/commands/sync.js.map +0 -1
  135. package/dist/commands/teams-picker.d.ts +0 -18
  136. package/dist/commands/teams-picker.d.ts.map +0 -1
  137. package/dist/commands/teams-picker.js +0 -290
  138. package/dist/commands/teams-picker.js.map +0 -1
  139. package/dist/commands/teams.d.ts +0 -18
  140. package/dist/commands/teams.d.ts.map +0 -1
  141. package/dist/commands/teams.js +0 -1144
  142. package/dist/commands/teams.js.map +0 -1
  143. package/dist/commands/utils.d.ts +0 -45
  144. package/dist/commands/utils.d.ts.map +0 -1
  145. package/dist/commands/utils.js +0 -106
  146. package/dist/commands/utils.js.map +0 -1
  147. package/dist/commands/versions.d.ts +0 -11
  148. package/dist/commands/versions.d.ts.map +0 -1
  149. package/dist/commands/versions.js +0 -701
  150. package/dist/commands/versions.js.map +0 -1
  151. package/dist/commands/view.d.ts +0 -43
  152. package/dist/commands/view.d.ts.map +0 -1
  153. package/dist/commands/view.js +0 -894
  154. package/dist/commands/view.js.map +0 -1
  155. package/dist/index.d.ts +0 -9
  156. package/dist/index.d.ts.map +0 -1
  157. package/dist/index.js +0 -496
  158. package/dist/index.js.map +0 -1
  159. package/dist/lib/__tests__/bugfixes.test.d.ts +0 -2
  160. package/dist/lib/__tests__/bugfixes.test.d.ts.map +0 -1
  161. package/dist/lib/__tests__/bugfixes.test.js +0 -192
  162. package/dist/lib/__tests__/bugfixes.test.js.map +0 -1
  163. package/dist/lib/__tests__/exec.test.d.ts +0 -2
  164. package/dist/lib/__tests__/exec.test.d.ts.map +0 -1
  165. package/dist/lib/__tests__/exec.test.js +0 -446
  166. package/dist/lib/__tests__/exec.test.js.map +0 -1
  167. package/dist/lib/__tests__/git-sync.test.d.ts +0 -2
  168. package/dist/lib/__tests__/git-sync.test.d.ts.map +0 -1
  169. package/dist/lib/__tests__/git-sync.test.js +0 -138
  170. package/dist/lib/__tests__/git-sync.test.js.map +0 -1
  171. package/dist/lib/__tests__/hooks.test.d.ts +0 -2
  172. package/dist/lib/__tests__/hooks.test.d.ts.map +0 -1
  173. package/dist/lib/__tests__/hooks.test.js +0 -203
  174. package/dist/lib/__tests__/hooks.test.js.map +0 -1
  175. package/dist/lib/__tests__/memory-compile.test.d.ts +0 -2
  176. package/dist/lib/__tests__/memory-compile.test.d.ts.map +0 -1
  177. package/dist/lib/__tests__/memory-compile.test.js +0 -95
  178. package/dist/lib/__tests__/memory-compile.test.js.map +0 -1
  179. package/dist/lib/__tests__/models.test.d.ts +0 -2
  180. package/dist/lib/__tests__/models.test.d.ts.map +0 -1
  181. package/dist/lib/__tests__/models.test.js +0 -239
  182. package/dist/lib/__tests__/models.test.js.map +0 -1
  183. package/dist/lib/__tests__/rotate.test.d.ts +0 -2
  184. package/dist/lib/__tests__/rotate.test.d.ts.map +0 -1
  185. package/dist/lib/__tests__/rotate.test.js +0 -80
  186. package/dist/lib/__tests__/rotate.test.js.map +0 -1
  187. package/dist/lib/__tests__/secrets-bundles.test.d.ts +0 -2
  188. package/dist/lib/__tests__/secrets-bundles.test.d.ts.map +0 -1
  189. package/dist/lib/__tests__/secrets-bundles.test.js +0 -104
  190. package/dist/lib/__tests__/secrets-bundles.test.js.map +0 -1
  191. package/dist/lib/__tests__/secrets.test.d.ts +0 -2
  192. package/dist/lib/__tests__/secrets.test.d.ts.map +0 -1
  193. package/dist/lib/__tests__/secrets.test.js +0 -90
  194. package/dist/lib/__tests__/secrets.test.js.map +0 -1
  195. package/dist/lib/__tests__/shims.test.d.ts +0 -2
  196. package/dist/lib/__tests__/shims.test.d.ts.map +0 -1
  197. package/dist/lib/__tests__/shims.test.js +0 -57
  198. package/dist/lib/__tests__/shims.test.js.map +0 -1
  199. package/dist/lib/__tests__/usage.test.d.ts +0 -2
  200. package/dist/lib/__tests__/usage.test.d.ts.map +0 -1
  201. package/dist/lib/__tests__/usage.test.js +0 -220
  202. package/dist/lib/__tests__/usage.test.js.map +0 -1
  203. package/dist/lib/__tests__/versions.test.d.ts +0 -2
  204. package/dist/lib/__tests__/versions.test.d.ts.map +0 -1
  205. package/dist/lib/__tests__/versions.test.js +0 -63
  206. package/dist/lib/__tests__/versions.test.js.map +0 -1
  207. package/dist/lib/agents.d.ts +0 -158
  208. package/dist/lib/agents.d.ts.map +0 -1
  209. package/dist/lib/agents.js +0 -1159
  210. package/dist/lib/agents.js.map +0 -1
  211. package/dist/lib/artifact-actions.d.ts +0 -27
  212. package/dist/lib/artifact-actions.d.ts.map +0 -1
  213. package/dist/lib/artifact-actions.js +0 -58
  214. package/dist/lib/artifact-actions.js.map +0 -1
  215. package/dist/lib/cloud/codex.d.ts +0 -26
  216. package/dist/lib/cloud/codex.d.ts.map +0 -1
  217. package/dist/lib/cloud/codex.js +0 -237
  218. package/dist/lib/cloud/codex.js.map +0 -1
  219. package/dist/lib/cloud/factory.d.ts +0 -32
  220. package/dist/lib/cloud/factory.d.ts.map +0 -1
  221. package/dist/lib/cloud/factory.js +0 -43
  222. package/dist/lib/cloud/factory.js.map +0 -1
  223. package/dist/lib/cloud/registry.d.ts +0 -16
  224. package/dist/lib/cloud/registry.d.ts.map +0 -1
  225. package/dist/lib/cloud/registry.js +0 -68
  226. package/dist/lib/cloud/registry.js.map +0 -1
  227. package/dist/lib/cloud/rush.d.ts +0 -37
  228. package/dist/lib/cloud/rush.d.ts.map +0 -1
  229. package/dist/lib/cloud/rush.js +0 -230
  230. package/dist/lib/cloud/rush.js.map +0 -1
  231. package/dist/lib/cloud/rush.test.d.ts +0 -2
  232. package/dist/lib/cloud/rush.test.d.ts.map +0 -1
  233. package/dist/lib/cloud/rush.test.js +0 -63
  234. package/dist/lib/cloud/rush.test.js.map +0 -1
  235. package/dist/lib/cloud/store.d.ts +0 -23
  236. package/dist/lib/cloud/store.d.ts.map +0 -1
  237. package/dist/lib/cloud/store.js +0 -116
  238. package/dist/lib/cloud/store.js.map +0 -1
  239. package/dist/lib/cloud/stream.d.ts +0 -24
  240. package/dist/lib/cloud/stream.d.ts.map +0 -1
  241. package/dist/lib/cloud/stream.js +0 -145
  242. package/dist/lib/cloud/stream.js.map +0 -1
  243. package/dist/lib/cloud/types.d.ts +0 -109
  244. package/dist/lib/cloud/types.d.ts.map +0 -1
  245. package/dist/lib/cloud/types.js +0 -33
  246. package/dist/lib/cloud/types.js.map +0 -1
  247. package/dist/lib/cloud/types.test.d.ts +0 -2
  248. package/dist/lib/cloud/types.test.d.ts.map +0 -1
  249. package/dist/lib/cloud/types.test.js +0 -41
  250. package/dist/lib/cloud/types.test.js.map +0 -1
  251. package/dist/lib/commands.d.ts +0 -141
  252. package/dist/lib/commands.d.ts.map +0 -1
  253. package/dist/lib/commands.js +0 -514
  254. package/dist/lib/commands.js.map +0 -1
  255. package/dist/lib/convert.d.ts +0 -21
  256. package/dist/lib/convert.d.ts.map +0 -1
  257. package/dist/lib/convert.js +0 -54
  258. package/dist/lib/convert.js.map +0 -1
  259. package/dist/lib/daemon.d.ts +0 -43
  260. package/dist/lib/daemon.d.ts.map +0 -1
  261. package/dist/lib/daemon.js +0 -332
  262. package/dist/lib/daemon.js.map +0 -1
  263. package/dist/lib/drive-sync.d.ts +0 -46
  264. package/dist/lib/drive-sync.d.ts.map +0 -1
  265. package/dist/lib/drive-sync.js +0 -209
  266. package/dist/lib/drive-sync.js.map +0 -1
  267. package/dist/lib/exec.d.ts +0 -101
  268. package/dist/lib/exec.d.ts.map +0 -1
  269. package/dist/lib/exec.js +0 -450
  270. package/dist/lib/exec.js.map +0 -1
  271. package/dist/lib/factory/__tests__/config.test.d.ts +0 -2
  272. package/dist/lib/factory/__tests__/config.test.d.ts.map +0 -1
  273. package/dist/lib/factory/__tests__/config.test.js +0 -128
  274. package/dist/lib/factory/__tests__/config.test.js.map +0 -1
  275. package/dist/lib/factory/config.d.ts +0 -49
  276. package/dist/lib/factory/config.d.ts.map +0 -1
  277. package/dist/lib/factory/config.js +0 -127
  278. package/dist/lib/factory/config.js.map +0 -1
  279. package/dist/lib/factory.d.ts +0 -57
  280. package/dist/lib/factory.d.ts.map +0 -1
  281. package/dist/lib/factory.js +0 -107
  282. package/dist/lib/factory.js.map +0 -1
  283. package/dist/lib/git.d.ts +0 -157
  284. package/dist/lib/git.d.ts.map +0 -1
  285. package/dist/lib/git.js +0 -647
  286. package/dist/lib/git.js.map +0 -1
  287. package/dist/lib/help.d.ts +0 -10
  288. package/dist/lib/help.d.ts.map +0 -1
  289. package/dist/lib/help.js +0 -66
  290. package/dist/lib/help.js.map +0 -1
  291. package/dist/lib/hooks.d.ts +0 -125
  292. package/dist/lib/hooks.d.ts.map +0 -1
  293. package/dist/lib/hooks.js +0 -846
  294. package/dist/lib/hooks.js.map +0 -1
  295. package/dist/lib/ledger/__tests__/local.test.d.ts +0 -2
  296. package/dist/lib/ledger/__tests__/local.test.d.ts.map +0 -1
  297. package/dist/lib/ledger/__tests__/local.test.js +0 -177
  298. package/dist/lib/ledger/__tests__/local.test.js.map +0 -1
  299. package/dist/lib/ledger/__tests__/sync.test.d.ts +0 -2
  300. package/dist/lib/ledger/__tests__/sync.test.d.ts.map +0 -1
  301. package/dist/lib/ledger/__tests__/sync.test.js +0 -117
  302. package/dist/lib/ledger/__tests__/sync.test.js.map +0 -1
  303. package/dist/lib/ledger/index.d.ts +0 -18
  304. package/dist/lib/ledger/index.d.ts.map +0 -1
  305. package/dist/lib/ledger/index.js +0 -32
  306. package/dist/lib/ledger/index.js.map +0 -1
  307. package/dist/lib/ledger/local.d.ts +0 -22
  308. package/dist/lib/ledger/local.d.ts.map +0 -1
  309. package/dist/lib/ledger/local.js +0 -333
  310. package/dist/lib/ledger/local.js.map +0 -1
  311. package/dist/lib/ledger/r2.d.ts +0 -41
  312. package/dist/lib/ledger/r2.d.ts.map +0 -1
  313. package/dist/lib/ledger/r2.js +0 -335
  314. package/dist/lib/ledger/r2.js.map +0 -1
  315. package/dist/lib/ledger/sync.d.ts +0 -33
  316. package/dist/lib/ledger/sync.d.ts.map +0 -1
  317. package/dist/lib/ledger/sync.js +0 -106
  318. package/dist/lib/ledger/sync.js.map +0 -1
  319. package/dist/lib/ledger/types.d.ts +0 -100
  320. package/dist/lib/ledger/types.d.ts.map +0 -1
  321. package/dist/lib/ledger/types.js +0 -21
  322. package/dist/lib/ledger/types.js.map +0 -1
  323. package/dist/lib/manifest.d.ts +0 -14
  324. package/dist/lib/manifest.d.ts.map +0 -1
  325. package/dist/lib/manifest.js +0 -48
  326. package/dist/lib/manifest.js.map +0 -1
  327. package/dist/lib/markdown.d.ts +0 -5
  328. package/dist/lib/markdown.d.ts.map +0 -1
  329. package/dist/lib/markdown.js +0 -17
  330. package/dist/lib/markdown.js.map +0 -1
  331. package/dist/lib/mcp.d.ts +0 -64
  332. package/dist/lib/mcp.d.ts.map +0 -1
  333. package/dist/lib/mcp.js +0 -327
  334. package/dist/lib/mcp.js.map +0 -1
  335. package/dist/lib/memory-compile.d.ts +0 -65
  336. package/dist/lib/memory-compile.d.ts.map +0 -1
  337. package/dist/lib/memory-compile.js +0 -174
  338. package/dist/lib/memory-compile.js.map +0 -1
  339. package/dist/lib/memory.d.ts +0 -64
  340. package/dist/lib/memory.d.ts.map +0 -1
  341. package/dist/lib/memory.js +0 -275
  342. package/dist/lib/memory.js.map +0 -1
  343. package/dist/lib/models.d.ts +0 -98
  344. package/dist/lib/models.d.ts.map +0 -1
  345. package/dist/lib/models.js +0 -728
  346. package/dist/lib/models.js.map +0 -1
  347. package/dist/lib/permissions.d.ts +0 -227
  348. package/dist/lib/permissions.d.ts.map +0 -1
  349. package/dist/lib/permissions.js +0 -1085
  350. package/dist/lib/permissions.js.map +0 -1
  351. package/dist/lib/picker.d.ts +0 -27
  352. package/dist/lib/picker.d.ts.map +0 -1
  353. package/dist/lib/picker.js +0 -110
  354. package/dist/lib/picker.js.map +0 -1
  355. package/dist/lib/plugins.d.ts +0 -80
  356. package/dist/lib/plugins.d.ts.map +0 -1
  357. package/dist/lib/plugins.js +0 -556
  358. package/dist/lib/plugins.js.map +0 -1
  359. package/dist/lib/profiles-keychain.d.ts +0 -11
  360. package/dist/lib/profiles-keychain.d.ts.map +0 -1
  361. package/dist/lib/profiles-keychain.js +0 -14
  362. package/dist/lib/profiles-keychain.js.map +0 -1
  363. package/dist/lib/profiles-presets.d.ts +0 -25
  364. package/dist/lib/profiles-presets.d.ts.map +0 -1
  365. package/dist/lib/profiles-presets.js +0 -104
  366. package/dist/lib/profiles-presets.js.map +0 -1
  367. package/dist/lib/profiles.d.ts +0 -70
  368. package/dist/lib/profiles.d.ts.map +0 -1
  369. package/dist/lib/profiles.js +0 -145
  370. package/dist/lib/profiles.js.map +0 -1
  371. package/dist/lib/pty-client.d.ts +0 -23
  372. package/dist/lib/pty-client.d.ts.map +0 -1
  373. package/dist/lib/pty-client.js +0 -181
  374. package/dist/lib/pty-client.js.map +0 -1
  375. package/dist/lib/pty-server.d.ts +0 -21
  376. package/dist/lib/pty-server.d.ts.map +0 -1
  377. package/dist/lib/pty-server.js +0 -427
  378. package/dist/lib/pty-server.js.map +0 -1
  379. package/dist/lib/registry.d.ts +0 -45
  380. package/dist/lib/registry.d.ts.map +0 -1
  381. package/dist/lib/registry.js +0 -220
  382. package/dist/lib/registry.js.map +0 -1
  383. package/dist/lib/resources.d.ts +0 -55
  384. package/dist/lib/resources.d.ts.map +0 -1
  385. package/dist/lib/resources.js +0 -103
  386. package/dist/lib/resources.js.map +0 -1
  387. package/dist/lib/rotate.d.ts +0 -58
  388. package/dist/lib/rotate.d.ts.map +0 -1
  389. package/dist/lib/rotate.js +0 -93
  390. package/dist/lib/rotate.js.map +0 -1
  391. package/dist/lib/routines.d.ts +0 -99
  392. package/dist/lib/routines.d.ts.map +0 -1
  393. package/dist/lib/routines.js +0 -352
  394. package/dist/lib/routines.js.map +0 -1
  395. package/dist/lib/runner.d.ts +0 -26
  396. package/dist/lib/runner.d.ts.map +0 -1
  397. package/dist/lib/runner.js +0 -325
  398. package/dist/lib/runner.js.map +0 -1
  399. package/dist/lib/sandbox.d.ts +0 -26
  400. package/dist/lib/sandbox.d.ts.map +0 -1
  401. package/dist/lib/sandbox.js +0 -218
  402. package/dist/lib/sandbox.js.map +0 -1
  403. package/dist/lib/scheduler.d.ts +0 -26
  404. package/dist/lib/scheduler.d.ts.map +0 -1
  405. package/dist/lib/scheduler.js +0 -77
  406. package/dist/lib/scheduler.js.map +0 -1
  407. package/dist/lib/secrets-bundles.d.ts +0 -38
  408. package/dist/lib/secrets-bundles.d.ts.map +0 -1
  409. package/dist/lib/secrets-bundles.js +0 -176
  410. package/dist/lib/secrets-bundles.js.map +0 -1
  411. package/dist/lib/secrets.d.ts +0 -53
  412. package/dist/lib/secrets.d.ts.map +0 -1
  413. package/dist/lib/secrets.js +0 -140
  414. package/dist/lib/secrets.js.map +0 -1
  415. package/dist/lib/session/__tests__/db.test.d.ts +0 -2
  416. package/dist/lib/session/__tests__/db.test.d.ts.map +0 -1
  417. package/dist/lib/session/__tests__/db.test.js +0 -54
  418. package/dist/lib/session/__tests__/db.test.js.map +0 -1
  419. package/dist/lib/session/__tests__/discover.test.d.ts +0 -2
  420. package/dist/lib/session/__tests__/discover.test.d.ts.map +0 -1
  421. package/dist/lib/session/__tests__/discover.test.js +0 -63
  422. package/dist/lib/session/__tests__/discover.test.js.map +0 -1
  423. package/dist/lib/session/__tests__/prompt.test.d.ts +0 -2
  424. package/dist/lib/session/__tests__/prompt.test.d.ts.map +0 -1
  425. package/dist/lib/session/__tests__/prompt.test.js +0 -44
  426. package/dist/lib/session/__tests__/prompt.test.js.map +0 -1
  427. package/dist/lib/session/__tests__/render.test.d.ts +0 -2
  428. package/dist/lib/session/__tests__/render.test.d.ts.map +0 -1
  429. package/dist/lib/session/__tests__/render.test.js +0 -602
  430. package/dist/lib/session/__tests__/render.test.js.map +0 -1
  431. package/dist/lib/session/active.d.ts +0 -44
  432. package/dist/lib/session/active.d.ts.map +0 -1
  433. package/dist/lib/session/active.js +0 -379
  434. package/dist/lib/session/active.js.map +0 -1
  435. package/dist/lib/session/artifacts.d.ts +0 -15
  436. package/dist/lib/session/artifacts.d.ts.map +0 -1
  437. package/dist/lib/session/artifacts.js +0 -86
  438. package/dist/lib/session/artifacts.js.map +0 -1
  439. package/dist/lib/session/db.d.ts +0 -140
  440. package/dist/lib/session/db.d.ts.map +0 -1
  441. package/dist/lib/session/db.js +0 -599
  442. package/dist/lib/session/db.js.map +0 -1
  443. package/dist/lib/session/discover.d.ts +0 -72
  444. package/dist/lib/session/discover.d.ts.map +0 -1
  445. package/dist/lib/session/discover.js +0 -1315
  446. package/dist/lib/session/discover.js.map +0 -1
  447. package/dist/lib/session/parse.d.ts +0 -34
  448. package/dist/lib/session/parse.d.ts.map +0 -1
  449. package/dist/lib/session/parse.js +0 -663
  450. package/dist/lib/session/parse.js.map +0 -1
  451. package/dist/lib/session/prompt.d.ts +0 -13
  452. package/dist/lib/session/prompt.d.ts.map +0 -1
  453. package/dist/lib/session/prompt.js +0 -79
  454. package/dist/lib/session/prompt.js.map +0 -1
  455. package/dist/lib/session/prompt.test.d.ts +0 -2
  456. package/dist/lib/session/prompt.test.d.ts.map +0 -1
  457. package/dist/lib/session/prompt.test.js +0 -57
  458. package/dist/lib/session/prompt.test.js.map +0 -1
  459. package/dist/lib/session/render.d.ts +0 -103
  460. package/dist/lib/session/render.d.ts.map +0 -1
  461. package/dist/lib/session/render.js +0 -798
  462. package/dist/lib/session/render.js.map +0 -1
  463. package/dist/lib/session/team-filter.d.ts +0 -35
  464. package/dist/lib/session/team-filter.d.ts.map +0 -1
  465. package/dist/lib/session/team-filter.js +0 -75
  466. package/dist/lib/session/team-filter.js.map +0 -1
  467. package/dist/lib/session/team-filter.test.d.ts +0 -2
  468. package/dist/lib/session/team-filter.test.d.ts.map +0 -1
  469. package/dist/lib/session/team-filter.test.js +0 -157
  470. package/dist/lib/session/team-filter.test.js.map +0 -1
  471. package/dist/lib/session/types.d.ts +0 -84
  472. package/dist/lib/session/types.d.ts.map +0 -1
  473. package/dist/lib/session/types.js +0 -11
  474. package/dist/lib/session/types.js.map +0 -1
  475. package/dist/lib/shims.d.ts +0 -272
  476. package/dist/lib/shims.d.ts.map +0 -1
  477. package/dist/lib/shims.js +0 -1322
  478. package/dist/lib/shims.js.map +0 -1
  479. package/dist/lib/skills.d.ts +0 -142
  480. package/dist/lib/skills.d.ts.map +0 -1
  481. package/dist/lib/skills.js +0 -791
  482. package/dist/lib/skills.js.map +0 -1
  483. package/dist/lib/state.d.ts +0 -87
  484. package/dist/lib/state.d.ts.map +0 -1
  485. package/dist/lib/state.js +0 -333
  486. package/dist/lib/state.js.map +0 -1
  487. package/dist/lib/subagents.d.ts +0 -84
  488. package/dist/lib/subagents.d.ts.map +0 -1
  489. package/dist/lib/subagents.js +0 -410
  490. package/dist/lib/subagents.js.map +0 -1
  491. package/dist/lib/teams/__tests__/oracle.test.d.ts +0 -2
  492. package/dist/lib/teams/__tests__/oracle.test.d.ts.map +0 -1
  493. package/dist/lib/teams/__tests__/oracle.test.js +0 -89
  494. package/dist/lib/teams/__tests__/oracle.test.js.map +0 -1
  495. package/dist/lib/teams/__tests__/supervisor.test.d.ts +0 -2
  496. package/dist/lib/teams/__tests__/supervisor.test.d.ts.map +0 -1
  497. package/dist/lib/teams/__tests__/supervisor.test.js +0 -179
  498. package/dist/lib/teams/__tests__/supervisor.test.js.map +0 -1
  499. package/dist/lib/teams/agents.d.ts +0 -247
  500. package/dist/lib/teams/agents.d.ts.map +0 -1
  501. package/dist/lib/teams/agents.js +0 -1244
  502. package/dist/lib/teams/agents.js.map +0 -1
  503. package/dist/lib/teams/api.d.ts +0 -91
  504. package/dist/lib/teams/api.d.ts.map +0 -1
  505. package/dist/lib/teams/api.js +0 -239
  506. package/dist/lib/teams/api.js.map +0 -1
  507. package/dist/lib/teams/cloud.d.ts +0 -11
  508. package/dist/lib/teams/cloud.d.ts.map +0 -1
  509. package/dist/lib/teams/cloud.js +0 -169
  510. package/dist/lib/teams/cloud.js.map +0 -1
  511. package/dist/lib/teams/debug.d.ts +0 -8
  512. package/dist/lib/teams/debug.d.ts.map +0 -1
  513. package/dist/lib/teams/debug.js +0 -12
  514. package/dist/lib/teams/debug.js.map +0 -1
  515. package/dist/lib/teams/file_ops.d.ts +0 -13
  516. package/dist/lib/teams/file_ops.d.ts.map +0 -1
  517. package/dist/lib/teams/file_ops.js +0 -66
  518. package/dist/lib/teams/file_ops.js.map +0 -1
  519. package/dist/lib/teams/index.d.ts +0 -16
  520. package/dist/lib/teams/index.d.ts.map +0 -1
  521. package/dist/lib/teams/index.js +0 -15
  522. package/dist/lib/teams/index.js.map +0 -1
  523. package/dist/lib/teams/oracle.d.ts +0 -20
  524. package/dist/lib/teams/oracle.d.ts.map +0 -1
  525. package/dist/lib/teams/oracle.js +0 -59
  526. package/dist/lib/teams/oracle.js.map +0 -1
  527. package/dist/lib/teams/parsers.d.ts +0 -9
  528. package/dist/lib/teams/parsers.d.ts.map +0 -1
  529. package/dist/lib/teams/parsers.js +0 -837
  530. package/dist/lib/teams/parsers.js.map +0 -1
  531. package/dist/lib/teams/persistence.d.ts +0 -43
  532. package/dist/lib/teams/persistence.d.ts.map +0 -1
  533. package/dist/lib/teams/persistence.js +0 -299
  534. package/dist/lib/teams/persistence.js.map +0 -1
  535. package/dist/lib/teams/ralph.d.ts +0 -8
  536. package/dist/lib/teams/ralph.d.ts.map +0 -1
  537. package/dist/lib/teams/ralph.js +0 -59
  538. package/dist/lib/teams/ralph.js.map +0 -1
  539. package/dist/lib/teams/registry.d.ts +0 -18
  540. package/dist/lib/teams/registry.d.ts.map +0 -1
  541. package/dist/lib/teams/registry.js +0 -68
  542. package/dist/lib/teams/registry.js.map +0 -1
  543. package/dist/lib/teams/summarizer.d.ts +0 -73
  544. package/dist/lib/teams/summarizer.d.ts.map +0 -1
  545. package/dist/lib/teams/summarizer.js +0 -780
  546. package/dist/lib/teams/summarizer.js.map +0 -1
  547. package/dist/lib/teams/supervisor.d.ts +0 -49
  548. package/dist/lib/teams/supervisor.d.ts.map +0 -1
  549. package/dist/lib/teams/supervisor.js +0 -74
  550. package/dist/lib/teams/supervisor.js.map +0 -1
  551. package/dist/lib/template.d.ts +0 -27
  552. package/dist/lib/template.d.ts.map +0 -1
  553. package/dist/lib/template.js +0 -60
  554. package/dist/lib/template.js.map +0 -1
  555. package/dist/lib/types.d.ts +0 -331
  556. package/dist/lib/types.d.ts.map +0 -1
  557. package/dist/lib/types.js +0 -29
  558. package/dist/lib/types.js.map +0 -1
  559. package/dist/lib/usage.d.ts +0 -105
  560. package/dist/lib/usage.d.ts.map +0 -1
  561. package/dist/lib/usage.js +0 -686
  562. package/dist/lib/usage.js.map +0 -1
  563. package/dist/lib/versions.d.ts +0 -253
  564. package/dist/lib/versions.d.ts.map +0 -1
  565. package/dist/lib/versions.js +0 -1796
  566. package/dist/lib/versions.js.map +0 -1
  567. package/scripts/rebuild-sqlite.sh +0 -46
@@ -1,1796 +0,0 @@
1
- /**
2
- * Version management module for agents-cli.
3
- *
4
- * Handles installing, removing, listing, and switching between agent CLI versions.
5
- * Each version is installed into an isolated directory under ~/.agents/versions/{agent}/{version}/
6
- * with its own HOME directory for config isolation. Resources (commands, skills, hooks, memory,
7
- * MCP servers, permissions, subagents, plugins) from ~/.agents/ are synced into version homes
8
- * via copies or conversions (not symlinks).
9
- *
10
- * Key responsibilities:
11
- * - Version lifecycle: install, remove, list, resolve (project-level or global default)
12
- * - Resource discovery: scan ~/.agents/ for available resources across all types
13
- * - Resource sync: copy/convert resources into a version's isolated config directory
14
- * - Diff and reconciliation: detect new/unsynced resources and prompt users to sync them
15
- * - Agent/version target resolution: parse agent@version specs from CLI flags
16
- */
17
- import * as fs from 'fs';
18
- import * as path from 'path';
19
- import * as os from 'os';
20
- import * as yaml from 'yaml';
21
- import { exec } from 'child_process';
22
- import { promisify } from 'util';
23
- import chalk from 'chalk';
24
- import * as TOML from 'smol-toml';
25
- import { checkbox, select } from '@inquirer/prompts';
26
- import { getVersionsDir, ensureAgentsDir, readMeta, writeMeta, getCommandsDir, getSkillsDir, getHooksDir, getMemoryDir, clearVersionResources, recordVersionResources, getProjectAgentsDir, getPromptcutsPath } from './state.js';
27
- import { AGENTS, getAccountEmail, MCP_CAPABLE_AGENTS, COMMANDS_CAPABLE_AGENTS, getMcpConfigPathForHome, parseMcpConfig, resolveAgentName, formatAgentError, CODEX_HOOKS_MIN_VERSION } from './agents.js';
28
- import { applyPermissionsToVersion as applyPermsToVersion, PERMISSIONS_CAPABLE_AGENTS, discoverPermissionGroups, buildPermissionsFromGroups, CODEX_RULES_FILENAME, getActivePermissionSetName, readPermissionSetRecipe, PERMISSION_SET_ENV_VAR } from './permissions.js';
29
- import { installMcpServers } from './mcp.js';
30
- import { markdownToToml } from './convert.js';
31
- import { createVersionedAlias, removeVersionedAlias, getConfigSymlinkVersion, ensureClaudeInsideSymlink } from './shims.js';
32
- import { listInstalledSubagents, transformSubagentForClaude, syncSubagentToOpenclaw, SUBAGENT_CAPABLE_AGENTS } from './subagents.js';
33
- import { registerHooksToSettings } from './hooks.js';
34
- import { discoverPlugins, syncPluginToVersion, isPluginSynced, pluginSupportsAgent, cleanOrphanedPluginSkills } from './plugins.js';
35
- import { compileMemoryForAgent } from './memory-compile.js';
36
- import { PLUGINS_CAPABLE_AGENTS } from './agents.js';
37
- /** Promisified exec for running shell commands. */
38
- const execAsync = promisify(exec);
39
- /**
40
- * Get all available resources from ~/.agents/.
41
- */
42
- export function getAvailableResources(cwd = process.cwd()) {
43
- const result = {
44
- commands: [],
45
- skills: [],
46
- hooks: [],
47
- memory: [],
48
- mcp: [],
49
- permissions: [],
50
- subagents: [],
51
- plugins: [],
52
- promptcuts: false,
53
- };
54
- const projectAgentsDir = getProjectAgentsDir(cwd);
55
- const userBase = path.dirname(getCommandsDir());
56
- const resourceBases = [];
57
- if (projectAgentsDir) {
58
- resourceBases.push({ scope: 'project', base: projectAgentsDir });
59
- }
60
- resourceBases.push({ scope: 'user', base: userBase });
61
- // Commands (*.md files)
62
- const commandNames = new Set();
63
- for (const { base } of resourceBases) {
64
- const commandsDir = path.join(base, 'commands');
65
- if (!fs.existsSync(commandsDir))
66
- continue;
67
- const names = fs.readdirSync(commandsDir)
68
- .filter(f => f.endsWith('.md'))
69
- .map(f => f.replace(/\.md$/, ''));
70
- for (const name of names) {
71
- commandNames.add(name);
72
- }
73
- }
74
- result.commands = Array.from(commandNames);
75
- // Skills (directories, excluding hidden)
76
- const skillNames = new Set();
77
- for (const { base } of resourceBases) {
78
- const skillsDir = path.join(base, 'skills');
79
- if (!fs.existsSync(skillsDir))
80
- continue;
81
- const names = fs.readdirSync(skillsDir, { withFileTypes: true })
82
- .filter(d => d.isDirectory() && !d.name.startsWith('.'))
83
- .map(d => d.name);
84
- for (const name of names) {
85
- skillNames.add(name);
86
- }
87
- }
88
- result.skills = Array.from(skillNames);
89
- // Hooks (files)
90
- const hookNames = new Set();
91
- for (const { base } of resourceBases) {
92
- const hooksDir = path.join(base, 'hooks');
93
- if (!fs.existsSync(hooksDir))
94
- continue;
95
- const names = fs.readdirSync(hooksDir).filter(f => !f.startsWith('.'));
96
- for (const name of names) {
97
- hookNames.add(name);
98
- }
99
- }
100
- result.hooks = Array.from(hookNames);
101
- // Memory (*.md files, excluding symlinks)
102
- const memoryNames = new Set();
103
- for (const { base } of resourceBases) {
104
- const memoryDir = path.join(base, 'memory');
105
- if (!fs.existsSync(memoryDir))
106
- continue;
107
- const names = fs.readdirSync(memoryDir)
108
- .filter(f => {
109
- if (!f.endsWith('.md'))
110
- return false;
111
- const stat = fs.lstatSync(path.join(memoryDir, f));
112
- return !stat.isSymbolicLink();
113
- })
114
- .map(f => f.replace(/\.md$/, ''));
115
- for (const name of names) {
116
- memoryNames.add(name);
117
- }
118
- }
119
- result.memory = Array.from(memoryNames);
120
- // MCP servers (*.yaml files)
121
- const mcpNames = new Set();
122
- for (const { base } of resourceBases) {
123
- const mcpDir = path.join(base, 'mcp');
124
- if (!fs.existsSync(mcpDir))
125
- continue;
126
- const names = fs.readdirSync(mcpDir)
127
- .filter(f => f.endsWith('.yaml') || f.endsWith('.yml'))
128
- .map(f => f.replace(/\.(yaml|yml)$/, ''));
129
- for (const name of names) {
130
- mcpNames.add(name);
131
- }
132
- }
133
- result.mcp = Array.from(mcpNames);
134
- // Permission groups (from permissions/groups/*.yaml)
135
- const permissionNames = new Set();
136
- for (const { base } of resourceBases) {
137
- const permsGroupsDir = path.join(base, 'permissions', 'groups');
138
- if (!fs.existsSync(permsGroupsDir))
139
- continue;
140
- const names = fs.readdirSync(permsGroupsDir)
141
- .filter(f => f.endsWith('.yaml') || f.endsWith('.yml'))
142
- .map(f => f.replace(/\.(yaml|yml)$/, ''));
143
- for (const name of names) {
144
- permissionNames.add(name);
145
- }
146
- }
147
- result.permissions = Array.from(permissionNames);
148
- // Subagents (directories with AGENT.md)
149
- const subagentNames = new Set();
150
- for (const { base } of resourceBases) {
151
- const subagentsDir = path.join(base, 'subagents');
152
- if (!fs.existsSync(subagentsDir))
153
- continue;
154
- const names = fs.readdirSync(subagentsDir, { withFileTypes: true })
155
- .filter(d => d.isDirectory() && fs.existsSync(path.join(subagentsDir, d.name, 'AGENT.md')))
156
- .map(d => d.name);
157
- for (const name of names) {
158
- subagentNames.add(name);
159
- }
160
- }
161
- result.subagents = Array.from(subagentNames);
162
- // Plugins (directories with .claude-plugin/plugin.json)
163
- const allPlugins = discoverPlugins();
164
- result.plugins = allPlugins.map(p => p.name);
165
- // Promptcuts — single file at ~/.agents/promptcuts.yaml, not per-agent.
166
- // Project-scoped .agents/promptcuts.yaml is intentionally not supported
167
- // (user-global shortcuts only — they follow the user, not the repo).
168
- result.promptcuts = fs.existsSync(getPromptcutsPath());
169
- return result;
170
- }
171
- /**
172
- * Recursively compare two directories: every file in src must exist in dest with identical content.
173
- */
174
- function skillDirsMatch(src, dest) {
175
- const entries = fs.readdirSync(src, { withFileTypes: true });
176
- for (const entry of entries) {
177
- const srcPath = path.join(src, entry.name);
178
- const destPath = path.join(dest, entry.name);
179
- if (entry.isDirectory()) {
180
- if (!fs.existsSync(destPath))
181
- return false;
182
- if (!skillDirsMatch(srcPath, destPath))
183
- return false;
184
- }
185
- else {
186
- if (!fs.existsSync(destPath))
187
- return false;
188
- const srcContent = fs.readFileSync(srcPath, 'utf-8');
189
- const destContent = fs.readFileSync(destPath, 'utf-8');
190
- if (srcContent !== destContent)
191
- return false;
192
- }
193
- }
194
- return true;
195
- }
196
- /**
197
- * Get what's ACTUALLY synced to a version by inspecting the version home.
198
- * This is the source of truth - not the tracking in agents.yaml.
199
- */
200
- export function getActuallySyncedResources(agent, version, options = {}) {
201
- const agentConfig = AGENTS[agent];
202
- const versionHome = path.join(getVersionsDir(), agent, version, 'home');
203
- const configDir = path.join(versionHome, `.${agent}`);
204
- const projectAgentsDir = getProjectAgentsDir(options.cwd || process.cwd());
205
- const result = {
206
- commands: [],
207
- skills: [],
208
- hooks: [],
209
- memory: [],
210
- mcp: [],
211
- permissions: [],
212
- subagents: [],
213
- plugins: [],
214
- promptcuts: false,
215
- };
216
- // Commands - check what files exist in version home
217
- const commandsDir = path.join(configDir, agentConfig.commandsSubdir);
218
- if (fs.existsSync(commandsDir)) {
219
- const ext = agentConfig.format === 'toml' ? '.toml' : '.md';
220
- result.commands = fs.readdirSync(commandsDir)
221
- .filter(f => f.endsWith(ext))
222
- .map(f => f.replace(new RegExp(`\\${ext}$`), ''));
223
- }
224
- // Skills - check what directories exist AND content matches central source
225
- const skillsDir = path.join(configDir, 'skills');
226
- const centralSkillsDir = getSkillsDir();
227
- const projectSkillsDir = projectAgentsDir ? path.join(projectAgentsDir, 'skills') : null;
228
- if (fs.existsSync(skillsDir)) {
229
- const installedSkills = fs.readdirSync(skillsDir, { withFileTypes: true })
230
- .filter(d => d.isDirectory() && !d.name.startsWith('.'))
231
- .map(d => d.name);
232
- for (const skill of installedSkills) {
233
- const versionSkillDir = path.join(skillsDir, skill);
234
- const projectSourceDir = projectSkillsDir ? path.join(projectSkillsDir, skill) : null;
235
- const centralSkillDir = path.join(centralSkillsDir, skill);
236
- const hasProjectSource = projectSourceDir ? fs.existsSync(projectSourceDir) : false;
237
- const hasUserSource = fs.existsSync(centralSkillDir);
238
- if (!hasProjectSource && !hasUserSource) {
239
- result.skills.push(skill);
240
- continue;
241
- }
242
- const sourceDir = hasProjectSource ? projectSourceDir : centralSkillDir;
243
- const allMatch = skillDirsMatch(sourceDir, versionSkillDir);
244
- if (allMatch) {
245
- result.skills.push(skill);
246
- }
247
- }
248
- }
249
- // Hooks - check what files exist AND content matches central source
250
- const hooksDir = path.join(configDir, 'hooks');
251
- const centralHooksDir = getHooksDir();
252
- const projectHooksDir = projectAgentsDir ? path.join(projectAgentsDir, 'hooks') : null;
253
- if (fs.existsSync(hooksDir)) {
254
- const installedHooks = fs.readdirSync(hooksDir).filter(f => !f.startsWith('.'));
255
- for (const hook of installedHooks) {
256
- const projectFile = projectHooksDir ? path.join(projectHooksDir, hook) : null;
257
- const centralFile = path.join(centralHooksDir, hook);
258
- const versionFile = path.join(hooksDir, hook);
259
- const hasProject = projectFile ? fs.existsSync(projectFile) : false;
260
- const hasCentral = fs.existsSync(centralFile);
261
- const sourceFile = hasProject ? projectFile : centralFile;
262
- if (!hasProject && !hasCentral) {
263
- result.hooks.push(hook);
264
- continue;
265
- }
266
- try {
267
- const centralContent = fs.readFileSync(sourceFile, 'utf-8');
268
- const versionContent = fs.readFileSync(versionFile, 'utf-8');
269
- if (centralContent === versionContent) {
270
- result.hooks.push(hook);
271
- }
272
- }
273
- catch {
274
- // If read fails, consider not synced
275
- }
276
- }
277
- }
278
- // Memory - check which memory files are actually in sync (content matches)
279
- const memoryDir = getMemoryDir();
280
- const projectMemoryDir = projectAgentsDir ? path.join(projectAgentsDir, 'memory') : null;
281
- const memoryFiles = new Set();
282
- if (fs.existsSync(memoryDir)) {
283
- fs.readdirSync(memoryDir).filter(f => f.endsWith('.md')).forEach(f => memoryFiles.add(f));
284
- }
285
- if (projectMemoryDir && fs.existsSync(projectMemoryDir)) {
286
- fs.readdirSync(projectMemoryDir).filter(f => f.endsWith('.md')).forEach(f => memoryFiles.add(f));
287
- }
288
- for (const file of memoryFiles) {
289
- const memName = file.replace(/\.md$/, '');
290
- const targetName = file === 'AGENTS.md' ? agentConfig.instructionsFile : file;
291
- const versionFile = path.join(configDir, targetName);
292
- if (!fs.existsSync(versionFile))
293
- continue;
294
- const projectFile = projectMemoryDir ? path.join(projectMemoryDir, file) : null;
295
- const centralFile = path.join(memoryDir, file);
296
- const hasProject = projectFile ? fs.existsSync(projectFile) : false;
297
- const hasCentral = fs.existsSync(centralFile);
298
- const sourceFile = hasProject ? projectFile : centralFile;
299
- if (!hasProject && !hasCentral) {
300
- result.memory.push(memName);
301
- continue;
302
- }
303
- try {
304
- const centralContent = fs.readFileSync(sourceFile, 'utf-8');
305
- const versionContent = fs.readFileSync(versionFile, 'utf-8');
306
- if (centralContent === versionContent) {
307
- result.memory.push(memName);
308
- }
309
- }
310
- catch {
311
- // Ignore
312
- }
313
- }
314
- // MCP - use canonical config path + parser per agent
315
- if (MCP_CAPABLE_AGENTS.includes(agent)) {
316
- const mcpConfigPath = getMcpConfigPathForHome(agent, versionHome);
317
- if (fs.existsSync(mcpConfigPath)) {
318
- try {
319
- const servers = parseMcpConfig(agent, mcpConfigPath);
320
- result.mcp = Object.keys(servers);
321
- }
322
- catch {
323
- // Ignore parse errors
324
- }
325
- }
326
- }
327
- // Permissions - check agent-specific config files
328
- const settingsPath = path.join(configDir, 'settings.json');
329
- if (PERMISSIONS_CAPABLE_AGENTS.includes(agent)) {
330
- if (agent === 'claude' && fs.existsSync(settingsPath)) {
331
- // Claude: check settings.json permissions.allow and deny
332
- try {
333
- const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
334
- const allowRules = settings.permissions?.allow || [];
335
- const denyRules = settings.permissions?.deny || [];
336
- if (allowRules.length > 0 || denyRules.length > 0) {
337
- const permGroups = discoverPermissionGroups();
338
- const appliedGroups = [];
339
- for (const group of permGroups) {
340
- const groupSet = buildPermissionsFromGroups([group.name]);
341
- // Empty groups (like header files) are considered synced if ANY permissions are applied
342
- if (groupSet.allow.length === 0 && (!groupSet.deny || groupSet.deny.length === 0)) {
343
- appliedGroups.push(group.name);
344
- continue;
345
- }
346
- const hasAllowRule = groupSet.allow.some(rule => allowRules.includes(rule));
347
- const hasDenyRule = groupSet.deny?.some(rule => denyRules.includes(rule)) || false;
348
- if (hasAllowRule || hasDenyRule) {
349
- appliedGroups.push(group.name);
350
- }
351
- }
352
- result.permissions = appliedGroups;
353
- }
354
- }
355
- catch {
356
- // Ignore parse errors
357
- }
358
- }
359
- else if (agent === 'codex') {
360
- // Codex: config.toml for approval_policy/sandbox_mode, .rules for deny
361
- const codexConfigPath = path.join(configDir, 'config.toml');
362
- const codexRulesPath = path.join(configDir, 'rules', CODEX_RULES_FILENAME);
363
- const hasConfig = fs.existsSync(codexConfigPath);
364
- const hasRules = fs.existsSync(codexRulesPath);
365
- if (hasConfig || hasRules) {
366
- try {
367
- // Codex format is lossy — all groups merge into a few keys.
368
- // If any permission artifacts exist, all groups were applied together.
369
- let hasPermKeys = false;
370
- if (hasConfig) {
371
- const content = fs.readFileSync(codexConfigPath, 'utf-8');
372
- const config = TOML.parse(content);
373
- hasPermKeys = !!(config.approval_policy || config.sandbox_mode || config.sandbox_workspace_write);
374
- }
375
- if (hasPermKeys || hasRules) {
376
- result.permissions = discoverPermissionGroups().map(g => g.name);
377
- }
378
- }
379
- catch {
380
- // Ignore parse errors
381
- }
382
- }
383
- }
384
- else if (agent === 'opencode') {
385
- // OpenCode: opencode.jsonc for permission.bash
386
- const opencodeConfigPath = path.join(configDir, 'opencode.jsonc');
387
- if (fs.existsSync(opencodeConfigPath)) {
388
- try {
389
- const content = fs.readFileSync(opencodeConfigPath, 'utf-8');
390
- const stripped = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, '');
391
- const config = JSON.parse(stripped);
392
- if (config.permission && Object.keys(config.permission.bash || {}).length > 0) {
393
- result.permissions = discoverPermissionGroups().map(g => g.name);
394
- }
395
- }
396
- catch {
397
- // Ignore parse errors
398
- }
399
- }
400
- }
401
- }
402
- // Subagents - check agent-specific locations
403
- if (SUBAGENT_CAPABLE_AGENTS.includes(agent)) {
404
- if (agent === 'claude') {
405
- const agentsDir = path.join(configDir, 'agents');
406
- if (fs.existsSync(agentsDir)) {
407
- result.subagents = fs.readdirSync(agentsDir)
408
- .filter(f => f.endsWith('.md'))
409
- .map(f => f.replace('.md', ''));
410
- }
411
- }
412
- else if (agent === 'openclaw') {
413
- // OpenClaw: directories with AGENTS.md
414
- const openclawDir = path.join(versionHome, '.openclaw');
415
- if (fs.existsSync(openclawDir)) {
416
- result.subagents = fs.readdirSync(openclawDir, { withFileTypes: true })
417
- .filter(d => d.isDirectory() && fs.existsSync(path.join(openclawDir, d.name, 'AGENTS.md')))
418
- .map(d => d.name);
419
- }
420
- }
421
- }
422
- // Plugins - check which discovered plugins have their skills in the version
423
- if (PLUGINS_CAPABLE_AGENTS.includes(agent)) {
424
- const allPlugins = discoverPlugins();
425
- for (const plugin of allPlugins) {
426
- if (isPluginSynced(plugin, agent, versionHome)) {
427
- result.plugins.push(plugin.name);
428
- }
429
- }
430
- }
431
- return result;
432
- }
433
- /**
434
- * Compare available resources with what's ACTUALLY synced to version home.
435
- * Returns only NEW resources that haven't been synced yet.
436
- * Source of truth: the actual files/config, NOT agents.yaml tracking.
437
- */
438
- export function getNewResources(available, actuallySynced) {
439
- return {
440
- commands: available.commands.filter(c => !actuallySynced.commands.includes(c)),
441
- skills: available.skills.filter(s => !actuallySynced.skills.includes(s)),
442
- hooks: available.hooks.filter(h => !actuallySynced.hooks.includes(h)),
443
- memory: available.memory.filter(m => !actuallySynced.memory.includes(m)),
444
- mcp: available.mcp.filter(m => !actuallySynced.mcp.includes(m)),
445
- permissions: available.permissions.filter(p => !actuallySynced.permissions.includes(p)),
446
- subagents: available.subagents.filter(s => !actuallySynced.subagents.includes(s)),
447
- plugins: available.plugins.filter(p => !actuallySynced.plugins.includes(p)),
448
- // Promptcuts aren't version-scoped — the hook reads ~/.agents/promptcuts.yaml
449
- // directly, so there is never a "new" per-version state to reconcile.
450
- promptcuts: false,
451
- };
452
- }
453
- /**
454
- * Check if there are any new resources to sync.
455
- */
456
- export function hasNewResources(diff, agent) {
457
- const commandsApply = agent ? COMMANDS_CAPABLE_AGENTS.includes(agent) : true;
458
- const hooksApply = agent ? AGENTS[agent].supportsHooks : true;
459
- const mcpApply = agent ? MCP_CAPABLE_AGENTS.includes(agent) : true;
460
- const permsApply = agent ? PERMISSIONS_CAPABLE_AGENTS.includes(agent) : true;
461
- const subagentsApply = agent ? SUBAGENT_CAPABLE_AGENTS.includes(agent) : true;
462
- const pluginsApply = agent ? PLUGINS_CAPABLE_AGENTS.includes(agent) : true;
463
- return ((diff.commands.length > 0 && commandsApply) ||
464
- diff.skills.length > 0 ||
465
- (diff.hooks.length > 0 && hooksApply) ||
466
- (diff.memory.length > 0 && commandsApply) ||
467
- (diff.mcp.length > 0 && mcpApply) ||
468
- (diff.permissions.length > 0 && permsApply) ||
469
- (diff.subagents.length > 0 && subagentsApply) ||
470
- (diff.plugins.length > 0 && pluginsApply));
471
- }
472
- /**
473
- * Build a summary string of new resources.
474
- * E.g., "2 commands, 5 permission groups"
475
- */
476
- function buildNewResourcesSummary(newResources, agent) {
477
- const agentConfig = AGENTS[agent];
478
- const parts = [];
479
- if (newResources.commands.length > 0 && COMMANDS_CAPABLE_AGENTS.includes(agent)) {
480
- parts.push(`${newResources.commands.length} command${newResources.commands.length === 1 ? '' : 's'}`);
481
- }
482
- if (newResources.skills.length > 0) {
483
- parts.push(`${newResources.skills.length} skill${newResources.skills.length === 1 ? '' : 's'}`);
484
- }
485
- if (newResources.hooks.length > 0 && agentConfig.supportsHooks) {
486
- parts.push(`${newResources.hooks.length} hook${newResources.hooks.length === 1 ? '' : 's'}`);
487
- }
488
- if (newResources.memory.length > 0 && COMMANDS_CAPABLE_AGENTS.includes(agent)) {
489
- parts.push(`${newResources.memory.length} rule file${newResources.memory.length === 1 ? '' : 's'}`);
490
- }
491
- if (newResources.mcp.length > 0 && MCP_CAPABLE_AGENTS.includes(agent)) {
492
- parts.push(`${newResources.mcp.length} MCP${newResources.mcp.length === 1 ? '' : 's'}`);
493
- }
494
- if (newResources.permissions.length > 0 && PERMISSIONS_CAPABLE_AGENTS.includes(agent)) {
495
- parts.push(`${newResources.permissions.length} permission group${newResources.permissions.length === 1 ? '' : 's'}`);
496
- }
497
- if (newResources.subagents.length > 0 && SUBAGENT_CAPABLE_AGENTS.includes(agent)) {
498
- parts.push(`${newResources.subagents.length} subagent${newResources.subagents.length === 1 ? '' : 's'}`);
499
- }
500
- if (newResources.plugins.length > 0 && PLUGINS_CAPABLE_AGENTS.includes(agent)) {
501
- parts.push(`${newResources.plugins.length} plugin${newResources.plugins.length === 1 ? '' : 's'}`);
502
- }
503
- return parts.join(', ');
504
- }
505
- /**
506
- * Prompt user to select which NEW resources to sync.
507
- * Only shows resources that haven't been synced yet.
508
- */
509
- export async function promptNewResourceSelection(agent, newResources) {
510
- const agentConfig = AGENTS[agent];
511
- const selection = {};
512
- // Get permission group info for display
513
- const permissionGroups = discoverPermissionGroups();
514
- const newPermissionGroups = permissionGroups.filter(g => newResources.permissions.includes(g.name));
515
- const totalNewPermissionRules = newPermissionGroups.reduce((sum, g) => sum + g.ruleCount, 0);
516
- // Build the summary
517
- const summary = buildNewResourcesSummary(newResources, agent);
518
- console.log(chalk.cyan(`\nNew resources available:`));
519
- console.log(chalk.gray(` ${summary}`));
520
- // Ask how to handle new resources
521
- const action = await select({
522
- message: 'Sync new resources?',
523
- choices: [
524
- { value: 'all', name: 'Yes, sync all new' },
525
- { value: 'specific', name: 'Select specific items' },
526
- { value: 'skip', name: 'Skip' },
527
- ],
528
- default: 'all',
529
- });
530
- if (action === 'skip') {
531
- return null;
532
- }
533
- if (action === 'all') {
534
- // Sync all new resources
535
- if (newResources.commands.length > 0 && COMMANDS_CAPABLE_AGENTS.includes(agent))
536
- selection.commands = newResources.commands;
537
- if (newResources.skills.length > 0)
538
- selection.skills = newResources.skills;
539
- if (newResources.hooks.length > 0 && agentConfig.supportsHooks)
540
- selection.hooks = newResources.hooks;
541
- if (newResources.memory.length > 0 && COMMANDS_CAPABLE_AGENTS.includes(agent))
542
- selection.memory = newResources.memory;
543
- if (newResources.mcp.length > 0 && MCP_CAPABLE_AGENTS.includes(agent))
544
- selection.mcp = newResources.mcp;
545
- if (newResources.permissions.length > 0 && PERMISSIONS_CAPABLE_AGENTS.includes(agent))
546
- selection.permissions = newResources.permissions;
547
- if (newResources.subagents.length > 0 && SUBAGENT_CAPABLE_AGENTS.includes(agent))
548
- selection.subagents = newResources.subagents;
549
- if (newResources.plugins.length > 0 && PLUGINS_CAPABLE_AGENTS.includes(agent))
550
- selection.plugins = newResources.plugins;
551
- return selection;
552
- }
553
- // Select specific items for each category
554
- if (newResources.commands.length > 0 && COMMANDS_CAPABLE_AGENTS.includes(agent)) {
555
- const selected = await checkbox({
556
- message: 'Select new commands to sync:',
557
- choices: newResources.commands.map(c => ({ name: c, value: c, checked: true })),
558
- });
559
- if (selected.length > 0)
560
- selection.commands = selected;
561
- }
562
- if (newResources.skills.length > 0) {
563
- const selected = await checkbox({
564
- message: 'Select new skills to sync:',
565
- choices: newResources.skills.map(s => ({ name: s, value: s, checked: true })),
566
- });
567
- if (selected.length > 0)
568
- selection.skills = selected;
569
- }
570
- if (newResources.hooks.length > 0 && agentConfig.supportsHooks) {
571
- const selected = await checkbox({
572
- message: 'Select new hooks to sync:',
573
- choices: newResources.hooks.map(h => ({ name: h, value: h, checked: true })),
574
- });
575
- if (selected.length > 0)
576
- selection.hooks = selected;
577
- }
578
- if (newResources.memory.length > 0 && COMMANDS_CAPABLE_AGENTS.includes(agent)) {
579
- const selected = await checkbox({
580
- message: 'Select new rule files to sync:',
581
- choices: newResources.memory.map(m => ({ name: m, value: m, checked: true })),
582
- });
583
- if (selected.length > 0)
584
- selection.memory = selected;
585
- }
586
- if (newResources.mcp.length > 0 && MCP_CAPABLE_AGENTS.includes(agent)) {
587
- const selected = await checkbox({
588
- message: 'Select new MCPs to sync:',
589
- choices: newResources.mcp.map(m => ({ name: m, value: m, checked: true })),
590
- });
591
- if (selected.length > 0)
592
- selection.mcp = selected;
593
- }
594
- if (newResources.permissions.length > 0 && PERMISSIONS_CAPABLE_AGENTS.includes(agent)) {
595
- const selected = await checkbox({
596
- message: 'Select new permission groups to sync:',
597
- choices: newPermissionGroups.map(g => ({
598
- name: `${g.name} (${g.ruleCount} rules)`,
599
- value: g.name,
600
- checked: true,
601
- })),
602
- });
603
- if (selected.length > 0)
604
- selection.permissions = selected;
605
- }
606
- if (newResources.subagents.length > 0 && SUBAGENT_CAPABLE_AGENTS.includes(agent)) {
607
- const selected = await checkbox({
608
- message: 'Select new subagents to sync:',
609
- choices: newResources.subagents.map(s => ({ name: s, value: s, checked: true })),
610
- });
611
- if (selected.length > 0)
612
- selection.subagents = selected;
613
- }
614
- if (newResources.plugins.length > 0 && PLUGINS_CAPABLE_AGENTS.includes(agent)) {
615
- const allPlugins = discoverPlugins();
616
- const pluginMap = new Map(allPlugins.map(p => [p.name, p]));
617
- const selected = await checkbox({
618
- message: 'Select new plugins to sync:',
619
- choices: newResources.plugins.map(name => {
620
- const plugin = pluginMap.get(name);
621
- const desc = plugin?.manifest.description;
622
- return { name: desc ? `${name} - ${desc}` : name, value: name, checked: true };
623
- }),
624
- });
625
- if (selected.length > 0)
626
- selection.plugins = selected;
627
- }
628
- return selection;
629
- }
630
- /**
631
- * Prompt user to select which resources to sync from ~/.agents/.
632
- * Returns the selection, or null if user cancels.
633
- */
634
- export async function promptResourceSelection(agent) {
635
- const available = getAvailableResources();
636
- const agentConfig = AGENTS[agent];
637
- const selection = {};
638
- // Get permission group info for display
639
- const permissionGroups = discoverPermissionGroups();
640
- const totalPermissionRules = permissionGroups.reduce((sum, g) => sum + g.ruleCount, 0);
641
- const categories = [
642
- { key: 'commands', label: 'Commands', available: COMMANDS_CAPABLE_AGENTS.includes(agent) && available.commands.length > 0, displayCount: `${available.commands.length} available` },
643
- { key: 'skills', label: 'Skills', available: available.skills.length > 0, displayCount: `${available.skills.length} available` },
644
- { key: 'hooks', label: 'Hooks', available: agentConfig.supportsHooks && available.hooks.length > 0, displayCount: `${available.hooks.length} available` },
645
- { key: 'memory', label: 'Rules', available: COMMANDS_CAPABLE_AGENTS.includes(agent) && available.memory.length > 0, displayCount: `${available.memory.length} available` },
646
- { key: 'mcp', label: 'MCPs', available: MCP_CAPABLE_AGENTS.includes(agent) && available.mcp.length > 0, displayCount: `${available.mcp.length} available` },
647
- { key: 'permissions', label: 'Permissions', available: PERMISSIONS_CAPABLE_AGENTS.includes(agent) && permissionGroups.length > 0, displayCount: `${permissionGroups.length} groups, ${totalPermissionRules} rules` },
648
- { key: 'subagents', label: 'Subagents', available: SUBAGENT_CAPABLE_AGENTS.includes(agent) && available.subagents.length > 0, displayCount: `${available.subagents.length} available` },
649
- { key: 'plugins', label: 'Plugins', available: PLUGINS_CAPABLE_AGENTS.includes(agent) && available.plugins.length > 0, displayCount: `${available.plugins.length} available` },
650
- ];
651
- const availableCategories = categories.filter(c => c.available);
652
- if (availableCategories.length === 0) {
653
- console.log(chalk.gray('No resources available in ~/.agents/'));
654
- return {};
655
- }
656
- // Step 1: Select categories (with "Select All" shortcut at the top)
657
- console.log();
658
- const SELECT_ALL_KEY = '__select_all__';
659
- const selectedCategories = await checkbox({
660
- message: 'Which resources from ~/.agents/ would you like to sync?',
661
- choices: [
662
- { name: chalk.bold('Select All (sync everything)'), value: SELECT_ALL_KEY, checked: false },
663
- ...availableCategories.map(c => ({
664
- name: `${c.label} (${c.displayCount})`,
665
- value: c.key,
666
- checked: true, // Default all checked
667
- })),
668
- ],
669
- });
670
- if (selectedCategories.length === 0) {
671
- return {};
672
- }
673
- // If "Select All" was picked, sync everything without per-category prompts
674
- if (selectedCategories.includes(SELECT_ALL_KEY)) {
675
- for (const c of availableCategories) {
676
- selection[c.key] = 'all';
677
- }
678
- return selection;
679
- }
680
- // Step 2: For each selected category, ask all/specific/skip
681
- for (const category of selectedCategories) {
682
- const categoryLabel = categories.find(c => c.key === category).label;
683
- // Special handling for permissions - show groups
684
- if (category === 'permissions') {
685
- const choice = await select({
686
- message: `${categoryLabel}:`,
687
- choices: [
688
- { name: `Select all (${permissionGroups.length} groups)`, value: 'all' },
689
- { name: 'Select specific groups', value: 'specific' },
690
- { name: 'Skip', value: 'skip' },
691
- ],
692
- default: 'all',
693
- });
694
- if (choice === 'all') {
695
- selection.permissions = 'all';
696
- }
697
- else if (choice === 'specific') {
698
- const selected = await checkbox({
699
- message: 'Select permission groups to sync:',
700
- choices: permissionGroups.map(g => ({
701
- name: `${g.name} (${g.ruleCount} rules)`,
702
- value: g.name,
703
- checked: true,
704
- })),
705
- });
706
- if (selected.length > 0) {
707
- selection.permissions = selected;
708
- }
709
- }
710
- }
711
- else {
712
- // Standard handling for other categories
713
- const items = available[category];
714
- const choice = await select({
715
- message: `${categoryLabel}:`,
716
- choices: [
717
- { name: `Select all (${items.length})`, value: 'all' },
718
- { name: 'Select specific', value: 'specific' },
719
- { name: 'Skip', value: 'skip' },
720
- ],
721
- default: 'all',
722
- });
723
- if (choice === 'all') {
724
- selection[category] = 'all';
725
- }
726
- else if (choice === 'specific') {
727
- const selected = await checkbox({
728
- message: `Select ${categoryLabel.toLowerCase()} to sync:`,
729
- choices: items.map(item => ({
730
- name: item,
731
- value: item,
732
- checked: true,
733
- })),
734
- });
735
- if (selected.length > 0) {
736
- selection[category] = selected;
737
- }
738
- }
739
- }
740
- // 'skip' means we don't set anything for this category
741
- }
742
- return selection;
743
- }
744
- /**
745
- * Parse agent@version syntax.
746
- * Examples:
747
- * "claude@1.5.0" -> { agent: "claude", version: "1.5.0" }
748
- * "claude" -> { agent: "claude", version: "latest" }
749
- * "codex@latest" -> { agent: "codex", version: "latest" }
750
- */
751
- export function parseAgentSpec(spec) {
752
- const parts = spec.split('@');
753
- const agentName = parts[0].toLowerCase();
754
- const version = parts[1] || 'latest';
755
- if (!AGENTS[agentName]) {
756
- return null;
757
- }
758
- return {
759
- agent: agentName,
760
- version,
761
- };
762
- }
763
- /**
764
- * Get the directory where a specific version is installed.
765
- */
766
- export function getVersionDir(agent, version) {
767
- return path.join(getVersionsDir(), agent, version);
768
- }
769
- /**
770
- * Get the binary path for a specific agent version.
771
- */
772
- export function getBinaryPath(agent, version) {
773
- const versionDir = getVersionDir(agent, version);
774
- const agentConfig = AGENTS[agent];
775
- return path.join(versionDir, 'node_modules', '.bin', agentConfig.cliCommand);
776
- }
777
- /**
778
- * Get the isolated HOME directory for a specific agent version.
779
- * Each version has its own config isolation (like jobs sandbox).
780
- */
781
- export function getVersionHomePath(agent, version) {
782
- return path.join(getVersionDir(agent, version), 'home');
783
- }
784
- /**
785
- * Check if a specific version is installed.
786
- */
787
- export function isVersionInstalled(agent, version) {
788
- const binaryPath = getBinaryPath(agent, version);
789
- return fs.existsSync(binaryPath);
790
- }
791
- /**
792
- * Get the latest available version from npm for an agent.
793
- */
794
- export async function getLatestNpmVersion(agent) {
795
- const agentConfig = AGENTS[agent];
796
- if (!agentConfig.npmPackage)
797
- return null;
798
- try {
799
- const { stdout } = await execAsync(`npm view ${agentConfig.npmPackage} version`);
800
- return stdout.trim();
801
- }
802
- catch {
803
- return null;
804
- }
805
- }
806
- /**
807
- * Check if 'latest' version is already installed (by resolving to actual version).
808
- */
809
- export async function isLatestInstalled(agent) {
810
- const latestVersion = await getLatestNpmVersion(agent);
811
- if (!latestVersion) {
812
- return { installed: false, version: null };
813
- }
814
- return { installed: isVersionInstalled(agent, latestVersion), version: latestVersion };
815
- }
816
- /**
817
- * List all installed versions for an agent.
818
- */
819
- export function listInstalledVersions(agent) {
820
- const agentVersionsDir = path.join(getVersionsDir(), agent);
821
- if (!fs.existsSync(agentVersionsDir)) {
822
- return [];
823
- }
824
- const entries = fs.readdirSync(agentVersionsDir, { withFileTypes: true });
825
- const versions = [];
826
- for (const entry of entries) {
827
- if (entry.isDirectory()) {
828
- const binaryPath = getBinaryPath(agent, entry.name);
829
- if (fs.existsSync(binaryPath)) {
830
- versions.push(entry.name);
831
- }
832
- }
833
- }
834
- return versions.sort(compareVersions);
835
- }
836
- /**
837
- * Get the global default version for an agent.
838
- */
839
- export function getGlobalDefault(agent) {
840
- const meta = readMeta();
841
- return meta.agents?.[agent] || null;
842
- }
843
- /**
844
- * Set the global default version for an agent.
845
- */
846
- export function setGlobalDefault(agent, version) {
847
- const meta = readMeta();
848
- if (!meta.agents) {
849
- meta.agents = {};
850
- }
851
- if (version === undefined) {
852
- delete meta.agents[agent];
853
- }
854
- else {
855
- meta.agents[agent] = version;
856
- }
857
- writeMeta(meta);
858
- }
859
- /**
860
- * Install a specific version of an agent.
861
- */
862
- export async function installVersion(agent, version, onProgress) {
863
- const agentConfig = AGENTS[agent];
864
- if (!agentConfig.npmPackage) {
865
- return { success: false, installedVersion: version, error: 'Agent has no npm package' };
866
- }
867
- ensureAgentsDir();
868
- const versionDir = getVersionDir(agent, version);
869
- // Create version directory and isolated home
870
- fs.mkdirSync(versionDir, { recursive: true });
871
- fs.mkdirSync(path.join(versionDir, 'home'), { recursive: true });
872
- // Initialize package.json
873
- const packageJson = {
874
- name: `agents-${agent}-${version}`,
875
- version: '1.0.0',
876
- private: true,
877
- };
878
- fs.writeFileSync(path.join(versionDir, 'package.json'), JSON.stringify(packageJson, null, 2));
879
- // Install the package
880
- const packageSpec = version === 'latest'
881
- ? agentConfig.npmPackage
882
- : `${agentConfig.npmPackage}@${version}`;
883
- try {
884
- onProgress?.(`Installing ${packageSpec}...`);
885
- const { stdout } = await execAsync(`npm install ${packageSpec}`, { cwd: versionDir });
886
- // Determine the actual installed version
887
- let installedVersion = version;
888
- if (version === 'latest') {
889
- const pkgJsonPath = path.join(versionDir, 'node_modules', agentConfig.npmPackage.replace(/^@/, '').split('/')[0], 'package.json');
890
- // Try to read the actual version from installed package
891
- try {
892
- const installedPkgPath = path.join(versionDir, 'node_modules', agentConfig.npmPackage, 'package.json');
893
- if (fs.existsSync(installedPkgPath)) {
894
- const installedPkg = JSON.parse(fs.readFileSync(installedPkgPath, 'utf-8'));
895
- installedVersion = installedPkg.version;
896
- // Rename the directory to the actual version
897
- if (installedVersion !== 'latest') {
898
- const actualVersionDir = getVersionDir(agent, installedVersion);
899
- if (!fs.existsSync(actualVersionDir)) {
900
- fs.renameSync(versionDir, actualVersionDir);
901
- }
902
- else {
903
- // Already exists, remove the 'latest' dir
904
- fs.rmSync(versionDir, { recursive: true, force: true });
905
- }
906
- }
907
- }
908
- }
909
- catch (e) {
910
- // Failed to determine version - this shouldn't happen
911
- throw new Error(`Failed to determine installed version: ${e.message}`);
912
- }
913
- }
914
- // Create versioned alias (e.g., claude@2.0.65)
915
- createVersionedAlias(agent, installedVersion);
916
- // Claude reads its global config from CLAUDE_CONFIG_DIR/.claude.json —
917
- // i.e. inside the per-version .claude dir — while the rest of agents-cli
918
- // manages the home-level file. Symlink INSIDE to OUTSIDE so Claude and
919
- // agents-cli see the same content.
920
- if (agent === 'claude') {
921
- try {
922
- ensureClaudeInsideSymlink(installedVersion);
923
- }
924
- catch {
925
- /* non-fatal; the install itself succeeded */
926
- }
927
- }
928
- return { success: true, installedVersion };
929
- }
930
- catch (err) {
931
- // Clean up on failure
932
- if (fs.existsSync(versionDir)) {
933
- fs.rmSync(versionDir, { recursive: true, force: true });
934
- }
935
- return { success: false, installedVersion: version, error: err.message };
936
- }
937
- }
938
- /**
939
- * Remove a specific version of an agent.
940
- */
941
- export function removeVersion(agent, version) {
942
- const versionDir = getVersionDir(agent, version);
943
- if (!fs.existsSync(versionDir)) {
944
- return false;
945
- }
946
- fs.rmSync(versionDir, { recursive: true, force: true });
947
- // Remove versioned alias (e.g., claude@2.0.65)
948
- removeVersionedAlias(agent, version);
949
- // Clear resource tracking for this version
950
- clearVersionResources(agent, version);
951
- // Clear default if it was the removed version - user must explicitly pick a new one
952
- if (getGlobalDefault(agent) === version) {
953
- const meta = readMeta();
954
- if (meta.agents?.[agent]) {
955
- delete meta.agents[agent];
956
- writeMeta(meta);
957
- }
958
- const remaining = listInstalledVersions(agent);
959
- if (remaining.length > 0) {
960
- console.log(chalk.yellow(`Default version removed. Run: agents use ${agent}@<version> to set a new default`));
961
- }
962
- }
963
- // Clean up dangling config symlink if it pointed to the removed version
964
- const symlinkVersion = getConfigSymlinkVersion(agent);
965
- if (symlinkVersion === version) {
966
- const configPath = path.join(os.homedir(), `.${agent}`);
967
- try {
968
- fs.unlinkSync(configPath);
969
- }
970
- catch {
971
- // Ignore if already gone
972
- }
973
- }
974
- return true;
975
- }
976
- /**
977
- * Remove all versions of an agent.
978
- */
979
- export function removeAllVersions(agent) {
980
- const versions = listInstalledVersions(agent);
981
- let removed = 0;
982
- for (const version of versions) {
983
- if (removeVersion(agent, version)) {
984
- removed++;
985
- }
986
- }
987
- // Clean up the agent directory
988
- const agentDir = path.join(getVersionsDir(), agent);
989
- if (fs.existsSync(agentDir)) {
990
- fs.rmSync(agentDir, { recursive: true, force: true });
991
- }
992
- return removed;
993
- }
994
- /**
995
- * Get the resolved version for an agent in the current context.
996
- * Checks project manifest first, then global default.
997
- */
998
- export function resolveVersion(agent, projectPath) {
999
- // Check project manifest
1000
- if (projectPath) {
1001
- const version = getProjectVersion(agent, projectPath);
1002
- if (version) {
1003
- return version;
1004
- }
1005
- }
1006
- // Fall back to global default
1007
- return getGlobalDefault(agent);
1008
- }
1009
- /**
1010
- * Get version specified in a project-root agents.yaml (not the user ~/.agents/agents.yaml).
1011
- */
1012
- export function getProjectVersion(agent, startPath) {
1013
- const userAgentsYaml = path.join(os.homedir(), '.agents', 'agents.yaml');
1014
- let dir = path.resolve(startPath);
1015
- while (dir !== path.dirname(dir)) {
1016
- const manifestPath = path.join(dir, 'agents.yaml');
1017
- if (manifestPath !== userAgentsYaml && fs.existsSync(manifestPath)) {
1018
- try {
1019
- const content = fs.readFileSync(manifestPath, 'utf-8');
1020
- const parsed = yaml.parse(content);
1021
- const version = parsed?.agents?.[agent];
1022
- if (typeof version === 'string' && version.trim()) {
1023
- return version.trim();
1024
- }
1025
- }
1026
- catch {
1027
- // Ignore parsing errors
1028
- }
1029
- }
1030
- dir = path.dirname(dir);
1031
- }
1032
- return null;
1033
- }
1034
- /**
1035
- * Compare semver versions for sorting.
1036
- */
1037
- export function compareVersions(a, b) {
1038
- const aParts = a.split('.').map((n) => parseInt(n, 10) || 0);
1039
- const bParts = b.split('.').map((n) => parseInt(n, 10) || 0);
1040
- for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
1041
- const aVal = aParts[i] || 0;
1042
- const bVal = bParts[i] || 0;
1043
- if (aVal !== bVal) {
1044
- return aVal - bVal;
1045
- }
1046
- }
1047
- return 0;
1048
- }
1049
- /**
1050
- * Get actual version from an installed 'latest' directory.
1051
- */
1052
- export async function getInstalledVersion(agent, version) {
1053
- const binaryPath = getBinaryPath(agent, version);
1054
- if (!fs.existsSync(binaryPath)) {
1055
- return null;
1056
- }
1057
- try {
1058
- const { stdout } = await execAsync(`${binaryPath} --version`);
1059
- const match = stdout.match(/(\d+\.\d+\.\d+)/);
1060
- return match ? match[1] : version;
1061
- }
1062
- catch {
1063
- return version;
1064
- }
1065
- }
1066
- /**
1067
- * Get the diff between central resources (~/.agents/) and what's synced to a version.
1068
- * Uses filesystem state - no tracking needed.
1069
- */
1070
- export function getResourceDiff(agent, version) {
1071
- const agentConfig = AGENTS[agent];
1072
- const versionHome = getVersionHomePath(agent, version);
1073
- const agentDir = path.join(versionHome, `.${agent}`);
1074
- const diff = {
1075
- commands: { added: [], dangling: [] },
1076
- skills: { added: [], dangling: [] },
1077
- hooks: { added: [], dangling: [] },
1078
- memory: { added: [], dangling: [] },
1079
- totalAdded: 0,
1080
- totalDangling: 0,
1081
- };
1082
- // Helper to check symlink status
1083
- const getSymlinkStatus = (linkPath) => {
1084
- try {
1085
- const stat = fs.lstatSync(linkPath);
1086
- if (!stat.isSymbolicLink())
1087
- return 'none';
1088
- // Check if target exists
1089
- try {
1090
- fs.statSync(linkPath);
1091
- return 'valid';
1092
- }
1093
- catch {
1094
- return 'dangling';
1095
- }
1096
- }
1097
- catch {
1098
- return 'none';
1099
- }
1100
- };
1101
- // Commands: check directory symlink (or individual files for Gemini)
1102
- const centralCommands = getCommandsDir();
1103
- const commandsTarget = path.join(agentDir, agentConfig.commandsSubdir);
1104
- if (agentConfig.format === 'toml') {
1105
- // Gemini: compare .md files in central vs .toml files in version
1106
- if (fs.existsSync(centralCommands)) {
1107
- const centralFiles = fs.readdirSync(centralCommands).filter(f => f.endsWith('.md'));
1108
- const versionFiles = fs.existsSync(commandsTarget)
1109
- ? fs.readdirSync(commandsTarget).filter(f => f.endsWith('.toml'))
1110
- : [];
1111
- const versionNames = new Set(versionFiles.map(f => f.replace('.toml', '')));
1112
- for (const file of centralFiles) {
1113
- const name = file.replace('.md', '');
1114
- if (!versionNames.has(name)) {
1115
- diff.commands.added.push(file);
1116
- }
1117
- }
1118
- // Check for dangling (toml exists but no md source)
1119
- const centralNames = new Set(centralFiles.map(f => f.replace('.md', '')));
1120
- for (const file of versionFiles) {
1121
- const name = file.replace('.toml', '');
1122
- if (!centralNames.has(name)) {
1123
- diff.commands.dangling.push(file);
1124
- }
1125
- }
1126
- }
1127
- }
1128
- else {
1129
- // Other agents: check directory symlink
1130
- const status = getSymlinkStatus(commandsTarget);
1131
- if (status === 'none' && fs.existsSync(centralCommands)) {
1132
- const files = fs.readdirSync(centralCommands).filter(f => f.endsWith('.md'));
1133
- diff.commands.added = files;
1134
- }
1135
- else if (status === 'dangling') {
1136
- diff.commands.dangling = ['commands/'];
1137
- }
1138
- }
1139
- // Skills: check directory symlink (skip if agent natively reads ~/.agents/skills/)
1140
- if (!agentConfig.nativeAgentsSkillsDir) {
1141
- const centralSkills = getSkillsDir();
1142
- const skillsTarget = path.join(agentDir, 'skills');
1143
- const skillsStatus = getSymlinkStatus(skillsTarget);
1144
- if (skillsStatus === 'none' && fs.existsSync(centralSkills)) {
1145
- const dirs = fs.readdirSync(centralSkills).filter(f => {
1146
- const stat = fs.statSync(path.join(centralSkills, f));
1147
- return stat.isDirectory() && !f.startsWith('.');
1148
- });
1149
- diff.skills.added = dirs;
1150
- }
1151
- else if (skillsStatus === 'dangling') {
1152
- diff.skills.dangling = ['skills/'];
1153
- }
1154
- }
1155
- // Hooks: check directory symlink (if agent supports hooks)
1156
- if (agentConfig.supportsHooks) {
1157
- const centralHooks = getHooksDir();
1158
- const hooksTarget = path.join(agentDir, 'hooks');
1159
- const hooksStatus = getSymlinkStatus(hooksTarget);
1160
- if (hooksStatus === 'none' && fs.existsSync(centralHooks)) {
1161
- const files = fs.readdirSync(centralHooks).filter(f => !f.startsWith('.'));
1162
- diff.hooks.added = files;
1163
- }
1164
- else if (hooksStatus === 'dangling') {
1165
- diff.hooks.dangling = ['hooks/'];
1166
- }
1167
- }
1168
- // Memory: check individual file symlinks
1169
- const centralMemory = getMemoryDir();
1170
- if (fs.existsSync(centralMemory)) {
1171
- const memoryFiles = fs.readdirSync(centralMemory).filter(f => f.endsWith('.md'));
1172
- for (const file of memoryFiles) {
1173
- const targetName = file === 'AGENTS.md' ? agentConfig.instructionsFile : file;
1174
- const targetPath = path.join(agentDir, targetName);
1175
- const status = getSymlinkStatus(targetPath);
1176
- if (status === 'none') {
1177
- diff.memory.added.push(file);
1178
- }
1179
- else if (status === 'dangling') {
1180
- diff.memory.dangling.push(targetName);
1181
- }
1182
- }
1183
- }
1184
- // Calculate totals
1185
- diff.totalAdded = diff.commands.added.length + diff.skills.added.length +
1186
- diff.hooks.added.length + diff.memory.added.length;
1187
- diff.totalDangling = diff.commands.dangling.length + diff.skills.dangling.length +
1188
- diff.hooks.dangling.length + diff.memory.dangling.length;
1189
- return diff;
1190
- }
1191
- /**
1192
- * Sync central resources (~/.agents/) into a specific version's config directory.
1193
- * Copies selected resources from central storage into {versionHome}/.{agent}/.
1194
- *
1195
- * @param agent - The agent ID
1196
- * @param version - The version string
1197
- * @param selection - Optional resource selection. If not provided, syncs all resources.
1198
- *
1199
- * For Gemini: commands are converted from markdown to TOML.
1200
- */
1201
- export function syncResourcesToVersion(agent, version, selection, options = {}) {
1202
- const agentConfig = AGENTS[agent];
1203
- const versionHome = getVersionHomePath(agent, version);
1204
- const agentDir = path.join(versionHome, `.${agent}`);
1205
- fs.mkdirSync(agentDir, { recursive: true });
1206
- const result = { commands: false, skills: false, hooks: false, memory: [], permissions: false, mcp: [], subagents: [], plugins: [] };
1207
- const cwd = options.cwd || process.cwd();
1208
- const projectAgentsDir = options.projectDir || getProjectAgentsDir(cwd);
1209
- const available = getAvailableResources(cwd);
1210
- // Helper: remove a path (symlink or real) if it exists
1211
- const removePath = (p) => {
1212
- try {
1213
- const stat = fs.lstatSync(p);
1214
- if (stat.isSymbolicLink() || stat.isFile()) {
1215
- fs.unlinkSync(p);
1216
- }
1217
- else if (stat.isDirectory()) {
1218
- fs.rmSync(p, { recursive: true, force: true });
1219
- }
1220
- }
1221
- catch { /* file already removed or inaccessible */ }
1222
- };
1223
- // Helper: copy a directory recursively
1224
- const copyDir = (src, dest) => {
1225
- fs.mkdirSync(dest, { recursive: true });
1226
- const entries = fs.readdirSync(src, { withFileTypes: true });
1227
- for (const entry of entries) {
1228
- const srcPath = path.join(src, entry.name);
1229
- const destPath = path.join(dest, entry.name);
1230
- if (entry.isDirectory()) {
1231
- copyDir(srcPath, destPath);
1232
- }
1233
- else {
1234
- fs.copyFileSync(srcPath, destPath);
1235
- }
1236
- }
1237
- };
1238
- // Helper: resolve selection to list of items
1239
- const resolveSelection = (sel, available) => {
1240
- if (sel === 'all')
1241
- return available;
1242
- if (Array.isArray(sel))
1243
- return sel;
1244
- return [];
1245
- };
1246
- // Sync commands
1247
- const commandsToSync = selection
1248
- ? resolveSelection(selection.commands, available.commands)
1249
- : available.commands; // No selection = sync all
1250
- if (commandsToSync.length > 0 && COMMANDS_CAPABLE_AGENTS.includes(agent)) {
1251
- const centralCommands = getCommandsDir();
1252
- const projectCommandsDir = projectAgentsDir ? path.join(projectAgentsDir, 'commands') : null;
1253
- const commandsTarget = path.join(agentDir, agentConfig.commandsSubdir);
1254
- fs.mkdirSync(commandsTarget, { recursive: true });
1255
- const syncedCommands = [];
1256
- for (const cmd of commandsToSync) {
1257
- const projectSource = projectCommandsDir ? path.join(projectCommandsDir, `${cmd}.md`) : null;
1258
- const userSource = path.join(centralCommands, `${cmd}.md`);
1259
- const srcFile = projectSource && fs.existsSync(projectSource) ? projectSource : userSource;
1260
- if (!fs.existsSync(srcFile))
1261
- continue;
1262
- if (agentConfig.format === 'toml') {
1263
- const content = fs.readFileSync(srcFile, 'utf-8');
1264
- const tomlContent = markdownToToml(cmd, content);
1265
- fs.writeFileSync(path.join(commandsTarget, `${cmd}.toml`), tomlContent);
1266
- }
1267
- else {
1268
- fs.copyFileSync(srcFile, path.join(commandsTarget, `${cmd}.md`));
1269
- }
1270
- syncedCommands.push(cmd);
1271
- }
1272
- result.commands = syncedCommands.length > 0;
1273
- if (syncedCommands.length > 0) {
1274
- recordVersionResources(agent, version, 'commands', syncedCommands);
1275
- }
1276
- }
1277
- // Sync skills (skip if agent natively reads ~/.agents/skills/)
1278
- if (agentConfig.nativeAgentsSkillsDir) {
1279
- // Clean up stale skills symlink/dir — agent reads from ~/.agents/skills/ directly
1280
- const skillsTarget = path.join(agentDir, 'skills');
1281
- removePath(skillsTarget);
1282
- }
1283
- else {
1284
- const skillsToSync = selection
1285
- ? resolveSelection(selection.skills, available.skills)
1286
- : available.skills;
1287
- if (skillsToSync.length > 0) {
1288
- const centralSkills = getSkillsDir();
1289
- const projectSkills = projectAgentsDir ? path.join(projectAgentsDir, 'skills') : null;
1290
- const skillsTarget = path.join(agentDir, 'skills');
1291
- fs.mkdirSync(skillsTarget, { recursive: true });
1292
- const syncedSkills = [];
1293
- for (const skill of skillsToSync) {
1294
- const projectSource = projectSkills ? path.join(projectSkills, skill) : null;
1295
- const srcDir = projectSource && fs.existsSync(projectSource) ? projectSource : path.join(centralSkills, skill);
1296
- if (!fs.existsSync(srcDir))
1297
- continue;
1298
- const destDir = path.join(skillsTarget, skill);
1299
- removePath(destDir);
1300
- copyDir(srcDir, destDir);
1301
- syncedSkills.push(skill);
1302
- }
1303
- result.skills = syncedSkills.length > 0;
1304
- if (syncedSkills.length > 0) {
1305
- recordVersionResources(agent, version, 'skills', syncedSkills);
1306
- }
1307
- }
1308
- }
1309
- // Sync hooks (if agent supports them)
1310
- if (agentConfig.supportsHooks) {
1311
- // Version gate: Codex hooks require >= CODEX_HOOKS_MIN_VERSION
1312
- if (agent === 'codex' && compareVersions(version, CODEX_HOOKS_MIN_VERSION) < 0) {
1313
- console.warn(`hooks skipped: codex@${version} < ${CODEX_HOOKS_MIN_VERSION}`);
1314
- }
1315
- else {
1316
- const hooksToSync = selection
1317
- ? resolveSelection(selection.hooks, available.hooks)
1318
- : available.hooks;
1319
- if (hooksToSync.length > 0) {
1320
- const centralHooks = getHooksDir();
1321
- const projectHooksDir = projectAgentsDir ? path.join(projectAgentsDir, 'hooks') : null;
1322
- const hooksTarget = path.join(agentDir, 'hooks');
1323
- fs.mkdirSync(hooksTarget, { recursive: true });
1324
- const syncedHooks = [];
1325
- for (const hook of hooksToSync) {
1326
- const projectSource = projectHooksDir ? path.join(projectHooksDir, hook) : null;
1327
- const srcFile = projectSource && fs.existsSync(projectSource) ? projectSource : path.join(centralHooks, hook);
1328
- if (!fs.existsSync(srcFile))
1329
- continue;
1330
- const destFile = path.join(hooksTarget, hook);
1331
- fs.copyFileSync(srcFile, destFile);
1332
- fs.chmodSync(destFile, 0o755);
1333
- syncedHooks.push(hook);
1334
- }
1335
- // Remove orphan hook files that exist in version home but not in central
1336
- const centralHookNames = new Set(fs.existsSync(getHooksDir())
1337
- ? fs.readdirSync(getHooksDir()).filter(f => !f.startsWith('.'))
1338
- : []);
1339
- if (fs.existsSync(hooksTarget)) {
1340
- for (const file of fs.readdirSync(hooksTarget).filter(f => !f.startsWith('.'))) {
1341
- if (!centralHookNames.has(file)) {
1342
- removePath(path.join(hooksTarget, file));
1343
- }
1344
- }
1345
- }
1346
- result.hooks = syncedHooks.length > 0;
1347
- if (syncedHooks.length > 0) {
1348
- recordVersionResources(agent, version, 'hooks', syncedHooks);
1349
- }
1350
- if (agent === 'claude' || agent === 'codex') {
1351
- registerHooksToSettings(agent, versionHome);
1352
- }
1353
- }
1354
- }
1355
- }
1356
- // Sync memory files
1357
- const memoryToSync = selection
1358
- ? resolveSelection(selection.memory, available.memory)
1359
- : available.memory;
1360
- if (memoryToSync.length > 0 && COMMANDS_CAPABLE_AGENTS.includes(agent)) {
1361
- const centralMemory = getMemoryDir();
1362
- const projectMemoryDir = projectAgentsDir ? path.join(projectAgentsDir, 'memory') : null;
1363
- const syncedMemory = [];
1364
- const agentSupportsImports = !!agentConfig.capabilities.memoryImports;
1365
- for (const mem of memoryToSync) {
1366
- const projectSource = projectMemoryDir ? path.join(projectMemoryDir, `${mem}.md`) : null;
1367
- const srcFile = projectSource && fs.existsSync(projectSource)
1368
- ? projectSource
1369
- : path.join(centralMemory, `${mem}.md`);
1370
- if (!fs.existsSync(srcFile))
1371
- continue;
1372
- const targetName = mem === 'AGENTS' ? agentConfig.instructionsFile : `${mem}.md`;
1373
- const destFile = path.join(agentDir, targetName);
1374
- removePath(destFile);
1375
- // For the primary memory file (AGENTS.md), agents that don't natively
1376
- // resolve @-imports get a compiled (inlined) copy + sidecar manifest.
1377
- // Everything else (secondary memory files, @-capable agents) gets a
1378
- // straight copy.
1379
- if (mem === 'AGENTS' && !agentSupportsImports) {
1380
- compileMemoryForAgent(agent, version);
1381
- }
1382
- else {
1383
- fs.copyFileSync(srcFile, destFile);
1384
- }
1385
- result.memory.push(targetName);
1386
- syncedMemory.push(mem);
1387
- }
1388
- if (syncedMemory.length > 0) {
1389
- recordVersionResources(agent, version, 'memory', syncedMemory);
1390
- }
1391
- }
1392
- // Apply permissions (if agent supports them).
1393
- // Groups live in ~/.agents/permissions/groups/. Optional recipes in
1394
- // ~/.agents/permissions/sets/<name>.yaml pick a subset via `includes:`.
1395
- // If AGENTS_PERMISSION_SET is set, we resolve that recipe and use its
1396
- // includes list as the group filter (intersected with groups on disk).
1397
- const permissionGroups = discoverPermissionGroups();
1398
- const allGroupNames = permissionGroups.map(g => g.name);
1399
- const activeSetName = getActivePermissionSetName();
1400
- let setFilteredGroups = null;
1401
- if (activeSetName) {
1402
- const recipe = readPermissionSetRecipe(activeSetName);
1403
- if (recipe) {
1404
- const available = new Set(allGroupNames);
1405
- setFilteredGroups = recipe.includes.filter(g => available.has(g));
1406
- }
1407
- else {
1408
- console.warn(`${PERMISSION_SET_ENV_VAR}=${activeSetName} but no recipe at ~/.agents/permissions/sets/${activeSetName}.yaml — falling back to all groups`);
1409
- }
1410
- }
1411
- let permsToSync;
1412
- if (selection) {
1413
- permsToSync = resolveSelection(selection.permissions, allGroupNames);
1414
- // If a set recipe is active, the recipe's includes list always wins —
1415
- // even when the caller passed an explicit array via selection. Without
1416
- // this intersection, `agents add`'s buildAutomaticSelection would pass
1417
- // every group name discovered on disk (including 99-deny), bypassing
1418
- // the sandbox filter.
1419
- if (setFilteredGroups) {
1420
- const filterSet = new Set(setFilteredGroups);
1421
- permsToSync = permsToSync.filter(g => filterSet.has(g));
1422
- }
1423
- }
1424
- else {
1425
- permsToSync = PERMISSIONS_CAPABLE_AGENTS.includes(agent)
1426
- ? (setFilteredGroups ?? allGroupNames)
1427
- : [];
1428
- }
1429
- if (permsToSync.length > 0 && PERMISSIONS_CAPABLE_AGENTS.includes(agent)) {
1430
- // Build permissions from selected groups
1431
- const builtPerms = buildPermissionsFromGroups(permsToSync);
1432
- if (builtPerms.allow.length > 0 || (builtPerms.deny && builtPerms.deny.length > 0)) {
1433
- const permResult = applyPermsToVersion(agent, builtPerms, versionHome, true);
1434
- result.permissions = permResult.success;
1435
- if (permResult.success) {
1436
- recordVersionResources(agent, version, 'permissions', permsToSync);
1437
- }
1438
- }
1439
- }
1440
- // Install MCP servers (if agent supports them)
1441
- // For Claude/Codex: uses CLI commands (claude mcp add, codex mcp add)
1442
- // For others: edits config files directly
1443
- const mcpToSync = selection
1444
- ? resolveSelection(selection.mcp, available.mcp)
1445
- : (MCP_CAPABLE_AGENTS.includes(agent) ? available.mcp : []);
1446
- if (mcpToSync.length > 0 && MCP_CAPABLE_AGENTS.includes(agent)) {
1447
- const mcpResult = installMcpServers(agent, version, versionHome, mcpToSync, { cwd });
1448
- result.mcp = mcpResult.applied;
1449
- if (mcpResult.applied.length > 0) {
1450
- recordVersionResources(agent, version, 'mcp', mcpResult.applied);
1451
- }
1452
- }
1453
- // Sync subagents (claude and openclaw only)
1454
- const subagentsToSync = selection
1455
- ? resolveSelection(selection.subagents, available.subagents)
1456
- : (SUBAGENT_CAPABLE_AGENTS.includes(agent) ? available.subagents : []);
1457
- if (subagentsToSync.length > 0 && SUBAGENT_CAPABLE_AGENTS.includes(agent)) {
1458
- const allSubagents = listInstalledSubagents();
1459
- const subagentsMap = new Map(allSubagents.map(s => [s.name, s]));
1460
- for (const name of subagentsToSync) {
1461
- const subagent = subagentsMap.get(name);
1462
- if (!subagent)
1463
- continue;
1464
- try {
1465
- if (agent === 'claude') {
1466
- // Claude: flatten to single .md file
1467
- const agentsDir = path.join(agentDir, 'agents');
1468
- fs.mkdirSync(agentsDir, { recursive: true });
1469
- const transformed = transformSubagentForClaude(subagent.path);
1470
- fs.writeFileSync(path.join(agentsDir, `${subagent.name}.md`), transformed);
1471
- result.subagents.push(subagent.name);
1472
- }
1473
- else if (agent === 'openclaw') {
1474
- // OpenClaw: copy full directory, rename AGENT.md -> AGENTS.md
1475
- const targetDir = path.join(versionHome, '.openclaw', subagent.name);
1476
- const syncResult = syncSubagentToOpenclaw(subagent.path, targetDir);
1477
- if (syncResult.success) {
1478
- result.subagents.push(subagent.name);
1479
- }
1480
- }
1481
- }
1482
- catch { /* resource sync failed for this item */ }
1483
- }
1484
- if (result.subagents.length > 0) {
1485
- recordVersionResources(agent, version, 'subagents', result.subagents);
1486
- }
1487
- }
1488
- // Sync plugins (claude and openclaw)
1489
- const pluginsToSync = selection
1490
- ? resolveSelection(selection.plugins, available.plugins)
1491
- : (PLUGINS_CAPABLE_AGENTS.includes(agent) ? available.plugins : []);
1492
- if (pluginsToSync.length > 0 && PLUGINS_CAPABLE_AGENTS.includes(agent)) {
1493
- const allPlugins = discoverPlugins();
1494
- const pluginMap = new Map(allPlugins.map(p => [p.name, p]));
1495
- // Clean orphaned plugin skills from plugins that no longer exist
1496
- const activePluginNames = new Set(allPlugins.map(p => p.name));
1497
- cleanOrphanedPluginSkills(agent, versionHome, activePluginNames);
1498
- for (const name of pluginsToSync) {
1499
- const plugin = pluginMap.get(name);
1500
- if (!plugin || !pluginSupportsAgent(plugin, agent))
1501
- continue;
1502
- const pluginResult = syncPluginToVersion(plugin, agent, versionHome);
1503
- if (pluginResult.success) {
1504
- result.plugins.push(name);
1505
- }
1506
- }
1507
- if (result.plugins.length > 0) {
1508
- recordVersionResources(agent, version, 'plugins', result.plugins);
1509
- }
1510
- }
1511
- return result;
1512
- }
1513
- /**
1514
- * Get the effective HOME directory for an agent.
1515
- * If version-managed with a resolved version, returns the version's home directory.
1516
- * Otherwise returns the real HOME.
1517
- */
1518
- export function getEffectiveHome(agentId) {
1519
- const resolved = resolveVersion(agentId, process.cwd());
1520
- if (resolved && isVersionInstalled(agentId, resolved)) {
1521
- return getVersionHomePath(agentId, resolved);
1522
- }
1523
- return os.homedir();
1524
- }
1525
- /**
1526
- * Resolve a comma-separated --agents list into concrete version selections.
1527
- * Bare agents target the default version, or the newest installed version when no default exists.
1528
- * Explicit agent@version targets only that installed version.
1529
- */
1530
- export function resolveAgentVersionTargets(value, availableAgents, options = {}) {
1531
- const selectedAgents = [];
1532
- const versionSelections = new Map();
1533
- const explicitSelections = new Set();
1534
- const targets = value
1535
- .split(',')
1536
- .map((item) => item.trim())
1537
- .filter(Boolean);
1538
- for (const target of targets) {
1539
- const atIndex = target.indexOf('@');
1540
- const agentToken = (atIndex === -1 ? target : target.slice(0, atIndex)).trim();
1541
- const versionToken = atIndex === -1 ? null : target.slice(atIndex + 1).trim();
1542
- if (!agentToken) {
1543
- continue;
1544
- }
1545
- if (atIndex !== -1 && !versionToken) {
1546
- throw new Error(`Missing version in --agents entry '${target}'. Use agent@x.y.z or agent@default.`);
1547
- }
1548
- const agentId = resolveAgentName(agentToken);
1549
- if (!agentId || !availableAgents.includes(agentId)) {
1550
- throw new Error(formatAgentError(agentToken, [...availableAgents]));
1551
- }
1552
- if (!selectedAgents.includes(agentId)) {
1553
- selectedAgents.push(agentId);
1554
- }
1555
- if (explicitSelections.has(agentId) && !versionToken) {
1556
- continue;
1557
- }
1558
- const installedVersions = listInstalledVersions(agentId);
1559
- const defaultVersion = getGlobalDefault(agentId);
1560
- if (!versionToken) {
1561
- if (installedVersions.length === 0) {
1562
- continue;
1563
- }
1564
- versionSelections.set(agentId, options.allVersions
1565
- ? [...installedVersions]
1566
- : [defaultVersion || installedVersions[installedVersions.length - 1]]);
1567
- continue;
1568
- }
1569
- if (installedVersions.length === 0) {
1570
- throw new Error(`No managed versions are installed for ${AGENTS[agentId].name}. Run: agents add ${agentId}@latest`);
1571
- }
1572
- if (versionToken === 'default') {
1573
- if (!defaultVersion) {
1574
- throw new Error(`No default version set for ${AGENTS[agentId].name}. Run: agents use ${agentId}@<version>`);
1575
- }
1576
- const explicitVersions = explicitSelections.has(agentId)
1577
- ? (versionSelections.get(agentId) || [])
1578
- : [];
1579
- if (!explicitVersions.includes(defaultVersion)) {
1580
- explicitVersions.push(defaultVersion);
1581
- }
1582
- versionSelections.set(agentId, explicitVersions);
1583
- explicitSelections.add(agentId);
1584
- continue;
1585
- }
1586
- if (!installedVersions.includes(versionToken)) {
1587
- throw new Error(`Version ${versionToken} is not installed for ${AGENTS[agentId].name}. Installed versions: ${installedVersions.join(', ')}`);
1588
- }
1589
- const explicitVersions = explicitSelections.has(agentId)
1590
- ? (versionSelections.get(agentId) || [])
1591
- : [];
1592
- if (!explicitVersions.includes(versionToken)) {
1593
- explicitVersions.push(versionToken);
1594
- }
1595
- versionSelections.set(agentId, explicitVersions);
1596
- explicitSelections.add(agentId);
1597
- }
1598
- return { selectedAgents, versionSelections };
1599
- }
1600
- /**
1601
- * Resolve a comma-separated --agents list into install/apply targets.
1602
- * Bare agents target the default version (or newest installed version) when managed,
1603
- * and fall back to the agent's effective HOME when unmanaged.
1604
- * Explicit agent@version targets only that installed version.
1605
- */
1606
- export function resolveInstalledAgentTargets(value, availableAgents, options = {}) {
1607
- const selectedAgents = [];
1608
- const directAgents = [];
1609
- const versionSelections = new Map();
1610
- const targets = value
1611
- .split(',')
1612
- .map((item) => item.trim())
1613
- .filter(Boolean);
1614
- const addVersionTarget = (agentId, version) => {
1615
- const versions = versionSelections.get(agentId) || [];
1616
- if (!versions.includes(version)) {
1617
- versions.push(version);
1618
- versionSelections.set(agentId, versions);
1619
- }
1620
- const directIndex = directAgents.indexOf(agentId);
1621
- if (directIndex !== -1) {
1622
- directAgents.splice(directIndex, 1);
1623
- }
1624
- };
1625
- for (const target of targets) {
1626
- const atIndex = target.indexOf('@');
1627
- const agentToken = (atIndex === -1 ? target : target.slice(0, atIndex)).trim();
1628
- const versionToken = atIndex === -1 ? null : target.slice(atIndex + 1).trim();
1629
- if (!agentToken) {
1630
- continue;
1631
- }
1632
- if (atIndex !== -1 && !versionToken) {
1633
- throw new Error(`Missing version in --agents entry '${target}'. Use agent@x.y.z or agent@default.`);
1634
- }
1635
- const agentId = resolveAgentName(agentToken);
1636
- if (!agentId || !availableAgents.includes(agentId)) {
1637
- throw new Error(formatAgentError(agentToken, [...availableAgents]));
1638
- }
1639
- if (!selectedAgents.includes(agentId)) {
1640
- selectedAgents.push(agentId);
1641
- }
1642
- const installedVersions = listInstalledVersions(agentId);
1643
- const defaultVersion = getGlobalDefault(agentId);
1644
- if (!versionToken) {
1645
- if (installedVersions.length === 0) {
1646
- if (!directAgents.includes(agentId)) {
1647
- directAgents.push(agentId);
1648
- }
1649
- continue;
1650
- }
1651
- const targetVersions = options.allVersions
1652
- ? [...installedVersions]
1653
- : [defaultVersion || installedVersions[installedVersions.length - 1]];
1654
- for (const version of targetVersions) {
1655
- addVersionTarget(agentId, version);
1656
- }
1657
- continue;
1658
- }
1659
- if (versionToken === 'default') {
1660
- if (!defaultVersion) {
1661
- throw new Error(`No default version set for ${AGENTS[agentId].name}. Run: agents use ${agentId}@<version>`);
1662
- }
1663
- addVersionTarget(agentId, defaultVersion);
1664
- continue;
1665
- }
1666
- if (installedVersions.length === 0) {
1667
- throw new Error(`No managed versions are installed for ${AGENTS[agentId].name}. Run: agents add ${agentId}@latest`);
1668
- }
1669
- if (!installedVersions.includes(versionToken)) {
1670
- throw new Error(`Version ${versionToken} is not installed for ${AGENTS[agentId].name}. Installed versions: ${installedVersions.join(', ')}`);
1671
- }
1672
- addVersionTarget(agentId, versionToken);
1673
- }
1674
- return { selectedAgents, directAgents, versionSelections };
1675
- }
1676
- /**
1677
- * Resolve configured manifest targets into direct homes and managed versions.
1678
- */
1679
- export function resolveConfiguredAgentTargets(agents, agentVersions, availableAgents, options = {}) {
1680
- const targetSpecs = [];
1681
- const broadTargets = agents ? [...agents] : [...availableAgents];
1682
- for (const agentId of broadTargets) {
1683
- if (availableAgents.includes(agentId)) {
1684
- targetSpecs.push(agentId);
1685
- }
1686
- }
1687
- if (agentVersions) {
1688
- for (const [agentId, versions] of Object.entries(agentVersions)) {
1689
- if (!availableAgents.includes(agentId) || !versions)
1690
- continue;
1691
- for (const version of versions) {
1692
- targetSpecs.push(`${agentId}@${version}`);
1693
- }
1694
- }
1695
- }
1696
- if (targetSpecs.length === 0) {
1697
- return {
1698
- selectedAgents: [],
1699
- directAgents: [],
1700
- versionSelections: new Map(),
1701
- };
1702
- }
1703
- return resolveInstalledAgentTargets(targetSpecs.join(','), availableAgents, options);
1704
- }
1705
- /**
1706
- * Prompt user to select agents and versions for resource installation.
1707
- * Returns selected agents and their version selections.
1708
- */
1709
- export async function promptAgentVersionSelection(availableAgents, options = {}) {
1710
- const versionSelections = new Map();
1711
- // Filter to installed agents (only those with versions managed by agents CLI)
1712
- const installedAgents = availableAgents.filter((id) => {
1713
- const versions = listInstalledVersions(id);
1714
- return versions.length > 0;
1715
- });
1716
- if (installedAgents.length === 0) {
1717
- return { selectedAgents: [], versionSelections };
1718
- }
1719
- const formatAgentLabel = (agentId) => {
1720
- const versions = listInstalledVersions(agentId);
1721
- const defaultVer = getGlobalDefault(agentId);
1722
- if (versions.length === 0)
1723
- return `${AGENTS[agentId].name} ${chalk.gray('(not installed)')}`;
1724
- if (defaultVer)
1725
- return `${AGENTS[agentId].name} ${chalk.gray(`(active: ${defaultVer})`)}`;
1726
- return `${AGENTS[agentId].name} ${chalk.gray(`(${versions[0]})`)}`;
1727
- };
1728
- let selectedAgents;
1729
- if (options.skipPrompts) {
1730
- // Auto-select all installed agents with default versions
1731
- selectedAgents = [...installedAgents];
1732
- for (const agentId of selectedAgents) {
1733
- const versions = listInstalledVersions(agentId);
1734
- if (versions.length > 0) {
1735
- const defaultVer = getGlobalDefault(agentId);
1736
- versionSelections.set(agentId, defaultVer ? [defaultVer] : [versions[versions.length - 1]]);
1737
- }
1738
- }
1739
- }
1740
- else {
1741
- // Prompt for agent selection
1742
- const checkboxResult = await checkbox({
1743
- message: 'Which agents should receive these resources?',
1744
- choices: [
1745
- { name: chalk.bold('All'), value: 'all', checked: true },
1746
- ...installedAgents.map((id) => ({
1747
- name: ` ${formatAgentLabel(id)}`,
1748
- value: id,
1749
- checked: false,
1750
- })),
1751
- ],
1752
- });
1753
- if (checkboxResult.includes('all')) {
1754
- selectedAgents = [...installedAgents];
1755
- }
1756
- else {
1757
- selectedAgents = checkboxResult;
1758
- }
1759
- // Version selection per agent
1760
- for (const agentId of selectedAgents) {
1761
- const versions = listInstalledVersions(agentId);
1762
- if (versions.length === 0)
1763
- continue;
1764
- if (versions.length === 1) {
1765
- versionSelections.set(agentId, [versions[0]]);
1766
- continue;
1767
- }
1768
- const defaultVer = getGlobalDefault(agentId);
1769
- const versionEmails = await Promise.all(versions.map((v) => getAccountEmail(agentId, getVersionHomePath(agentId, v)).then((email) => ({ v, email }))));
1770
- const versionEmailMap = new Map(versionEmails.map((e) => [e.v, e.email]));
1771
- const maxLabelLen = Math.max(...versions.map((v) => (v === defaultVer ? `${v} (default)` : v).length));
1772
- const versionResult = await checkbox({
1773
- message: `Which versions of ${AGENTS[agentId].name} should receive these resources?`,
1774
- choices: [
1775
- { name: chalk.bold('All versions'), value: 'all', checked: false },
1776
- ...versions.map((v) => {
1777
- const base = v === defaultVer ? `${v} (default)` : v;
1778
- let label = base.padEnd(maxLabelLen);
1779
- const email = versionEmailMap.get(v);
1780
- if (email)
1781
- label += chalk.cyan(` ${email}`);
1782
- return { name: label, value: v, checked: v === defaultVer };
1783
- }),
1784
- ],
1785
- });
1786
- if (versionResult.includes('all')) {
1787
- versionSelections.set(agentId, [...versions]);
1788
- }
1789
- else {
1790
- versionSelections.set(agentId, versionResult);
1791
- }
1792
- }
1793
- }
1794
- return { selectedAgents, versionSelections };
1795
- }
1796
- //# sourceMappingURL=versions.js.map