@claude-collective/cli 0.13.4 → 0.25.1

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 (314) hide show
  1. package/CHANGELOG.md +357 -0
  2. package/README.md +41 -27
  3. package/config/skills-matrix.yaml +202 -134
  4. package/config/stacks.yaml +14 -20
  5. package/dist/chunk-3X5D7RM5.js +69 -0
  6. package/dist/chunk-3X5D7RM5.js.map +1 -0
  7. package/dist/chunk-4S4FCAA2.js +100 -0
  8. package/dist/chunk-4S4FCAA2.js.map +1 -0
  9. package/dist/chunk-4WGN6SUE.js +197 -0
  10. package/dist/chunk-4WGN6SUE.js.map +1 -0
  11. package/dist/{chunk-DHET7RCE.js → chunk-AWKZ5BDL.js} +9 -2
  12. package/dist/{chunk-DHET7RCE.js.map → chunk-AWKZ5BDL.js.map} +1 -1
  13. package/dist/{chunk-6Q3Y7KVB.js → chunk-DBRUQQUF.js} +8 -2
  14. package/dist/chunk-DBRUQQUF.js.map +1 -0
  15. package/dist/{chunk-Z7G4B5HJ.js → chunk-ETCVEV3S.js} +73 -150
  16. package/dist/chunk-ETCVEV3S.js.map +1 -0
  17. package/dist/chunk-F4RD5FYM.js +45 -0
  18. package/dist/chunk-F4RD5FYM.js.map +1 -0
  19. package/dist/{chunk-ACNBKXXJ.js → chunk-GGFOD5PK.js} +13 -44
  20. package/dist/chunk-GGFOD5PK.js.map +1 -0
  21. package/dist/chunk-H7SSBSPR.js +29 -0
  22. package/dist/chunk-H7SSBSPR.js.map +1 -0
  23. package/dist/chunk-HWD32NP7.js +19 -0
  24. package/dist/chunk-HWD32NP7.js.map +1 -0
  25. package/dist/{chunk-JIPWV2FX.js → chunk-IAYAE6MG.js} +12 -34
  26. package/dist/chunk-IAYAE6MG.js.map +1 -0
  27. package/dist/{chunk-RTE64SJA.js → chunk-IXBCRT3F.js} +2 -2
  28. package/dist/chunk-IXBCRT3F.js.map +1 -0
  29. package/dist/chunk-KWYO3M5Q.js +67 -0
  30. package/dist/chunk-KWYO3M5Q.js.map +1 -0
  31. package/dist/{chunk-E3FJH4TF.js → chunk-MCTSHLAF.js} +18 -18
  32. package/dist/chunk-MCTSHLAF.js.map +1 -0
  33. package/dist/chunk-MH66WDFV.js +251 -0
  34. package/dist/chunk-MH66WDFV.js.map +1 -0
  35. package/dist/{chunk-K3NB6DSG.js → chunk-MTPM7BX5.js} +108 -110
  36. package/dist/chunk-MTPM7BX5.js.map +1 -0
  37. package/dist/chunk-NQJ47R4N.js +1092 -0
  38. package/dist/chunk-NQJ47R4N.js.map +1 -0
  39. package/dist/chunk-NRC7XYCI.js +211 -0
  40. package/dist/chunk-NRC7XYCI.js.map +1 -0
  41. package/dist/{chunk-76DWXGQE.js → chunk-O6ZTD7ZI.js} +14 -3
  42. package/dist/chunk-O6ZTD7ZI.js.map +1 -0
  43. package/dist/chunk-OBXAY23Y.js +56 -0
  44. package/dist/chunk-OBXAY23Y.js.map +1 -0
  45. package/dist/{chunk-XY3XDVMI.js → chunk-QR2EBWL2.js} +3 -3
  46. package/dist/{chunk-66UDJBF6.js → chunk-REJGRCVQ.js} +2 -2
  47. package/dist/{chunk-D237EVNB.js → chunk-TMED5DQ2.js} +71 -48
  48. package/dist/chunk-TMED5DQ2.js.map +1 -0
  49. package/dist/chunk-U7HFKR74.js +21 -0
  50. package/dist/chunk-U7HFKR74.js.map +1 -0
  51. package/dist/chunk-UEMRJI2K.js +146 -0
  52. package/dist/chunk-UEMRJI2K.js.map +1 -0
  53. package/dist/{chunk-Z2CWURZ6.js → chunk-UNN7523L.js} +2 -2
  54. package/dist/chunk-V2ZIH7HV.js +29 -0
  55. package/dist/chunk-V2ZIH7HV.js.map +1 -0
  56. package/dist/{chunk-X6QONICW.js → chunk-VVYNZZUX.js} +7 -19
  57. package/dist/chunk-VVYNZZUX.js.map +1 -0
  58. package/dist/chunk-WXS4S3MA.js +220 -0
  59. package/dist/chunk-WXS4S3MA.js.map +1 -0
  60. package/dist/{chunk-CDX4W4DM.js → chunk-XENOESJZ.js} +53 -33
  61. package/dist/chunk-XENOESJZ.js.map +1 -0
  62. package/dist/chunk-YDBSSAJ6.js +4207 -0
  63. package/dist/chunk-YDBSSAJ6.js.map +1 -0
  64. package/dist/chunk-ZDREFYD2.js +696 -0
  65. package/dist/chunk-ZDREFYD2.js.map +1 -0
  66. package/dist/chunk-ZW2PELOH.js +197 -0
  67. package/dist/chunk-ZW2PELOH.js.map +1 -0
  68. package/dist/cli/defaults/agent-mappings.yaml +13 -14
  69. package/dist/commands/build/marketplace.js +19 -23
  70. package/dist/commands/build/marketplace.js.map +1 -1
  71. package/dist/commands/build/plugins.js +13 -240
  72. package/dist/commands/build/plugins.js.map +1 -1
  73. package/dist/commands/build/stack.js +13 -25
  74. package/dist/commands/build/stack.js.map +1 -1
  75. package/dist/commands/compile.js +45 -82
  76. package/dist/commands/compile.js.map +1 -1
  77. package/dist/commands/config/get.js +9 -9
  78. package/dist/commands/config/get.js.map +1 -1
  79. package/dist/commands/config/index.js +8 -8
  80. package/dist/commands/config/index.js.map +1 -1
  81. package/dist/commands/config/path.js +7 -9
  82. package/dist/commands/config/path.js.map +1 -1
  83. package/dist/commands/config/set-project.js +12 -13
  84. package/dist/commands/config/set-project.js.map +1 -1
  85. package/dist/commands/config/show.js +7 -7
  86. package/dist/commands/config/unset-project.js +12 -13
  87. package/dist/commands/config/unset-project.js.map +1 -1
  88. package/dist/commands/diff.js +15 -44
  89. package/dist/commands/diff.js.map +1 -1
  90. package/dist/commands/doctor.js +23 -67
  91. package/dist/commands/doctor.js.map +1 -1
  92. package/dist/commands/edit.js +98 -81
  93. package/dist/commands/edit.js.map +1 -1
  94. package/dist/commands/eject.js +27 -79
  95. package/dist/commands/eject.js.map +1 -1
  96. package/dist/commands/import/skill.js +38 -58
  97. package/dist/commands/import/skill.js.map +1 -1
  98. package/dist/commands/info.js +17 -24
  99. package/dist/commands/info.js.map +1 -1
  100. package/dist/commands/init.js +103 -779
  101. package/dist/commands/init.js.map +1 -1
  102. package/dist/commands/list.js +8 -11
  103. package/dist/commands/list.js.map +1 -1
  104. package/dist/commands/new/agent.js +11 -16
  105. package/dist/commands/new/agent.js.map +1 -1
  106. package/dist/commands/new/skill.js +14 -18
  107. package/dist/commands/new/skill.js.map +1 -1
  108. package/dist/commands/outdated.js +16 -97
  109. package/dist/commands/outdated.js.map +1 -1
  110. package/dist/commands/search.js +24 -43
  111. package/dist/commands/search.js.map +1 -1
  112. package/dist/commands/uninstall.js +22 -30
  113. package/dist/commands/uninstall.js.map +1 -1
  114. package/dist/commands/update.js +23 -154
  115. package/dist/commands/update.js.map +1 -1
  116. package/dist/commands/validate.js +38 -89
  117. package/dist/commands/validate.js.map +1 -1
  118. package/dist/commands/version/bump.js +12 -28
  119. package/dist/commands/version/bump.js.map +1 -1
  120. package/dist/commands/version/index.js +8 -24
  121. package/dist/commands/version/index.js.map +1 -1
  122. package/dist/commands/version/set.js +11 -26
  123. package/dist/commands/version/set.js.map +1 -1
  124. package/dist/commands/version/show.js +8 -24
  125. package/dist/commands/version/show.js.map +1 -1
  126. package/dist/components/common/confirm.js +2 -2
  127. package/dist/components/common/confirm.test.js +203 -0
  128. package/dist/components/common/confirm.test.js.map +1 -0
  129. package/dist/components/common/message.js +3 -7
  130. package/dist/components/common/message.js.map +1 -1
  131. package/dist/components/common/spinner.js +1 -1
  132. package/dist/components/common/spinner.js.map +1 -1
  133. package/dist/components/skill-search/skill-search.js +3 -3
  134. package/dist/components/wizard/category-grid.js +2 -2
  135. package/dist/components/wizard/category-grid.test.js +138 -156
  136. package/dist/components/wizard/category-grid.test.js.map +1 -1
  137. package/dist/components/wizard/menu-item.js +9 -0
  138. package/dist/components/wizard/search-modal.js +9 -0
  139. package/dist/components/wizard/search-modal.test.js +216 -0
  140. package/dist/components/wizard/search-modal.test.js.map +1 -0
  141. package/dist/components/wizard/section-progress.js +2 -2
  142. package/dist/components/wizard/section-progress.test.js +16 -106
  143. package/dist/components/wizard/section-progress.test.js.map +1 -1
  144. package/dist/components/wizard/source-grid.js +10 -0
  145. package/dist/components/wizard/source-grid.js.map +1 -0
  146. package/dist/components/wizard/source-grid.test.js +500 -0
  147. package/dist/components/wizard/source-grid.test.js.map +1 -0
  148. package/dist/components/wizard/step-approach.js +7 -5
  149. package/dist/components/wizard/step-approach.test.js +115 -0
  150. package/dist/components/wizard/step-approach.test.js.map +1 -0
  151. package/dist/components/wizard/step-build.js +9 -5
  152. package/dist/components/wizard/step-build.test.js +160 -284
  153. package/dist/components/wizard/step-build.test.js.map +1 -1
  154. package/dist/components/wizard/step-confirm.js +3 -3
  155. package/dist/components/wizard/step-confirm.test.js +364 -0
  156. package/dist/components/wizard/step-confirm.test.js.map +1 -0
  157. package/dist/components/wizard/step-refine.js +2 -3
  158. package/dist/components/wizard/step-refine.test.js +24 -26
  159. package/dist/components/wizard/step-refine.test.js.map +1 -1
  160. package/dist/components/wizard/step-settings.js +14 -0
  161. package/dist/components/wizard/step-settings.js.map +1 -0
  162. package/dist/components/wizard/step-settings.test.js +240 -0
  163. package/dist/components/wizard/step-settings.test.js.map +1 -0
  164. package/dist/components/wizard/step-sources.js +17 -0
  165. package/dist/components/wizard/step-sources.js.map +1 -0
  166. package/dist/components/wizard/step-sources.test.js +290 -0
  167. package/dist/components/wizard/step-sources.test.js.map +1 -0
  168. package/dist/components/wizard/step-stack.js +7 -4
  169. package/dist/components/wizard/step-stack.test.js +344 -0
  170. package/dist/components/wizard/step-stack.test.js.map +1 -0
  171. package/dist/components/wizard/view-title.js +9 -0
  172. package/dist/components/wizard/view-title.js.map +1 -0
  173. package/dist/components/wizard/wizard-layout.js +17 -0
  174. package/dist/components/wizard/wizard-layout.js.map +1 -0
  175. package/dist/components/wizard/wizard-tabs.js +2 -2
  176. package/dist/components/wizard/wizard-tabs.test.js +292 -0
  177. package/dist/components/wizard/wizard-tabs.test.js.map +1 -0
  178. package/dist/components/wizard/wizard.js +22 -15
  179. package/dist/config/skills-matrix.yaml +202 -134
  180. package/dist/config/stacks.yaml +14 -20
  181. package/dist/hooks/init.js +6 -8
  182. package/dist/hooks/init.js.map +1 -1
  183. package/dist/index.js +1 -1
  184. package/dist/index.js.map +1 -1
  185. package/dist/{magic-string.es-RGXYGAW3.js → magic-string.es-PAH2SOTR.js} +2 -2
  186. package/dist/source-manager-DSYZEVGZ.js +16 -0
  187. package/dist/source-manager-DSYZEVGZ.js.map +1 -0
  188. package/dist/src/agents/developer/api-developer/agent.yaml +1 -1
  189. package/dist/src/agents/developer/cli-developer/agent.yaml +1 -1
  190. package/dist/src/agents/developer/web-architecture/agent.yaml +1 -1
  191. package/dist/src/agents/developer/web-developer/agent.yaml +1 -1
  192. package/dist/src/agents/developer/web-developer/examples.md +1 -6
  193. package/dist/src/agents/meta/agent-summoner/agent.yaml +1 -1
  194. package/dist/src/agents/meta/documentor/agent.yaml +1 -1
  195. package/dist/src/agents/meta/documentor/workflow.md +1 -5
  196. package/dist/src/agents/meta/skill-summoner/agent.yaml +1 -1
  197. package/dist/src/agents/migration/cli-migrator/agent.yaml +1 -1
  198. package/dist/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
  199. package/dist/src/agents/pattern/pattern-scout/agent.yaml +1 -1
  200. package/dist/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
  201. package/dist/src/agents/planning/web-pm/agent.yaml +1 -1
  202. package/dist/src/agents/researcher/api-researcher/agent.yaml +1 -1
  203. package/dist/src/agents/researcher/web-researcher/agent.yaml +1 -1
  204. package/dist/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
  205. package/dist/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
  206. package/dist/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
  207. package/dist/src/agents/tester/cli-tester/agent.yaml +1 -1
  208. package/dist/src/agents/tester/web-tester/agent.yaml +1 -1
  209. package/dist/src/agents/tester/web-tester/output-format.md +1 -3
  210. package/dist/stores/wizard-store.js +4 -3
  211. package/dist/stores/wizard-store.test.js +94 -88
  212. package/dist/stores/wizard-store.test.js.map +1 -1
  213. package/package.json +5 -3
  214. package/src/agents/developer/api-developer/agent.yaml +1 -1
  215. package/src/agents/developer/cli-developer/agent.yaml +1 -1
  216. package/src/agents/developer/web-architecture/agent.yaml +1 -1
  217. package/src/agents/developer/web-developer/agent.yaml +1 -1
  218. package/src/agents/developer/web-developer/examples.md +1 -6
  219. package/src/agents/meta/agent-summoner/agent.yaml +1 -1
  220. package/src/agents/meta/documentor/agent.yaml +1 -1
  221. package/src/agents/meta/documentor/workflow.md +1 -5
  222. package/src/agents/meta/skill-summoner/agent.yaml +1 -1
  223. package/src/agents/migration/cli-migrator/agent.yaml +1 -1
  224. package/src/agents/migration/cli-migrator/anti-patterns.md +1 -3
  225. package/src/agents/pattern/pattern-scout/agent.yaml +1 -1
  226. package/src/agents/pattern/web-pattern-critique/agent.yaml +1 -1
  227. package/src/agents/planning/web-pm/agent.yaml +1 -1
  228. package/src/agents/researcher/api-researcher/agent.yaml +1 -1
  229. package/src/agents/researcher/web-researcher/agent.yaml +1 -1
  230. package/src/agents/reviewer/api-reviewer/agent.yaml +1 -1
  231. package/src/agents/reviewer/cli-reviewer/agent.yaml +1 -1
  232. package/src/agents/reviewer/web-reviewer/agent.yaml +1 -1
  233. package/src/agents/tester/cli-tester/agent.yaml +1 -1
  234. package/src/agents/tester/web-tester/agent.yaml +1 -1
  235. package/src/agents/tester/web-tester/output-format.md +1 -3
  236. package/dist/chunk-3U3R4NCG.js +0 -22
  237. package/dist/chunk-3U3R4NCG.js.map +0 -1
  238. package/dist/chunk-4K4ZXQRM.js +0 -317
  239. package/dist/chunk-4K4ZXQRM.js.map +0 -1
  240. package/dist/chunk-6Q3Y7KVB.js.map +0 -1
  241. package/dist/chunk-76DWXGQE.js.map +0 -1
  242. package/dist/chunk-7Q44DMSP.js +0 -582
  243. package/dist/chunk-7Q44DMSP.js.map +0 -1
  244. package/dist/chunk-ACNBKXXJ.js.map +0 -1
  245. package/dist/chunk-B7CCVP6Q.js +0 -639
  246. package/dist/chunk-B7CCVP6Q.js.map +0 -1
  247. package/dist/chunk-BDLUZVKU.js +0 -54
  248. package/dist/chunk-BDLUZVKU.js.map +0 -1
  249. package/dist/chunk-CDX4W4DM.js.map +0 -1
  250. package/dist/chunk-D237EVNB.js.map +0 -1
  251. package/dist/chunk-DRXPNNPB.js +0 -393
  252. package/dist/chunk-DRXPNNPB.js.map +0 -1
  253. package/dist/chunk-E3FJH4TF.js.map +0 -1
  254. package/dist/chunk-ED4E6Q2T.js +0 -114
  255. package/dist/chunk-ED4E6Q2T.js.map +0 -1
  256. package/dist/chunk-EHS3TWWP.js +0 -95
  257. package/dist/chunk-EHS3TWWP.js.map +0 -1
  258. package/dist/chunk-GDH553MV.js +0 -91
  259. package/dist/chunk-GDH553MV.js.map +0 -1
  260. package/dist/chunk-HLJX2FTL.js +0 -95
  261. package/dist/chunk-HLJX2FTL.js.map +0 -1
  262. package/dist/chunk-I2DSLOXZ.js +0 -75
  263. package/dist/chunk-I2DSLOXZ.js.map +0 -1
  264. package/dist/chunk-I4TPKIYX.js +0 -493
  265. package/dist/chunk-I4TPKIYX.js.map +0 -1
  266. package/dist/chunk-IAUAQJQ2.js +0 -57
  267. package/dist/chunk-IAUAQJQ2.js.map +0 -1
  268. package/dist/chunk-IBE7JIAG.js +0 -129
  269. package/dist/chunk-IBE7JIAG.js.map +0 -1
  270. package/dist/chunk-IMDW5ZUP.js +0 -132
  271. package/dist/chunk-IMDW5ZUP.js.map +0 -1
  272. package/dist/chunk-JIPWV2FX.js.map +0 -1
  273. package/dist/chunk-K3NB6DSG.js.map +0 -1
  274. package/dist/chunk-K7EVM5LY.js +0 -141
  275. package/dist/chunk-K7EVM5LY.js.map +0 -1
  276. package/dist/chunk-KAAEN2PO.js +0 -57
  277. package/dist/chunk-KAAEN2PO.js.map +0 -1
  278. package/dist/chunk-NDY25DTL.js +0 -453
  279. package/dist/chunk-NDY25DTL.js.map +0 -1
  280. package/dist/chunk-P26A2K5N.js +0 -64
  281. package/dist/chunk-P26A2K5N.js.map +0 -1
  282. package/dist/chunk-RFTSZDHV.js +0 -313
  283. package/dist/chunk-RFTSZDHV.js.map +0 -1
  284. package/dist/chunk-RTE64SJA.js.map +0 -1
  285. package/dist/chunk-SVYPSDWY.js +0 -84
  286. package/dist/chunk-SVYPSDWY.js.map +0 -1
  287. package/dist/chunk-TKFPKEV3.js +0 -69
  288. package/dist/chunk-TKFPKEV3.js.map +0 -1
  289. package/dist/chunk-UQTEPWU7.js +0 -108
  290. package/dist/chunk-UQTEPWU7.js.map +0 -1
  291. package/dist/chunk-V46GGCCI.js +0 -294
  292. package/dist/chunk-V46GGCCI.js.map +0 -1
  293. package/dist/chunk-X6QONICW.js.map +0 -1
  294. package/dist/chunk-Y2LW7R3Y.js +0 -23
  295. package/dist/chunk-Y2LW7R3Y.js.map +0 -1
  296. package/dist/chunk-Z7G4B5HJ.js.map +0 -1
  297. package/dist/chunk-ZENYS6KW.js +0 -90
  298. package/dist/chunk-ZENYS6KW.js.map +0 -1
  299. package/dist/chunk-ZFPSUQOU.js +0 -396
  300. package/dist/chunk-ZFPSUQOU.js.map +0 -1
  301. package/dist/commands/config/set.js +0 -61
  302. package/dist/commands/config/set.js.map +0 -1
  303. package/dist/commands/config/unset.js +0 -57
  304. package/dist/commands/config/unset.js.map +0 -1
  305. package/dist/commands/test-imports.js +0 -92
  306. package/dist/commands/test-imports.js.map +0 -1
  307. package/dist/components/wizard/step-stack-options.js +0 -11
  308. package/dist/components/wizard/wizard-footer.js +0 -9
  309. /package/dist/{chunk-XY3XDVMI.js.map → chunk-QR2EBWL2.js.map} +0 -0
  310. /package/dist/{chunk-66UDJBF6.js.map → chunk-REJGRCVQ.js.map} +0 -0
  311. /package/dist/{chunk-Z2CWURZ6.js.map → chunk-UNN7523L.js.map} +0 -0
  312. /package/dist/components/wizard/{step-stack-options.js.map → menu-item.js.map} +0 -0
  313. /package/dist/components/wizard/{wizard-footer.js.map → search-modal.js.map} +0 -0
  314. /package/dist/{magic-string.es-RGXYGAW3.js.map → magic-string.es-PAH2SOTR.js.map} +0 -0
