@agents-inc/cli 0.50.0 → 0.60.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 (237) hide show
  1. package/CHANGELOG.md +155 -5
  2. package/dist/{chunk-YDYRAXSY.js → chunk-52M2XF3W.js} +6 -6
  3. package/dist/{chunk-2BWCR762.js → chunk-52XO4ULK.js} +6 -8
  4. package/dist/chunk-52XO4ULK.js.map +1 -0
  5. package/dist/{chunk-KQOU4POU.js → chunk-6G3KZSO4.js} +72 -51
  6. package/dist/chunk-6G3KZSO4.js.map +1 -0
  7. package/dist/{chunk-AWP5A6IM.js → chunk-6OWHQ7HM.js} +14 -12
  8. package/dist/chunk-6OWHQ7HM.js.map +1 -0
  9. package/dist/{chunk-D72AFYQR.js → chunk-7FMEMXJ4.js} +71 -71
  10. package/dist/chunk-7FMEMXJ4.js.map +1 -0
  11. package/dist/{chunk-RA2IPRO2.js → chunk-AJJJE7F7.js} +2 -2
  12. package/dist/{chunk-4R52TQ3K.js → chunk-AX3SZZWA.js} +2 -2
  13. package/dist/{chunk-U2W5SENM.js → chunk-BFD5NZQ4.js} +5 -4
  14. package/dist/chunk-BFD5NZQ4.js.map +1 -0
  15. package/dist/{chunk-HYEUETIC.js → chunk-BKJHAJQW.js} +2 -2
  16. package/dist/{chunk-HYEUETIC.js.map → chunk-BKJHAJQW.js.map} +1 -1
  17. package/dist/{chunk-DCE423KO.js → chunk-BMJZBLP7.js} +5 -5
  18. package/dist/{chunk-GBOW6FUW.js → chunk-BNQ5O6LE.js} +2 -2
  19. package/dist/{chunk-KAO3LKB5.js → chunk-C577AJE7.js} +3 -3
  20. package/dist/{chunk-C3Q43WLC.js → chunk-CIG7IKX3.js} +4 -4
  21. package/dist/chunk-EC3UJRKZ.js +1534 -0
  22. package/dist/chunk-EC3UJRKZ.js.map +1 -0
  23. package/dist/{chunk-I6IOGZSZ.js → chunk-EMIUPGPL.js} +11 -15
  24. package/dist/chunk-EMIUPGPL.js.map +1 -0
  25. package/dist/{chunk-4QWDB2MD.js → chunk-G6WHCALR.js} +127 -105
  26. package/dist/chunk-G6WHCALR.js.map +1 -0
  27. package/dist/{chunk-JFF7P4LC.js → chunk-H7WJK7NJ.js} +22 -6
  28. package/dist/chunk-H7WJK7NJ.js.map +1 -0
  29. package/dist/chunk-HGTC76BX.js +16 -0
  30. package/dist/chunk-HGTC76BX.js.map +1 -0
  31. package/dist/{chunk-RDWGYKDY.js → chunk-K6OLORQL.js} +6 -6
  32. package/dist/{chunk-XDSVV5GZ.js → chunk-KIWFEBKH.js} +41 -11
  33. package/dist/chunk-KIWFEBKH.js.map +1 -0
  34. package/dist/{chunk-WBHPCBVN.js → chunk-LWXRUR6B.js} +66 -94
  35. package/dist/chunk-LWXRUR6B.js.map +1 -0
  36. package/dist/{chunk-CMNKHDOX.js → chunk-MGNYPVOJ.js} +2 -2
  37. package/dist/{chunk-5FPIKTSA.js → chunk-MKCHLXMY.js} +7 -7
  38. package/dist/{chunk-U7X4V4HE.js → chunk-MMFQNJPE.js} +2 -2
  39. package/dist/{chunk-WLZHCM7O.js → chunk-MR6OBL3B.js} +3 -11
  40. package/dist/{chunk-WLZHCM7O.js.map → chunk-MR6OBL3B.js.map} +1 -1
  41. package/dist/{chunk-RFKDGJAJ.js → chunk-O6BA7Q2B.js} +6 -6
  42. package/dist/chunk-O6BA7Q2B.js.map +1 -0
  43. package/dist/chunk-OCEFD7V6.js +201 -0
  44. package/dist/chunk-OCEFD7V6.js.map +1 -0
  45. package/dist/{chunk-YZTWZVGX.js → chunk-PUT7X3GA.js} +1 -1
  46. package/dist/chunk-PUT7X3GA.js.map +1 -0
  47. package/dist/{chunk-WFFV254H.js → chunk-RO6LX3UV.js} +110 -82
  48. package/dist/chunk-RO6LX3UV.js.map +1 -0
  49. package/dist/{chunk-QYLCINGC.js → chunk-SDKCQXWE.js} +2 -2
  50. package/dist/{chunk-M3GQ2R3E.js → chunk-SEJF7CGJ.js} +19 -7
  51. package/dist/chunk-SEJF7CGJ.js.map +1 -0
  52. package/dist/{chunk-SPFHPHYL.js → chunk-SZRK3VOR.js} +24 -14
  53. package/dist/chunk-SZRK3VOR.js.map +1 -0
  54. package/dist/{chunk-QB5HHTAA.js → chunk-TC3NHO34.js} +28 -12
  55. package/dist/chunk-TC3NHO34.js.map +1 -0
  56. package/dist/{chunk-5L724R4C.js → chunk-TGLRDEEL.js} +8 -13
  57. package/dist/chunk-TGLRDEEL.js.map +1 -0
  58. package/dist/{chunk-HMSHB5EQ.js → chunk-TZXYBG3R.js} +3544 -3037
  59. package/dist/chunk-TZXYBG3R.js.map +1 -0
  60. package/dist/{chunk-PGY5XROM.js → chunk-VR3CDXDT.js} +2 -6
  61. package/dist/chunk-VR3CDXDT.js.map +1 -0
  62. package/dist/{chunk-5FCHJLM7.js → chunk-WF6RM73R.js} +252 -38
  63. package/dist/chunk-WF6RM73R.js.map +1 -0
  64. package/dist/{chunk-3VOL4WEG.js → chunk-WYVDNGJB.js} +3 -3
  65. package/dist/{chunk-WJHFV6RI.js → chunk-X5EG4EFP.js} +2 -2
  66. package/dist/{chunk-JWYRXE6C.js → chunk-XUDTFI4M.js} +2 -2
  67. package/dist/{chunk-7LV4V6A4.js → chunk-YHCYKUA3.js} +14 -10
  68. package/dist/chunk-YHCYKUA3.js.map +1 -0
  69. package/dist/commands/build/marketplace.js +4 -4
  70. package/dist/commands/build/plugins.js +9 -7
  71. package/dist/commands/build/plugins.js.map +1 -1
  72. package/dist/commands/build/stack.js +13 -10
  73. package/dist/commands/build/stack.js.map +1 -1
  74. package/dist/commands/compile.js +42 -71
  75. package/dist/commands/compile.js.map +1 -1
  76. package/dist/commands/config/index.js +7 -5
  77. package/dist/commands/config/index.js.map +1 -1
  78. package/dist/commands/config/path.js +8 -6
  79. package/dist/commands/config/path.js.map +1 -1
  80. package/dist/commands/config/show.js +7 -5
  81. package/dist/commands/diff.js +9 -7
  82. package/dist/commands/diff.js.map +1 -1
  83. package/dist/commands/doctor.js +20 -16
  84. package/dist/commands/doctor.js.map +1 -1
  85. package/dist/commands/edit.js +175 -79
  86. package/dist/commands/edit.js.map +1 -1
  87. package/dist/commands/eject.js +20 -41
  88. package/dist/commands/eject.js.map +1 -1
  89. package/dist/commands/import/skill.js +10 -18
  90. package/dist/commands/import/skill.js.map +1 -1
  91. package/dist/commands/info.js +21 -20
  92. package/dist/commands/info.js.map +1 -1
  93. package/dist/commands/init.js +32 -31
  94. package/dist/commands/list.js +8 -6
  95. package/dist/commands/list.js.map +1 -1
  96. package/dist/commands/new/agent.js +23 -11
  97. package/dist/commands/new/agent.js.map +1 -1
  98. package/dist/commands/new/marketplace.js +63 -46
  99. package/dist/commands/new/marketplace.js.map +1 -1
  100. package/dist/commands/new/skill.js +11 -9
  101. package/dist/commands/outdated.js +9 -7
  102. package/dist/commands/outdated.js.map +1 -1
  103. package/dist/commands/search.js +45 -35
  104. package/dist/commands/search.js.map +1 -1
  105. package/dist/commands/uninstall.js +93 -123
  106. package/dist/commands/uninstall.js.map +1 -1
  107. package/dist/commands/update.js +11 -9
  108. package/dist/commands/update.js.map +1 -1
  109. package/dist/commands/validate.js +23 -27
  110. package/dist/commands/validate.js.map +1 -1
  111. package/dist/components/common/confirm.test.js +4 -4
  112. package/dist/components/skill-search/skill-search.js +3 -3
  113. package/dist/components/wizard/category-grid.js +3 -3
  114. package/dist/components/wizard/category-grid.test.js +4 -4
  115. package/dist/components/wizard/category-grid.test.js.map +1 -1
  116. package/dist/components/wizard/checkbox-grid.js +5 -5
  117. package/dist/components/wizard/checkbox-grid.test.js +6 -6
  118. package/dist/components/wizard/domain-selection.js +12 -11
  119. package/dist/components/wizard/help-modal.js +2 -2
  120. package/dist/components/wizard/menu-item.js +1 -1
  121. package/dist/components/wizard/search-modal.js +2 -2
  122. package/dist/components/wizard/search-modal.test.js +3 -3
  123. package/dist/components/wizard/search-modal.test.js.map +1 -1
  124. package/dist/components/wizard/section-progress.js +2 -2
  125. package/dist/components/wizard/section-progress.test.js +4 -4
  126. package/dist/components/wizard/section-progress.test.js.map +1 -1
  127. package/dist/components/wizard/selection-card.js +2 -2
  128. package/dist/components/wizard/source-grid.js +4 -4
  129. package/dist/components/wizard/source-grid.test.js +5 -5
  130. package/dist/components/wizard/source-grid.test.js.map +1 -1
  131. package/dist/components/wizard/stack-selection.js +9 -8
  132. package/dist/components/wizard/step-agents.js +11 -10
  133. package/dist/components/wizard/step-agents.test.js +13 -12
  134. package/dist/components/wizard/step-agents.test.js.map +1 -1
  135. package/dist/components/wizard/step-build.js +11 -9
  136. package/dist/components/wizard/step-build.test.js +18 -22
  137. package/dist/components/wizard/step-build.test.js.map +1 -1
  138. package/dist/components/wizard/step-confirm.js +4 -4
  139. package/dist/components/wizard/step-confirm.test.js +83 -23
  140. package/dist/components/wizard/step-confirm.test.js.map +1 -1
  141. package/dist/components/wizard/step-refine.js +2 -2
  142. package/dist/components/wizard/step-refine.test.js +3 -3
  143. package/dist/components/wizard/step-settings.js +9 -7
  144. package/dist/components/wizard/step-settings.test.js +13 -11
  145. package/dist/components/wizard/step-settings.test.js.map +1 -1
  146. package/dist/components/wizard/step-sources.js +13 -11
  147. package/dist/components/wizard/step-sources.test.js +19 -17
  148. package/dist/components/wizard/step-sources.test.js.map +1 -1
  149. package/dist/components/wizard/step-stack.js +15 -14
  150. package/dist/components/wizard/step-stack.test.js +17 -16
  151. package/dist/components/wizard/step-stack.test.js.map +1 -1
  152. package/dist/components/wizard/view-title.js +2 -2
  153. package/dist/components/wizard/wizard-layout.js +10 -8
  154. package/dist/components/wizard/wizard-tabs.js +2 -2
  155. package/dist/components/wizard/wizard-tabs.test.js +2 -2
  156. package/dist/components/wizard/wizard.js +29 -27
  157. package/dist/config-exports.js +20 -0
  158. package/dist/config-exports.js.map +1 -0
  159. package/dist/hooks/init.js +34 -33
  160. package/dist/hooks/init.js.map +1 -1
  161. package/dist/loader-2O32KKAQ.js +19 -0
  162. package/dist/source-loader-A6B3NDI4.js +16 -0
  163. package/dist/source-loader-A6B3NDI4.js.map +1 -0
  164. package/dist/source-manager-Q7IQSGIX.js +18 -0
  165. package/dist/source-manager-Q7IQSGIX.js.map +1 -0
  166. package/dist/src/agents/meta/agent-summoner/workflow.md +3 -3
  167. package/dist/src/agents/meta/skill-summoner/critical-reminders.md +2 -2
  168. package/dist/src/agents/meta/skill-summoner/critical-requirements.md +1 -1
  169. package/dist/src/agents/meta/skill-summoner/intro.md +1 -1
  170. package/dist/src/agents/meta/skill-summoner/output-format.md +3 -3
  171. package/dist/src/agents/meta/skill-summoner/workflow.md +8 -8
  172. package/dist/stores/wizard-store.js +6 -5
  173. package/dist/stores/wizard-store.test.js +299 -59
  174. package/dist/stores/wizard-store.test.js.map +1 -1
  175. package/package.json +5 -1
  176. package/src/agents/meta/agent-summoner/workflow.md +3 -3
  177. package/src/agents/meta/skill-summoner/critical-reminders.md +2 -2
  178. package/src/agents/meta/skill-summoner/critical-requirements.md +1 -1
  179. package/src/agents/meta/skill-summoner/intro.md +1 -1
  180. package/src/agents/meta/skill-summoner/output-format.md +3 -3
  181. package/src/agents/meta/skill-summoner/workflow.md +8 -8
  182. package/src/schemas/metadata.schema.json +6 -0
  183. package/src/schemas/stacks.schema.json +1 -1
  184. package/config/skill-categories.yaml +0 -344
  185. package/config/skill-rules.yaml +0 -740
  186. package/config/stacks.yaml +0 -1864
  187. package/dist/chunk-26MXZUHU.js +0 -183
  188. package/dist/chunk-26MXZUHU.js.map +0 -1
  189. package/dist/chunk-2BWCR762.js.map +0 -1
  190. package/dist/chunk-4QWDB2MD.js.map +0 -1
  191. package/dist/chunk-5FCHJLM7.js.map +0 -1
  192. package/dist/chunk-5L724R4C.js.map +0 -1
  193. package/dist/chunk-7LV4V6A4.js.map +0 -1
  194. package/dist/chunk-AWP5A6IM.js.map +0 -1
  195. package/dist/chunk-D72AFYQR.js.map +0 -1
  196. package/dist/chunk-HMSHB5EQ.js.map +0 -1
  197. package/dist/chunk-I6IOGZSZ.js.map +0 -1
  198. package/dist/chunk-JFF7P4LC.js.map +0 -1
  199. package/dist/chunk-KQOU4POU.js.map +0 -1
  200. package/dist/chunk-M3GQ2R3E.js.map +0 -1
  201. package/dist/chunk-PGY5XROM.js.map +0 -1
  202. package/dist/chunk-QB5HHTAA.js.map +0 -1
  203. package/dist/chunk-RFKDGJAJ.js.map +0 -1
  204. package/dist/chunk-SPFHPHYL.js.map +0 -1
  205. package/dist/chunk-U2W5SENM.js.map +0 -1
  206. package/dist/chunk-UAD3SC27.js +0 -107
  207. package/dist/chunk-UAD3SC27.js.map +0 -1
  208. package/dist/chunk-WBHPCBVN.js.map +0 -1
  209. package/dist/chunk-WFFV254H.js.map +0 -1
  210. package/dist/chunk-XDSVV5GZ.js.map +0 -1
  211. package/dist/chunk-YZTWZVGX.js.map +0 -1
  212. package/dist/commands/config/get.js +0 -61
  213. package/dist/commands/config/get.js.map +0 -1
  214. package/dist/commands/config/set-project.js +0 -61
  215. package/dist/commands/config/set-project.js.map +0 -1
  216. package/dist/commands/config/unset-project.js +0 -57
  217. package/dist/commands/config/unset-project.js.map +0 -1
  218. package/dist/config/skill-categories.yaml +0 -344
  219. package/dist/config/skill-rules.yaml +0 -740
  220. package/dist/config/stacks.yaml +0 -1864
  221. package/dist/source-manager-BVB2SG73.js +0 -16
  222. /package/dist/{chunk-YDYRAXSY.js.map → chunk-52M2XF3W.js.map} +0 -0
  223. /package/dist/{chunk-RA2IPRO2.js.map → chunk-AJJJE7F7.js.map} +0 -0
  224. /package/dist/{chunk-4R52TQ3K.js.map → chunk-AX3SZZWA.js.map} +0 -0
  225. /package/dist/{chunk-DCE423KO.js.map → chunk-BMJZBLP7.js.map} +0 -0
  226. /package/dist/{chunk-GBOW6FUW.js.map → chunk-BNQ5O6LE.js.map} +0 -0
  227. /package/dist/{chunk-KAO3LKB5.js.map → chunk-C577AJE7.js.map} +0 -0
  228. /package/dist/{chunk-C3Q43WLC.js.map → chunk-CIG7IKX3.js.map} +0 -0
  229. /package/dist/{chunk-RDWGYKDY.js.map → chunk-K6OLORQL.js.map} +0 -0
  230. /package/dist/{chunk-CMNKHDOX.js.map → chunk-MGNYPVOJ.js.map} +0 -0
  231. /package/dist/{chunk-5FPIKTSA.js.map → chunk-MKCHLXMY.js.map} +0 -0
  232. /package/dist/{chunk-U7X4V4HE.js.map → chunk-MMFQNJPE.js.map} +0 -0
  233. /package/dist/{chunk-QYLCINGC.js.map → chunk-SDKCQXWE.js.map} +0 -0
  234. /package/dist/{chunk-3VOL4WEG.js.map → chunk-WYVDNGJB.js.map} +0 -0
  235. /package/dist/{chunk-WJHFV6RI.js.map → chunk-X5EG4EFP.js.map} +0 -0
  236. /package/dist/{chunk-JWYRXE6C.js.map → chunk-XUDTFI4M.js.map} +0 -0
  237. /package/dist/{source-manager-BVB2SG73.js.map → loader-2O32KKAQ.js.map} +0 -0
