bi-superpowers 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. package/.claude-plugin/marketplace.json +31 -0
  2. package/.claude-plugin/plugin.json +34 -0
  3. package/.claude-plugin/skill-manifest.json +79 -0
  4. package/.mcp.json +13 -0
  5. package/.plugin/plugin.json +14 -0
  6. package/LICENSE +21 -0
  7. package/README.md +849 -0
  8. package/bin/build-plugin.js +97 -0
  9. package/bin/cli.js +891 -0
  10. package/bin/commands/autoupdate.js +128 -0
  11. package/bin/commands/build-desktop.js +368 -0
  12. package/bin/commands/create-from-template.js +165 -0
  13. package/bin/commands/diff.js +435 -0
  14. package/bin/commands/install.js +542 -0
  15. package/bin/commands/lint.js +441 -0
  16. package/bin/commands/mcp-setup.js +255 -0
  17. package/bin/commands/session-update.js +204 -0
  18. package/bin/commands/smoke-test.js +20 -0
  19. package/bin/commands/uninstall.js +611 -0
  20. package/bin/commands/update-check.js +427 -0
  21. package/bin/commands/validate-cases.js +264 -0
  22. package/bin/commands/validate-projects.js +426 -0
  23. package/bin/commands/watch.js +251 -0
  24. package/bin/lib/agents.js +62 -0
  25. package/bin/lib/base-template-smoke.js +299 -0
  26. package/bin/lib/claude-hooks.js +160 -0
  27. package/bin/lib/generators/claude-plugin.js +529 -0
  28. package/bin/lib/generators/index.js +116 -0
  29. package/bin/lib/generators/shared.js +257 -0
  30. package/bin/lib/mcp-config.js +835 -0
  31. package/bin/lib/microsoft-mcp.js +206 -0
  32. package/bin/lib/powerbi-mcp-session.js +140 -0
  33. package/bin/lib/skills.js +164 -0
  34. package/bin/lib/template-scaffold.js +366 -0
  35. package/bin/mcp/powerbi-modeling-launcher.js +42 -0
  36. package/bin/postinstall.js +50 -0
  37. package/bin/utils/mcp-detect.js +346 -0
  38. package/bin/utils/tui.js +314 -0
  39. package/commands/bi-connect.md +520 -0
  40. package/commands/bi-dax.md +464 -0
  41. package/commands/bi-kickoff.md +550 -0
  42. package/commands/bi-modeling.md +485 -0
  43. package/commands/bi-performance.md +521 -0
  44. package/commands/bi-powerquery.md +229 -0
  45. package/commands/bi-refactor.md +249 -0
  46. package/commands/bi-scorecard.md +268 -0
  47. package/commands/bi-start.md +272 -0
  48. package/config.example.json +23 -0
  49. package/config.json +23 -0
  50. package/desktop-extension/manifest.json +30 -0
  51. package/desktop-extension/package.json +10 -0
  52. package/desktop-extension/server.js +137 -0
  53. package/package.json +94 -0
  54. package/skills/bi-connect/SKILL.md +522 -0
  55. package/skills/bi-connect/scripts/update-check.js +427 -0
  56. package/skills/bi-dax/SKILL.md +466 -0
  57. package/skills/bi-dax/scripts/update-check.js +427 -0
  58. package/skills/bi-kickoff/SKILL.md +552 -0
  59. package/skills/bi-kickoff/references/flow.html +78 -0
  60. package/skills/bi-kickoff/references/flow.md +62 -0
  61. package/skills/bi-kickoff/scripts/update-check.js +427 -0
  62. package/skills/bi-modeling/SKILL.md +487 -0
  63. package/skills/bi-modeling/scripts/update-check.js +427 -0
  64. package/skills/bi-performance/SKILL.md +523 -0
  65. package/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
  66. package/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
  67. package/skills/bi-performance/scripts/update-check.js +427 -0
  68. package/skills/bi-powerquery/SKILL.md +231 -0
  69. package/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
  70. package/skills/bi-powerquery/references/power-query-standards.md +74 -0
  71. package/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
  72. package/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
  73. package/skills/bi-powerquery/scripts/update-check.js +427 -0
  74. package/skills/bi-refactor/SKILL.md +251 -0
  75. package/skills/bi-refactor/references/flow.md +27 -0
  76. package/skills/bi-refactor/scripts/update-check.js +427 -0
  77. package/skills/bi-scorecard/SKILL.md +270 -0
  78. package/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
  79. package/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
  80. package/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
  81. package/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
  82. package/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
  83. package/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
  84. package/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
  85. package/skills/bi-scorecard/scripts/update-check.js +427 -0
  86. package/skills/bi-start/SKILL.md +274 -0
  87. package/skills/bi-start/scripts/update-check.js +427 -0
  88. package/src/content/base.md +197 -0
  89. package/src/content/mcp-requirements.json +57 -0
  90. package/src/content/routing.md +201 -0
  91. package/src/content/skills/bi-connect.md +493 -0
  92. package/src/content/skills/bi-dax.md +437 -0
  93. package/src/content/skills/bi-kickoff/SKILL.md +523 -0
  94. package/src/content/skills/bi-kickoff/references/flow.html +78 -0
  95. package/src/content/skills/bi-kickoff/references/flow.md +62 -0
  96. package/src/content/skills/bi-modeling.md +458 -0
  97. package/src/content/skills/bi-performance/SKILL.md +494 -0
  98. package/src/content/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
  99. package/src/content/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
  100. package/src/content/skills/bi-powerquery/SKILL.md +202 -0
  101. package/src/content/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
  102. package/src/content/skills/bi-powerquery/references/power-query-standards.md +74 -0
  103. package/src/content/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
  104. package/src/content/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
  105. package/src/content/skills/bi-refactor/SKILL.md +222 -0
  106. package/src/content/skills/bi-refactor/references/flow.md +27 -0
  107. package/src/content/skills/bi-scorecard/SKILL.md +241 -0
  108. package/src/content/skills/bi-scorecard/examples/base-template-scorecard-blueprint.expected.json +105 -0
  109. package/src/content/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
  110. package/src/content/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
  111. package/src/content/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
  112. package/src/content/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
  113. package/src/content/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
  114. package/src/content/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
  115. package/src/content/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
  116. package/src/content/skills/bi-start.md +266 -0
  117. package/templates/base-template/AGENTS.md +33 -0
  118. package/templates/base-template/base-template.Report/.platform +11 -0
  119. package/templates/base-template/base-template.Report/StaticResources/RegisteredResources/BISuperpowers.json +3888 -0
  120. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/CY18SU07.json +177 -0
  121. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/Fluent2-CY26SU03.json +4104 -0
  122. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleCityPark.json +26 -0
  123. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleDefault.json +26 -0
  124. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleNeutral.json +26 -0
  125. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleOrchid.json +26 -0
  126. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleTidal.json +26 -0
  127. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Bloom.json +139 -0
  128. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CityPark.json +40 -0
  129. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Classroom.json +40 -0
  130. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/ColorblindSafe.json +48 -0
  131. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CopilotDefault.json +1861 -0
  132. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Divergent.json +127 -0
  133. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Electric.json +48 -0
  134. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Frontier.json +136 -0
  135. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/HighContrast.json +40 -0
  136. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Highrise.json +41 -0
  137. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Innovate.json +227 -0
  138. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/NewExecutive.json +41 -0
  139. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Solar.json +33 -0
  140. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Storm.json +25 -0
  141. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Sunset.json +48 -0
  142. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Temperature.json +33 -0
  143. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Tidal.json +100 -0
  144. package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Twilight.json +40 -0
  145. package/templates/base-template/base-template.Report/definition/bookmarks/1d40d43c7ade66e8603c.bookmark.json +2297 -0
  146. package/templates/base-template/base-template.Report/definition/bookmarks/af068ff51c0ca3089ea7.bookmark.json +2300 -0
  147. package/templates/base-template/base-template.Report/definition/bookmarks/bookmarks.json +11 -0
  148. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/page.json +130 -0
  149. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/mobile.json +11 -0
  150. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/visual.json +669 -0
  151. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/mobile.json +11 -0
  152. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/visual.json +723 -0
  153. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/mobile.json +11 -0
  154. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/visual.json +333 -0
  155. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/mobile.json +11 -0
  156. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/visual.json +109 -0
  157. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/mobile.json +31 -0
  158. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/visual.json +378 -0
  159. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/mobile.json +11 -0
  160. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/visual.json +175 -0
  161. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/mobile.json +11 -0
  162. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/visual.json +468 -0
  163. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/mobile.json +11 -0
  164. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/visual.json +359 -0
  165. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/mobile.json +11 -0
  166. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/visual.json +690 -0
  167. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/90677f13cea5d1275990/visual.json +17 -0
  168. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/mobile.json +11 -0
  169. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/visual.json +468 -0
  170. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/mobile.json +10 -0
  171. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/visual.json +328 -0
  172. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/mobile.json +11 -0
  173. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/visual.json +578 -0
  174. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/mobile.json +11 -0
  175. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/visual.json +432 -0
  176. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/mobile.json +11 -0
  177. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/visual.json +801 -0
  178. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/mobile.json +37 -0
  179. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/visual.json +1318 -0
  180. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b529688fe5a226643322/visual.json +209 -0
  181. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/mobile.json +11 -0
  182. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/visual.json +174 -0
  183. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/mobile.json +29 -0
  184. package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/visual.json +241 -0
  185. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/page.json +130 -0
  186. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/mobile.json +11 -0
  187. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/visual.json +690 -0
  188. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/mobile.json +11 -0
  189. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/visual.json +468 -0
  190. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/mobile.json +11 -0
  191. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/visual.json +359 -0
  192. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/mobile.json +11 -0
  193. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/visual.json +669 -0
  194. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/mobile.json +11 -0
  195. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/visual.json +109 -0
  196. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/31c21f8cbeb3b208940a/visual.json +209 -0
  197. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/3ab72c25062437149b03/visual.json +17 -0
  198. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/mobile.json +11 -0
  199. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/visual.json +788 -0
  200. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/mobile.json +11 -0
  201. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/visual.json +592 -0
  202. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/mobile.json +11 -0
  203. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/visual.json +468 -0
  204. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/mobile.json +11 -0
  205. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/visual.json +1310 -0
  206. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/mobile.json +11 -0
  207. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/visual.json +175 -0
  208. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/mobile.json +11 -0
  209. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/visual.json +516 -0
  210. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d1e86f213a3841d12e20/visual.json +328 -0
  211. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/mobile.json +11 -0
  212. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/visual.json +432 -0
  213. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/mobile.json +11 -0
  214. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/visual.json +241 -0
  215. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/mobile.json +11 -0
  216. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/visual.json +174 -0
  217. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/mobile.json +11 -0
  218. package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/visual.json +333 -0
  219. package/templates/base-template/base-template.Report/definition/pages/pages.json +8 -0
  220. package/templates/base-template/base-template.Report/definition/report.json +89 -0
  221. package/templates/base-template/base-template.Report/definition/version.json +4 -0
  222. package/templates/base-template/base-template.Report/definition.pbir +9 -0
  223. package/templates/base-template/base-template.SemanticModel/.platform +11 -0
  224. package/templates/base-template/base-template.SemanticModel/definition/cultures/es-AR.tmdl +11185 -0
  225. package/templates/base-template/base-template.SemanticModel/definition/database.tmdl +3 -0
  226. package/templates/base-template/base-template.SemanticModel/definition/expressions.tmdl +234 -0
  227. package/templates/base-template/base-template.SemanticModel/definition/functions.tmdl +637 -0
  228. package/templates/base-template/base-template.SemanticModel/definition/model.tmdl +82 -0
  229. package/templates/base-template/base-template.SemanticModel/definition/relationships.tmdl +271 -0
  230. package/templates/base-template/base-template.SemanticModel/definition/tables/Calendario.tmdl +200 -0
  231. package/templates/base-template/base-template.SemanticModel/definition/tables/Campa/303/261as.tmdl +75 -0
  232. package/templates/base-template/base-template.SemanticModel/definition/tables/Canales.tmdl +84 -0
  233. package/templates/base-template/base-template.SemanticModel/definition/tables/Clientes.tmdl +143 -0
  234. package/templates/base-template/base-template.SemanticModel/definition/tables/Devoluciones.tmdl +95 -0
  235. package/templates/base-template/base-template.SemanticModel/definition/tables/Ejecuci/303/263n proyectos.tmdl" +130 -0
  236. package/templates/base-template/base-template.SemanticModel/definition/tables/Entregas.tmdl +122 -0
  237. package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos m/303/251tricas.tmdl" +40 -0
  238. package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos.tmdl +73 -0
  239. package/templates/base-template/base-template.SemanticModel/definition/tables/Horas.tmdl +122 -0
  240. package/templates/base-template/base-template.SemanticModel/definition/tables/Interacciones clientes.tmdl +146 -0
  241. package/templates/base-template/base-template.SemanticModel/definition/tables/Leads.tmdl +119 -0
  242. package/templates/base-template/base-template.SemanticModel/definition/tables/Monedas.tmdl +44 -0
  243. package/templates/base-template/base-template.SemanticModel/definition/tables/Movimientos financieros.tmdl +145 -0
  244. package/templates/base-template/base-template.SemanticModel/definition/tables/M/303/251tricas.tmdl +1294 -0
  245. package/templates/base-template/base-template.SemanticModel/definition/tables/N/303/263mina.tmdl +110 -0
  246. package/templates/base-template/base-template.SemanticModel/definition/tables/Oportunidades.tmdl +135 -0
  247. package/templates/base-template/base-template.SemanticModel/definition/tables/Presupuesto.tmdl +125 -0
  248. package/templates/base-template/base-template.SemanticModel/definition/tables/Productos.tmdl +98 -0
  249. package/templates/base-template/base-template.SemanticModel/definition/tables/Proyectos.tmdl +77 -0
  250. package/templates/base-template/base-template.SemanticModel/definition/tables/Servicios.tmdl +75 -0
  251. package/templates/base-template/base-template.SemanticModel/definition/tables/Tareas proyecto.tmdl +102 -0
  252. package/templates/base-template/base-template.SemanticModel/definition/tables/Tipo de cambio.tmdl +67 -0
  253. package/templates/base-template/base-template.SemanticModel/definition/tables/Ventas.tmdl +180 -0
  254. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux An/303/241lisis dimensiones.tmdl" +38 -0
  255. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Comparaciones.tmdl +227 -0
  256. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Compatibilidad m/303/251trica-dimensi/303/263n.tmdl" +68 -0
  257. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modelo configuraci/303/263n.tmdl" +44 -0
  258. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modo fechas.tmdl +36 -0
  259. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux M/303/251trica-Equipo.tmdl" +102 -0
  260. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Overrides m/303/251trica-dimensi/303/263n.tmdl" +54 -0
  261. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Per/303/255odos.tmdl" +182 -0
  262. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas modo.tmdl +36 -0
  263. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas.tmdl +27 -0
  264. package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Vista de calendario.tmdl +30 -0
  265. package/templates/base-template/base-template.SemanticModel/definition/tables/_GC C/303/241lculo.tmdl" +70 -0
  266. package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Eje X.tmdl +63 -0
  267. package/templates/base-template/base-template.SemanticModel/definition/tables/_GC M/303/251trica.tmdl" +374 -0
  268. package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Tipo c/303/241lculo.tmdl" +223 -0
  269. package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Dimensi/303/263n.tmdl" +98 -0
  270. package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Eje X.tmdl +68 -0
  271. package/templates/base-template/base-template.SemanticModel/definition/tables//303/223rdenes servicio.tmdl" +151 -0
  272. package/templates/base-template/base-template.SemanticModel/definition.pbism +5 -0
  273. package/templates/base-template/base-template.SemanticModel/diagramLayout.json +568 -0
  274. package/templates/base-template/base-template.pbip +14 -0
  275. package/templates/base-template/template.manifest.json +41 -0
  276. package/theme/BISuperpowers.json +3888 -0