@@ -1,117 +1,35 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- hashFile
4
- } from "../chunk-KAAEN2PO.js";
5
- import {
6
- loadSkillsMatrixFromSource
7
- } from "../chunk-RFTSZDHV.js";
8
- import "../chunk-B7CCVP6Q.js";
9
- import "../chunk-IMDW5ZUP.js";
10
2
  import {
11
3
  BaseCommand,
12
4
  EXIT_CODES
13
- } from "../chunk-EHS3TWWP.js";
14
- import "../chunk-V46GGCCI.js";
15
- import "../chunk-3U3R4NCG.js";
5
+ } from "../chunk-OBXAY23Y.js";
6
+ import {
7
+ compareSkills,
8
+ loadSkillsMatrixFromSource
9
+ } from "../chunk-YDBSSAJ6.js";
16
10
  import {
17
- fileExists,
18
- listDirectories,
19
- readFile
20
- } from "../chunk-TKFPKEV3.js";
11
+ fileExists
12
+ } from "../chunk-ZDREFYD2.js";
13
+ import "../chunk-HWD32NP7.js";
21
14
  import {
22
15
  LOCAL_SKILLS_PATH
23
- } from "../chunk-76DWXGQE.js";
16
+ } from "../chunk-O6ZTD7ZI.js";
24
17
  import {
25
18
  init_esm_shims
26
- } from "../chunk-DHET7RCE.js";
19
+ } from "../chunk-AWKZ5BDL.js";
27
20
 
28
21
  // src/cli/commands/outdated.ts
29
22
  init_esm_shims();
30
23
  import { Flags } from "@oclif/core";
31
24
  import { printTable } from "@oclif/table";
32
25
  import path from "path";