@@ -1,35 +1,40 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  SkillSearch
4
- } from "../chunk-U2W5SENM.js";
5
- import "../chunk-JWYRXE6C.js";
4
+ } from "../chunk-BFD5NZQ4.js";
5
+ import "../chunk-XUDTFI4M.js";
6
6
  import "../chunk-U3IGFMCY.js";
7
7
  import {
8
8
  INFO_MESSAGES,
9
9
  STATUS_MESSAGES,
10
10
  SUCCESS_MESSAGES
11
- } from "../chunk-WLZHCM7O.js";
12
- import {
13
- BaseCommand,
14
- EXIT_CODES
15
- } from "../chunk-PGY5XROM.js";
11
+ } from "../chunk-MR6OBL3B.js";
16
12
  import {
17
13
  fetchFromSource,
18
14
  loadSkillsMatrixFromSource,
19
15
  resolveAllSources
20
- } from "../chunk-HMSHB5EQ.js";
16
+ } from "../chunk-TZXYBG3R.js";
17
+ import {
18
+ parseFrontmatter
19
+ } from "../chunk-OCEFD7V6.js";
21
20
  import "../chunk-T4EXUIBY.js";
21
+ import {
22
+ BaseCommand,
23
+ EXIT_CODES
24
+ } from "../chunk-VR3CDXDT.js";
22
25
  import {
23
26
  copy,
24
27
  ensureDir,
25
28
  fileExists,
26
- listDirectories
27
- } from "../chunk-WBHPCBVN.js";
29
+ listDirectories,
30
+ readFile
31
+ } from "../chunk-LWXRUR6B.js";
28
32
  import {
29
33
  DEFAULT_SKILLS_SUBDIR,
30
34
  LOCAL_SKILLS_PATH,
31
35
  STANDARD_FILES
32
- } from "../chunk-AWP5A6IM.js";
36
+ } from "../chunk-6OWHQ7HM.js";
37
+ import "../chunk-EC3UJRKZ.js";
33
38
  import {
34
39
  init_esm_shims
35
40
  } from "../chunk-DHET7RCE.js";
