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,62 @@
1
+ /**
2
+ * Agent Registry - Supported AI coding agents
3
+ * =============================================
4
+ *
5
+ * Single source of truth for the agents that bi-superpowers officially
6
+ * supports. Used by the install command (skill installation paths) and
7
+ * any future command that needs to know which agents exist.
8
+ *
9
+ * Each agent has:
10
+ * - A stable ID (used as CLI flag value, e.g. --agent claude-code)
11
+ * - A human-readable name (shown in the UI)
12
+ * - A directory relative to the user's home where its skills live
13
+ *
14
+ * UNIVERSAL_DIR is the path most agents read from by convention
15
+ * (.agents/skills/). The installer always writes here first, then
16
+ * symlinks agent-specific directories to it. Agents whose dir === UNIVERSAL_DIR
17
+ * (e.g. Codex, OpenCode) are served directly by the universal install.
18
+ *
19
+ * @module lib/agents
20
+ */
21
+
22
+ /**
23
+ * Supported agents, in the order they appear in the interactive installer.
24
+ * Object insertion order matters — the installer renders the list in this order.
25
+ *
26
+ * IMPORTANT: the `dir` values are the USER-LEVEL skill directories for each
27
+ * agent. They're relative to the user's home directory (installed with
28
+ * `super install` at ~/). Each path comes from official docs — if you
29
+ * change one, verify it against the linked source first.
30
+ *
31
+ * Source docs:
32
+ * - GitHub Copilot: https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/create-skills
33
+ * "For personal skills, shared across projects, use ~/.copilot/skills"
34
+ * (NOT ~/.github/skills — that's project-level for the cloud agent.)
35
+ * - Claude Code: https://code.claude.com/docs/en/skills
36
+ * "Personal skills go in ~/.claude/skills/"
37
+ * - Codex: https://developers.openai.com/codex/skills
38
+ * "Personal skills go in ~/.codex/skills or ~/.agents/skills"
39
+ * We use the universal ~/.agents/skills path.
40
+ * - Gemini CLI: https://geminicli.com/docs/cli/skills/
41
+ * "User skills in $HOME/.gemini/skills"
42
+ * - Kilo Code: https://kilo.ai/docs/customize/skills
43
+ * "Global skills in ~/.kilo/skills/" (NOT ~/.kilocode/)
44
+ */
45
+ const AGENTS = {
46
+ 'github-copilot': { name: 'GitHub Copilot', dir: '.copilot/skills' },
47
+ 'claude-code': { name: 'Claude Code', dir: '.claude/skills' },
48
+ codex: { name: 'Codex (OpenAI)', dir: '.agents/skills' },
49
+ 'gemini-cli': { name: 'Gemini CLI', dir: '.gemini/skills' },
50
+ kilo: { name: 'Kilo Code', dir: '.kilo/skills' },
51
+ };
52
+
53
+ /**
54
+ * Universal path — most agents read from .agents/skills/ by the Agent Skills spec.
55
+ * The installer copies skills here first and symlinks agent-specific dirs to it.
56
+ */
57
+ const UNIVERSAL_DIR = '.agents/skills';
58
+
59
+ module.exports = {
60
+ AGENTS,
61
+ UNIVERSAL_DIR,
62
+ };
@@ -0,0 +1,299 @@
1
+ /**
2
+ * Base Template Live Smoke Test Helpers
3
+ * =====================================
4
+ *
5
+ * Runs the canonical base-template validation playbook against the running
6
+ * Power BI Desktop session. The helper probes each local Desktop instance and
7
+ * keeps the one whose live evidence matches the template contract.
8
+ *
9
+ * @module lib/base-template-smoke
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const mcpDetect = require('../utils/mcp-detect');
15
+ const { createPowerBiMcpSession } = require('./powerbi-mcp-session');
16
+
17
+ const BASE_TEMPLATE_CASE_PATH = path.join(
18
+ __dirname,
19
+ '..',
20
+ '..',
21
+ 'validation',
22
+ 'cases',
23
+ 'base-template-smoke-test.md'
24
+ );
25
+
26
+ const SMOKE_QUERY_PATTERN = /## Smoke Query\s+```DAX\s+([\s\S]*?)```/i;
27
+ const DAY_MS = 24 * 60 * 60 * 1000;
28
+ const WEEK_MS = 7 * DAY_MS;
29
+ const DEMO_CUSTOMER_COUNT = 210;
30
+
31
+ function extractSmokeQuery(caseMarkdown) {
32
+ const match = caseMarkdown.match(SMOKE_QUERY_PATTERN);
33
+ if (!match) {
34
+ throw new Error('Unable to find the smoke query in the validation case.');
35
+ }
36
+
37
+ return match[1].trim();
38
+ }
39
+
40
+ function formatLocalDate(date) {
41
+ const year = date.getFullYear();
42
+ const month = String(date.getMonth() + 1).padStart(2, '0');
43
+ const day = String(date.getDate()).padStart(2, '0');
44
+ return `${year}-${month}-${day}`;
45
+ }
46
+
47
+ function addLocalDays(date, days) {
48
+ const result = new Date(date.getFullYear(), date.getMonth(), date.getDate());
49
+ result.setDate(result.getDate() + days);
50
+ return result;
51
+ }
52
+
53
+ function startOfMondayWeek(date) {
54
+ const result = new Date(date.getFullYear(), date.getMonth(), date.getDate());
55
+ const mondayOffset = (result.getDay() + 6) % 7;
56
+ result.setDate(result.getDate() - mondayOffset);
57
+ return result;
58
+ }
59
+
60
+ function countMondayWeeks(startDate, endDate) {
61
+ const firstWeek = startOfMondayWeek(startDate);
62
+ const lastWeek = startOfMondayWeek(endDate);
63
+ return Math.floor((lastWeek.getTime() - firstWeek.getTime()) / WEEK_MS) + 1;
64
+ }
65
+
66
+ function estimateVentasRows(weekCount, customerCount = DEMO_CUSTOMER_COUNT) {
67
+ let rows = 0;
68
+
69
+ for (let weekNumber = 1; weekNumber <= weekCount; weekNumber++) {
70
+ rows += Math.min(customerCount, weekNumber * 2);
71
+ }
72
+
73
+ return rows;
74
+ }
75
+
76
+ function getExpectedSmokeEvidence(referenceDate = new Date()) {
77
+ const currentDate = new Date(
78
+ referenceDate.getFullYear(),
79
+ referenceDate.getMonth(),
80
+ referenceDate.getDate()
81
+ );
82
+ const minDate = addLocalDays(currentDate, -729);
83
+ const validationStartDate = addLocalDays(currentDate, -719);
84
+ const ventasWeeks = countMondayWeeks(minDate, currentDate);
85
+ const validationWeeks = countMondayWeeks(validationStartDate, currentDate);
86
+
87
+ return {
88
+ Metricas: '56',
89
+ Equipos: '9',
90
+ BridgeRows: '63',
91
+ MetricTeamMin: '7',
92
+ MetricTeamMax: '7',
93
+ WindowWeeks: String(validationWeeks),
94
+ FactTablesWithFullWeeks: '13',
95
+ MetricCoverageFailures: '0',
96
+ MetricDimensionPairs: '379',
97
+ MetricDimensionFailures: '0',
98
+ VentasRows: String(estimateVentasRows(ventasWeeks)),
99
+ MinFecha: formatLocalDate(minDate),
100
+ MaxFecha: formatLocalDate(currentDate),
101
+ };
102
+ }
103
+
104
+ function normalizeMcpJsonResult(toolResult) {
105
+ const textContent = (toolResult && toolResult.content) || [];
106
+ const textItem = textContent.find((entry) => entry && entry.type === 'text' && entry.text);
107
+
108
+ if (!textItem) {
109
+ throw new Error('MCP response did not include a text payload.');
110
+ }
111
+
112
+ try {
113
+ return JSON.parse(textItem.text);
114
+ } catch (error) {
115
+ throw new Error(`Unable to parse MCP JSON payload: ${error.message}`);
116
+ }
117
+ }
118
+
119
+ function extractCsvText(toolResult) {
120
+ const resourceItems = (toolResult && toolResult.content) || [];
121
+ const resourceItem = resourceItems.find(
122
+ (entry) => entry && entry.type === 'resource' && entry.resource
123
+ );
124
+
125
+ if (!resourceItem || typeof resourceItem.resource.text !== 'string') {
126
+ throw new Error('DAX query result did not include a CSV resource.');
127
+ }
128
+
129
+ return resourceItem.resource.text;
130
+ }
131
+
132
+ function parseSingleRowCsv(csvText) {
133
+ const lines = String(csvText)
134
+ .split(/\r?\n/)
135
+ .map((line) => line.trim())
136
+ .filter(Boolean);
137
+
138
+ if (lines.length < 2) {
139
+ throw new Error('Expected a CSV header and one data row from the smoke query.');
140
+ }
141
+
142
+ const headers = lines[0].split(',').map((header) => header.replace(/^\[(.*)\]$/, '$1'));
143
+ const values = lines[1].split(',');
144
+ const row = {};
145
+
146
+ headers.forEach((header, index) => {
147
+ row[header] = values[index] != null ? values[index] : '';
148
+ });
149
+
150
+ return row;
151
+ }
152
+
153
+ function selectConnectionForPort(connections, port) {
154
+ const portText = `localhost:${port}`;
155
+ const matchingConnections = connections.filter((connection) => {
156
+ return (
157
+ connection &&
158
+ typeof connection.serverConnectionString === 'string' &&
159
+ connection.serverConnectionString.includes(portText)
160
+ );
161
+ });
162
+
163
+ const candidates = matchingConnections.length > 0 ? matchingConnections : connections;
164
+ return candidates.slice().sort((left, right) => {
165
+ const leftTime = new Date(left.connectedAt || 0).getTime();
166
+ const rightTime = new Date(right.connectedAt || 0).getTime();
167
+ return rightTime - leftTime;
168
+ })[0];
169
+ }
170
+
171
+ function isExpectedSmokeEvidence(row, expected) {
172
+ return Object.entries(expected).every(([key, value]) => String(row[key] ?? '') === String(value));
173
+ }
174
+
175
+ function formatEvidence(row) {
176
+ return Object.entries(row)
177
+ .map(([key, value]) => `${key}=${value}`)
178
+ .join(', ');
179
+ }
180
+
181
+ async function runBaseTemplateLiveSmokeTest(options = {}) {
182
+ const casePath = options.casePath || BASE_TEMPLATE_CASE_PATH;
183
+ const sessionFactory = options.sessionFactory || ((exePath) => createPowerBiMcpSession(exePath));
184
+ const referenceDate = options.referenceDate || new Date();
185
+ const serverPath = options.mcpPath || mcpDetect.findLocalMcp();
186
+
187
+ if (!serverPath) {
188
+ throw new Error(mcpDetect.getModelingMcpError());
189
+ }
190
+
191
+ if (!fs.existsSync(casePath)) {
192
+ throw new Error(`Smoke test case not found: ${casePath}`);
193
+ }
194
+
195
+ const smokeQuery = extractSmokeQuery(fs.readFileSync(casePath, 'utf8'));
196
+ const expected = getExpectedSmokeEvidence(referenceDate);
197
+ const session = sessionFactory(serverPath);
198
+ const attempts = [];
199
+
200
+ try {
201
+ await session.initialize(options.clientInfo);
202
+
203
+ const localInstancesResult = await session.callTool('connection_operations', {
204
+ request: {
205
+ operation: 'ListLocalInstances',
206
+ },
207
+ });
208
+ const localInstances = normalizeMcpJsonResult(localInstancesResult).data || [];
209
+
210
+ for (const instance of localInstances) {
211
+ const attempt = {
212
+ processId: instance.processId,
213
+ port: instance.port,
214
+ connectionName: null,
215
+ observed: null,
216
+ matched: false,
217
+ error: null,
218
+ };
219
+
220
+ try {
221
+ await session.callTool('connection_operations', {
222
+ request: {
223
+ operation: 'Connect',
224
+ connectionString: `Provider=MSOLAP;Data Source=localhost:${instance.port};Application Name=MCP-PBIModeling`,
225
+ },
226
+ });
227
+
228
+ const connectionsResult = await session.callTool('connection_operations', {
229
+ request: {
230
+ operation: 'ListConnections',
231
+ },
232
+ });
233
+ const connections = normalizeMcpJsonResult(connectionsResult).data || [];
234
+ const selectedConnection = selectConnectionForPort(connections, instance.port);
235
+ attempt.connectionName = selectedConnection ? selectedConnection.connectionName : null;
236
+
237
+ const daxResult = await session.callTool('dax_query_operations', {
238
+ request: {
239
+ operation: 'Execute',
240
+ connectionName: attempt.connectionName || undefined,
241
+ timeoutSeconds: 180,
242
+ maxRows: 1,
243
+ query: smokeQuery,
244
+ },
245
+ });
246
+
247
+ const observed = parseSingleRowCsv(extractCsvText(daxResult));
248
+ attempt.observed = observed;
249
+ attempt.matched = isExpectedSmokeEvidence(observed, expected);
250
+ } catch (error) {
251
+ attempt.error = error.message;
252
+ }
253
+
254
+ attempts.push(attempt);
255
+
256
+ if (attempt.matched) {
257
+ return {
258
+ success: true,
259
+ caseId: 'base-template-smoke-test',
260
+ casePath,
261
+ expected,
262
+ observed: attempt.observed,
263
+ matchedInstance: {
264
+ processId: attempt.processId,
265
+ port: attempt.port,
266
+ connectionName: attempt.connectionName,
267
+ },
268
+ attempts,
269
+ };
270
+ }
271
+ }
272
+
273
+ return {
274
+ success: false,
275
+ caseId: 'base-template-smoke-test',
276
+ casePath,
277
+ expected,
278
+ observed: null,
279
+ matchedInstance: null,
280
+ attempts,
281
+ };
282
+ } finally {
283
+ session.close();
284
+ }
285
+ }
286
+
287
+ module.exports = {
288
+ BASE_TEMPLATE_CASE_PATH,
289
+ extractSmokeQuery,
290
+ formatLocalDate,
291
+ getExpectedSmokeEvidence,
292
+ normalizeMcpJsonResult,
293
+ extractCsvText,
294
+ parseSingleRowCsv,
295
+ selectConnectionForPort,
296
+ isExpectedSmokeEvidence,
297
+ formatEvidence,
298
+ runBaseTemplateLiveSmokeTest,
299
+ };
@@ -0,0 +1,160 @@
1
+ /**
2
+ * Claude Code SessionStart hook registration
3
+ * ===========================================
4
+ *
5
+ * Helpers to register / unregister a single `SessionStart` hook in the
6
+ * user's `~/.claude/settings.json`, used by `super autoupdate on|off`.
7
+ *
8
+ * Claude Code's hook schema for SessionStart is a list of matcher groups:
9
+ *
10
+ * {
11
+ * "hooks": {
12
+ * "SessionStart": [
13
+ * { "hooks": [ { "type": "command", "command": "...", "timeout": 20 } ] }
14
+ * ]
15
+ * }
16
+ * }
17
+ *
18
+ * We omit the optional `matcher` so the hook fires on every SessionStart
19
+ * source (startup / resume / clear / compact); the auto-update script's own
20
+ * throttle (once/hour) keeps that cheap. The hook command contains the
21
+ * marker `session-update.js`, which we use to find and dedupe our own entry
22
+ * without disturbing the user's other hooks.
23
+ *
24
+ * All writes reuse the installer's safe pattern (atomic + `.bak` + symlink
25
+ * rejection + strict parse) from lib/mcp-config so a corrupt or
26
+ * symlink-attacked settings.json is refused, never clobbered.
27
+ *
28
+ * @module lib/claude-hooks
29
+ */
30
+
31
+ const fs = require('fs');
32
+ const path = require('path');
33
+ const os = require('os');
34
+
35
+ const { readJsonStrict, writeJson, isObjectRecord } = require('./mcp-config');
36
+
37
+ // Any hook command containing this substring is considered ours.
38
+ const HOOK_MARKER = 'session-update.js';
39
+
40
+ /**
41
+ * Absolute path to the user-level Claude Code settings file.
42
+ */
43
+ function claudeSettingsPath() {
44
+ return path.join(os.homedir(), '.claude', 'settings.json');
45
+ }
46
+
47
+ /**
48
+ * Build the SessionStart matcher group we register.
49
+ * @param {string} commandStr - Full shell command (e.g. `node "<abs>/session-update.js"`)
50
+ */
51
+ function buildHookGroup(commandStr) {
52
+ return {
53
+ hooks: [{ type: 'command', command: commandStr, timeout: 20 }],
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Is this matcher group one of ours (its command mentions the marker)?
59
+ */
60
+ function isOurGroup(group) {
61
+ return (
62
+ isObjectRecord(group) &&
63
+ Array.isArray(group.hooks) &&
64
+ group.hooks.some(
65
+ (h) => isObjectRecord(h) && typeof h.command === 'string' && h.command.includes(HOOK_MARKER)
66
+ )
67
+ );
68
+ }
69
+
70
+ /**
71
+ * Register (or refresh) our SessionStart hook, preserving every other
72
+ * setting and hook. Idempotent: any prior entry of ours is replaced so the
73
+ * absolute command path stays current after a package move/upgrade.
74
+ *
75
+ * @param {string} commandStr - The shell command the hook runs.
76
+ * @param {{ settingsFile?: string }} [opts]
77
+ * @returns {{ file: string, action: 'created'|'updated' }}
78
+ */
79
+ function registerSessionStartHook(commandStr, opts = {}) {
80
+ const file = opts.settingsFile || claudeSettingsPath();
81
+ const existed = fs.existsSync(file);
82
+ const parsed = readJsonStrict(file);
83
+ const settings = isObjectRecord(parsed) ? parsed : {};
84
+
85
+ if (!isObjectRecord(settings.hooks)) settings.hooks = {};
86
+ const current = Array.isArray(settings.hooks.SessionStart) ? settings.hooks.SessionStart : [];
87
+
88
+ const others = current.filter((g) => !isOurGroup(g));
89
+ others.push(buildHookGroup(commandStr));
90
+ settings.hooks.SessionStart = others;
91
+
92
+ writeJson(file, settings);
93
+ return { file, action: existed ? 'updated' : 'created' };
94
+ }
95
+
96
+ /**
97
+ * Remove our SessionStart hook, leaving all other settings and hooks intact.
98
+ * Tidies away now-empty `SessionStart` array and `hooks` object.
99
+ *
100
+ * @param {{ settingsFile?: string }} [opts]
101
+ * @returns {{ file: string, removed: boolean }}
102
+ */
103
+ function unregisterSessionStartHook(opts = {}) {
104
+ const file = opts.settingsFile || claudeSettingsPath();
105
+ if (!fs.existsSync(file)) return { file, removed: false };
106
+
107
+ const settings = readJsonStrict(file);
108
+ if (
109
+ !isObjectRecord(settings) ||
110
+ !isObjectRecord(settings.hooks) ||
111
+ !Array.isArray(settings.hooks.SessionStart)
112
+ ) {
113
+ return { file, removed: false };
114
+ }
115
+
116
+ const kept = settings.hooks.SessionStart.filter((g) => !isOurGroup(g));
117
+ const removed = kept.length < settings.hooks.SessionStart.length;
118
+ if (!removed) return { file, removed: false };
119
+
120
+ if (kept.length > 0) {
121
+ settings.hooks.SessionStart = kept;
122
+ } else {
123
+ delete settings.hooks.SessionStart;
124
+ if (Object.keys(settings.hooks).length === 0) {
125
+ delete settings.hooks;
126
+ }
127
+ }
128
+
129
+ writeJson(file, settings);
130
+ return { file, removed: true };
131
+ }
132
+
133
+ /**
134
+ * Is our SessionStart hook currently registered?
135
+ * @param {{ settingsFile?: string }} [opts]
136
+ * @returns {boolean}
137
+ */
138
+ function isSessionStartHookRegistered(opts = {}) {
139
+ const file = opts.settingsFile || claudeSettingsPath();
140
+ if (!fs.existsSync(file)) return false;
141
+ let settings;
142
+ try {
143
+ settings = readJsonStrict(file);
144
+ } catch (_) {
145
+ return false;
146
+ }
147
+ const arr =
148
+ isObjectRecord(settings) && isObjectRecord(settings.hooks) && settings.hooks.SessionStart;
149
+ return Array.isArray(arr) && arr.some((g) => isOurGroup(g));
150
+ }
151
+
152
+ module.exports = {
153
+ HOOK_MARKER,
154
+ claudeSettingsPath,
155
+ buildHookGroup,
156
+ isOurGroup,
157
+ registerSessionStartHook,
158
+ unregisterSessionStartHook,
159
+ isSessionStartHookRegistered,
160
+ };