33
- import { parse as parseYaml } from "yaml";
34
- async function readForkedFromMetadata(skillDir) {
35
- const metadataPath = path.join(skillDir, "metadata.yaml");
36
- if (!await fileExists(metadataPath)) {
37
- return null;
38
- }
39
- const content = await readFile(metadataPath);
40
- const metadata = parseYaml(content);
41
- return metadata.forked_from ?? null;
42
- }
43
- async function getLocalSkillsWithMetadata(projectDir) {
44
- const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);
45
- const result = /* @__PURE__ */ new Map();
46
- if (!await fileExists(localSkillsPath)) {
47
- return result;
48
- }
49
- const skillDirs = await listDirectories(localSkillsPath);
50
- for (const dirName of skillDirs) {
51
- const skillDir = path.join(localSkillsPath, dirName);
52
- const forkedFrom = await readForkedFromMetadata(skillDir);
53
- const skillId = forkedFrom?.skill_id ?? dirName;
54
- result.set(skillId, { dirName, forkedFrom });
55
- }
56
- return result;
57
- }
58
- async function computeSourceHash(sourcePath, skillPath) {
59
- const skillMdPath = path.join(sourcePath, "src", skillPath, "SKILL.md");
60
- if (!await fileExists(skillMdPath)) {
61
- return null;
62
- }
63
- return hashFile(skillMdPath);
64
- }
65
- async function compareSkills(projectDir, sourcePath, sourceSkills) {
66
- const results = [];
67
- const localSkills = await getLocalSkillsWithMetadata(projectDir);
68
- for (const [skillId, { forkedFrom }] of localSkills) {
69
- if (!forkedFrom) {
70
- results.push({
71
- id: skillId,
72
- localHash: null,
73
- sourceHash: null,
74
- status: "local-only"
75
- });
76
- continue;
77
- }
78
- const localHash = forkedFrom.content_hash;
79
- const sourceSkill = sourceSkills[forkedFrom.skill_id];
80
- if (!sourceSkill) {
81
- results.push({
82
- id: forkedFrom.skill_id,
83
- localHash,
84
- sourceHash: null,
85
- status: "local-only"
86
- });
87
- continue;
88
- }
89
- const sourceHash = await computeSourceHash(sourcePath, sourceSkill.path);
90
- if (sourceHash === null) {
91
- results.push({
92
- id: forkedFrom.skill_id,
93
- localHash,
94
- sourceHash: null,
95
- status: "local-only"
96
- });
97
- continue;
98
- }
99
- const status = localHash === sourceHash ? "current" : "outdated";
100
- results.push({
101
- id: forkedFrom.skill_id,
102
- localHash,
103
- sourceHash,
104
- status
105
- });
106
- }
107
- results.sort((a, b) => a.id.localeCompare(b.id));
108
- return results;
109
- }
26
+ import { countBy } from "remeda";
110
27
  function calculateSummary(results) {
28
+ const counts = countBy(results, (r) => r.status);
111
29
  return {
112
- outdated: results.filter((r) => r.status === "outdated").length,
113
- current: results.filter((r) => r.status === "current").length,
114
- localOnly: results.filter((r) => r.status === "local-only").length
30
+ outdated: counts["outdated"] ?? 0,
31
+ current: counts["current"] ?? 0,
32
+ localOnly: counts["local-only"] ?? 0
115
33
  };
116
34
  }