@@ -55,7 +60,8 @@ function truncate(str, maxLength) {
55
60
  function matchesQuery(skill, query) {
56
61
  const lowerQuery = query.toLowerCase();
57
62
  if (skill.id.toLowerCase().includes(lowerQuery)) return true;
58
- if (skill.displayName?.toLowerCase().includes(lowerQuery)) return true;
63
+ if (skill.displayName.toLowerCase().includes(lowerQuery)) return true;
64
+ if (skill.slug?.toLowerCase().includes(lowerQuery)) return true;
59
65
  if (skill.description.toLowerCase().includes(lowerQuery)) return true;
60
66
  if (skill.category.toLowerCase().includes(lowerQuery)) return true;
61
67
  return skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery));
@@ -82,28 +88,32 @@ async function fetchSkillsFromSource(source, forceRefresh) {
82
88
  const skills = [];
83
89
  for (const skillDir of skillDirs) {
84
90
  const skillMdPath = path.join(skillsDir, skillDir, STANDARD_FILES.SKILL_MD);
85
- if (await fileExists(skillMdPath)) {
86
- skills.push({
87
- // Directory name is an untyped string — cast at data boundary
88
- id: skillDir,
89
- description: `Skill from ${source.name}`,
90
- // Synthetic category for third-party sources — not in CategoryPath union
91
- category: "imported",
92
- tags: [],
93
- author: `@${source.name}`,
94
- conflictsWith: [],
95
- recommends: [],
96
- requires: [],
97
- alternatives: [],
98
- discourages: [],
99
- compatibleWith: [],
100
- requiresSetup: [],
101
- providesSetupFor: [],
102
- sourceName: source.name,
103
- sourceUrl: source.url,
104
- path: path.join(skillsDir, skillDir)
105
- });
106
- }
91
+ if (!await fileExists(skillMdPath)) continue;
92
+ const content = await readFile(skillMdPath);
93
+ const frontmatter = parseFrontmatter(content, skillMdPath);
94
+ if (!frontmatter) continue;
95
+ skills.push({
96
+ id: frontmatter.name,
97
+ description: frontmatter.description,
98
+ // Boundary cast: directory name used as slug for third-party source skill
99
+ slug: skillDir,
100
+ displayName: skillDir,
101
+ // Boundary cast: external source skills have no category metadata
102
+ category: "imported",
103
+ tags: [],
104
+ author: `@${source.name}`,
105
+ conflictsWith: [],
106
+ isRecommended: false,
107
+ requires: [],
108
+ alternatives: [],
109
+ discourages: [],
110
+ compatibleWith: [],
111
+ requiresSetup: [],
112
+ providesSetupFor: [],
113
+ sourceName: source.name,
114
+ sourceUrl: source.url,
115
+ path: path.join(skillsDir, skillDir)
116
+ });
107
117
  }
108
118
  return skills;
109
119
  } catch {
@@ -246,7 +256,7 @@ var Search = class _Search extends BaseCommand {
246
256
  if (flags.category) {
247
257
  results = results.filter((skill) => matchesCategory(skill, flags.category));
248
258
  }
249
- results = sortBy(results, (r) => r.displayName || r.id);
259
+ results = sortBy(results, (r) => (r.displayName || r.id).toLowerCase());
250
260
  this.log("");
251
261
  if (results.length === 0) {
252
262
  this.warn(`No skills found matching "${query}"`);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/search.tsx","../../src/cli/components/skill-search/index.ts"],"sourcesContent":["import { Args, Flags } from \"@oclif/core\";\nimport { printTable } from \"@oclif/table\";\nimport { render } from \"ink\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { SkillSearch, type SkillSearchResult } from \"../components/skill-search/index.js\";\nimport type { SourcedSkill } from \"../components/skill-search/skill-search.js\";\nimport { DEFAULT_SKILLS_SUBDIR, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { resolveAllSources, type SourceEntry } from \"../lib/configuration/index.js\";\nimport { loadSkillsMatrixFromSource, fetchFromSource } from \"../lib/loading/index.js\";\nimport type { CategoryPath, ResolvedSkill, SkillId } from \"../types/index.js\";\nimport { listDirectories, fileExists, copy, ensureDir } from \"../utils/fs.js\";\nimport { SUCCESS_MESSAGES, STATUS_MESSAGES, INFO_MESSAGES } from \"../utils/messages.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\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 return skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery));\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, STANDARD_FILES.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 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(SUCCESS_MESSAGES.IMPORT_COMPLETE);\n this.log(`Skills location: ${destDir}`);\n this.log(INFO_MESSAGES.RUN_COMPILE);\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(STATUS_MESSAGES.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 SkillSearchResult } 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 { printTable } from \"@oclif/table\";\nimport { render } from \"ink\";\nimport path from \"path\";\nimport { sortBy } from \"remeda\";\n\nimport { BaseCommand } from \"../base-command.js\";\nimport { SkillSearch, type SkillSearchResult } from \"../components/skill-search/index.js\";\nimport type { SourcedSkill } from \"../components/skill-search/skill-search.js\";\nimport { DEFAULT_SKILLS_SUBDIR, LOCAL_SKILLS_PATH, STANDARD_FILES } from \"../consts.js\";\nimport { EXIT_CODES } from \"../lib/exit-codes.js\";\nimport { resolveAllSources, type SourceEntry } from \"../lib/configuration/index.js\";\nimport {\n loadSkillsMatrixFromSource,\n fetchFromSource,\n parseFrontmatter,\n} from \"../lib/loading/index.js\";\nimport type { CategoryPath, ResolvedSkill, SkillSlug } from \"../types/index.js\";\nimport { listDirectories, fileExists, readFile, copy, ensureDir } from \"../utils/fs.js\";\nimport { SUCCESS_MESSAGES, STATUS_MESSAGES, INFO_MESSAGES } from \"../utils/messages.js\";\n\nconst MAX_DESCRIPTION_WIDTH = 50;\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.slug?.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 return skill.tags.some((tag) => tag.toLowerCase().includes(lowerQuery));\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, STANDARD_FILES.SKILL_MD);\n if (!(await fileExists(skillMdPath))) continue;\n\n const content = await readFile(skillMdPath);\n const frontmatter = parseFrontmatter(content, skillMdPath);\n if (!frontmatter) continue;\n\n skills.push({\n id: frontmatter.name,\n description: frontmatter.description,\n // Boundary cast: directory name used as slug for third-party source skill\n slug: skillDir as SkillSlug,\n displayName: skillDir,\n // Boundary cast: external source skills have no category metadata\n category: \"imported\" as CategoryPath,\n tags: [],\n author: `@${source.name}`,\n conflictsWith: [],\n isRecommended: false,\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 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(SUCCESS_MESSAGES.IMPORT_COMPLETE);\n this.log(`Skills location: ${destDir}`);\n this.log(INFO_MESSAGES.RUN_COMPILE);\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(STATUS_MESSAGES.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).toLowerCase());\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 SkillSearchResult } from \"./skill-search.js\";\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA,SAAS,MAAM,aAAa;AAC5B,SAAS,kBAAkB;AAC3B,SAAS,cAAc;AACvB,OAAO,UAAU;AACjB,SAAS,cAAc;;;ACJvB;;;AD8MU;AAzLV,IAAM,wBAAwB;AAE9B,SAAS,SAAS,KAAa,WAA2B;AACxD,MAAI,IAAI,UAAU,UAAW,QAAO;AACpC,SAAO,GAAG,IAAI,MAAM,GAAG,YAAY,CAAC,CAAC;AACvC;AAEA,SAAS,aAAa,OAAsB,OAAwB;AAClE,QAAM,aAAa,MAAM,YAAY;AAErC,MAAI,MAAM,GAAG,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AACxD,MAAI,MAAM,YAAY,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AACjE,MAAI,MAAM,MAAM,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AAC3D,MAAI,MAAM,YAAY,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AACjE,MAAI,MAAM,SAAS,YAAY,EAAE,SAAS,UAAU,EAAG,QAAO;AAE9D,SAAO,MAAM,KAAK,KAAK,CAAC,QAAQ,IAAI,YAAY,EAAE,SAAS,UAAU,CAAC;AACxE;AAEA,SAAS,gBAAgB,OAAsB,UAAiC;AAC9E,QAAM,gBAAgB,SAAS,YAAY;AAC3C,SAAO,MAAM,SAAS,YAAY,EAAE,SAAS,aAAa;AAC5D;AAEA,SAAS,eACP,OACA,YACA,WACc;AACd,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,EACF;AACF;AAEA,eAAe,sBACb,QACA,cACyB;AACzB,MAAI;AACF,UAAM,SAAS,MAAM,gBAAgB,OAAO,KAAK,EAAE,aAAa,CAAC;AACjE,UAAM,YAAY,KAAK,KAAK,OAAO,MAAM,qBAAqB;AAE9D,QAAI,CAAE,MAAM,WAAW,SAAS,GAAI;AAClC,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,YAAY,MAAM,gBAAgB,SAAS;AACjD,UAAM,SAAyB,CAAC;AAEhC,eAAW,YAAY,WAAW;AAChC,YAAM,cAAc,KAAK,KAAK,WAAW,UAAU,eAAe,QAAQ;AAC1E,UAAI,CAAE,MAAM,WAAW,WAAW,EAAI;AAEtC,YAAM,UAAU,MAAM,SAAS,WAAW;AAC1C,YAAM,cAAc,iBAAiB,SAAS,WAAW;AACzD,UAAI,CAAC,YAAa;AAElB,aAAO,KAAK;AAAA,QACV,IAAI,YAAY;AAAA,QAChB,aAAa,YAAY;AAAA;AAAA,QAEzB,MAAM;AAAA,QACN,aAAa;AAAA;AAAA,QAEb,UAAU;AAAA,QACV,MAAM,CAAC;AAAA,QACP,QAAQ,IAAI,OAAO,IAAI;AAAA,QACvB,eAAe,CAAC;AAAA,QAChB,eAAe;AAAA,QACf,UAAU,CAAC;AAAA,QACX,cAAc,CAAC;AAAA,QACf,aAAa,CAAC;AAAA,QACd,gBAAgB,CAAC;AAAA,QACjB,eAAe,CAAC;AAAA,QAChB,kBAAkB,CAAC;AAAA,QACnB,YAAY,OAAO;AAAA,QACnB,WAAW,OAAO;AAAA,QAClB,MAAM,KAAK,KAAK,WAAW,QAAQ;AAAA,MACrC,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT,QAAQ;AAEN,WAAO,CAAC;AAAA,EACV;AACF;AAEA,IAAqB,SAArB,MAAqB,gBAAe,YAAY;AAAA,EAC9C,OAAO,UAAU;AAAA,EACjB,OAAO,cACL;AAAA,EAGF,OAAO,WAAW;AAAA,IAChB;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,IACA;AAAA,MACE,aAAa;AAAA,MACb,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,OAAO,OAAO;AAAA,IACZ,OAAO,KAAK,OAAO;AAAA,MACjB,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,QAAQ;AAAA,IACb,GAAG,YAAY;AAAA,IACf,aAAa,MAAM,QAAQ;AAAA,MACzB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,IACD,UAAU,MAAM,OAAO;AAAA,MACrB,MAAM;AAAA,MACN,aAAa;AAAA,MACb,UAAU;AAAA,IACZ,CAAC;AAAA,IACD,SAAS,MAAM,QAAQ;AAAA,MACrB,aAAa;AAAA,MACb,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,MAAqB;AACzB,UAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,MAAM,OAAM;AAC/C,UAAM,aAAa,QAAQ,IAAI;AAE/B,UAAM,gBAAgB,MAAM,eAAe,CAAC,KAAK;AAEjD,QAAI,eAAe;AACjB,YAAM,KAAK,eAAe,KAAK,OAAO,MAAM,SAAS,UAAU;AAAA,IACjE,OAAO;AACL,YAAM,KAAK,UAAU,KAAK,OAAQ,KAAK;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAc,eACZ,cACA,cACA,YACe;AACf,SAAK,IAAI,oCAAoC;AAE7C,QAAI;AACF,YAAM,EAAE,QAAQ,WAAW,IAAI,MAAM,2BAA2B;AAAA,QAC9D,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,MACF,CAAC;AAED,YAAM,gBAAgB,OAAO,OAAO,OAAO,MAAM,EAC9C,OAAO,CAAC,UAAkC,UAAU,MAAS,EAC7D,IAAI,CAAC,UAAU,eAAe,OAAO,eAAe,UAAU,CAAC;AAElE,YAAM,EAAE,OAAO,IAAI,MAAM,kBAAkB,UAAU;AAErD,YAAM,mBAAmB,MAAM,QAAQ;AAAA,QACrC,OAAO,IAAI,CAAC,WAAW,sBAAsB,QAAQ,YAAY,CAAC;AAAA,MACpE;AAEA,YAAM,YAA4B,CAAC,GAAG,eAAe,GAAG,iBAAiB,KAAK,CAAC;AAC/E,YAAM,cAAc,IAAI,OAAO;AAE/B,WAAK,IAAI,UAAU,UAAU,MAAM,gBAAgB,WAAW,YAAY;AAC1E,WAAK,IAAI,EAAE;AAEX,YAAM,sBAAsB,IAAI,QAA2B,CAAC,YAAY;AACtE,cAAM,EAAE,cAAc,IAAI;AAAA,UACxB;AAAA,YAAC;AAAA;AAAA,cACC,QAAQ;AAAA,cACR;AAAA,cACA;AAAA,cACA,YAAY,CAAC,WAAW;AACtB,wBAAQ,MAAM;AAAA,cAChB;AAAA,cACA,UAAU,MAAM;AACd,wBAAQ,EAAE,gBAAgB,CAAC,GAAG,WAAW,KAAK,CAAC;AAAA,cACjD;AAAA;AAAA,UACF;AAAA,QACF;AAEA,sBAAc,EAAE,KAAK,MAAM;AACzB,kBAAQ,EAAE,gBAAgB,CAAC,GAAG,WAAW,KAAK,CAAC;AAAA,QACjD,CAAC;AAAA,MACH,CAAC;AAED,YAAM,eAAe,MAAM;AAE3B,UAAI,aAAa,WAAW;AAC1B,aAAK,IAAI,kBAAkB;AAC3B,aAAK,KAAK,WAAW,SAAS;AAAA,MAChC;AAEA,UAAI,aAAa,eAAe,WAAW,GAAG;AAC5C,aAAK,IAAI,oBAAoB;AAC7B;AAAA,MACF;AAEA,WAAK,IAAI,EAAE;AACX,WAAK,IAAI,aAAa,aAAa,eAAe,MAAM,cAAc;AAEtE,YAAM,UAAU,KAAK,KAAK,YAAY,iBAAiB;AAEvD,iBAAW,SAAS,aAAa,gBAAgB;AAC/C,YAAI,MAAM,MAAM;AACd,gBAAM,WAAW,KAAK,KAAK,SAAS,MAAM,EAAE;AAC5C,gBAAM,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACtC,gBAAM,KAAK,MAAM,MAAM,QAAQ;AAC/B,eAAK,WAAW,aAAa,MAAM,EAAE,EAAE;AAAA,QACzC,OAAO;AACL,eAAK,KAAK,YAAY,MAAM,EAAE,4BAA4B;AAAA,QAC5D;AAAA,MACF;AAEA,WAAK,IAAI,EAAE;AACX,WAAK,WAAW,iBAAiB,eAAe;AAChD,WAAK,IAAI,oBAAoB,OAAO,EAAE;AACtC,WAAK,IAAI,cAAc,WAAW;AAAA,IACpC,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AAAA,EAEA,MAAc,UACZ,OACA,OACe;AACf,QAAI;AACF,WAAK,IAAI,gBAAgB,cAAc;AAEvC,YAAM,EAAE,QAAQ,YAAY,QAAQ,IAAI,MAAM,2BAA2B;AAAA,QACvE,YAAY,MAAM;AAAA,MACpB,CAAC;AAED,WAAK,IAAI,eAAe,UAAU,UAAU,QAAQ,KAAK,UAAU,EAAE;AAErE,YAAM,YAAY,OAAO,OAAO,OAAO,MAAM,EAAE;AAAA,QAC7C,CAAC,UAAkC,UAAU;AAAA,MAC/C;AAEA,UAAI,UAAU,UAAU,OAAO,CAAC,UAAU,aAAa,OAAO,KAAK,CAAC;AAEpE,UAAI,MAAM,UAAU;AAElB,kBAAU,QAAQ,OAAO,CAAC,UAAU,gBAAgB,OAAO,MAAM,QAAwB,CAAC;AAAA,MAC5F;AAEA,gBAAU,OAAO,SAAS,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,YAAY,CAAC;AAEtE,WAAK,IAAI,EAAE;AACX,UAAI,QAAQ,WAAW,GAAG;AACxB,aAAK,KAAK,6BAA6B,KAAK,GAAG;AAC/C,YAAI,MAAM,UAAU;AAClB,eAAK,QAAQ,oBAAoB,MAAM,QAAQ,EAAE;AAAA,QACnD;AAAA,MACF,OAAO;AACL,aAAK;AAAA,UACH,SAAS,QAAQ,MAAM,SAAS,QAAQ,WAAW,IAAI,KAAK,GAAG,cAAc,KAAK;AAAA,QACpF;AACA,YAAI,MAAM,UAAU;AAClB,eAAK,QAAQ,oBAAoB,MAAM,QAAQ,EAAE;AAAA,QACnD;AACA,aAAK,IAAI,EAAE;AAEX,mBAAW;AAAA,UACT,MAAM,QAAQ,IAAI,CAAC,WAAW;AAAA,YAC5B,IAAI,MAAM,eAAe,MAAM;AAAA,YAC/B,UAAU,MAAM;AAAA,YAChB,aAAa,SAAS,MAAM,aAAa,qBAAqB;AAAA,UAChE,EAAE;AAAA,UACF,SAAS;AAAA,YACP,EAAE,KAAK,MAAM,MAAM,KAAK;AAAA,YACxB,EAAE,KAAK,YAAY,MAAM,WAAW;AAAA,YACpC,EAAE,KAAK,eAAe,MAAM,cAAc;AAAA,UAC5C;AAAA,UACA,eAAe,EAAE,MAAM,KAAK;AAAA,QAC9B,CAAC;AAAA,MACH;AACA,WAAK,IAAI,EAAE;AAAA,IACb,SAAS,OAAO;AACd,WAAK,YAAY,KAAK;AAAA,IACxB;AAAA,EACF;AACF;","names":[]}
@@ -3,37 +3,36 @@ import {
3
3
  Confirm
4
4
  } from "../chunk-N6S7ZRIL.js";
5
5
  import {
6
- claudePluginUninstall,
7
- isClaudeCLIAvailable
8
- } from "../chunk-26MXZUHU.js";
9
- import {
10
- DRY_RUN_MESSAGES,
11
6
  INFO_MESSAGES,
12
7
  SUCCESS_MESSAGES
13
- } from "../chunk-WLZHCM7O.js";
14
- import {
15
- BaseCommand,
16
- EXIT_CODES
17
- } from "../chunk-PGY5XROM.js";
8
+ } from "../chunk-MR6OBL3B.js";
18
9
  import {
10
+ claudePluginUninstall,
19
11
  getProjectPluginsDir,
12
+ isClaudeCLIAvailable,
20
13
  listPluginNames,
21
14
  loadProjectSourceConfig,
22
15
  readForkedFromMetadata
23
- } from "../chunk-HMSHB5EQ.js";
16
+ } from "../chunk-TZXYBG3R.js";
17
+ import "../chunk-OCEFD7V6.js";
24
18
  import "../chunk-T4EXUIBY.js";