@@ -0,0 +1,611 @@
1
+ /**
2
+ * Uninstall Command — Multi-agent skill + MCP remover
3
+ * ====================================================
4
+ *
5
+ * The exact inverse of `super install`. Removes the bi-superpowers skills
6
+ * and the 2 Microsoft MCP servers from every selected agent, touching ONLY
7
+ * what we installed:
8
+ * - Skills: deletes our managed skill directories (the symlink, or our
9
+ * own skill subdirs in a copy-fallback dir). Never removes a user's
10
+ * unrelated skills.
11
+ * - MCPs: deletes only the `powerbi-modeling-mcp` + `microsoft-learn`
12
+ * entries from each agent's config, preserving every other server and
13
+ * top-level key (see `lib/mcp-config.js` → removeMcpConfigForAgent).
14
+ *
15
+ * Safety:
16
+ * - `--dry-run` previews every change without writing anything.
17
+ * - A confirmation prompt guards the destructive run unless `--yes`.
18
+ * - Each config rewrite goes through the same atomic + `.bak` backup
19
+ * pattern the installer uses.
20
+ * - The universal skills dir (~/.agents/skills, also Codex's dir and the
21
+ * symlink target for other agents) is only deleted when every agent
22
+ * that consumes it is part of this uninstall.
23
+ *
24
+ * Fully open source (MIT). CLI copy, comments, and JSDoc stay in English.
25
+ *
26
+ * Usage:
27
+ * super uninstall
28
+ * super uninstall --all --yes
29
+ * super uninstall --agent claude-code --agent codex
30
+ * super uninstall --dry-run
31
+ * super uninstall --skills-only # leave MCP config untouched
32
+ * super uninstall --mcp-only # leave skills on disk
33
+ *
34
+ * @module commands/uninstall
35
+ */
36
+
37
+ const fs = require('fs');
38
+ const path = require('path');
39
+ const os = require('os');
40
+ const readline = require('readline');
41
+ const { AGENTS, UNIVERSAL_DIR } = require('../lib/agents');
42
+ const { removeMcpConfigForAgent } = require('../lib/mcp-config');
43
+
44
+ const LEGACY_SESSION_DIR = '.bi-superpowers';
45
+
46
+ /**
47
+ * Parse CLI arguments into an options object. Mirrors install's flags and
48
+ * adds `--dry-run`, `--skills-only`, and `--mcp-only`.
49
+ */
50
+ function parseArgs(args) {
51
+ const opts = {
52
+ isYes: args.includes('--yes') || args.includes('-y'),
53
+ isAll: args.includes('--all'),
54
+ isDryRun: args.includes('--dry-run'),
55
+ skillsOnly: args.includes('--skills-only'),
56
+ mcpOnly: args.includes('--mcp-only'),
57
+ agentFlags: [],
58
+ };
59
+
60
+ // Contradictory scope flags cancel out into a full uninstall.
61
+ if (opts.skillsOnly && opts.mcpOnly) {
62
+ console.warn('⚠ --skills-only and --mcp-only are mutually exclusive. Doing a full uninstall.');
63
+ opts.skillsOnly = false;
64
+ opts.mcpOnly = false;
65
+ }
66
+
67
+ for (let i = 0; i < args.length; i++) {
68
+ if (args[i] === '--agent' || args[i] === '-a') {
69
+ const next = args[i + 1];
70
+ if (next === undefined || next.startsWith('-')) {
71
+ console.warn(
72
+ `⚠ Flag ${args[i]} is missing a value. Usage: ${args[i]} <agent-id>. Ignoring.`
73
+ );
74
+ continue;
75
+ }
76
+ opts.agentFlags.push(next);
77
+ i++;
78
+ }
79
+ }
80
+
81
+ return opts;
82
+ }
83
+
84
+ /**
85
+ * Create a readline interface for interactive prompts.
86
+ */
87
+ function createReadline() {
88
+ return readline.createInterface({ input: process.stdin, output: process.stdout });
89
+ }
90
+
91
+ /**
92
+ * Promise-wrapped readline question.
93
+ */
94
+ function prompt(rl, question) {
95
+ return new Promise((resolve) => {
96
+ rl.question(question, (answer) => resolve(answer.trim()));
97
+ });
98
+ }
99
+
100
+ /**
101
+ * Resolve the symlink target of a path, or null if it isn't a symlink or
102
+ * can't be resolved.
103
+ */
104
+ function symlinkRealTarget(linkPath) {
105
+ const st = fs.lstatSync(linkPath, { throwIfNoEntry: false });
106
+ if (!st || !st.isSymbolicLink()) return null;
107
+ try {
108
+ return fs.realpathSync(linkPath);
109
+ } catch (_) {
110
+ return null;
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Does `linkPath` resolve to the universal skills directory? Used to decide
116
+ * whether an agent still consumes the universal copy.
117
+ */
118
+ function isSymlinkToUniversal(linkPath, baseDir) {
119
+ const target = symlinkRealTarget(linkPath);
120
+ if (!target) return false;
121
+ const universal = path.join(baseDir, UNIVERSAL_DIR);
122
+ let resolvedUniversal = universal;
123
+ try {
124
+ resolvedUniversal = fs.realpathSync(universal);
125
+ } catch (_) {
126
+ /* universal may not exist; fall back to the joined path */
127
+ }
128
+ return path.resolve(target) === path.resolve(resolvedUniversal);
129
+ }
130
+
131
+ /**
132
+ * Read the managed skill names from the installed package's `skills/` dir.
133
+ * These are the only skill directories uninstall will ever delete, so the
134
+ * removal stays in lockstep with whatever the package actually ships.
135
+ */
136
+ function getManagedSkillNames(packageDir) {
137
+ const skillsSourceDir = path.join(packageDir, 'skills');
138
+ if (!fs.existsSync(skillsSourceDir)) return [];
139
+ return fs
140
+ .readdirSync(skillsSourceDir, { withFileTypes: true })
141
+ .filter((d) => d.isDirectory() && fs.existsSync(path.join(skillsSourceDir, d.name, 'SKILL.md')))
142
+ .map((d) => d.name);
143
+ }
144
+
145
+ /**
146
+ * Detect agents that currently have a bi-superpowers footprint (managed
147
+ * skills installed or our MCP servers configured). Used to pre-select the
148
+ * interactive list so the user removes exactly what's installed.
149
+ */
150
+ function detectInstalledAgents(baseDir, skillNames) {
151
+ const detected = [];
152
+ for (const id of Object.keys(AGENTS)) {
153
+ if (hasSkillFootprint(baseDir, id, skillNames) || hasMcpFootprint(baseDir, id)) {
154
+ detected.push(id);
155
+ }
156
+ }
157
+ return detected;
158
+ }
159
+
160
+ /**
161
+ * Skill footprint: the agent's dir is a symlink to universal, or it holds
162
+ * at least one of our managed skill subdirs (copy fallback / universal).
163
+ */
164
+ function hasSkillFootprint(baseDir, agentId, skillNames) {
165
+ const agent = AGENTS[agentId];
166
+ const dir = path.join(baseDir, agent.dir);
167
+ const st = fs.lstatSync(dir, { throwIfNoEntry: false });
168
+ if (!st) return false;
169
+ if (st.isSymbolicLink()) return true;
170
+ return skillNames.some((name) => fs.existsSync(path.join(dir, name, 'SKILL.md')));
171
+ }
172
+
173
+ /**
174
+ * MCP footprint: the agent's config file mentions our modeling server name.
175
+ * A cheap substring check is enough for pre-selection; the actual removal
176
+ * is precise.
177
+ */
178
+ function hasMcpFootprint(baseDir, agentId) {
179
+ const configPaths = {
180
+ 'claude-code': path.join(baseDir, '.claude.json'),
181
+ 'github-copilot': path.join(baseDir, '.copilot', 'mcp-config.json'),
182
+ codex: path.join(baseDir, '.codex', 'config.toml'),
183
+ 'gemini-cli': path.join(baseDir, '.gemini', 'settings.json'),
184
+ kilo: path.join(baseDir, '.config', 'kilo', 'kilo.jsonc'),
185
+ };
186
+ const configPath = configPaths[agentId];
187
+ if (!configPath || !fs.existsSync(configPath)) return false;
188
+ try {
189
+ return fs.readFileSync(configPath, 'utf8').includes('powerbi-modeling-mcp');
190
+ } catch (_) {
191
+ return false;
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Render a numbered multi-select list and wait for the user's choice.
197
+ */
198
+ async function selectMultiple(rl, items, preselected = []) {
199
+ items.forEach((item, i) => {
200
+ const marker = preselected.includes(item.id) ? '●' : '○';
201
+ console.log(` ${i + 1}) ${marker} ${item.name}`);
202
+ });
203
+ console.log();
204
+ console.log(' Enter numbers separated by commas (for example: 1,2,3)');
205
+ console.log(' Press Enter for detected agents, or "a" for all agents');
206
+
207
+ const answer = await prompt(rl, '\n > ');
208
+
209
+ if (answer.toLowerCase() === 'a') {
210
+ return items.map((item) => item.id);
211
+ }
212
+ if (answer === '') {
213
+ return preselected.length > 0 ? preselected : items.map((item) => item.id);
214
+ }
215
+
216
+ const indices = answer
217
+ .split(',')
218
+ .map((s) => parseInt(s.trim(), 10) - 1)
219
+ .filter((i) => i >= 0 && i < items.length);
220
+
221
+ return indices.map((i) => items[i].id);
222
+ }
223
+
224
+ /**
225
+ * Resolve which agents to uninstall based on flags or interactive prompt.
226
+ */
227
+ async function resolveSelectedAgents(opts, baseDir, skillNames, chalk) {
228
+ if (opts.isAll) {
229
+ return Object.keys(AGENTS);
230
+ }
231
+
232
+ if (opts.agentFlags.length > 0) {
233
+ const known = opts.agentFlags.filter((a) => AGENTS[a]);
234
+ const unknown = opts.agentFlags.filter((a) => !AGENTS[a]);
235
+ if (unknown.length > 0) {
236
+ console.log(chalk.yellow(` Unknown agents: ${unknown.join(', ')}`));
237
+ console.log(chalk.gray(` Available agents: ${Object.keys(AGENTS).join(', ')}\n`));
238
+ }
239
+ return known;
240
+ }
241
+
242
+ if (opts.isYes) {
243
+ // Non-interactive without --all: target exactly what's installed.
244
+ const detected = detectInstalledAgents(baseDir, skillNames);
245
+ return detected.length > 0 ? detected : Object.keys(AGENTS);
246
+ }
247
+
248
+ const detected = detectInstalledAgents(baseDir, skillNames);
249
+ console.log(chalk.cyan(' Select the agents to uninstall from:\n'));
250
+ const items = Object.entries(AGENTS).map(([id, agent]) => ({
251
+ id,
252
+ name: detected.includes(id) ? `${agent.name} ${chalk.green('(installed)')}` : agent.name,
253
+ }));
254
+
255
+ const rl = createReadline();
256
+ try {
257
+ return await selectMultiple(rl, items, detected);
258
+ } finally {
259
+ rl.close();
260
+ }
261
+ }
262
+
263
+ /**
264
+ * Remove a directory only if it exists and is empty. Best-effort; returns
265
+ * true if it was removed.
266
+ */
267
+ function removeIfEmpty(dir) {
268
+ try {
269
+ if (!fs.existsSync(dir)) return false;
270
+ if (fs.readdirSync(dir).length > 0) return false;
271
+ fs.rmdirSync(dir);
272
+ return true;
273
+ } catch (_) {
274
+ return false;
275
+ }
276
+ }
277
+
278
+ /**
279
+ * Remove our managed skills for a single agent. Codex shares the universal
280
+ * dir, so it is handled by removeUniversalSkills instead and skipped here.
281
+ *
282
+ * @returns {{ action: string, dir?: string, count?: number }}
283
+ */
284
+ function removeAgentSkills(baseDir, agentId, skillNames, dryRun, removeEmpty) {
285
+ const agent = AGENTS[agentId];
286
+ if (agent.dir === UNIVERSAL_DIR) {
287
+ return { action: 'universal' };
288
+ }
289
+
290
+ const dir = path.join(baseDir, agent.dir);
291
+ const st = fs.lstatSync(dir, { throwIfNoEntry: false });
292
+ if (!st) {
293
+ return { action: 'absent', dir: agent.dir };
294
+ }
295
+
296
+ if (st.isSymbolicLink()) {
297
+ if (!dryRun) fs.unlinkSync(dir);
298
+ if (removeEmpty && !dryRun) removeIfEmpty(path.dirname(dir));
299
+ return { action: 'unlinked', dir: agent.dir };
300
+ }
301
+
302
+ // Real directory (copy fallback or user-managed): remove only our subdirs.
303
+ let count = 0;
304
+ for (const name of skillNames) {
305
+ const sub = path.join(dir, name);
306
+ if (fs.existsSync(sub)) {
307
+ if (!dryRun) fs.rmSync(sub, { recursive: true, force: true });
308
+ count++;
309
+ }
310
+ }
311
+ if (removeEmpty && !dryRun) {
312
+ if (removeIfEmpty(dir)) removeIfEmpty(path.dirname(dir));
313
+ }
314
+ return { action: 'removed-copies', dir: agent.dir, count };
315
+ }
316
+
317
+ /**
318
+ * Remove our managed skills from the universal dir (~/.agents/skills) and
319
+ * tidy up the now-empty parent dirs. This is what actually deletes the
320
+ * skills for Codex and any agent symlinked to the universal copy.
321
+ *
322
+ * @returns {{ action: string, count?: number }}
323
+ */
324
+ function removeUniversalSkills(baseDir, skillNames, dryRun, removeEmpty) {
325
+ const universal = path.join(baseDir, UNIVERSAL_DIR);
326
+ const st = fs.lstatSync(universal, { throwIfNoEntry: false });
327
+ if (!st) {
328
+ return { action: 'absent' };
329
+ }
330
+
331
+ if (st.isSymbolicLink()) {
332
+ if (!dryRun) fs.unlinkSync(universal);
333
+ return { action: 'unlinked' };
334
+ }
335
+
336
+ let count = 0;
337
+ for (const name of skillNames) {
338
+ const sub = path.join(universal, name);
339
+ if (fs.existsSync(sub)) {
340
+ if (!dryRun) fs.rmSync(sub, { recursive: true, force: true });
341
+ count++;
342
+ }
343
+ }
344
+
345
+ if (removeEmpty && !dryRun) {
346
+ // ~/.agents/skills → ~/.agents, removing each only while empty.
347
+ if (removeIfEmpty(universal)) {
348
+ removeIfEmpty(path.dirname(universal));
349
+ }
350
+ }
351
+ return { action: 'removed', count };
352
+ }
353
+
354
+ /**
355
+ * Decide whether the universal skills dir is safe to delete: only when
356
+ * every agent that consumes it (Codex, plus any agent symlinked to it) is
357
+ * part of this uninstall. Must be evaluated BEFORE any symlink is removed.
358
+ */
359
+ function universalIsFullyReleased(baseDir, selectedAgents) {
360
+ const consumers = new Set(['codex']); // codex.dir === UNIVERSAL_DIR
361
+ for (const [id, agent] of Object.entries(AGENTS)) {
362
+ if (id === 'codex') continue;
363
+ const dir = path.join(baseDir, agent.dir);
364
+ if (isSymlinkToUniversal(dir, baseDir)) {
365
+ consumers.add(id);
366
+ }
367
+ }
368
+ return [...consumers].every((id) => selectedAgents.includes(id));
369
+ }
370
+
371
+ /**
372
+ * Remove the legacy ~/.bi-superpowers session dir left by the 5.0.3 auth
373
+ * feature. Nothing writes there anymore; this is defensive cleanup.
374
+ *
375
+ * @returns {{ existed: boolean, path: string }}
376
+ */
377
+ function cleanLegacySessionDir(baseDir, dryRun) {
378
+ const dir = path.join(baseDir, LEGACY_SESSION_DIR);
379
+ const existed = fs.existsSync(dir);
380
+ if (existed && !dryRun) {
381
+ fs.rmSync(dir, { recursive: true, force: true });
382
+ }
383
+ return { existed, path: dir };
384
+ }
385
+
386
+ /**
387
+ * Main handler for the `super uninstall` command.
388
+ * @param {string[]} args - CLI arguments
389
+ * @param {Object} config - Command config from the CLI (packageDir, version)
390
+ */
391
+ async function uninstallCommand(args, config) {
392
+ const chalk = require('chalk');
393
+ const boxen = require('boxen');
394
+
395
+ const opts = parseArgs(args);
396
+ const baseDir = os.homedir();
397
+ const packageDir = config.packageDir || path.dirname(path.dirname(__dirname));
398
+ const skillNames = getManagedSkillNames(packageDir);
399
+
400
+ console.log(
401
+ boxen(
402
+ chalk.bold.cyan('BI Agent Superpowers') +
403
+ chalk.gray(` v${config.version}`) +
404
+ '\n' +
405
+ chalk.gray(opts.isDryRun ? 'Uninstaller (dry run)' : 'Uninstaller'),
406
+ { padding: 1, borderStyle: 'round', borderColor: 'cyan' }
407
+ )
408
+ );
409
+
410
+ const selectedAgents = await resolveSelectedAgents(opts, baseDir, skillNames, chalk);
411
+ if (selectedAgents.length === 0) {
412
+ console.log(chalk.yellow('\n No agent selected. Nothing to uninstall.'));
413
+ return;
414
+ }
415
+
416
+ const doSkills = !opts.mcpOnly;
417
+ const doMcp = !opts.skillsOnly;
418
+ const doExtras = !opts.skillsOnly && !opts.mcpOnly; // legacy dir cleanup
419
+
420
+ // Plan the universal-skills decision up front (before removing symlinks).
421
+ const releaseUniversal = doSkills && universalIsFullyReleased(baseDir, selectedAgents);
422
+
423
+ // Confirmation gate for the destructive run.
424
+ if (!opts.isDryRun && !opts.isYes) {
425
+ const scope = [doSkills && 'skills', doMcp && 'MCP servers'].filter(Boolean).join(' + ');
426
+ console.log(
427
+ chalk.yellow(
428
+ `\n This will remove bi-superpowers ${scope} from: ${selectedAgents.join(', ')}.`
429
+ )
430
+ );
431
+ const rl = createReadline();
432
+ let answer;
433
+ try {
434
+ answer = await prompt(rl, ' Continue? (y/N) ');
435
+ } finally {
436
+ rl.close();
437
+ }
438
+ if (!/^y(es)?$/i.test(answer)) {
439
+ console.log(chalk.gray('\n Aborted. Nothing was removed.'));
440
+ return;
441
+ }
442
+ }
443
+
444
+ const dry = opts.isDryRun;
445
+ console.log(
446
+ chalk.cyan(
447
+ `\n ${dry ? 'Would remove' : 'Removing'} from ${selectedAgents.length} agent(s)...\n`
448
+ )
449
+ );
450
+
451
+ // Phase 1: skills.
452
+ const skillResults = [];
453
+ if (doSkills) {
454
+ for (const agentId of selectedAgents) {
455
+ try {
456
+ const result = removeAgentSkills(baseDir, agentId, skillNames, dry, true);
457
+ skillResults.push({ agent: AGENTS[agentId].name, ...result });
458
+ } catch (err) {
459
+ skillResults.push({ agent: AGENTS[agentId].name, action: 'error', error: err.message });
460
+ }
461
+ }
462
+
463
+ if (releaseUniversal) {
464
+ try {
465
+ const uni = removeUniversalSkills(baseDir, skillNames, dry, true);
466
+ skillResults.push({ agent: `${UNIVERSAL_DIR}`, ...uni });
467
+ } catch (err) {
468
+ skillResults.push({ agent: UNIVERSAL_DIR, action: 'error', error: err.message });
469
+ }
470
+ }
471
+
472
+ for (const r of skillResults) {
473
+ if (r.action === 'unlinked') {
474
+ console.log(chalk.green(` ${dry ? '·' : '✓'} ${r.dir}/ (symlink removed) — ${r.agent}`));
475
+ } else if (r.action === 'removed-copies') {
476
+ console.log(
477
+ chalk.green(` ${dry ? '·' : '✓'} ${r.dir}/ (${r.count} skill dirs removed) — ${r.agent}`)
478
+ );
479
+ } else if (r.action === 'removed') {
480
+ console.log(chalk.green(` ${dry ? '·' : '✓'} ${r.agent}/ (${r.count} skills removed)`));
481
+ } else if (r.action === 'absent') {
482
+ console.log(chalk.gray(` – ${r.agent}: no managed skills found`));
483
+ } else if (r.action === 'error') {
484
+ console.log(chalk.red(` ✗ ${r.agent}: ${r.error}`));
485
+ }
486
+ }
487
+ if (doSkills && !releaseUniversal) {
488
+ console.log(
489
+ chalk.gray(
490
+ ` – ${UNIVERSAL_DIR}/ kept (still used by an agent that isn't part of this uninstall)`
491
+ )
492
+ );
493
+ }
494
+ }
495
+
496
+ // Phase 2: MCP config.
497
+ const mcpResults = [];
498
+ if (doMcp) {
499
+ console.log(chalk.cyan(`\n ${dry ? 'Would remove' : 'Removing'} MCP servers...\n`));
500
+ for (const agentId of selectedAgents) {
501
+ try {
502
+ // On a dry run, inspect without writing by reading the current state.
503
+ const res = dry ? previewMcpRemoval(baseDir, agentId) : removeMcpConfigForAgent(agentId);
504
+ if (res && res.removed && res.removed.length > 0) {
505
+ const rel = res.configPath.replace(baseDir, '~');
506
+ console.log(
507
+ chalk.green(
508
+ ` ${dry ? '·' : '✓'} ${rel} — ${AGENTS[agentId].name} (${res.removed.length} servers)`
509
+ )
510
+ );
511
+ } else {
512
+ console.log(chalk.gray(` – ${AGENTS[agentId].name}: no managed MCP servers found`));
513
+ }
514
+ mcpResults.push({ agent: AGENTS[agentId].name, ...(res || { removed: [] }) });
515
+ } catch (err) {
516
+ console.log(chalk.red(` ✗ ${AGENTS[agentId].name}: ${err.message}`));
517
+ mcpResults.push({ agent: AGENTS[agentId].name, error: err.message });
518
+ }
519
+ }
520
+ }
521
+
522
+ // Phase 3: legacy session dir.
523
+ let legacy = { existed: false };
524
+ if (doExtras) {
525
+ legacy = cleanLegacySessionDir(baseDir, dry);
526
+ if (legacy.existed) {
527
+ console.log(
528
+ chalk.green(
529
+ `\n ${dry ? '·' : '✓'} ${legacy.path.replace(baseDir, '~')} (legacy session removed)`
530
+ )
531
+ );
532
+ }
533
+ }
534
+
535
+ // Summary.
536
+ const mcpErrors = mcpResults.filter((r) => r.error);
537
+ const skillErrors = skillResults.filter((r) => r.action === 'error');
538
+ const hasErrors = mcpErrors.length > 0 || skillErrors.length > 0;
539
+
540
+ const headline = dry
541
+ ? chalk.cyan.bold('Dry run complete — no changes were made.')
542
+ : hasErrors
543
+ ? chalk.yellow.bold('Uninstall finished with some errors.')
544
+ : chalk.green.bold('Uninstall complete.');
545
+
546
+ console.log(
547
+ boxen(
548
+ headline +
549
+ '\n\n' +
550
+ chalk.gray(`Agents: ${selectedAgents.join(', ')}`) +
551
+ '\n' +
552
+ chalk.gray(
553
+ dry
554
+ ? 'Re-run without --dry-run to apply.'
555
+ : 'Restart your AI agent so it drops the removed MCP servers.'
556
+ ),
557
+ {
558
+ padding: 1,
559
+ margin: { top: 1 },
560
+ borderStyle: 'round',
561
+ borderColor: dry ? 'cyan' : hasErrors ? 'yellow' : 'green',
562
+ }
563
+ )
564
+ );
565
+
566
+ if (hasErrors && !dry) {
567
+ process.exitCode = 2;
568
+ }
569
+ }
570
+
571
+ /**
572
+ * Read-only MCP removal preview for dry runs: reports which of our servers
573
+ * are present without touching the file. Mirrors removeMcpConfigForAgent's
574
+ * return shape.
575
+ */
576
+ function previewMcpRemoval(baseDir, agentId) {
577
+ const configPaths = {
578
+ 'claude-code': path.join(baseDir, '.claude.json'),
579
+ 'github-copilot': path.join(baseDir, '.copilot', 'mcp-config.json'),
580
+ codex: path.join(baseDir, '.codex', 'config.toml'),
581
+ 'gemini-cli': path.join(baseDir, '.gemini', 'settings.json'),
582
+ kilo: path.join(baseDir, '.config', 'kilo', 'kilo.jsonc'),
583
+ };
584
+ const configPath = configPaths[agentId];
585
+ if (!configPath || !fs.existsSync(configPath)) {
586
+ return { configPath: configPath || '', existed: false, removed: [] };
587
+ }
588
+ let raw = '';
589
+ try {
590
+ raw = fs.readFileSync(configPath, 'utf8');
591
+ } catch (_) {
592
+ return { configPath, existed: true, removed: [] };
593
+ }
594
+ const removed = [];
595
+ if (raw.includes('powerbi-modeling-mcp')) removed.push('powerbi-modeling-mcp');
596
+ if (raw.includes('microsoft-learn')) removed.push('microsoft-learn');
597
+ return { configPath, existed: true, removed };
598
+ }
599
+
600
+ // Internal exports for testing.
601
+ module.exports = uninstallCommand;
602
+ module.exports.parseArgs = parseArgs;
603
+ module.exports.getManagedSkillNames = getManagedSkillNames;
604
+ module.exports.detectInstalledAgents = detectInstalledAgents;
605
+ module.exports.removeAgentSkills = removeAgentSkills;
606
+ module.exports.removeUniversalSkills = removeUniversalSkills;
607
+ module.exports.universalIsFullyReleased = universalIsFullyReleased;
608
+ module.exports.cleanLegacySessionDir = cleanLegacySessionDir;
609
+ module.exports.removeIfEmpty = removeIfEmpty;
610
+ module.exports.AGENTS = AGENTS;
611
+ module.exports.UNIVERSAL_DIR = UNIVERSAL_DIR;