117
35
  function formatHash(hash, isLocal) {
@@ -160,6 +78,7 @@ var Outdated = class _Outdated extends BaseCommand {
160
78
  }
161
79
  const sourceSkills = {};
162
80
  for (const [skillId, skill] of Object.entries(matrix.skills)) {
81
+ if (!skill) continue;
163
82
  if (!skill.local) {
164
83
  sourceSkills[skillId] = { path: skill.path };
165
84
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/outdated.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport path from \"path\";\nimport { parse as parseYaml } from \"yaml\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport { hashFile } from \"../lib/versioning.js\";\nimport { fileExists, readFile, listDirectories } from \"../utils/fs.js\";\nimport { LOCAL_SKILLS_PATH } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\n\n/**\n * Status values for skill comparison\n */\ntype SkillStatus = \"current\" | \"outdated\" | \"local-only\";\n\n/**\n * Result of comparing a local skill to its source\n */\ninterface SkillComparisonResult {\n id: string;\n localHash: string | null;\n sourceHash: string | null;\n status: SkillStatus;\n}\n\n/**\n * Summary counts for the comparison results\n */\ninterface ComparisonSummary {\n outdated: number;\n current: number;\n localOnly: number;\n}\n\n/**\n * ForkedFrom metadata stored in local skill's metadata.yaml\n */\ninterface ForkedFromMetadata {\n skill_id: string;\n content_hash: string;\n date: string;\n}\n\n/**\n * Local skill metadata structure\n */\ninterface LocalSkillMetadata {\n forked_from?: ForkedFromMetadata;\n [key: string]: unknown;\n}\n\n/**\n * Read forked_from metadata from a local skill's metadata.yaml\n */\nasync function readForkedFromMetadata(\n skillDir: string,\n): Promise<ForkedFromMetadata | null> {\n const metadataPath = path.join(skillDir, \"metadata.yaml\");\n\n if (!(await fileExists(metadataPath))) {\n return null;\n }\n\n const content = await readFile(metadataPath);\n const metadata = parseYaml(content) as LocalSkillMetadata;\n\n return metadata.forked_from ?? null;\n}\n\n/**\n * Get local skills with their forked_from metadata\n */\nasync function getLocalSkillsWithMetadata(\n projectDir: string,\n): Promise<\n Map<string, { dirName: string; forkedFrom: ForkedFromMetadata | null }>\n> {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n const result = new Map<\n string,\n { dirName: string; forkedFrom: ForkedFromMetadata | null }\n >();\n\n if (!(await fileExists(localSkillsPath))) {\n return result;\n }\n\n const skillDirs = await listDirectories(localSkillsPath);\n\n for (const dirName of skillDirs) {\n const skillDir = path.join(localSkillsPath, dirName);\n const forkedFrom = await readForkedFromMetadata(skillDir);\n\n // Use the skill_id from forked_from if available, otherwise use directory name\n const skillId = forkedFrom?.skill_id ?? dirName;\n\n result.set(skillId, { dirName, forkedFrom });\n }\n\n return result;\n}\n\n/**\n * Compute source hash for a skill's SKILL.md file\n */\nasync function computeSourceHash(\n sourcePath: string,\n skillPath: string,\n): Promise<string | null> {\n const skillMdPath = path.join(sourcePath, \"src\", skillPath, \"SKILL.md\");\n\n if (!(await fileExists(skillMdPath))) {\n return null;\n }\n\n return hashFile(skillMdPath);\n}\n\n/**\n * Compare local skills against source and determine status\n */\nasync function compareSkills(\n projectDir: string,\n sourcePath: string,\n sourceSkills: Record<string, { path: string }>,\n): Promise<SkillComparisonResult[]> {\n const results: SkillComparisonResult[] = [];\n const localSkills = await getLocalSkillsWithMetadata(projectDir);\n\n // Process local skills\n for (const [skillId, { forkedFrom }] of localSkills) {\n if (!forkedFrom) {\n // Local-only skill (no forked_from metadata)\n results.push({\n id: skillId,\n localHash: null,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const localHash = forkedFrom.content_hash;\n const sourceSkill = sourceSkills[forkedFrom.skill_id];\n\n if (!sourceSkill) {\n // Skill was forked from a source that no longer exists\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const sourceHash = await computeSourceHash(sourcePath, sourceSkill.path);\n\n if (sourceHash === null) {\n // Source skill's SKILL.md not found\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash: null,\n status: \"local-only\",\n });\n continue;\n }\n\n const status: SkillStatus =\n localHash === sourceHash ? \"current\" : \"outdated\";\n\n results.push({\n id: forkedFrom.skill_id,\n localHash,\n sourceHash,\n status,\n });\n }\n\n // Sort results by skill ID\n results.sort((a, b) => a.id.localeCompare(b.id));\n\n return results;\n}\n\n/**\n * Calculate summary counts from comparison results\n */\nfunction calculateSummary(results: SkillComparisonResult[]): ComparisonSummary {\n return {\n outdated: results.filter((r) => r.status === \"outdated\").length,\n current: results.filter((r) => r.status === \"current\").length,\n localOnly: results.filter((r) => r.status === \"local-only\").length,\n };\n}\n\n/**\n * Format hash for display\n */\nfunction formatHash(hash: string | null, isLocal: boolean): string {\n if (hash === null) {\n return isLocal ? \"(local)\" : \"-\";\n }\n return hash;\n}\n\nexport default class Outdated extends BaseCommand {\n static summary =\n \"Check which local skills are out of date compared to source\";\n static description =\n \"Compare local skills against their source repository to identify outdated skills that need updating\";\n\n static flags = {\n ...BaseCommand.baseFlags,\n json: Flags.boolean({\n description: \"Output results as JSON\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Outdated);\n const projectDir = process.cwd();\n\n try {\n // Check if local skills directory exists\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n if (!(await fileExists(localSkillsPath))) {\n if (flags.json) {\n this.log(\n JSON.stringify({\n skills: [],\n summary: { outdated: 0, current: 0, localOnly: 0 },\n }),\n );\n } else {\n this.warn(\"No local skills found. Run `cc init` or `cc edit` first.\");\n }\n return;\n }\n\n if (!flags.json) {\n this.log(\"Loading skills...\");\n }\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n projectDir,\n });\n\n if (!flags.json) {\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n }\n\n // Build source skills map for lookup\n const sourceSkills: Record<string, { path: string }> = {};\n for (const [skillId, skill] of Object.entries(matrix.skills)) {\n if (!skill.local) {\n sourceSkills[skillId] = { path: skill.path };\n }\n }\n\n // Compare local skills against source\n const results = await compareSkills(projectDir, sourcePath, sourceSkills);\n const summary = calculateSummary(results);\n\n // Output results\n if (flags.json) {\n this.log(\n JSON.stringify(\n {\n skills: results.map((r) => ({\n id: r.id,\n localHash: r.localHash,\n sourceHash: r.sourceHash,\n status: r.status,\n })),\n summary: {\n outdated: summary.outdated,\n current: summary.current,\n localOnly: summary.localOnly,\n },\n },\n null,\n 2,\n ),\n );\n } else {\n this.log(\"\");\n if (results.length === 0) {\n this.logInfo(\"No local skills found to compare.\");\n } else {\n // Use @oclif/table for table output\n printTable({\n data: results.map((result) => ({\n skill: result.id,\n localHash: formatHash(result.localHash, true),\n sourceHash: formatHash(result.sourceHash, false),\n status: result.status,\n })),\n columns: [\n { key: \"skill\", name: \"Skill\" },\n { key: \"localHash\", name: \"Local Hash\" },\n { key: \"sourceHash\", name: \"Source Hash\" },\n { key: \"status\", name: \"Status\" },\n ],\n headerOptions: { bold: true },\n });\n\n this.log(\"\");\n\n // Display summary\n const parts: string[] = [];\n if (summary.outdated > 0) {\n parts.push(`${summary.outdated} outdated`);\n }\n if (summary.current > 0) {\n parts.push(`${summary.current} current`);\n }\n if (summary.localOnly > 0) {\n parts.push(`${summary.localOnly} local-only`);\n }\n this.log(`Summary: ${parts.join(\", \")}`);\n }\n this.log(\"\");\n }\n\n // Exit with appropriate code if there are outdated skills\n if (summary.outdated > 0) {\n this.error(\"Some skills are outdated\", { exit: EXIT_CODES.ERROR });\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (flags.json) {\n this.error(JSON.stringify({ error: message }), {\n exit: EXIT_CODES.ERROR,\n });\n } else {\n this.error(`Error: ${message}`, { exit: EXIT_CODES.ERROR });\n }\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAS,aAAa;AACtB,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AACjB,SAAS,SAAS,iBAAiB;AAoDnC,eAAe,uBACb,UACoC;AACpC,QAAM,eAAe,KAAK,KAAK,UAAU,eAAe;AAExD,MAAI,CAAE,MAAM,WAAW,YAAY,GAAI;AACrC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,MAAM,SAAS,YAAY;AAC3C,QAAM,WAAW,UAAU,OAAO;AAElC,SAAO,SAAS,eAAe;AACjC;AAKA,eAAe,2BACb,YAGA;AACA,QAAM,kBAAkB,KAAK,KAAK,YAAY,iBAAiB;AAC/D,QAAM,SAAS,oBAAI,IAGjB;AAEF,MAAI,CAAE,MAAM,WAAW,eAAe,GAAI;AACxC,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,MAAM,gBAAgB,eAAe;AAEvD,aAAW,WAAW,WAAW;AAC/B,UAAM,WAAW,KAAK,KAAK,iBAAiB,OAAO;AACnD,UAAM,aAAa,MAAM,uBAAuB,QAAQ;AAGxD,UAAM,UAAU,YAAY,YAAY;AAExC,WAAO,IAAI,SAAS,EAAE,SAAS,WAAW,CAAC;AAAA,EAC7C;AAEA,SAAO;AACT;AAKA,eAAe,kBACb,YACA,WACwB;AACxB,QAAM,cAAc,KAAK,KAAK,YAAY,OAAO,WAAW,UAAU;AAEtE,MAAI,CAAE,MAAM,WAAW,WAAW,GAAI;AACpC,WAAO;AAAA,EACT;AAEA,SAAO,SAAS,WAAW;AAC7B;AAKA,eAAe,cACb,YACA,YACA,cACkC;AAClC,QAAM,UAAmC,CAAC;AAC1C,QAAM,cAAc,MAAM,2BAA2B,UAAU;AAG/D,aAAW,CAAC,SAAS,EAAE,WAAW,CAAC,KAAK,aAAa;AACnD,QAAI,CAAC,YAAY;AAEf,cAAQ,KAAK;AAAA,QACX,IAAI;AAAA,QACJ,WAAW;AAAA,QACX,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AACD;AAAA,IACF;AAEA,UAAM,YAAY,WAAW;AAC7B,UAAM,cAAc,aAAa,WAAW,QAAQ;AAEpD,QAAI,CAAC,aAAa;AAEhB,cAAQ,KAAK;AAAA,QACX,IAAI,WAAW;AAAA,QACf;AAAA,QACA,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AACD;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,kBAAkB,YAAY,YAAY,IAAI;AAEvE,QAAI,eAAe,MAAM;AAEvB,cAAQ,KAAK;AAAA,QACX,IAAI,WAAW;AAAA,QACf;AAAA,QACA,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV,CAAC;AACD;AAAA,IACF;AAEA,UAAM,SACJ,cAAc,aAAa,YAAY;AAEzC,YAAQ,KAAK;AAAA,MACX,IAAI,WAAW;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAAA,EACH;AAGA,UAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,GAAG,cAAc,EAAE,EAAE,CAAC;AAE/C,SAAO;AACT;AAKA,SAAS,iBAAiB,SAAqD;AAC7E,SAAO;AAAA,IACL,UAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,UAAU,EAAE;AAAA,IACzD,SAAS,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AAAA,IACvD,WAAW,QAAQ,OAAO,CAAC,MAAM,EAAE,WAAW,YAAY,EAAE;AAAA,EAC9D;AACF;AAKA,SAAS,WAAW,MAAqB,SAA0B;AACjE,MAAI,SAAS,MAAM;AACjB,WAAO,UAAU,YAAY;AAAA,EAC/B;AACA,SAAO;AACT;AAEA,IAAqB,WAArB,MAAqB,kBAAiB,YAAY;AAAA,EAChD,OAAO,UACL;AAAA,EACF,OAAO,cACL;AAAA,EAEF,OAAO,QAAQ;AAAA,IACb,GAAG,YAAY;AAAA,IACf,MAAM,MAAM,QAAQ;AAAA,MAClB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,IAAI,MAAM,KAAK,MAAM,SAAQ;AAC3C,UAAM,aAAa,QAAQ,IAAI;AAE/B,QAAI;AAEF,YAAM,kBAAkB,KAAK,KAAK,YAAY,iBAAiB;AAC/D,UAAI,CAAE,MAAM,WAAW,eAAe,GAAI;AACxC,YAAI,MAAM,MAAM;AACd,eAAK;AAAA,YACH,KAAK,UAAU;AAAA,cACb,QAAQ,CAAC;AAAA,cACT,SAAS,EAAE,UAAU,GAAG,SAAS,GAAG,WAAW,EAAE;AAAA,YACnD,CAAC;AAAA,UACH;AAAA,QACF,OAAO;AACL,eAAK,KAAK,0DAA0D;AAAA,QACtE;AACA;AAAA,MACF;AAEA,UAAI,CAAC,MAAM,MAAM;AACf,aAAK,IAAI,mBAAmB;AAAA,MAC9B;AAEA,YAAM,EAAE,QAAQ,YAAY,QAAQ,IAAI,MAAM,2BAA2B;AAAA,QACvE,YAAY,MAAM;AAAA,QAClB;AAAA,MACF,CAAC;AAED,UAAI,CAAC,MAAM,MAAM;AACf,aAAK,IAAI,eAAe,UAAU,UAAU,QAAQ,KAAK,UAAU,EAAE;AAAA,MACvE;AAGA,YAAM,eAAiD,CAAC;AACxD,iBAAW,CAAC,SAAS,KAAK,KAAK,OAAO,QAAQ,OAAO,MAAM,GAAG;AAC5D,YAAI,CAAC,MAAM,OAAO;AAChB,uBAAa,OAAO,IAAI,EAAE,MAAM,MAAM,KAAK;AAAA,QAC7C;AAAA,MACF;AAGA,YAAM,UAAU,MAAM,cAAc,YAAY,YAAY,YAAY;AACxE,YAAM,UAAU,iBAAiB,OAAO;AAGxC,UAAI,MAAM,MAAM;AACd,aAAK;AAAA,UACH,KAAK;AAAA,YACH;AAAA,cACE,QAAQ,QAAQ,IAAI,CAAC,OAAO;AAAA,gBAC1B,IAAI,EAAE;AAAA,gBACN,WAAW,EAAE;AAAA,gBACb,YAAY,EAAE;AAAA,gBACd,QAAQ,EAAE;AAAA,cACZ,EAAE;AAAA,cACF,SAAS;AAAA,gBACP,UAAU,QAAQ;AAAA,gBAClB,SAAS,QAAQ;AAAA,gBACjB,WAAW,QAAQ;AAAA,cACrB;AAAA,YACF;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF,OAAO;AACL,aAAK,IAAI,EAAE;AACX,YAAI,QAAQ,WAAW,GAAG;AACxB,eAAK,QAAQ,mCAAmC;AAAA,QAClD,OAAO;AAEL,qBAAW;AAAA,YACT,MAAM,QAAQ,IAAI,CAAC,YAAY;AAAA,cAC7B,OAAO,OAAO;AAAA,cACd,WAAW,WAAW,OAAO,WAAW,IAAI;AAAA,cAC5C,YAAY,WAAW,OAAO,YAAY,KAAK;AAAA,cAC/C,QAAQ,OAAO;AAAA,YACjB,EAAE;AAAA,YACF,SAAS;AAAA,cACP,EAAE,KAAK,SAAS,MAAM,QAAQ;AAAA,cAC9B,EAAE,KAAK,aAAa,MAAM,aAAa;AAAA,cACvC,EAAE,KAAK,cAAc,MAAM,cAAc;AAAA,cACzC,EAAE,KAAK,UAAU,MAAM,SAAS;AAAA,YAClC;AAAA,YACA,eAAe,EAAE,MAAM,KAAK;AAAA,UAC9B,CAAC;AAED,eAAK,IAAI,EAAE;AAGX,gBAAM,QAAkB,CAAC;AACzB,cAAI,QAAQ,WAAW,GAAG;AACxB,kBAAM,KAAK,GAAG,QAAQ,QAAQ,WAAW;AAAA,UAC3C;AACA,cAAI,QAAQ,UAAU,GAAG;AACvB,kBAAM,KAAK,GAAG,QAAQ,OAAO,UAAU;AAAA,UACzC;AACA,cAAI,QAAQ,YAAY,GAAG;AACzB,kBAAM,KAAK,GAAG,QAAQ,SAAS,aAAa;AAAA,UAC9C;AACA,eAAK,IAAI,YAAY,MAAM,KAAK,IAAI,CAAC,EAAE;AAAA,QACzC;AACA,aAAK,IAAI,EAAE;AAAA,MACb;AAGA,UAAI,QAAQ,WAAW,GAAG;AACxB,aAAK,MAAM,4BAA4B,EAAE,MAAM,WAAW,MAAM,CAAC;AAAA,MACnE;AAAA,IACF,SAAS,OAAO;AACd,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAErE,UAAI,MAAM,MAAM;AACd,aAAK,MAAM,KAAK,UAAU,EAAE,OAAO,QAAQ,CAAC,GAAG;AAAA,UAC7C,MAAM,WAAW;AAAA,QACnB,CAAC;AAAA,MACH,OAAO;AACL,aAAK,MAAM,UAAU,OAAO,IAAI,EAAE,MAAM,WAAW,MAAM,CAAC;AAAA,MAC5D;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/outdated.ts"],"sourcesContent":["import { Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport path from \"path\";\nimport { countBy } from \"remeda\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/loading/index.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { compareSkills, type SkillComparisonResult } from \"../lib/skills/index.js\";\nimport { fileExists } from \"../utils/fs.js\";\nimport { LOCAL_SKILLS_PATH } from \"../consts.js\";\n\ntype ComparisonSummary = {\n outdated: number;\n current: number;\n localOnly: number;\n};\n\nfunction calculateSummary(results: SkillComparisonResult[]): ComparisonSummary {\n const counts = countBy(results, (r) => r.status);\n return {\n outdated: counts[\"outdated\"] ?? 0,\n current: counts[\"current\"] ?? 0,\n localOnly: counts[\"local-only\"] ?? 0,\n };\n}\n\nfunction formatHash(hash: string | null, isLocal: boolean): string {\n if (hash === null) {\n return isLocal ? \"(local)\" : \"-\";\n }\n return hash;\n}\n\nexport default class Outdated extends BaseCommand {\n static summary = \"Check which local skills are out of date compared to source\";\n static description =\n \"Compare local skills against their source repository to identify outdated skills that need updating\";\n\n static flags = {\n ...BaseCommand.baseFlags,\n json: Flags.boolean({\n description: \"Output results as JSON\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Outdated);\n const projectDir = process.cwd();\n\n try {\n const localSkillsPath = path.join(projectDir, LOCAL_SKILLS_PATH);\n if (!(await fileExists(localSkillsPath))) {\n if (flags.json) {\n this.log(\n JSON.stringify({\n skills: [],\n summary: { outdated: 0, current: 0, localOnly: 0 },\n }),\n );\n } else {\n this.warn(\"No local skills found. Run `cc init` or `cc edit` first.\");\n }\n return;\n }\n\n if (!flags.json) {\n this.log(\"Loading skills...\");\n }\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n projectDir,\n });\n\n if (!flags.json) {\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n }\n\n const sourceSkills: Record<string, { path: string }> = {};\n for (const [skillId, skill] of Object.entries(matrix.skills)) {\n if (!skill) continue;\n if (!skill.local) {\n sourceSkills[skillId] = { path: skill.path };\n }\n }\n\n const results = await compareSkills(projectDir, sourcePath, sourceSkills);\n const summary = calculateSummary(results);\n\n if (flags.json) {\n this.log(\n JSON.stringify(\n {\n skills: results.map((r) => ({\n id: r.id,\n localHash: r.localHash,\n sourceHash: r.sourceHash,\n status: r.status,\n })),\n summary: {\n outdated: summary.outdated,\n current: summary.current,\n localOnly: summary.localOnly,\n },\n },\n null,\n 2,\n ),\n );\n } else {\n this.log(\"\");\n if (results.length === 0) {\n this.logInfo(\"No local skills found to compare.\");\n } else {\n printTable({\n data: results.map((result) => ({\n skill: result.id,\n localHash: formatHash(result.localHash, true),\n sourceHash: formatHash(result.sourceHash, false),\n status: result.status,\n })),\n columns: [\n { key: \"skill\", name: \"Skill\" },\n { key: \"localHash\", name: \"Local Hash\" },\n { key: \"sourceHash\", name: \"Source Hash\" },\n { key: \"status\", name: \"Status\" },\n ],\n headerOptions: { bold: true },\n });\n\n this.log(\"\");\n\n const parts: string[] = [];\n if (summary.outdated > 0) {\n parts.push(`${summary.outdated} outdated`);\n }\n if (summary.current > 0) {\n parts.push(`${summary.current} current`);\n }\n if (summary.localOnly > 0) {\n parts.push(`${summary.localOnly} local-only`);\n }\n this.log(`Summary: ${parts.join(\", \")}`);\n }\n this.log(\"\");\n }\n\n if (summary.outdated > 0) {\n this.error(\"Some skills are outdated\", { exit: EXIT_CODES.ERROR });\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (flags.json) {\n this.error(JSON.stringify({ error: message }), {\n exit: EXIT_CODES.ERROR,\n });\n } else {\n this.error(`Error: ${message}`, { exit: EXIT_CODES.ERROR });\n }\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,35 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SkillSearch
4
- } from "../chunk-ACNBKXXJ.js";
5
- import "../chunk-Z2CWURZ6.js";
6
- import {
7
- loadSkillsMatrixFromSource
8
- } from "../chunk-RFTSZDHV.js";
9
- import "../chunk-B7CCVP6Q.js";
10
- import {
11
- fetchFromSource
12
- } from "../chunk-IMDW5ZUP.js";
4
+ } from "../chunk-GGFOD5PK.js";
5
+ import "../chunk-UNN7523L.js";
13
6
  import {
14
7
  BaseCommand,
15
8
  EXIT_CODES
16
- } from "../chunk-EHS3TWWP.js";
9
+ } from "../chunk-OBXAY23Y.js";
17
10
  import {
11
+ fetchFromSource,
12
+ loadSkillsMatrixFromSource,
18
13
  resolveAllSources
19
- } from "../chunk-V46GGCCI.js";
20
- import "../chunk-3U3R4NCG.js";
14
+ } from "../chunk-YDBSSAJ6.js";
21
15
  import {
22
16
  copy,
23
17
  ensureDir,
24
18
  fileExists,
25
19
  listDirectories
26
- } from "../chunk-TKFPKEV3.js";
20
+ } from "../chunk-ZDREFYD2.js";
21
+ import "../chunk-HWD32NP7.js";
27
22
  import {
28
23
  LOCAL_SKILLS_PATH
29
- } from "../chunk-76DWXGQE.js";
24
+ } from "../chunk-O6ZTD7ZI.js";
30
25
  import {
31
26
  init_esm_shims
32
- } from "../chunk-DHET7RCE.js";
27
+ } from "../chunk-AWKZ5BDL.js";
33
28
 