19
+ import {
20
+ BaseCommand,
21
+ EXIT_CODES
22
+ } from "../chunk-VR3CDXDT.js";
25
23
  import {
26
24
  directoryExists,
27
25
  getErrorMessage,
28
26
  listDirectories,
29
27
  remove
30
- } from "../chunk-WBHPCBVN.js";
28
+ } from "../chunk-LWXRUR6B.js";
31
29
  import {
32
30
  CLAUDE_DIR,
33
31
  CLAUDE_SRC_DIR,
34
32
  CLI_COLORS,
35
33
  DEFAULT_BRANDING
36
- } from "../chunk-AWP5A6IM.js";
34
+ } from "../chunk-6OWHQ7HM.js";
35
+ import "../chunk-EC3UJRKZ.js";
37
36
  import {
38
37
  init_esm_shims
39
38
  } from "../chunk-DHET7RCE.js";
@@ -46,16 +45,16 @@ import path from "path";
46
45
  import { jsx, jsxs } from "react/jsx-runtime";
47
46
  function collectConfiguredSources(config) {
48
47
  if (!config) return [];
49
- const sources = [];
50
- if (config.source) {
51
- sources.push(config.source);
52
- }
53
- if (config.sources) {
54
- for (const entry of config.sources) {
55
- sources.push(entry.url);
56
- }
57
- }
58
- return sources;
48
+ return [
49
+ ...config.source ? [config.source] : [],
50
+ ...config.sources?.map((entry) => entry.url) ?? []
51
+ ];
52
+ }
53
+ function collectConfiguredAgents(config) {
54
+ if (!config) return [];
55
+ const agents = config.agents;
56
+ if (!Array.isArray(agents)) return [];
57
+ return agents.map((a) => a.name);
59
58
  }
60
59
  async function detectUninstallTarget(projectDir) {
61
60
  const pluginsDir = getProjectPluginsDir(projectDir);
@@ -78,6 +77,7 @@ async function detectUninstallTarget(projectDir) {
78
77
  } catch {
79
78
  }
80
79
  const configuredSources = collectConfiguredSources(config);
80
+ const configuredAgents = collectConfiguredAgents(config);
81
81
  return {
82
82
  hasPlugins: pluginNames.length > 0,
83
83
  pluginNames,
@@ -91,7 +91,8 @@ async function detectUninstallTarget(projectDir) {
91
91
  claudeDir,
92
92
  claudeSrcDir,
93
93
  config,
94
- configuredSources
94
+ configuredSources,
95
+ configuredAgents
95
96
  };
96
97
  }
97
98
  var UninstallConfirm = ({
@@ -163,14 +164,16 @@ function skillMatchesConfiguredSource(forkedFromSource, configuredSources) {
163
164
  if (!forkedFromSource || configuredSources.length === 0) return false;
164
165
  return configuredSources.includes(forkedFromSource);
165
166
  }
167
+ function shouldRemoveSkill(forkedFrom, configuredSources, hasConfig) {
168
+ return forkedFrom !== null && (skillMatchesConfiguredSource(forkedFrom.source, configuredSources) || !forkedFrom.source && hasConfig);
169
+ }
166
170
  var Uninstall = class _Uninstall extends BaseCommand {
167
171
  static summary = `Remove ${DEFAULT_BRANDING.NAME} from this project`;
168
172
  static description = `Uninstall ${DEFAULT_BRANDING.NAME} from this project. Removes CLI-managed skills (matched by source), compiled agents, and plugins. User-created content is preserved.`;
169
173
  static examples = [
170
174
  "<%= config.bin %> <%= command.id %>",
171
175
  "<%= config.bin %> <%= command.id %> --yes",
172
- "<%= config.bin %> <%= command.id %> --all",
173
- "<%= config.bin %> <%= command.id %> --dry-run"
176
+ "<%= config.bin %> <%= command.id %> --all"
174
177
  ];
175
178
  static flags = {
176
179
  ...BaseCommand.baseFlags,
@@ -190,10 +193,6 @@ var Uninstall = class _Uninstall extends BaseCommand {
190
193
  this.log("");
191
194
  this.log(`${DEFAULT_BRANDING.NAME} Uninstall`);
192
195
  this.log("");
193
- if (flags["dry-run"]) {
194
- this.log(DRY_RUN_MESSAGES.PREVIEW_NO_FILES_REMOVED);
195
- this.log("");
196
- }
197
196
  const target = await detectUninstallTarget(projectDir);
198
197
  const hasAnythingToRemove = target.hasPlugins || target.hasLocalSkills || target.hasLocalAgents || flags.all && target.hasClaudeSrcDir;
199
198
  if (!hasAnythingToRemove) {
@@ -204,7 +203,7 @@ var Uninstall = class _Uninstall extends BaseCommand {
204
203
  this.log(INFO_MESSAGES.NO_CHANGES_MADE);
205
204
  return;
206
205
  }
207
- if (!flags.yes && !flags["dry-run"]) {
206
+ if (!flags.yes) {
208
207
  const confirmed = await new Promise((resolve) => {
209
208
  const { waitUntilExit } = render(
210
209
  /* @__PURE__ */ jsx(
@@ -246,19 +245,6 @@ var Uninstall = class _Uninstall extends BaseCommand {
246
245
  }
247
246
  this.log("");
248
247
  }
249
- if (flags["dry-run"]) {
250
- if (target.hasPlugins) {
251
- this.log(`[dry-run] Would uninstall ${target.pluginNames.length} plugins:`);
252
- for (const pluginName of target.pluginNames) {
253
- this.log(`[dry-run] ${pluginName}`);
254
- }
255
- }
256
- await this.dryRunLocalRemoval(target, flags.all);
257
- this.log("");
258
- this.log(DRY_RUN_MESSAGES.COMPLETE_NO_FILES_REMOVED);
259
- this.log("");
260
- return;
261
- }
262
248
  if (target.hasPlugins) {
263
249
  this.log("Uninstalling plugins...");
264
250
  try {
@@ -298,97 +284,81 @@ var Uninstall = class _Uninstall extends BaseCommand {
298
284
  this.logSuccess(SUCCESS_MESSAGES.UNINSTALL_COMPLETE);
299
285
  this.log("");
300
286
  }
301
- /**
302
- * Selectively removes local files installed by the CLI using config-based matching.
303
- *
304
- * - Skills: removes skill dirs whose forked_from.source matches a configured source
305
- * - Agents: removes agents whose frontmatter name matches a configured agent, or
306
- * all agents if config.yaml exists (CLI was used to compile them)
307
- * - Plugins: removed separately (always)
308
- * - .claude-src/: only removed with --all flag
309
- * - .claude/: only removed if empty after selective cleanup
310
- */
311
287
  async removeLocalFiles(target, removeAll) {
312
- let removedSkillCount = 0;
313
- let skippedSkillCount = 0;
314
- if (target.hasLocalSkills) {
315
- const skillDirNames = await listDirectories(target.skillsDir);
316
- for (const skillDirName of skillDirNames) {
317
- const skillDir = path.join(target.skillsDir, skillDirName);
318
- const forkedFrom = await readForkedFromMetadata(skillDir);
319
- const shouldRemove = forkedFrom !== null && (skillMatchesConfiguredSource(forkedFrom.source, target.configuredSources) || // Legacy skills without source field are treated as CLI-managed when config exists
320
- !forkedFrom.source && target.config !== null);
321
- if (shouldRemove) {
322
- await remove(skillDir);
323
- removedSkillCount++;
324
- this.log(` Uninstalled skill '${skillDirName}'`);
325
- } else {
326
- this.warn(`Skipping '${skillDirName}': not created by ${DEFAULT_BRANDING.NAME} CLI`);
327
- skippedSkillCount++;
328
- }
329
- }
330
- if (removedSkillCount > 0) {
331
- this.logSuccess(
332
- `Removed ${removedSkillCount} CLI-installed ${removedSkillCount === 1 ? "skill" : "skills"}`
333
- );
334
- }
335
- if (skippedSkillCount === 0 && await directoryExists(target.skillsDir)) {
336
- if (await isDirectoryEmpty(target.skillsDir)) {
337
- await remove(target.skillsDir);
338
- }
339
- }
340
- }
341
- if (target.hasLocalAgents) {
342
- if (target.config !== null) {
343
- const { readdir } = await import("fs/promises");
344
- try {
345
- const agentFiles = (await readdir(target.agentsDir)).filter((f) => f.endsWith(".md"));
346
- for (const agentFile of agentFiles) {
347
- this.log(` Uninstalled agent '${agentFile.replace(/\.md$/, "")}'`);
348
- }
349
- } catch {
350
- }
351
- await remove(target.agentsDir);
352
- this.logSuccess("Removed compiled agents");
353
- }
354
- }
288
+ await this.removeMatchingSkills(target);
289
+ await this.removeMatchingAgents(target);
355
290
  if (removeAll && target.hasClaudeSrcDir) {
356
291
  await remove(target.claudeSrcDir);
357
292
  this.logSuccess(`Removed ${CLAUDE_SRC_DIR}/`);
358
293
  }
359
- if (target.hasClaudeDir && await directoryExists(target.claudeDir)) {
360
- if (await isDirectoryEmpty(target.claudeDir)) {
361
- await remove(target.claudeDir);
362
- this.logSuccess(`Removed ${CLAUDE_DIR}/`);
294
+ await this.removeEmptyClaudeDir(target);
295
+ }
296
+ async removeMatchingSkills(target) {
297
+ if (!target.hasLocalSkills) return;
298
+ const skillDirNames = await listDirectories(target.skillsDir);
299
+ let removedCount = 0;
300
+ let skippedCount = 0;
301
+ for (const skillDirName of skillDirNames) {
302
+ const skillDir = path.join(target.skillsDir, skillDirName);
303
+ const forkedFrom = await readForkedFromMetadata(skillDir);
304
+ if (shouldRemoveSkill(forkedFrom, target.configuredSources, target.config !== null)) {
305
+ await remove(skillDir);
306
+ removedCount++;
307
+ this.log(` Uninstalled skill '${skillDirName}'`);
363
308
  } else {
364
- this.log(`Kept ${CLAUDE_DIR}/ (contains user content)`);
309
+ this.warn(`Skipping '${skillDirName}': not created by ${DEFAULT_BRANDING.NAME} CLI`);
310
+ skippedCount++;
365
311
  }
366
312
  }
313
+ if (removedCount > 0) {
314
+ this.logSuccess(
315
+ `Removed ${removedCount} CLI-installed ${removedCount === 1 ? "skill" : "skills"}`
316
+ );
317
+ }
318
+ if (skippedCount > 0) return;
319
+ if (!await directoryExists(target.skillsDir)) return;
320
+ if (await isDirectoryEmpty(target.skillsDir)) {
321
+ await remove(target.skillsDir);
322
+ }
367
323
  }
368
- async dryRunLocalRemoval(target, removeAll) {
369
- if (target.hasLocalSkills) {
370
- const skillDirNames = await listDirectories(target.skillsDir);
371
- for (const skillDirName of skillDirNames) {
372
- const skillDir = path.join(target.skillsDir, skillDirName);
373
- const forkedFrom = await readForkedFromMetadata(skillDir);
374
- const shouldRemove = forkedFrom !== null && (skillMatchesConfiguredSource(forkedFrom.source, target.configuredSources) || !forkedFrom.source && target.config !== null);
375
- if (shouldRemove) {
376
- this.log(`[dry-run] Would remove skill '${skillDirName}'`);
377
- } else {
378
- this.log(
379
- `[dry-run] Would skip '${skillDirName}': not created by ${DEFAULT_BRANDING.NAME} CLI`
380
- );
381
- }
382
- }
324
+ async removeMatchingAgents(target) {
325
+ if (!target.hasLocalAgents) return;
326
+ if (target.configuredAgents.length === 0) return;
327
+ const agentFiles = await this.listAgentFiles(target.agentsDir);
328
+ let removedCount = 0;
329
+ for (const agentFile of agentFiles) {
330
+ const agentName = agentFile.replace(/\.md$/, "");
331
+ if (!target.configuredAgents.includes(agentName)) continue;
332
+ await remove(path.join(target.agentsDir, agentFile));
333
+ this.log(` Uninstalled agent '${agentName}'`);
334
+ removedCount++;
383
335
  }
384
- if (target.hasLocalAgents && target.config !== null) {
385
- this.log(`[dry-run] Would remove ${target.agentsDir}/`);
336
+ if (removedCount > 0) {
337
+ this.logSuccess(
338
+ `Removed ${removedCount} compiled ${removedCount === 1 ? "agent" : "agents"}`
339
+ );
386
340
  }
387
- if (removeAll && target.hasClaudeSrcDir) {
388
- this.log(`[dry-run] Would remove ${target.claudeSrcDir}/`);
341
+ if (!await directoryExists(target.agentsDir)) return;
342
+ if (await isDirectoryEmpty(target.agentsDir)) {
343
+ await remove(target.agentsDir);
344
+ }
345
+ }
346
+ async listAgentFiles(agentsDir) {
347
+ try {
348
+ const { readdir } = await import("fs/promises");
349
+ return (await readdir(agentsDir)).filter((f) => f.endsWith(".md"));
350
+ } catch {
351
+ return [];
389
352
  }
390
- if (target.hasClaudeDir) {
391
- this.log(`[dry-run] Would remove ${target.claudeDir}/ only if empty after cleanup`);
353
+ }
354
+ async removeEmptyClaudeDir(target) {
355
+ if (!target.hasClaudeDir) return;
356
+ if (!await directoryExists(target.claudeDir)) return;
357
+ if (await isDirectoryEmpty(target.claudeDir)) {
358
+ await remove(target.claudeDir);
359
+ this.logSuccess(`Removed ${CLAUDE_DIR}/`);
360
+ } else {
361
+ this.log(`Kept ${CLAUDE_DIR}/ (contains user content)`);
392
362
  }
393
363
  }
394
364
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/cli/commands/uninstall.tsx"],"sourcesContent":["import React from \"react\";\n\nimport { Flags } from \"@oclif/core\";\nimport { render, Box, Text, useApp } from \"ink\";\nimport path from \"path\";\n\nimport { BaseCommand } from \"../base-command\";\nimport { Confirm } from \"../components/common/confirm\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { directoryExists, listDirectories, remove } from \"../utils/fs\";\nimport { claudePluginUninstall, isClaudeCLIAvailable } from \"../utils/exec\";\nimport { listPluginNames, getProjectPluginsDir } from \"../lib/plugins\";\nimport { readForkedFromMetadata } from \"../lib/skills\";\nimport { loadProjectSourceConfig } from \"../lib/configuration/config\";\nimport type { ProjectSourceConfig } from \"../lib/configuration/config\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR, CLI_COLORS, DEFAULT_BRANDING } from \"../consts\";\nimport { EXIT_CODES } from \"../lib/exit-codes\";\nimport { SUCCESS_MESSAGES, INFO_MESSAGES, DRY_RUN_MESSAGES } from \"../utils/messages\";\n\ntype UninstallTarget = {\n hasPlugins: boolean;\n pluginNames: string[];\n hasLocalSkills: boolean;\n hasLocalAgents: boolean;\n hasClaudeDir: boolean;\n hasClaudeSrcDir: boolean;\n pluginsDir: string;\n skillsDir: string;\n agentsDir: string;\n claudeDir: string;\n claudeSrcDir: string;\n /** Resolved project source config from .claude-src/config.yaml */\n config: ProjectSourceConfig | null;\n /** All configured source URLs (primary + extras) */\n configuredSources: string[];\n};\n\nfunction collectConfiguredSources(config: ProjectSourceConfig | null): string[] {\n if (!config) return [];\n\n const sources: string[] = [];\n\n if (config.source) {\n sources.push(config.source);\n }\n\n if (config.sources) {\n for (const entry of config.sources) {\n sources.push(entry.url);\n }\n }\n\n return sources;\n}\n\nasync function detectUninstallTarget(projectDir: string): Promise<UninstallTarget> {\n const pluginsDir = getProjectPluginsDir(projectDir);\n const skillsDir = path.join(projectDir, CLAUDE_DIR, \"skills\");\n const agentsDir = path.join(projectDir, CLAUDE_DIR, \"agents\");\n const claudeDir = path.join(projectDir, CLAUDE_DIR);\n const claudeSrcDir = path.join(projectDir, CLAUDE_SRC_DIR);\n\n const [hasLocalSkills, hasLocalAgents, hasClaudeDir, hasClaudeSrcDir, config] = await Promise.all(\n [\n directoryExists(skillsDir),\n directoryExists(agentsDir),\n directoryExists(claudeDir),\n directoryExists(claudeSrcDir),\n loadProjectSourceConfig(projectDir),\n ],\n );\n\n let pluginNames: string[] = [];\n try {\n pluginNames = await listPluginNames(projectDir);\n } catch {\n // Best-effort: plugin detection may fail\n }\n\n const configuredSources = collectConfiguredSources(config);\n\n return {\n hasPlugins: pluginNames.length > 0,\n pluginNames,\n hasLocalSkills,\n hasLocalAgents,\n hasClaudeDir,\n hasClaudeSrcDir,\n pluginsDir,\n skillsDir,\n agentsDir,\n claudeDir,\n claudeSrcDir,\n config,\n configuredSources,\n };\n}\n\ntype UninstallConfirmProps = {\n target: UninstallTarget;\n removeAll: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n};\n\nconst UninstallConfirm: React.FC<UninstallConfirmProps> = ({\n target,\n removeAll,\n onConfirm,\n onCancel,\n}) => {\n const { exit } = useApp();\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>The following will be removed:</Text>\n <Text> </Text>\n\n {target.hasPlugins && (\n <Box flexDirection=\"column\">\n <Text color={CLI_COLORS.ERROR}> Plugins:</Text>\n <Text dimColor> {target.pluginsDir}</Text>\n </Box>\n )}\n\n {(target.hasLocalSkills || target.hasLocalAgents) && (\n <Box flexDirection=\"column\">\n <Text color={CLI_COLORS.ERROR}> CLI-managed files:</Text>\n {target.hasLocalSkills && <Text dimColor> {target.skillsDir}/ (matching sources)</Text>}\n {target.hasLocalAgents && <Text dimColor> {target.agentsDir}/ (CLI-compiled)</Text>}\n </Box>\n )}\n\n {removeAll && target.hasClaudeSrcDir && (\n <Box flexDirection=\"column\">\n <Text color={CLI_COLORS.ERROR}> Config:</Text>\n <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\nasync function isDirectoryEmpty(dirPath: string): Promise<boolean> {\n const { readdir } = await import(\"fs/promises\");\n try {\n const allEntries = await readdir(dirPath);\n return allEntries.length === 0;\n } catch {\n return true;\n }\n}\n\nfunction skillMatchesConfiguredSource(\n forkedFromSource: string | undefined,\n configuredSources: string[],\n): boolean {\n if (!forkedFromSource || configuredSources.length === 0) return false;\n return configuredSources.includes(forkedFromSource);\n}\n\nexport default class Uninstall extends BaseCommand {\n static summary = `Remove ${DEFAULT_BRANDING.NAME} from this project`;\n\n static description = `Uninstall ${DEFAULT_BRANDING.NAME} from this project. Removes CLI-managed skills (matched by source), compiled agents, and plugins. User-created content is preserved.`;\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --yes\",\n \"<%= config.bin %> <%= command.id %> --all\",\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 all: Flags.boolean({\n description: \"Also remove .claude-src/ config directory\",\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(`${DEFAULT_BRANDING.NAME} Uninstall`);\n this.log(\"\");\n\n if (flags[\"dry-run\"]) {\n this.log(DRY_RUN_MESSAGES.PREVIEW_NO_FILES_REMOVED);\n this.log(\"\");\n }\n\n const target = await detectUninstallTarget(projectDir);\n\n const hasAnythingToRemove =\n target.hasPlugins ||\n target.hasLocalSkills ||\n target.hasLocalAgents ||\n (flags.all && target.hasClaudeSrcDir);\n\n if (!hasAnythingToRemove) {\n this.warn(\"Nothing to uninstall.\");\n this.log(\"\");\n this.log(INFO_MESSAGES.NOT_INSTALLED);\n this.log(\"\");\n this.log(INFO_MESSAGES.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 removeAll={flags.all}\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 (target.hasPlugins) {\n this.log(\" Plugins:\");\n this.log(` ${target.pluginsDir}`);\n }\n\n if (target.hasLocalSkills || target.hasLocalAgents) {\n this.log(\" CLI-managed files:\");\n if (target.hasLocalSkills) {\n this.log(` ${target.skillsDir}/ (matching sources)`);\n }\n if (target.hasLocalAgents) {\n this.log(` ${target.agentsDir}/ (CLI-compiled)`);\n }\n }\n\n if (flags.all && target.hasClaudeSrcDir) {\n this.log(\" Config:\");\n this.log(` ${target.claudeSrcDir}/`);\n }\n\n this.log(\"\");\n }\n\n if (flags[\"dry-run\"]) {\n if (target.hasPlugins) {\n this.log(`[dry-run] Would uninstall ${target.pluginNames.length} plugins:`);\n for (const pluginName of target.pluginNames) {\n this.log(`[dry-run] ${pluginName}`);\n }\n }\n\n await this.dryRunLocalRemoval(target, flags.all);\n\n this.log(\"\");\n this.log(DRY_RUN_MESSAGES.COMPLETE_NO_FILES_REMOVED);\n this.log(\"\");\n return;\n }\n\n if (target.hasPlugins) {\n this.log(\"Uninstalling plugins...\");\n\n try {\n const cliAvailable = await isClaudeCLIAvailable();\n\n for (const pluginName of target.pluginNames) {\n if (cliAvailable) {\n try {\n await claudePluginUninstall(pluginName, \"project\", projectDir);\n } catch {\n // Best-effort: plugin may not be registered with Claude CLI\n }\n }\n\n const pluginPath = path.join(target.pluginsDir, pluginName);\n await remove(pluginPath);\n this.log(` Uninstalled plugin '${pluginName}'`);\n }\n\n this.logSuccess(\n `Uninstalled ${target.pluginNames.length} ${target.pluginNames.length === 1 ? \"plugin\" : \"plugins\"}`,\n );\n } catch (error) {\n this.log(\"Plugin uninstall failed\");\n this.error(getErrorMessage(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n\n try {\n await this.removeLocalFiles(target, flags.all);\n } catch (error) {\n this.log(\"Failed to remove local files\");\n this.error(getErrorMessage(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n this.log(\"\");\n this.log(`${DEFAULT_BRANDING.NAME} has been uninstalled.`);\n this.log(\"\");\n this.logSuccess(SUCCESS_MESSAGES.UNINSTALL_COMPLETE);\n this.log(\"\");\n }\n\n /**\n * Selectively removes local files installed by the CLI using config-based matching.\n *\n * - Skills: removes skill dirs whose forked_from.source matches a configured source\n * - Agents: removes agents whose frontmatter name matches a configured agent, or\n * all agents if config.yaml exists (CLI was used to compile them)\n * - Plugins: removed separately (always)\n * - .claude-src/: only removed with --all flag\n * - .claude/: only removed if empty after selective cleanup\n */\n private async removeLocalFiles(target: UninstallTarget, removeAll: boolean): Promise<void> {\n let removedSkillCount = 0;\n let skippedSkillCount = 0;\n\n if (target.hasLocalSkills) {\n const skillDirNames = await listDirectories(target.skillsDir);\n\n for (const skillDirName of skillDirNames) {\n const skillDir = path.join(target.skillsDir, skillDirName);\n const forkedFrom = await readForkedFromMetadata(skillDir);\n\n const shouldRemove =\n forkedFrom !== null &&\n (skillMatchesConfiguredSource(forkedFrom.source, target.configuredSources) ||\n // Legacy skills without source field are treated as CLI-managed when config exists\n (!forkedFrom.source && target.config !== null));\n\n if (shouldRemove) {\n await remove(skillDir);\n removedSkillCount++;\n this.log(` Uninstalled skill '${skillDirName}'`);\n } else {\n this.warn(`Skipping '${skillDirName}': not created by ${DEFAULT_BRANDING.NAME} CLI`);\n skippedSkillCount++;\n }\n }\n\n if (removedSkillCount > 0) {\n this.logSuccess(\n `Removed ${removedSkillCount} CLI-installed ${removedSkillCount === 1 ? \"skill\" : \"skills\"}`,\n );\n }\n\n if (skippedSkillCount === 0 && (await directoryExists(target.skillsDir))) {\n if (await isDirectoryEmpty(target.skillsDir)) {\n await remove(target.skillsDir);\n }\n }\n }\n\n if (target.hasLocalAgents) {\n // config.yaml presence indicates the CLI compiled these agents\n if (target.config !== null) {\n const { readdir } = await import(\"fs/promises\");\n try {\n const agentFiles = (await readdir(target.agentsDir)).filter((f) => f.endsWith(\".md\"));\n for (const agentFile of agentFiles) {\n this.log(` Uninstalled agent '${agentFile.replace(/\\.md$/, \"\")}'`);\n }\n } catch {\n // Best-effort: directory listing may fail\n }\n await remove(target.agentsDir);\n this.logSuccess(\"Removed compiled agents\");\n }\n }\n\n if (removeAll && target.hasClaudeSrcDir) {\n await remove(target.claudeSrcDir);\n this.logSuccess(`Removed ${CLAUDE_SRC_DIR}/`);\n }\n\n if (target.hasClaudeDir && (await directoryExists(target.claudeDir))) {\n if (await isDirectoryEmpty(target.claudeDir)) {\n await remove(target.claudeDir);\n this.logSuccess(`Removed ${CLAUDE_DIR}/`);\n } else {\n this.log(`Kept ${CLAUDE_DIR}/ (contains user content)`);\n }\n }\n }\n\n private async dryRunLocalRemoval(target: UninstallTarget, removeAll: boolean): Promise<void> {\n if (target.hasLocalSkills) {\n const skillDirNames = await listDirectories(target.skillsDir);\n\n for (const skillDirName of skillDirNames) {\n const skillDir = path.join(target.skillsDir, skillDirName);\n const forkedFrom = await readForkedFromMetadata(skillDir);\n\n const shouldRemove =\n forkedFrom !== null &&\n (skillMatchesConfiguredSource(forkedFrom.source, target.configuredSources) ||\n (!forkedFrom.source && target.config !== null));\n\n if (shouldRemove) {\n this.log(`[dry-run] Would remove skill '${skillDirName}'`);\n } else {\n this.log(\n `[dry-run] Would skip '${skillDirName}': not created by ${DEFAULT_BRANDING.NAME} CLI`,\n );\n }\n }\n }\n\n if (target.hasLocalAgents && target.config !== null) {\n this.log(`[dry-run] Would remove ${target.agentsDir}/`);\n }\n\n if (removeAll && target.hasClaudeSrcDir) {\n this.log(`[dry-run] Would remove ${target.claudeSrcDir}/`);\n }\n\n if (target.hasClaudeDir) {\n this.log(`[dry-run] Would remove ${target.claudeDir}/ only if empty after cleanup`);\n }\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/cli/commands/uninstall.tsx"],"sourcesContent":["import React from \"react\";\n\nimport { Flags } from \"@oclif/core\";\nimport { render, Box, Text, useApp } from \"ink\";\nimport path from \"path\";\n\nimport { BaseCommand } from \"../base-command\";\nimport { Confirm } from \"../components/common/confirm\";\nimport { getErrorMessage } from \"../utils/errors\";\nimport { directoryExists, listDirectories, remove } from \"../utils/fs\";\nimport { claudePluginUninstall, isClaudeCLIAvailable } from \"../utils/exec\";\nimport { listPluginNames, getProjectPluginsDir } from \"../lib/plugins\";\nimport { readForkedFromMetadata } from \"../lib/skills\";\nimport { loadProjectSourceConfig } from \"../lib/configuration/config\";\nimport type { ProjectSourceConfig } from \"../lib/configuration/config\";\nimport { CLAUDE_DIR, CLAUDE_SRC_DIR, CLI_COLORS, DEFAULT_BRANDING } from \"../consts\";\nimport { EXIT_CODES } from \"../lib/exit-codes\";\nimport { SUCCESS_MESSAGES, INFO_MESSAGES } from \"../utils/messages\";\n\ntype UninstallTarget = {\n hasPlugins: boolean;\n pluginNames: string[];\n hasLocalSkills: boolean;\n hasLocalAgents: boolean;\n hasClaudeDir: boolean;\n hasClaudeSrcDir: boolean;\n pluginsDir: string;\n skillsDir: string;\n agentsDir: string;\n claudeDir: string;\n claudeSrcDir: string;\n /** Resolved project source config from .claude-src/config.ts */\n config: ProjectSourceConfig | null;\n /** All configured source URLs (primary + extras) */\n configuredSources: string[];\n /** Agent names from the generated config (e.g., [\"web-developer\"]) */\n configuredAgents: string[];\n};\n\nfunction collectConfiguredSources(config: ProjectSourceConfig | null): string[] {\n if (!config) return [];\n return [\n ...(config.source ? [config.source] : []),\n ...(config.sources?.map((entry) => entry.url) ?? []),\n ];\n}\n\nfunction collectConfiguredAgents(config: ProjectSourceConfig | null): string[] {\n if (!config) return [];\n // Boundary cast: config loaded via .passthrough() schema, agents preserved as AgentScopeConfig[]\n const agents = (config as Record<string, unknown>).agents;\n if (!Array.isArray(agents)) return [];\n return agents.map((a: { name: string }) => a.name);\n}\n\nasync function detectUninstallTarget(projectDir: string): Promise<UninstallTarget> {\n const pluginsDir = getProjectPluginsDir(projectDir);\n const skillsDir = path.join(projectDir, CLAUDE_DIR, \"skills\");\n const agentsDir = path.join(projectDir, CLAUDE_DIR, \"agents\");\n const claudeDir = path.join(projectDir, CLAUDE_DIR);\n const claudeSrcDir = path.join(projectDir, CLAUDE_SRC_DIR);\n\n const [hasLocalSkills, hasLocalAgents, hasClaudeDir, hasClaudeSrcDir, config] = await Promise.all(\n [\n directoryExists(skillsDir),\n directoryExists(agentsDir),\n directoryExists(claudeDir),\n directoryExists(claudeSrcDir),\n loadProjectSourceConfig(projectDir),\n ],\n );\n\n let pluginNames: string[] = [];\n try {\n pluginNames = await listPluginNames(projectDir);\n } catch {\n // Best-effort: plugin detection may fail\n }\n\n const configuredSources = collectConfiguredSources(config);\n const configuredAgents = collectConfiguredAgents(config);\n\n return {\n hasPlugins: pluginNames.length > 0,\n pluginNames,\n hasLocalSkills,\n hasLocalAgents,\n hasClaudeDir,\n hasClaudeSrcDir,\n pluginsDir,\n skillsDir,\n agentsDir,\n claudeDir,\n claudeSrcDir,\n config,\n configuredSources,\n configuredAgents,\n };\n}\n\ntype UninstallConfirmProps = {\n target: UninstallTarget;\n removeAll: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n};\n\nconst UninstallConfirm: React.FC<UninstallConfirmProps> = ({\n target,\n removeAll,\n onConfirm,\n onCancel,\n}) => {\n const { exit } = useApp();\n\n return (\n <Box flexDirection=\"column\">\n <Text bold>The following will be removed:</Text>\n <Text> </Text>\n\n {target.hasPlugins && (\n <Box flexDirection=\"column\">\n <Text color={CLI_COLORS.ERROR}> Plugins:</Text>\n <Text dimColor> {target.pluginsDir}</Text>\n </Box>\n )}\n\n {(target.hasLocalSkills || target.hasLocalAgents) && (\n <Box flexDirection=\"column\">\n <Text color={CLI_COLORS.ERROR}> CLI-managed files:</Text>\n {target.hasLocalSkills && <Text dimColor> {target.skillsDir}/ (matching sources)</Text>}\n {target.hasLocalAgents && <Text dimColor> {target.agentsDir}/ (CLI-compiled)</Text>}\n </Box>\n )}\n\n {removeAll && target.hasClaudeSrcDir && (\n <Box flexDirection=\"column\">\n <Text color={CLI_COLORS.ERROR}> Config:</Text>\n <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\nasync function isDirectoryEmpty(dirPath: string): Promise<boolean> {\n const { readdir } = await import(\"fs/promises\");\n try {\n const allEntries = await readdir(dirPath);\n return allEntries.length === 0;\n } catch {\n return true;\n }\n}\n\nfunction skillMatchesConfiguredSource(\n forkedFromSource: string | undefined,\n configuredSources: string[],\n): boolean {\n if (!forkedFromSource || configuredSources.length === 0) return false;\n return configuredSources.includes(forkedFromSource);\n}\n\nfunction shouldRemoveSkill(\n forkedFrom: { source?: string } | null,\n configuredSources: string[],\n hasConfig: boolean,\n): boolean {\n return (\n forkedFrom !== null &&\n (skillMatchesConfiguredSource(forkedFrom.source, configuredSources) ||\n (!forkedFrom.source && hasConfig))\n );\n}\n\nexport default class Uninstall extends BaseCommand {\n static summary = `Remove ${DEFAULT_BRANDING.NAME} from this project`;\n\n static description = `Uninstall ${DEFAULT_BRANDING.NAME} from this project. Removes CLI-managed skills (matched by source), compiled agents, and plugins. User-created content is preserved.`;\n\n static examples = [\n \"<%= config.bin %> <%= command.id %>\",\n \"<%= config.bin %> <%= command.id %> --yes\",\n \"<%= config.bin %> <%= command.id %> --all\",\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 all: Flags.boolean({\n description: \"Also remove .claude-src/ config directory\",\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(`${DEFAULT_BRANDING.NAME} Uninstall`);\n this.log(\"\");\n\n const target = await detectUninstallTarget(projectDir);\n\n const hasAnythingToRemove =\n target.hasPlugins ||\n target.hasLocalSkills ||\n target.hasLocalAgents ||\n (flags.all && target.hasClaudeSrcDir);\n\n if (!hasAnythingToRemove) {\n this.warn(\"Nothing to uninstall.\");\n this.log(\"\");\n this.log(INFO_MESSAGES.NOT_INSTALLED);\n this.log(\"\");\n this.log(INFO_MESSAGES.NO_CHANGES_MADE);\n return;\n }\n\n if (!flags.yes) {\n const confirmed = await new Promise<boolean>((resolve) => {\n const { waitUntilExit } = render(\n <UninstallConfirm\n target={target}\n removeAll={flags.all}\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 (target.hasPlugins) {\n this.log(\" Plugins:\");\n this.log(` ${target.pluginsDir}`);\n }\n\n if (target.hasLocalSkills || target.hasLocalAgents) {\n this.log(\" CLI-managed files:\");\n if (target.hasLocalSkills) {\n this.log(` ${target.skillsDir}/ (matching sources)`);\n }\n if (target.hasLocalAgents) {\n this.log(` ${target.agentsDir}/ (CLI-compiled)`);\n }\n }\n\n if (flags.all && target.hasClaudeSrcDir) {\n this.log(\" Config:\");\n this.log(` ${target.claudeSrcDir}/`);\n }\n\n this.log(\"\");\n }\n\n if (target.hasPlugins) {\n this.log(\"Uninstalling plugins...\");\n\n try {\n const cliAvailable = await isClaudeCLIAvailable();\n\n for (const pluginName of target.pluginNames) {\n if (cliAvailable) {\n try {\n await claudePluginUninstall(pluginName, \"project\", projectDir);\n } catch {\n // Best-effort: plugin may not be registered with Claude CLI\n }\n }\n\n const pluginPath = path.join(target.pluginsDir, pluginName);\n await remove(pluginPath);\n this.log(` Uninstalled plugin '${pluginName}'`);\n }\n\n this.logSuccess(\n `Uninstalled ${target.pluginNames.length} ${target.pluginNames.length === 1 ? \"plugin\" : \"plugins\"}`,\n );\n } catch (error) {\n this.log(\"Plugin uninstall failed\");\n this.error(getErrorMessage(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n }\n\n try {\n await this.removeLocalFiles(target, flags.all);\n } catch (error) {\n this.log(\"Failed to remove local files\");\n this.error(getErrorMessage(error), {\n exit: EXIT_CODES.ERROR,\n });\n }\n\n this.log(\"\");\n this.log(`${DEFAULT_BRANDING.NAME} has been uninstalled.`);\n this.log(\"\");\n this.logSuccess(SUCCESS_MESSAGES.UNINSTALL_COMPLETE);\n this.log(\"\");\n }\n\n private async removeLocalFiles(target: UninstallTarget, removeAll: boolean): Promise<void> {\n await this.removeMatchingSkills(target);\n await this.removeMatchingAgents(target);\n\n if (removeAll && target.hasClaudeSrcDir) {\n await remove(target.claudeSrcDir);\n this.logSuccess(`Removed ${CLAUDE_SRC_DIR}/`);\n }\n\n await this.removeEmptyClaudeDir(target);\n }\n\n private async removeMatchingSkills(target: UninstallTarget): Promise<void> {\n if (!target.hasLocalSkills) return;\n\n const skillDirNames = await listDirectories(target.skillsDir);\n let removedCount = 0;\n let skippedCount = 0;\n\n for (const skillDirName of skillDirNames) {\n const skillDir = path.join(target.skillsDir, skillDirName);\n const forkedFrom = await readForkedFromMetadata(skillDir);\n\n if (shouldRemoveSkill(forkedFrom, target.configuredSources, target.config !== null)) {\n await remove(skillDir);\n removedCount++;\n this.log(` Uninstalled skill '${skillDirName}'`);\n } else {\n this.warn(`Skipping '${skillDirName}': not created by ${DEFAULT_BRANDING.NAME} CLI`);\n skippedCount++;\n }\n }\n\n if (removedCount > 0) {\n this.logSuccess(\n `Removed ${removedCount} CLI-installed ${removedCount === 1 ? \"skill\" : \"skills\"}`,\n );\n }\n\n if (skippedCount > 0) return;\n if (!(await directoryExists(target.skillsDir))) return;\n if (await isDirectoryEmpty(target.skillsDir)) {\n await remove(target.skillsDir);\n }\n }\n\n private async removeMatchingAgents(target: UninstallTarget): Promise<void> {\n if (!target.hasLocalAgents) return;\n if (target.configuredAgents.length === 0) return;\n\n const agentFiles = await this.listAgentFiles(target.agentsDir);\n let removedCount = 0;\n\n for (const agentFile of agentFiles) {\n const agentName = agentFile.replace(/\\.md$/, \"\");\n if (!target.configuredAgents.includes(agentName)) continue;\n\n await remove(path.join(target.agentsDir, agentFile));\n this.log(` Uninstalled agent '${agentName}'`);\n removedCount++;\n }\n\n if (removedCount > 0) {\n this.logSuccess(\n `Removed ${removedCount} compiled ${removedCount === 1 ? \"agent\" : \"agents\"}`,\n );\n }\n\n if (!(await directoryExists(target.agentsDir))) return;\n if (await isDirectoryEmpty(target.agentsDir)) {\n await remove(target.agentsDir);\n }\n }\n\n private async listAgentFiles(agentsDir: string): Promise<string[]> {\n try {\n const { readdir } = await import(\"fs/promises\");\n return (await readdir(agentsDir)).filter((f) => f.endsWith(\".md\"));\n } catch {\n return [];\n }\n }\n\n private async removeEmptyClaudeDir(target: UninstallTarget): Promise<void> {\n if (!target.hasClaudeDir) return;\n if (!(await directoryExists(target.claudeDir))) return;\n\n if (await isDirectoryEmpty(target.claudeDir)) {\n await remove(target.claudeDir);\n this.logSuccess(`Removed ${CLAUDE_DIR}/`);\n } else {\n this.log(`Kept ${CLAUDE_DIR}/ (contains user content)`);\n }\n }\n}\n"],"mappings":"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","names":[]}