34
29
  // src/cli/commands/search.tsx
35
30
  init_esm_shims();
@@ -37,6 +32,7 @@ import { Args, Flags } from "@oclif/core";
37
32
  import { render } from "ink";
38
33
  import { printTable } from "@oclif/table";
39
34
  import path from "path";
35
+ import { sortBy } from "remeda";
40
36
 
41
37
  // src/cli/components/skill-search/index.ts
42
38
  init_esm_shims();
@@ -51,9 +47,8 @@ function truncate(str, maxLength) {
51
47
  }
52
48
  function matchesQuery(skill, query) {
53
49
  const lowerQuery = query.toLowerCase();
54
- if (skill.name.toLowerCase().includes(lowerQuery)) return true;
55
50
  if (skill.id.toLowerCase().includes(lowerQuery)) return true;
56
- if (skill.alias?.toLowerCase().includes(lowerQuery)) return true;
51
+ if (skill.displayName?.toLowerCase().includes(lowerQuery)) return true;
57
52
  if (skill.description.toLowerCase().includes(lowerQuery)) return true;
58
53
  if (skill.category.toLowerCase().includes(lowerQuery)) return true;
59
54
  if (skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))) {
@@ -85,18 +80,17 @@ async function fetchSkillsFromSource(source, forceRefresh) {
85
80
  const skillMdPath = path.join(skillsDir, skillDir, "SKILL.md");
86
81
  if (await fileExists(skillMdPath)) {
87
82
  skills.push({
83
+ // Directory name is an untyped string — cast at data boundary
88
84
  id: skillDir,
89
- name: skillDir.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" "),
90
85
  description: `Skill from ${source.name}`,
86
+ // Synthetic category for third-party sources — not in CategoryPath union
91
87
  category: "imported",
92
88
  categoryExclusive: false,
93
89
  tags: [],
94
90
  author: "@" + source.name,
95
91
  conflictsWith: [],
96
92
  recommends: [],
97
- recommendedBy: [],
98
93
  requires: [],
99
- requiredBy: [],
100
94
  alternatives: [],
101
95
  discourages: [],
102
96
  compatibleWith: [],
@@ -115,7 +109,7 @@ async function fetchSkillsFromSource(source, forceRefresh) {
115
109
  }
116
110
  var Search = class _Search extends BaseCommand {
117
111
  static summary = "Search available skills";
118
- static description = "Search skills by name, description, category, or tags. Run without arguments or with -i for interactive mode with multi-select.";
112
+ static description = "Search skills by ID, alias, description, category, or tags. Run without arguments or with -i for interactive mode with multi-select.";
119
113
  static examples = [
120
114
  {
121
115
  description: "Search for React skills",
@@ -167,9 +161,6 @@ var Search = class _Search extends BaseCommand {
167
161
  await this.runStatic(args.query, flags);
168
162
  }
169
163
  }
170
- /**
171
- * Run interactive search mode with full-screen UI
172
- */
173
164
  async runInteractive(initialQuery, forceRefresh, projectDir) {
174
165
  this.log("Loading skills from all sources...");
175
166
  try {
@@ -178,21 +169,14 @@ var Search = class _Search extends BaseCommand {
178
169
  projectDir,
179
170
  forceRefresh
180
171
  });
181
- const primarySkills = Object.values(matrix.skills).map(
182
- (skill) => toSourcedSkill(skill, "marketplace", sourcePath)
183
- );
172
+ const primarySkills = Object.values(matrix.skills).filter((skill) => skill !== void 0).map((skill) => toSourcedSkill(skill, "marketplace", sourcePath));
184
173
  const { extras } = await resolveAllSources(projectDir);
185
174
  const extraSkillArrays = await Promise.all(
186
175
  extras.map((source) => fetchSkillsFromSource(source, forceRefresh))
187
176
  );
188
- const allSkills = [
189
- ...primarySkills,
190
- ...extraSkillArrays.flat()
191
- ];
177
+ const allSkills = [...primarySkills, ...extraSkillArrays.flat()];
192
178
  const sourceCount = 1 + extras.length;
193
- this.log(
194
- `Loaded ${allSkills.length} skills from ${sourceCount} source(s)`
195
- );
179
+ this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);
196
180
  this.log("");
197
181
  const searchResultPromise = new Promise((resolve) => {
198
182
  const { waitUntilExit } = render(
@@ -245,9 +229,6 @@ var Search = class _Search extends BaseCommand {
245
229
  this.handleError(error);
246
230
  }
247
231
  }
248
- /**
249
- * Run static search mode with table output
250
- */
251
232
  async runStatic(query, flags) {
252
233
  try {
253
234
  this.log("Loading skills...");
@@ -255,14 +236,14 @@ var Search = class _Search extends BaseCommand {
255
236
  sourceFlag: flags.source
256
237
  });
257
238
  this.log(`Loaded from ${isLocal ? "local" : "remote"}: ${sourcePath}`);
258
- const allSkills = Object.values(matrix.skills);
239
+ const allSkills = Object.values(matrix.skills).filter(
240
+ (skill) => skill !== void 0
241
+ );
259
242
  let results = allSkills.filter((skill) => matchesQuery(skill, query));
260
243
  if (flags.category) {
261
- results = results.filter(
262
- (skill) => matchesCategory(skill, flags.category)
263
- );
244
+ results = results.filter((skill) => matchesCategory(skill, flags.category));
264
245
  }
265
- results.sort((a, b) => a.name.localeCompare(b.name));
246
+ results = sortBy(results, (r) => r.displayName || r.id);
266
247
  this.log("");
267
248
  if (results.length === 0) {
268
249
  this.warn(`No skills found matching "${query}"`);
@@ -279,7 +260,7 @@ var Search = class _Search extends BaseCommand {
279
260
  this.log("");
280
261
  printTable({
281
262
  data: results.map((skill) => ({
282
- id: skill.alias || skill.id,
263
+ id: skill.displayName || skill.id,
283
264
  category: skill.category,
284
265
  description: truncate(skill.description, MAX_DESCRIPTION_WIDTH)
285
266
  })),
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/search.tsx","../../src/cli/components/skill-search/index.ts"],"sourcesContent":["/**\n * Search available skills command.\n *\n * Supports two modes:\n * - Static mode (with query arg): Traditional table output for scripting\n * - Interactive mode (no args or -i flag): Full-screen search with multi-select\n *\n * Interactive mode features:\n * - Live filtering as you type\n * - Multi-select for batch import\n * - Keyboard navigation (arrows, vim keys)\n * - Copy skill link to clipboard\n */\nimport React from \"react\";\nimport { Args, Flags } from \"@oclif/core\";\nimport { render } from \"ink\";\nimport { printTable } from \"@oclif/table\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource } from \"../lib/source-loader.js\";\nimport { resolveAllSources, type SourceEntry } from \"../lib/config.js\";\nimport { fetchFromSource } from \"../lib/source-fetcher.js\";\nimport { listDirectories, fileExists, copy, ensureDir } from \"../utils/fs.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport {\n SkillSearch,\n type SkillSearchResult,\n} from \"../components/skill-search/index.js\";\nimport type { SourcedSkill } from \"../components/skill-search/skill-search.js\";\nimport type { ResolvedSkill } from \"../types-matrix.js\";\nimport { LOCAL_SKILLS_PATH } from \"../consts.js\";\n\n/**\n * Maximum description width for table output\n */\nconst MAX_DESCRIPTION_WIDTH = 50;\n\n/** Default skills subdirectory in third-party repos */\nconst DEFAULT_SKILLS_SUBDIR = \"skills\";\n\n/**\n * Truncate a string to a maximum length with ellipsis\n */\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return str.slice(0, maxLength - 3) + \"...\";\n}\n\n/**\n * Check if a skill matches the search query (case-insensitive)\n */\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n\n // Match against name\n if (skill.name.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against ID\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against alias\n if (skill.alias?.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against description\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against category\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n // Match against tags\n if (skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Check if a skill matches the category filter (case-insensitive)\n */\nfunction matchesCategory(skill: ResolvedSkill, category: string): boolean {\n const lowerCategory = category.toLowerCase();\n return skill.category.toLowerCase().includes(lowerCategory);\n}\n\n/**\n * Convert ResolvedSkill to SourcedSkill with source attribution\n */\nfunction toSourcedSkill(\n skill: ResolvedSkill,\n sourceName: string,\n sourceUrl?: string,\n): SourcedSkill {\n return {\n ...skill,\n sourceName,\n sourceUrl,\n };\n}\n\n/**\n * Fetch skills from a third-party source.\n * Returns array of SourcedSkills with source attribution.\n */\nasync function fetchSkillsFromSource(\n source: SourceEntry,\n forceRefresh: boolean,\n): Promise<SourcedSkill[]> {\n try {\n const result = await fetchFromSource(source.url, { forceRefresh });\n const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);\n\n // Check if skills directory exists\n if (!(await fileExists(skillsDir))) {\n return [];\n }\n\n // List skill directories\n const skillDirs = await listDirectories(skillsDir);\n const skills: SourcedSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, \"SKILL.md\");\n if (await fileExists(skillMdPath)) {\n // Create a minimal skill entry\n skills.push({\n id: skillDir,\n name: skillDir\n .split(\"-\")\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1))\n .join(\" \"),\n description: `Skill from ${source.name}`,\n category: \"imported\",\n categoryExclusive: false,\n tags: [],\n author: \"@\" + source.name,\n conflictsWith: [],\n recommends: [],\n recommendedBy: [],\n requires: [],\n requiredBy: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n requiresSetup: [],\n providesSetupFor: [],\n sourceName: source.name,\n sourceUrl: source.url,\n path: path.join(skillsDir, skillDir),\n });\n }\n }\n\n return skills;\n } catch {\n // Source unavailable, return empty\n return [];\n }\n}\n\nexport default class Search extends BaseCommand {\n static summary = \"Search available skills\";\n static description =\n \"Search skills by name, description, category, or tags. \" +\n \"Run without arguments or with -i for interactive mode with multi-select.\";\n\n static examples = [\n {\n description: \"Search for React skills\",\n command: \"<%= config.bin %> search react\",\n },\n {\n description: \"Interactive search mode\",\n command: \"<%= config.bin %> search\",\n },\n {\n description: \"Interactive with pre-filled query\",\n command: \"<%= config.bin %> search -i react\",\n },\n {\n description: \"Search with category filter\",\n command: \"<%= config.bin %> search state -c frontend\",\n },\n ];\n\n static args = {\n query: Args.string({\n description: \"Search query (matches name, description, category, tags)\",\n required: false,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n interactive: Flags.boolean({\n char: \"i\",\n description: \"Launch interactive search with multi-select\",\n default: false,\n }),\n category: Flags.string({\n char: \"c\",\n description: \"Filter by category\",\n required: false,\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote sources\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Search);\n const projectDir = process.cwd();\n\n // Determine mode: interactive if no query or -i flag\n const isInteractive = flags.interactive || !args.query;\n\n if (isInteractive) {\n await this.runInteractive(args.query, flags.refresh, projectDir);\n } else {\n await this.runStatic(args.query!, flags);\n }\n }\n\n /**\n * Run interactive search mode with full-screen UI\n */\n private async runInteractive(\n initialQuery: string | undefined,\n forceRefresh: boolean,\n projectDir: string,\n ): Promise<void> {\n this.log(\"Loading skills from all sources...\");\n\n try {\n // Load primary source skills\n const { matrix, sourcePath } = await loadSkillsMatrixFromSource({\n sourceFlag: undefined,\n projectDir,\n forceRefresh,\n });\n\n // Convert to SourcedSkills\n const primarySkills = Object.values(matrix.skills).map((skill) =>\n toSourcedSkill(skill, \"marketplace\", sourcePath),\n );\n\n // Get configured extra sources\n const { extras } = await resolveAllSources(projectDir);\n\n // Fetch skills from extra sources\n const extraSkillArrays = await Promise.all(\n extras.map((source) => fetchSkillsFromSource(source, forceRefresh)),\n );\n\n // Merge all skills (primary first, then extras)\n const allSkills: SourcedSkill[] = [\n ...primarySkills,\n ...extraSkillArrays.flat(),\n ];\n\n // Total source count\n const sourceCount = 1 + extras.length;\n\n this.log(\n `Loaded ${allSkills.length} skills from ${sourceCount} source(s)`,\n );\n this.log(\"\");\n\n // Render interactive search\n const searchResultPromise = new Promise<SkillSearchResult>((resolve) => {\n const { waitUntilExit } = render(\n <SkillSearch\n skills={allSkills}\n sourceCount={sourceCount}\n initialQuery={initialQuery}\n onComplete={(result) => {\n resolve(result);\n }}\n onCancel={() => {\n resolve({ selectedSkills: [], cancelled: true });\n }}\n />,\n );\n\n // Also resolve on app exit\n waitUntilExit().then(() => {\n resolve({ selectedSkills: [], cancelled: true });\n });\n });\n\n const searchResult = await searchResultPromise;\n\n // Handle result\n if (searchResult.cancelled) {\n this.log(\"Search cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n\n if (searchResult.selectedSkills.length === 0) {\n this.log(\"No skills selected\");\n return;\n }\n\n // Import selected skills\n this.log(\"\");\n this.log(`Importing ${searchResult.selectedSkills.length} skill(s)...`);\n\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n for (const skill of searchResult.selectedSkills) {\n if (skill.path) {\n const destPath = path.join(destDir, skill.id);\n await ensureDir(path.dirname(destPath));\n await copy(skill.path, destPath);\n this.logSuccess(`Imported: ${skill.id}`);\n } else {\n this.warn(`Skipping ${skill.id}: No source path available`);\n }\n }\n\n this.log(\"\");\n this.logSuccess(\"Import complete!\");\n this.log(`Skills location: ${destDir}`);\n this.log(\"Run 'cc compile' to include imported skills in your agents.\");\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Run static search mode with table output\n */\n private async runStatic(\n query: string,\n flags: { source?: string; category?: string },\n ): Promise<void> {\n try {\n this.log(\"Loading skills...\");\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n });\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n // Get all skills as array\n const allSkills = Object.values(matrix.skills);\n\n // Filter by query\n let results = allSkills.filter((skill) => matchesQuery(skill, query));\n\n // Apply category filter if provided\n if (flags.category) {\n results = results.filter((skill) =>\n matchesCategory(skill, flags.category as string),\n );\n }\n\n // Sort results by name\n results.sort((a, b) => a.name.localeCompare(b.name));\n\n // Display results\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${query}\"`);\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n } else {\n this.logInfo(\n `Found ${results.length} skill${results.length === 1 ? \"\" : \"s\"} matching \"${query}\"`,\n );\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n this.log(\"\");\n\n // Use @oclif/table for table output\n printTable({\n data: results.map((skill) => ({\n id: skill.alias || skill.id,\n category: skill.category,\n description: truncate(skill.description, MAX_DESCRIPTION_WIDTH),\n })),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n }\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n","export {\n SkillSearch,\n type SkillSearchProps,\n type SkillSearchResult,\n} from \"./skill-search.js\";\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/search.tsx","../../src/cli/components/skill-search/index.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { render } from \"ink\";\nimport { printTable } from \"@oclif/table\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command.js\";\nimport { loadSkillsMatrixFromSource, fetchFromSource } from \"../lib/loading/index.js\";\nimport { resolveAllSources, type SourceEntry } from \"../lib/configuration/index.js\";\nimport { listDirectories, fileExists, copy, ensureDir } from \"../utils/fs.js\";\nimport { sortBy } from \"remeda\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { SkillSearch, type SkillSearchResult } from \"../components/skill-search/index.js\";\nimport type { SourcedSkill } from \"../components/skill-search/skill-search.js\";\nimport type { CategoryPath, ResolvedSkill, SkillId } from \"../types/index.js\";\nimport { LOCAL_SKILLS_PATH } from \"../consts.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\nconst DEFAULT_SKILLS_SUBDIR = \"skills\";\n\nfunction truncate(str: string, maxLength: number): string {\n if (str.length <= maxLength) return str;\n return str.slice(0, maxLength - 3) + \"...\";\n}\n\nfunction matchesQuery(skill: ResolvedSkill, query: string): boolean {\n const lowerQuery = query.toLowerCase();\n\n if (skill.id.toLowerCase().includes(lowerQuery)) return true;\n if (skill.displayName?.toLowerCase().includes(lowerQuery)) return true;\n if (skill.description.toLowerCase().includes(lowerQuery)) return true;\n if (skill.category.toLowerCase().includes(lowerQuery)) return true;\n\n if (skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery))) {\n return true;\n }\n\n return false;\n}\n\nfunction matchesCategory(skill: ResolvedSkill, category: CategoryPath): boolean {\n const lowerCategory = category.toLowerCase();\n return skill.category.toLowerCase().includes(lowerCategory);\n}\n\nfunction toSourcedSkill(\n skill: ResolvedSkill,\n sourceName: string,\n sourceUrl?: string,\n): SourcedSkill {\n return {\n ...skill,\n sourceName,\n sourceUrl,\n };\n}\n\nasync function fetchSkillsFromSource(\n source: SourceEntry,\n forceRefresh: boolean,\n): Promise<SourcedSkill[]> {\n try {\n const result = await fetchFromSource(source.url, { forceRefresh });\n const skillsDir = path.join(result.path, DEFAULT_SKILLS_SUBDIR);\n\n if (!(await fileExists(skillsDir))) {\n return [];\n }\n\n const skillDirs = await listDirectories(skillsDir);\n const skills: SourcedSkill[] = [];\n\n for (const skillDir of skillDirs) {\n const skillMdPath = path.join(skillsDir, skillDir, \"SKILL.md\");\n if (await fileExists(skillMdPath)) {\n skills.push({\n // Directory name is an untyped string — cast at data boundary\n id: skillDir as SkillId,\n description: `Skill from ${source.name}`,\n // Synthetic category for third-party sources — not in CategoryPath union\n category: \"imported\" as CategoryPath,\n categoryExclusive: false,\n tags: [],\n author: \"@\" + source.name,\n conflictsWith: [],\n recommends: [],\n requires: [],\n alternatives: [],\n discourages: [],\n compatibleWith: [],\n requiresSetup: [],\n providesSetupFor: [],\n sourceName: source.name,\n sourceUrl: source.url,\n path: path.join(skillsDir, skillDir),\n });\n }\n }\n\n return skills;\n } catch {\n // Source unavailable, return empty\n return [];\n }\n}\n\nexport default class Search extends BaseCommand {\n static summary = \"Search available skills\";\n static description =\n \"Search skills by ID, alias, description, category, or tags. \" +\n \"Run without arguments or with -i for interactive mode with multi-select.\";\n\n static examples = [\n {\n description: \"Search for React skills\",\n command: \"<%= config.bin %> search react\",\n },\n {\n description: \"Interactive search mode\",\n command: \"<%= config.bin %> search\",\n },\n {\n description: \"Interactive with pre-filled query\",\n command: \"<%= config.bin %> search -i react\",\n },\n {\n description: \"Search with category filter\",\n command: \"<%= config.bin %> search state -c frontend\",\n },\n ];\n\n static args = {\n query: Args.string({\n description: \"Search query (matches name, description, category, tags)\",\n required: false,\n }),\n };\n\n static flags = {\n ...BaseCommand.baseFlags,\n interactive: Flags.boolean({\n char: \"i\",\n description: \"Launch interactive search with multi-select\",\n default: false,\n }),\n category: Flags.string({\n char: \"c\",\n description: \"Filter by category\",\n required: false,\n }),\n refresh: Flags.boolean({\n description: \"Force refresh from remote sources\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { args, flags } = await this.parse(Search);\n const projectDir = process.cwd();\n\n const isInteractive = flags.interactive || !args.query;\n\n if (isInteractive) {\n await this.runInteractive(args.query, flags.refresh, projectDir);\n } else {\n await this.runStatic(args.query!, flags);\n }\n }\n\n private async runInteractive(\n initialQuery: string | undefined,\n forceRefresh: boolean,\n projectDir: string,\n ): Promise<void> {\n this.log(\"Loading skills from all sources...\");\n\n try {\n const { matrix, sourcePath } = await loadSkillsMatrixFromSource({\n sourceFlag: undefined,\n projectDir,\n forceRefresh,\n });\n\n const primarySkills = Object.values(matrix.skills)\n .filter((skill): skill is ResolvedSkill => skill !== undefined)\n .map((skill) => toSourcedSkill(skill, \"marketplace\", sourcePath));\n\n const { extras } = await resolveAllSources(projectDir);\n\n const extraSkillArrays = await Promise.all(\n extras.map((source) => fetchSkillsFromSource(source, forceRefresh)),\n );\n\n const allSkills: SourcedSkill[] = [...primarySkills, ...extraSkillArrays.flat()];\n const sourceCount = 1 + extras.length;\n\n this.log(`Loaded ${allSkills.length} skills from ${sourceCount} source(s)`);\n this.log(\"\");\n\n const searchResultPromise = new Promise<SkillSearchResult>((resolve) => {\n const { waitUntilExit } = render(\n <SkillSearch\n skills={allSkills}\n sourceCount={sourceCount}\n initialQuery={initialQuery}\n onComplete={(result) => {\n resolve(result);\n }}\n onCancel={() => {\n resolve({ selectedSkills: [], cancelled: true });\n }}\n />,\n );\n\n waitUntilExit().then(() => {\n resolve({ selectedSkills: [], cancelled: true });\n });\n });\n\n const searchResult = await searchResultPromise;\n\n if (searchResult.cancelled) {\n this.log(\"Search cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n\n if (searchResult.selectedSkills.length === 0) {\n this.log(\"No skills selected\");\n return;\n }\n\n this.log(\"\");\n this.log(`Importing ${searchResult.selectedSkills.length} skill(s)...`);\n\n const destDir = path.join(projectDir, LOCAL_SKILLS_PATH);\n\n for (const skill of searchResult.selectedSkills) {\n if (skill.path) {\n const destPath = path.join(destDir, skill.id);\n await ensureDir(path.dirname(destPath));\n await copy(skill.path, destPath);\n this.logSuccess(`Imported: ${skill.id}`);\n } else {\n this.warn(`Skipping ${skill.id}: No source path available`);\n }\n }\n\n this.log(\"\");\n this.logSuccess(\"Import complete!\");\n this.log(`Skills location: ${destDir}`);\n this.log(\"Run 'cc compile' to include imported skills in your agents.\");\n } catch (error) {\n this.handleError(error);\n }\n }\n\n private async runStatic(\n query: string,\n flags: { source?: string; category?: string },\n ): Promise<void> {\n try {\n this.log(\"Loading skills...\");\n\n const { matrix, sourcePath, isLocal } = await loadSkillsMatrixFromSource({\n sourceFlag: flags.source,\n });\n\n this.log(`Loaded from ${isLocal ? \"local\" : \"remote\"}: ${sourcePath}`);\n\n const allSkills = Object.values(matrix.skills).filter(\n (skill): skill is ResolvedSkill => skill !== undefined,\n );\n\n let results = allSkills.filter((skill) => matchesQuery(skill, query));\n\n if (flags.category) {\n // CLI flag is an untyped string — cast at data boundary\n results = results.filter((skill) => matchesCategory(skill, flags.category as CategoryPath));\n }\n\n results = sortBy(results, (r) => r.displayName || r.id);\n\n this.log(\"\");\n if (results.length === 0) {\n this.warn(`No skills found matching \"${query}\"`);\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n } else {\n this.logInfo(\n `Found ${results.length} skill${results.length === 1 ? \"\" : \"s\"} matching \"${query}\"`,\n );\n if (flags.category) {\n this.logInfo(`Category filter: ${flags.category}`);\n }\n this.log(\"\");\n\n printTable({\n data: results.map((skill) => ({\n id: skill.displayName || skill.id,\n category: skill.category,\n description: truncate(skill.description, MAX_DESCRIPTION_WIDTH),\n })),\n columns: [\n { key: \"id\", name: \"ID\" },\n { key: \"category\", name: \"Category\" },\n { key: \"description\", name: \"Description\" },\n ],\n headerOptions: { bold: true },\n });\n }\n this.log(\"\");\n } catch (error) {\n this.handleError(error);\n }\n }\n}\n","export { SkillSearch, type SkillSearchProps, type SkillSearchResult } from \"./skill-search.js\";\n"],"mappings":"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","names":[]}
@@ -1,31 +1,29 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  Confirm
4
- } from "../chunk-RTE64SJA.js";
5
- import {
6
- claudePluginUninstall,
7
- isClaudeCLIAvailable
8
- } from "../chunk-UQTEPWU7.js";
9
- import {
10
- getCollectivePluginDir
11
- } from "../chunk-ED4E6Q2T.js";
4
+ } from "../chunk-IXBCRT3F.js";
12
5
  import {
13
6
  BaseCommand,
14
7
  EXIT_CODES
15
- } from "../chunk-EHS3TWWP.js";
16
- import "../chunk-3U3R4NCG.js";
8
+ } from "../chunk-OBXAY23Y.js";
9
+ import {
10
+ claudePluginUninstall,
11
+ getCollectivePluginDir,
12
+ isClaudeCLIAvailable
13
+ } from "../chunk-YDBSSAJ6.js";
17
14
  import {
18
15
  directoryExists,
19
16
  fileExists,
20
17
  remove
21
- } from "../chunk-TKFPKEV3.js";
18
+ } from "../chunk-ZDREFYD2.js";
19
+ import "../chunk-HWD32NP7.js";
22
20
  import {
23
21
  CLAUDE_DIR,
24
22
  CLAUDE_SRC_DIR
25
- } from "../chunk-76DWXGQE.js";
23
+ } from "../chunk-O6ZTD7ZI.js";
26
24
  import {
27
25
  init_esm_shims
28
- } from "../chunk-DHET7RCE.js";
26
+ } from "../chunk-AWKZ5BDL.js";
29
27
 
30
28
  // src/cli/commands/uninstall.tsx
31
29
  init_esm_shims();
@@ -41,14 +39,7 @@ async function detectInstallation(projectDir) {
41
39
  const configPath = path.join(projectDir, CLAUDE_DIR, "config.yaml");
42
40
  const claudeDir = path.join(projectDir, CLAUDE_DIR);
43
41
  const claudeSrcDir = path.join(projectDir, CLAUDE_SRC_DIR);
44
- const [
45
- hasPlugin,
46
- hasLocalSkills,
47
- hasLocalAgents,
48
- hasLocalConfig,
49
- hasClaudeDir,
50
- hasClaudeSrcDir
51
- ] = await Promise.all([
42
+ const [hasPlugin, hasLocalSkills, hasLocalAgents, hasLocalConfig, hasClaudeDir, hasClaudeSrcDir] = await Promise.all([
52
43
  directoryExists(pluginDir),
53
44
  directoryExists(skillsDir),
54
45
  directoryExists(agentsDir),
@@ -241,16 +232,18 @@ var Uninstall = class _Uninstall extends BaseCommand {
241
232
  try {
242
233
  const cliAvailable = await isClaudeCLIAvailable();
243
234
  if (cliAvailable) {
244
- await claudePluginUninstall(PLUGIN_NAME, "project", projectDir);
235
+ try {
236
+ await claudePluginUninstall(PLUGIN_NAME, "project", projectDir);
237
+ } catch {
238
+ }
245
239
  }
246
240
  await remove(target.pluginDir);
247
241
  this.logSuccess("Plugin uninstalled");
248
242
  } catch (error) {
249
243
  this.log("Plugin uninstall failed");
250
- this.error(
251
- error instanceof Error ? error.message : "Unknown error occurred",
252
- { exit: EXIT_CODES.ERROR }
253
- );
244
+ this.error(error instanceof Error ? error.message : "Unknown error occurred", {
245
+ exit: EXIT_CODES.ERROR
246
+ });
254
247
  }
255
248
  }
256
249
  if (hasLocalToRemove) {
@@ -270,10 +263,9 @@ var Uninstall = class _Uninstall extends BaseCommand {
270
263
  );
271
264
  } catch (error) {
272
265
  this.log("Failed to remove local directories");
273
- this.error(
274
- error instanceof Error ? error.message : "Unknown error occurred",
275
- { exit: EXIT_CODES.ERROR }
276
- );
266
+ this.error(error instanceof Error ? error.message : "Unknown error occurred", {
267
+ exit: EXIT_CODES.ERROR
268
+ });
277
269
  }
278
270
  }
279
271
  this.log("");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/uninstall.tsx"],"sourcesContent":["import React from \"react\";\nimport { Flags } from \"@oclif/core\";\nimport { render, Box, Text, useApp } from \"ink\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command\";\nimport { Confirm } from \"../components/common/confirm\";\nimport { directoryExists, fileExists, remove } from \"../utils/fs\";\nimport { claudePluginUninstall, isClaudeCLIAvailable } from \"../utils/exec\";\nimport { getCollectivePluginDir } from \"../lib/plugin-finder\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR } from \"../consts\";\nimport { EXIT_CODES } from \"../lib/exit-codes\";\n\nconst PLUGIN_NAME = \"claude-collective\";\n\ninterface UninstallTarget {\n hasPlugin: boolean;\n hasLocalSkills: boolean;\n hasLocalAgents: boolean;\n hasLocalConfig: boolean;\n hasClaudeDir: boolean;\n hasClaudeSrcDir: boolean;\n pluginDir: string;\n skillsDir: string;\n agentsDir: string;\n configPath: string;\n claudeDir: string;\n claudeSrcDir: string;\n}\n\nasync function detectInstallation(\n projectDir: string,\n): Promise<UninstallTarget> {\n const pluginDir = getCollectivePluginDir(projectDir);\n const skillsDir = path.join(projectDir, CLAUDE_DIR, \"skills\");\n const agentsDir = path.join(projectDir, CLAUDE_DIR, \"agents\");\n const configPath = path.join(projectDir, CLAUDE_DIR, \"config.yaml\");\n const claudeDir = path.join(projectDir, CLAUDE_DIR);\n const claudeSrcDir = path.join(projectDir, CLAUDE_SRC_DIR);\n\n const [\n hasPlugin,\n hasLocalSkills,\n hasLocalAgents,\n hasLocalConfig,\n hasClaudeDir,\n hasClaudeSrcDir,\n ] = await Promise.all([\n directoryExists(pluginDir),\n directoryExists(skillsDir),\n directoryExists(agentsDir),\n fileExists(configPath),\n directoryExists(claudeDir),\n directoryExists(claudeSrcDir),\n ]);\n\n return {\n hasPlugin,\n hasLocalSkills,\n hasLocalAgents,\n hasLocalConfig,\n hasClaudeDir,\n hasClaudeSrcDir,\n pluginDir,\n skillsDir,\n agentsDir,\n configPath,\n claudeDir,\n claudeSrcDir,\n };\n}\n\ninterface UninstallConfirmProps {\n target: UninstallTarget;\n uninstallPlugin: boolean;\n uninstallLocal: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\nconst UninstallConfirm: React.FC<UninstallConfirmProps> = ({\n target,\n uninstallPlugin,\n uninstallLocal,\n onConfirm,\n onCancel,\n}) => {\n const { exit } = useApp();\n const hasPluginToRemove = uninstallPlugin && target.hasPlugin;\n const hasLocalToRemove =\n uninstallLocal && (target.hasClaudeDir || target.hasClaudeSrcDir);\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>The following will be removed:</Text>\n <Text> </Text>\n\n {hasPluginToRemove && (\n <Box flexDirection=\"column\">\n <Text color=\"red\"> Plugin:</Text>\n <Text dimColor> {target.pluginDir}</Text>\n </Box>\n )}\n\n {hasLocalToRemove && (\n <Box flexDirection=\"column\">\n <Text color=\"red\"> Local directories:</Text>\n {target.hasClaudeDir && <Text dimColor> {target.claudeDir}/</Text>}\n {target.hasClaudeSrcDir && (\n <Text dimColor> {target.claudeSrcDir}/</Text>\n )}\n </Box>\n )}\n\n <Text> </Text>\n <Confirm\n message=\"Are you sure you want to uninstall?\"\n onConfirm={() => {\n onConfirm();\n exit();\n }}\n onCancel={() => {\n onCancel();\n exit();\n }}\n defaultValue={false}\n />\n </Box>\n );\n};\n\nexport default class Uninstall extends BaseCommand {\n static summary = \"Remove Claude Collective from this project\";\n\n static description =\n \"Uninstall the Claude Collective plugin and/or local directories (.claude/ and .claude-src/). By default, removes everything.\";\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --yes\",\n \"<%= config.bin %> <%= command.id %> --plugin\",\n \"<%= config.bin %> <%= command.id %> --local\",\n \"<%= config.bin %> <%= command.id %> --dry-run\",\n ];\n\n static flags = {\n ...BaseCommand.baseFlags,\n yes: Flags.boolean({\n char: \"y\",\n description: \"Skip confirmation prompt\",\n default: false,\n }),\n plugin: Flags.boolean({\n description: \"Only uninstall the plugin (not local files)\",\n default: false,\n }),\n local: Flags.boolean({\n description: \"Only remove local files (not the plugin)\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Uninstall);\n const projectDir = process.cwd();\n\n this.log(\"\");\n this.log(\"Claude Collective Uninstall\");\n this.log(\"\");\n\n if (flags[\"dry-run\"]) {\n this.log(\"[dry-run] Preview mode - no files will be removed\");\n this.log(\"\");\n }\n\n // Detect what's installed\n const target = await detectInstallation(projectDir);\n\n // Determine what to uninstall based on flags\n const uninstallPlugin = !flags.local;\n const uninstallLocal = !flags.plugin;\n\n // Check if there's anything to uninstall\n const hasPluginToRemove = uninstallPlugin && target.hasPlugin;\n const hasLocalToRemove =\n uninstallLocal && (target.hasClaudeDir || target.hasClaudeSrcDir);\n\n if (!hasPluginToRemove && !hasLocalToRemove) {\n this.warn(\"Nothing to uninstall.\");\n this.log(\"\");\n\n if (flags.plugin && !target.hasPlugin) {\n this.log(\"No plugin installation found.\");\n }\n if (flags.local && !target.hasClaudeDir && !target.hasClaudeSrcDir) {\n this.log(\"No local installation found.\");\n }\n if (!flags.plugin && !flags.local) {\n this.log(\"Claude Collective is not installed in this project.\");\n }\n\n this.log(\"\");\n this.log(\"No changes made.\");\n return;\n }\n\n // Show what will be removed and get confirmation (unless --yes or --dry-run)\n if (!flags.yes && !flags[\"dry-run\"]) {\n const confirmed = await new Promise<boolean>((resolve) => {\n const { waitUntilExit } = render(\n <UninstallConfirm\n target={target}\n uninstallPlugin={uninstallPlugin}\n uninstallLocal={uninstallLocal}\n onConfirm={() => resolve(true)}\n onCancel={() => resolve(false)}\n />,\n );\n\n waitUntilExit().catch(() => resolve(false));\n });\n\n if (!confirmed) {\n this.log(\"\");\n this.log(\"Uninstall cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n } else {\n // In dry-run or --yes mode, just show what will be removed\n this.log(\"The following will be removed:\");\n this.log(\"\");\n\n if (hasPluginToRemove) {\n this.log(\" Plugin:\");\n this.log(` ${target.pluginDir}`);\n }\n\n if (hasLocalToRemove) {\n this.log(\" Local directories:\");\n if (target.hasClaudeDir) {\n this.log(` ${target.claudeDir}/`);\n }\n if (target.hasClaudeSrcDir) {\n this.log(` ${target.claudeSrcDir}/`);\n }\n }\n\n this.log(\"\");\n }\n\n // Dry run - show what would happen\n if (flags[\"dry-run\"]) {\n if (hasPluginToRemove) {\n this.log(`[dry-run] Would uninstall plugin \"${PLUGIN_NAME}\"`);\n this.log(`[dry-run] Would remove ${target.pluginDir}`);\n }\n if (hasLocalToRemove) {\n if (target.hasClaudeDir) {\n this.log(`[dry-run] Would remove ${target.claudeDir}/`);\n }\n if (target.hasClaudeSrcDir) {\n this.log(`[dry-run] Would remove ${target.claudeSrcDir}/`);\n }\n }\n this.log(\"\");\n this.log(\"[dry-run] Preview complete - no files were removed\");\n this.log(\"\");\n return;\n }\n\n // Uninstall plugin\n if (hasPluginToRemove) {\n this.log(\"Uninstalling plugin...\");\n\n try {\n // Try to use claude CLI to uninstall (handles settings.json)\n const cliAvailable = await isClaudeCLIAvailable();\n if (cliAvailable) {\n await claudePluginUninstall(PLUGIN_NAME, \"project\", projectDir);\n }\n\n // Remove plugin directory\n await remove(target.pluginDir);\n\n this.logSuccess(\"Plugin uninstalled\");\n } catch (error) {\n this.log(\"Plugin uninstall failed\");\n this.error(\n error instanceof Error ? error.message : \"Unknown error occurred\",\n { exit: EXIT_CODES.ERROR },\n );\n }\n }\n\n // Remove local directories\n if (hasLocalToRemove) {\n this.log(\"Removing local directories...\");\n\n try {\n const removed: string[] = [];\n\n if (target.hasClaudeDir) {\n await remove(target.claudeDir);\n removed.push(CLAUDE_DIR);\n }\n\n if (target.hasClaudeSrcDir) {\n await remove(target.claudeSrcDir);\n removed.push(CLAUDE_SRC_DIR);\n }\n\n this.logSuccess(\n `Removed ${removed.length} ${removed.length === 1 ? \"directory\" : \"directories\"}: ${removed.join(\", \")}`,\n );\n } catch (error) {\n this.log(\"Failed to remove local directories\");\n this.error(\n error instanceof Error ? error.message : \"Unknown error occurred\",\n { exit: EXIT_CODES.ERROR },\n );\n }\n }\n\n this.log(\"\");\n this.log(\"Claude Collective has been uninstalled.\");\n\n this.log(\"\");\n this.logSuccess(\"Uninstall complete!\");\n this.log(\"\");\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/uninstall.tsx"],"sourcesContent":["import React from \"react\";\nimport { Flags } from \"@oclif/core\";\nimport { render, Box, Text, useApp } from \"ink\";\nimport path from \"path\";\nimport { BaseCommand } from \"../base-command\";\nimport { Confirm } from \"../components/common/confirm\";\nimport { directoryExists, fileExists, remove } from \"../utils/fs\";\nimport { claudePluginUninstall, isClaudeCLIAvailable } from \"../utils/exec\";\nimport { getCollectivePluginDir } from \"../lib/plugins\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR } from \"../consts\";\nimport { EXIT_CODES } from \"../lib/exit-codes\";\n\nconst PLUGIN_NAME = \"claude-collective\";\n\ntype UninstallTarget = {\n hasPlugin: boolean;\n hasLocalSkills: boolean;\n hasLocalAgents: boolean;\n hasLocalConfig: boolean;\n hasClaudeDir: boolean;\n hasClaudeSrcDir: boolean;\n pluginDir: string;\n skillsDir: string;\n agentsDir: string;\n configPath: string;\n claudeDir: string;\n claudeSrcDir: string;\n};\n\nasync function detectInstallation(projectDir: string): Promise<UninstallTarget> {\n const pluginDir = getCollectivePluginDir(projectDir);\n const skillsDir = path.join(projectDir, CLAUDE_DIR, \"skills\");\n const agentsDir = path.join(projectDir, CLAUDE_DIR, \"agents\");\n const configPath = path.join(projectDir, CLAUDE_DIR, \"config.yaml\");\n const claudeDir = path.join(projectDir, CLAUDE_DIR);\n const claudeSrcDir = path.join(projectDir, CLAUDE_SRC_DIR);\n\n const [hasPlugin, hasLocalSkills, hasLocalAgents, hasLocalConfig, hasClaudeDir, hasClaudeSrcDir] =\n await Promise.all([\n directoryExists(pluginDir),\n directoryExists(skillsDir),\n directoryExists(agentsDir),\n fileExists(configPath),\n directoryExists(claudeDir),\n directoryExists(claudeSrcDir),\n ]);\n\n return {\n hasPlugin,\n hasLocalSkills,\n hasLocalAgents,\n hasLocalConfig,\n hasClaudeDir,\n hasClaudeSrcDir,\n pluginDir,\n skillsDir,\n agentsDir,\n configPath,\n claudeDir,\n claudeSrcDir,\n };\n}\n\ntype UninstallConfirmProps = {\n target: UninstallTarget;\n uninstallPlugin: boolean;\n uninstallLocal: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n};\n\nconst UninstallConfirm: React.FC<UninstallConfirmProps> = ({\n target,\n uninstallPlugin,\n uninstallLocal,\n onConfirm,\n onCancel,\n}) => {\n const { exit } = useApp();\n const hasPluginToRemove = uninstallPlugin && target.hasPlugin;\n const hasLocalToRemove = uninstallLocal && (target.hasClaudeDir || target.hasClaudeSrcDir);\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>The following will be removed:</Text>\n <Text> </Text>\n\n {hasPluginToRemove && (\n <Box flexDirection=\"column\">\n <Text color=\"red\"> Plugin:</Text>\n <Text dimColor> {target.pluginDir}</Text>\n </Box>\n )}\n\n {hasLocalToRemove && (\n <Box flexDirection=\"column\">\n <Text color=\"red\"> Local directories:</Text>\n {target.hasClaudeDir && <Text dimColor> {target.claudeDir}/</Text>}\n {target.hasClaudeSrcDir && <Text dimColor> {target.claudeSrcDir}/</Text>}\n </Box>\n )}\n\n <Text> </Text>\n <Confirm\n message=\"Are you sure you want to uninstall?\"\n onConfirm={() => {\n onConfirm();\n exit();\n }}\n onCancel={() => {\n onCancel();\n exit();\n }}\n defaultValue={false}\n />\n </Box>\n );\n};\n\nexport default class Uninstall extends BaseCommand {\n static summary = \"Remove Claude Collective from this project\";\n\n static description =\n \"Uninstall the Claude Collective plugin and/or local directories (.claude/ and .claude-src/). By default, removes everything.\";\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --yes\",\n \"<%= config.bin %> <%= command.id %> --plugin\",\n \"<%= config.bin %> <%= command.id %> --local\",\n \"<%= config.bin %> <%= command.id %> --dry-run\",\n ];\n\n static flags = {\n ...BaseCommand.baseFlags,\n yes: Flags.boolean({\n char: \"y\",\n description: \"Skip confirmation prompt\",\n default: false,\n }),\n plugin: Flags.boolean({\n description: \"Only uninstall the plugin (not local files)\",\n default: false,\n }),\n local: Flags.boolean({\n description: \"Only remove local files (not the plugin)\",\n default: false,\n }),\n };\n\n async run(): Promise<void> {\n const { flags } = await this.parse(Uninstall);\n const projectDir = process.cwd();\n\n this.log(\"\");\n this.log(\"Claude Collective Uninstall\");\n this.log(\"\");\n\n if (flags[\"dry-run\"]) {\n this.log(\"[dry-run] Preview mode - no files will be removed\");\n this.log(\"\");\n }\n\n const target = await detectInstallation(projectDir);\n\n const uninstallPlugin = !flags.local;\n const uninstallLocal = !flags.plugin;\n\n const hasPluginToRemove = uninstallPlugin && target.hasPlugin;\n const hasLocalToRemove = uninstallLocal && (target.hasClaudeDir || target.hasClaudeSrcDir);\n\n if (!hasPluginToRemove && !hasLocalToRemove) {\n this.warn(\"Nothing to uninstall.\");\n this.log(\"\");\n\n if (flags.plugin && !target.hasPlugin) {\n this.log(\"No plugin installation found.\");\n }\n if (flags.local && !target.hasClaudeDir && !target.hasClaudeSrcDir) {\n this.log(\"No local installation found.\");\n }\n if (!flags.plugin && !flags.local) {\n this.log(\"Claude Collective is not installed in this project.\");\n }\n\n this.log(\"\");\n this.log(\"No changes made.\");\n return;\n }\n\n if (!flags.yes && !flags[\"dry-run\"]) {\n const confirmed = await new Promise<boolean>((resolve) => {\n const { waitUntilExit } = render(\n <UninstallConfirm\n target={target}\n uninstallPlugin={uninstallPlugin}\n uninstallLocal={uninstallLocal}\n onConfirm={() => resolve(true)}\n onCancel={() => resolve(false)}\n />,\n );\n\n waitUntilExit().catch(() => resolve(false));\n });\n\n if (!confirmed) {\n this.log(\"\");\n this.log(\"Uninstall cancelled\");\n this.exit(EXIT_CODES.CANCELLED);\n }\n } else {\n this.log(\"The following will be removed:\");\n this.log(\"\");\n\n if (hasPluginToRemove) {\n this.log(\" Plugin:\");\n this.log(` ${target.pluginDir}`);\n }\n\n if (hasLocalToRemove) {\n this.log(\" Local directories:\");\n if (target.hasClaudeDir) {\n this.log(` ${target.claudeDir}/`);\n }\n if (target.hasClaudeSrcDir) {\n this.log(` ${target.claudeSrcDir}/`);\n }\n }\n\n this.log(\"\");\n }\n\n if (flags[\"dry-run\"]) {\n if (hasPluginToRemove) {\n this.log(`[dry-run] Would uninstall plugin \"${PLUGIN_NAME}\"`);\n this.log(`[dry-run] Would remove ${target.pluginDir}`);\n }\n if (hasLocalToRemove) {\n if (target.hasClaudeDir) {\n this.log(`[dry-run] Would remove ${target.claudeDir}/`);\n }\n if (target.hasClaudeSrcDir) {\n this.log(`[dry-run] Would remove ${target.claudeSrcDir}/`);\n }\n }\n this.log(\"\");\n this.log(\"[dry-run] Preview complete - no files were removed\");\n this.log(\"\");\n return;\n }\n\n if (hasPluginToRemove) {\n this.log(\"Uninstalling plugin...\");\n\n try {\n const cliAvailable = await isClaudeCLIAvailable();\n if (cliAvailable) {\n try {\n await claudePluginUninstall(PLUGIN_NAME, \"project\", projectDir);\n } catch {\n // Best-effort: Claude CLI plugin unregister may fail (e.g., plugin\n // not registered). We still proceed to remove the plugin directory.\n }\n }\n\n await remove(target.pluginDir);\n\n this.logSuccess(\"Plugin uninstalled\");\n } catch (error) {\n this.log(\"Plugin uninstall failed\");\n this.error(error instanceof Error ? error.message : \"Unknown error occurred\", {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n\n if (hasLocalToRemove) {\n this.log(\"Removing local directories...\");\n\n try {\n const removed: string[] = [];\n\n if (target.hasClaudeDir) {\n await remove(target.claudeDir);\n removed.push(CLAUDE_DIR);\n }\n\n if (target.hasClaudeSrcDir) {\n await remove(target.claudeSrcDir);\n removed.push(CLAUDE_SRC_DIR);\n }\n\n this.logSuccess(\n `Removed ${removed.length} ${removed.length === 1 ? \"directory\" : \"directories\"}: ${removed.join(\", \")}`,\n );\n } catch (error) {\n this.log(\"Failed to remove local directories\");\n this.error(error instanceof Error ? error.message : \"Unknown error occurred\", {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n\n this.log(\"\");\n this.log(\"Claude Collective has been uninstalled.\");\n\n this.log(\"\");\n this.logSuccess(\"Uninstall complete!\");\n this.log(\"\");\n }\n}\n"],"mappings":"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","names":[]}