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,197 @@
1
+ #requires -Version 7.0
2
+
3
+ Set-StrictMode -Version Latest
4
+ $ErrorActionPreference = 'Stop'
5
+ # Pin stdout to UTF-8 so accented payload text (Spanish goal names/descriptions)
6
+ # survives when the caller (Node/MCP) decodes the pipe as UTF-8, regardless of the
7
+ # host console codepage (CP437/CP1252 on many Windows shells). ConvertFrom-Json
8
+ # -Depth below also requires PowerShell 7+.
9
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
10
+
11
+ function Get-PowerBiBearerToken {
12
+ param(
13
+ [string] $AccessToken
14
+ )
15
+
16
+ if ($AccessToken) {
17
+ return $AccessToken
18
+ }
19
+
20
+ if ($env:POWERBI_ACCESS_TOKEN) {
21
+ return $env:POWERBI_ACCESS_TOKEN
22
+ }
23
+
24
+ $az = Get-Command az -ErrorAction SilentlyContinue
25
+ if ($az) {
26
+ $token = az account get-access-token --resource 'https://analysis.windows.net/powerbi/api' --query accessToken -o tsv
27
+ if ($LASTEXITCODE -eq 0 -and $token) {
28
+ return $token.Trim()
29
+ }
30
+ }
31
+
32
+ throw 'No Power BI access token found. Set POWERBI_ACCESS_TOKEN or sign in with Azure CLI.'
33
+ }
34
+
35
+ function Read-JsonObject {
36
+ param(
37
+ [Parameter(Mandatory = $true)]
38
+ [string] $Path
39
+ )
40
+
41
+ if (-not (Test-Path -LiteralPath $Path)) {
42
+ throw "JSON file not found: $Path"
43
+ }
44
+
45
+ return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json -Depth 100
46
+ }
47
+
48
+ function ConvertTo-JsonBody {
49
+ param(
50
+ [Parameter(Mandatory = $true)]
51
+ [object] $InputObject
52
+ )
53
+
54
+ return $InputObject | ConvertTo-Json -Depth 100
55
+ }
56
+
57
+ function Assert-ConfirmedWrite {
58
+ param(
59
+ [Parameter(Mandatory = $true)]
60
+ [string] $Action,
61
+
62
+ [switch] $ConfirmWrite
63
+ )
64
+
65
+ if (-not $ConfirmWrite) {
66
+ throw "Write action '$Action' requires -ConfirmWrite."
67
+ }
68
+ }
69
+
70
+ function Assert-RequiredValue {
71
+ param(
72
+ [Parameter(Mandatory = $true)]
73
+ [string] $Name,
74
+
75
+ [AllowNull()]
76
+ [string] $Value
77
+ )
78
+
79
+ if ([string]::IsNullOrWhiteSpace($Value)) {
80
+ throw "$Name is required."
81
+ }
82
+ }
83
+
84
+ function ConvertTo-PowerBiPathSegment {
85
+ param(
86
+ [Parameter(Mandatory = $true)]
87
+ [string] $Value,
88
+
89
+ [string] $Name = 'Value'
90
+ )
91
+
92
+ Assert-RequiredValue -Name $Name -Value $Value
93
+ return [System.Uri]::EscapeDataString($Value)
94
+ }
95
+
96
+ function Resolve-PowerBiRestUri {
97
+ param(
98
+ [Parameter(Mandatory = $true)]
99
+ [string] $BaseUri,
100
+
101
+ [Parameter(Mandatory = $true)]
102
+ [string] $Path
103
+ )
104
+
105
+ $parsedBaseUri = [System.Uri] $BaseUri
106
+ if (
107
+ -not $parsedBaseUri.IsAbsoluteUri -or
108
+ $parsedBaseUri.Scheme -ne 'https' -or
109
+ $parsedBaseUri.Host -ne 'api.powerbi.com' -or
110
+ $parsedBaseUri.UserInfo
111
+ ) {
112
+ throw 'Power BI REST calls must target https://api.powerbi.com without userinfo.'
113
+ }
114
+
115
+ return "$($BaseUri.TrimEnd('/'))/$($Path.TrimStart('/'))"
116
+ }
117
+
118
+ function New-PowerBiScorecardPath {
119
+ param(
120
+ [Parameter(Mandatory = $true)]
121
+ [string] $GroupId,
122
+
123
+ [string] $ScorecardId,
124
+
125
+ [string] $Suffix
126
+ )
127
+
128
+ $encodedGroupId = ConvertTo-PowerBiPathSegment -Name 'GroupId' -Value $GroupId
129
+ $path = "groups/$encodedGroupId/scorecards"
130
+ if ($ScorecardId) {
131
+ $encodedScorecardId = ConvertTo-PowerBiPathSegment -Name 'ScorecardId' -Value $ScorecardId
132
+ $path = "$path($encodedScorecardId)"
133
+ }
134
+ if ($Suffix) {
135
+ $path = "$path/$Suffix"
136
+ }
137
+ return $path
138
+ }
139
+
140
+ function Invoke-PowerBiRest {
141
+ param(
142
+ [Parameter(Mandatory = $true)]
143
+ [ValidateSet('GET', 'POST', 'PATCH', 'DELETE')]
144
+ [string] $Method,
145
+
146
+ [Parameter(Mandatory = $true)]
147
+ [string] $Path,
148
+
149
+ [object] $Body,
150
+
151
+ [string] $AccessToken,
152
+
153
+ [string] $BaseUri = 'https://api.powerbi.com/v1.0/myorg'
154
+ )
155
+
156
+ $uri = Resolve-PowerBiRestUri -BaseUri $BaseUri -Path $Path
157
+ $token = Get-PowerBiBearerToken -AccessToken $AccessToken
158
+ $headers = @{
159
+ Authorization = "Bearer $token"
160
+ }
161
+
162
+ $parameters = @{
163
+ Method = $Method
164
+ Uri = $uri
165
+ Headers = $headers
166
+ }
167
+
168
+ if ($null -ne $Body) {
169
+ $parameters.ContentType = 'application/json'
170
+ $parameters.Body = ConvertTo-JsonBody -InputObject $Body
171
+ }
172
+
173
+ try {
174
+ $response = Invoke-RestMethod @parameters
175
+ }
176
+ catch {
177
+ # Map the common Power BI REST failures to an actionable message instead
178
+ # of surfacing a raw .NET HttpResponseException. Token expiry (401) is the
179
+ # routine case because az-CLI tokens expire in ~1 hour.
180
+ $status = $null
181
+ try { $status = [int]$_.Exception.Response.StatusCode } catch { }
182
+ $hint = switch ($status) {
183
+ 401 { 'token missing/expired/invalid — re-run `az login` (az CLI tokens expire in ~1h) or refresh $env:POWERBI_ACCESS_TOKEN' }
184
+ 403 { 'insufficient Power BI permissions for this workspace/scorecard' }
185
+ 404 { 'workspace, scorecard, or goal not found — verify the GUID(s) in the request' }
186
+ 429 { 'rate-limited by the Power BI API — wait a moment and retry' }
187
+ default { $_.Exception.Message }
188
+ }
189
+ $label = if ($status) { "HTTP $status" } else { 'request failed' }
190
+ [Console]::Error.WriteLine("Power BI REST $Method $uri : $label — $hint")
191
+ exit 1
192
+ }
193
+
194
+ if ($null -ne $response) {
195
+ $response | ConvertTo-Json -Depth 100
196
+ }
197
+ }
@@ -0,0 +1,53 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [ValidateSet('List', 'Get', 'GetByReportId', 'Create', 'Update', 'Delete', 'MoveGoals')]
4
+ [string] $Action,
5
+
6
+ [Parameter(Mandatory = $true)]
7
+ [string] $GroupId,
8
+
9
+ [string] $ScorecardId,
10
+ [string] $ReportId,
11
+ [string] $BodyPath,
12
+ [string] $AccessToken,
13
+ [switch] $ConfirmWrite
14
+ )
15
+
16
+ . "$PSScriptRoot/powerbi-rest-common.ps1"
17
+
18
+ switch ($Action) {
19
+ 'List' {
20
+ Invoke-PowerBiRest -Method GET -Path (New-PowerBiScorecardPath -GroupId $GroupId) -AccessToken $AccessToken
21
+ }
22
+ 'Get' {
23
+ Assert-RequiredValue -Name 'ScorecardId' -Value $ScorecardId
24
+ Invoke-PowerBiRest -Method GET -Path (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId) -AccessToken $AccessToken
25
+ }
26
+ 'GetByReportId' {
27
+ $encodedGroupId = ConvertTo-PowerBiPathSegment -Name 'GroupId' -Value $GroupId
28
+ $encodedReportId = ConvertTo-PowerBiPathSegment -Name 'ReportId' -Value $ReportId
29
+ Invoke-PowerBiRest -Method GET -Path "groups/$encodedGroupId/scorecards/GetScorecardByReportId(reportId=$encodedReportId)" -AccessToken $AccessToken
30
+ }
31
+ 'Create' {
32
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
33
+ Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
34
+ Invoke-PowerBiRest -Method POST -Path (New-PowerBiScorecardPath -GroupId $GroupId) -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
35
+ }
36
+ 'Update' {
37
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
38
+ Assert-RequiredValue -Name 'ScorecardId' -Value $ScorecardId
39
+ Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
40
+ Invoke-PowerBiRest -Method PATCH -Path (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId) -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
41
+ }
42
+ 'Delete' {
43
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
44
+ Assert-RequiredValue -Name 'ScorecardId' -Value $ScorecardId
45
+ Invoke-PowerBiRest -Method DELETE -Path (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId) -AccessToken $AccessToken
46
+ }
47
+ 'MoveGoals' {
48
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
49
+ Assert-RequiredValue -Name 'ScorecardId' -Value $ScorecardId
50
+ Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
51
+ Invoke-PowerBiRest -Method POST -Path (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId -Suffix 'MoveGoals()') -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
52
+ }
53
+ }
@@ -0,0 +1,427 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * update-check — cross-agent version-check helper for bi-superpowers.
4
+ *
5
+ * The SKILL.md preamble (see lib/generators/claude-plugin.js) invokes this
6
+ * script at the start of every skill so the agent can surface an update
7
+ * notice to the user when a newer version is on npm — without hitting the
8
+ * network on every invocation. Cache TTL is 24h; repeated calls inside
9
+ * that window are served from `~/.bi-superpowers/update-state.json`.
10
+ *
11
+ * Output (stdout, one line):
12
+ * UPTODATE when installed >= latest
13
+ * UPDATE_AVAILABLE <installed> <latest> when installed < latest
14
+ * SNOOZED <iso> when user deferred the notice
15
+ *
16
+ * Flags:
17
+ * --force bypass cache (re-fetch npm, ignore snooze TTL)
18
+ * --silent-if-uptodate suppress UPTODATE line (used by the preamble)
19
+ * --silent-if-snoozed suppress SNOOZED line (used by the preamble)
20
+ * --json emit JSON instead of text
21
+ * --snooze 24h|48h|7d|clear set (or clear) the snooze state and exit
22
+ * --reset delete the state file and exit (used post-upgrade)
23
+ * --state-dir <path> override ~/.bi-superpowers/ (for tests)
24
+ * --package-name <name> override the package name (for tests)
25
+ * -h, --help show this help
26
+ *
27
+ * Exit code is always 0 when the script itself ran — errors during the
28
+ * network fetch degrade to "no output" so the caller never blocks. A
29
+ * non-zero exit means a user error (bad flags).
30
+ *
31
+ * Pure helpers (compareVersions, isCacheFresh, isSnoozed,
32
+ * computeNextSnoozeUntil, readState, writeState, fetchLatestVersion) are
33
+ * exported so unit tests can exercise them without spawning child
34
+ * processes or hitting the network.
35
+ */
36
+
37
+ 'use strict';
38
+
39
+ const fs = require('fs');
40
+ const os = require('os');
41
+ const path = require('path');
42
+ const https = require('https');
43
+
44
+ const PACKAGE_NAME = 'bi-superpowers';
45
+ const CACHE_TTL_MS = 1000 * 60 * 60 * 24; // 24 hours
46
+ const HTTPS_TIMEOUT_MS = 5000;
47
+ // Rewritten at generation time when this helper is copied into
48
+ // `skills/<name>/scripts/update-check.js`. In the canonical source under
49
+ // `bin/commands/`, it stays null and we fall back to package.json.
50
+ const BUNDLED_INSTALLED_VERSION = "1.0.0";
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Argument parsing
54
+ // ---------------------------------------------------------------------------
55
+
56
+ function parseArgs(argv) {
57
+ const out = {
58
+ force: false,
59
+ silentIfUptodate: false,
60
+ silentIfSnoozed: false,
61
+ json: false,
62
+ snooze: null,
63
+ reset: false,
64
+ help: false,
65
+ stateDir: null,
66
+ packageName: null,
67
+ installedVersion: null,
68
+ };
69
+ for (let i = 0; i < argv.length; i += 1) {
70
+ const a = argv[i];
71
+ if (a === '--force') out.force = true;
72
+ else if (a === '--silent-if-uptodate') out.silentIfUptodate = true;
73
+ else if (a === '--silent-if-snoozed') out.silentIfSnoozed = true;
74
+ else if (a === '--json') out.json = true;
75
+ else if (a === '--snooze') {
76
+ out.snooze = argv[++i];
77
+ if (out.snooze === undefined) {
78
+ process.stderr.write(
79
+ 'update-check: --snooze requires a value (e.g. 24h, 48h, 7d, auto, clear)\n'
80
+ );
81
+ process.exit(1);
82
+ }
83
+ } else if (a === '--reset') out.reset = true;
84
+ else if (a === '--state-dir') out.stateDir = argv[++i];
85
+ else if (a === '--package-name') out.packageName = argv[++i];
86
+ else if (a === '--installed-version') out.installedVersion = argv[++i];
87
+ else if (a === '-h' || a === '--help') out.help = true;
88
+ else {
89
+ process.stderr.write(`update-check: unknown flag: ${a}\n`);
90
+ process.exit(1);
91
+ }
92
+ }
93
+ return out;
94
+ }
95
+
96
+ function help() {
97
+ process.stdout.write(
98
+ [
99
+ 'Usage: update-check [options]',
100
+ '',
101
+ 'Prints one of: UPTODATE, UPDATE_AVAILABLE <installed> <latest>, SNOOZED <iso>.',
102
+ '',
103
+ 'Options:',
104
+ ' --force Bypass cache and snooze TTL',
105
+ ' --silent-if-uptodate Skip the UPTODATE line',
106
+ ' --silent-if-snoozed Skip the SNOOZED line',
107
+ ' --json Emit JSON',
108
+ ' --snooze <dur> Set snooze state (24h|48h|7d) or "clear" to reset snooze',
109
+ ' --reset Delete the state file (used after a successful upgrade)',
110
+ ' --state-dir <path> Override ~/.bi-superpowers/ (tests)',
111
+ ' --package-name <name> Override the package name (tests)',
112
+ ' --installed-version <v> Override the installed version (generated skill bundles)',
113
+ ' -h, --help Show this help',
114
+ '',
115
+ ].join('\n')
116
+ );
117
+ }
118
+
119
+ // ---------------------------------------------------------------------------
120
+ // Version comparison (semver-ish: MAJOR.MINOR.PATCH with optional -prerelease)
121
+ // No deps; handles the shapes bi-superpowers uses today.
122
+ // ---------------------------------------------------------------------------
123
+
124
+ /**
125
+ * Compare two semver strings.
126
+ * Returns -1 if a < b, 0 if equal, 1 if a > b.
127
+ * Pre-release tags (`-alpha.1`) sort before the release per semver.
128
+ */
129
+ function compareVersions(a, b) {
130
+ const parse = (v) => {
131
+ const [main, pre] = String(v).split('-');
132
+ const parts = main.split('.').map((n) => parseInt(n, 10) || 0);
133
+ while (parts.length < 3) parts.push(0);
134
+ return { parts, pre: pre || null };
135
+ };
136
+ const va = parse(a);
137
+ const vb = parse(b);
138
+ for (let i = 0; i < 3; i += 1) {
139
+ if (va.parts[i] !== vb.parts[i]) return va.parts[i] < vb.parts[i] ? -1 : 1;
140
+ }
141
+ // Main equal — pre-release < release.
142
+ if (va.pre && !vb.pre) return -1;
143
+ if (!va.pre && vb.pre) return 1;
144
+ if (va.pre && vb.pre) {
145
+ // Semver prerelease precedence: dot-separated identifiers compared
146
+ // left-to-right; numeric identifiers compared numerically, numeric ranks
147
+ // below alphanumeric, and a shorter identifier set has lower precedence.
148
+ const pa = va.pre.split('.');
149
+ const pb = vb.pre.split('.');
150
+ for (let i = 0; i < Math.max(pa.length, pb.length); i += 1) {
151
+ if (pa[i] === undefined) return -1;
152
+ if (pb[i] === undefined) return 1;
153
+ const an = /^\d+$/.test(pa[i]);
154
+ const bn = /^\d+$/.test(pb[i]);
155
+ if (an && bn) {
156
+ const d = parseInt(pa[i], 10) - parseInt(pb[i], 10);
157
+ if (d !== 0) return d < 0 ? -1 : 1;
158
+ } else if (an !== bn) {
159
+ return an ? -1 : 1;
160
+ } else if (pa[i] !== pb[i]) {
161
+ return pa[i] < pb[i] ? -1 : 1;
162
+ }
163
+ }
164
+ }
165
+ return 0;
166
+ }
167
+
168
+ // ---------------------------------------------------------------------------
169
+ // Cache + snooze state
170
+ // ---------------------------------------------------------------------------
171
+
172
+ function defaultStateDir() {
173
+ return path.join(os.homedir(), '.bi-superpowers');
174
+ }
175
+
176
+ function stateFilePath(stateDir) {
177
+ return path.join(stateDir, 'update-state.json');
178
+ }
179
+
180
+ function readState(stateDir) {
181
+ const filePath = stateFilePath(stateDir);
182
+ if (!fs.existsSync(filePath)) return null;
183
+ try {
184
+ return JSON.parse(fs.readFileSync(filePath, 'utf8'));
185
+ } catch (_) {
186
+ // Malformed → treat as no cache.
187
+ return null;
188
+ }
189
+ }
190
+
191
+ function writeState(stateDir, state) {
192
+ fs.mkdirSync(stateDir, { recursive: true });
193
+ fs.writeFileSync(stateFilePath(stateDir), JSON.stringify(state, null, 2) + '\n');
194
+ }
195
+
196
+ function resetState(stateDir) {
197
+ const filePath = stateFilePath(stateDir);
198
+ if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
199
+ }
200
+
201
+ function isCacheFresh(state, now, ttlMs) {
202
+ if (!state || !state.checkedAt) return false;
203
+ const checkedAt = Date.parse(state.checkedAt);
204
+ if (!Number.isFinite(checkedAt)) return false;
205
+ return now - checkedAt < ttlMs;
206
+ }
207
+
208
+ function isSnoozed(state, now) {
209
+ if (!state || !state.snoozeUntil) return false;
210
+ const until = Date.parse(state.snoozeUntil);
211
+ if (!Number.isFinite(until)) return false;
212
+ return until > now;
213
+ }
214
+
215
+ // Snooze escalation: 24h → 48h → 7d (capped).
216
+ function computeNextSnoozeUntil(currentLevel, now) {
217
+ const levels = [
218
+ 1000 * 60 * 60 * 24, // 24h
219
+ 1000 * 60 * 60 * 48, // 48h
220
+ 1000 * 60 * 60 * 24 * 7, // 7d
221
+ ];
222
+ const idx = Math.min(Math.max(currentLevel, 0), levels.length - 1);
223
+ return new Date(now + levels[idx]).toISOString();
224
+ }
225
+
226
+ function parseSnoozeArg(arg, now, currentLevel) {
227
+ if (arg === 'clear') return { clear: true };
228
+ if (arg === '24h') return { until: new Date(now + 1000 * 60 * 60 * 24).toISOString(), level: 0 };
229
+ if (arg === '48h') return { until: new Date(now + 1000 * 60 * 60 * 48).toISOString(), level: 1 };
230
+ if (arg === '7d')
231
+ return { until: new Date(now + 1000 * 60 * 60 * 24 * 7).toISOString(), level: 2 };
232
+ if (arg === 'auto')
233
+ return {
234
+ until: computeNextSnoozeUntil(currentLevel, now),
235
+ level: Math.min(currentLevel + 1, 2),
236
+ };
237
+ throw new Error(`invalid --snooze value: ${arg}. Expected 24h|48h|7d|auto|clear.`);
238
+ }
239
+
240
+ // ---------------------------------------------------------------------------
241
+ // npm registry fetch
242
+ // ---------------------------------------------------------------------------
243
+
244
+ /**
245
+ * Fetch the latest published version of a package from the npm registry.
246
+ * Never rejects with a network error — resolves null on timeout / failure
247
+ * so callers always degrade gracefully.
248
+ *
249
+ * @param {string} packageName - e.g. "bi-superpowers"
250
+ * @returns {Promise<string|null>}
251
+ */
252
+ function fetchLatestVersion(packageName) {
253
+ return new Promise((resolve) => {
254
+ const encoded = packageName.replace('/', '%2F');
255
+ const url = `https://registry.npmjs.org/${encoded}/latest`;
256
+
257
+ const req = https.get(
258
+ url,
259
+ { headers: { Accept: 'application/vnd.npm.install-v1+json' } },
260
+ (res) => {
261
+ if (res.statusCode !== 200) {
262
+ res.resume();
263
+ resolve(null);
264
+ return;
265
+ }
266
+ let body = '';
267
+ res.setEncoding('utf8');
268
+ res.on('data', (chunk) => (body += chunk));
269
+ res.on('end', () => {
270
+ try {
271
+ const json = JSON.parse(body);
272
+ resolve(typeof json.version === 'string' ? json.version : null);
273
+ } catch (_) {
274
+ resolve(null);
275
+ }
276
+ });
277
+ }
278
+ );
279
+ req.on('error', () => resolve(null));
280
+ req.setTimeout(HTTPS_TIMEOUT_MS, () => {
281
+ req.destroy();
282
+ resolve(null);
283
+ });
284
+ });
285
+ }
286
+
287
+ // ---------------------------------------------------------------------------
288
+ // Installed version — read from our own package.json
289
+ // ---------------------------------------------------------------------------
290
+
291
+ function readInstalledVersion(explicitVersion = null) {
292
+ if (explicitVersion) {
293
+ return String(explicitVersion);
294
+ }
295
+ if (BUNDLED_INSTALLED_VERSION) {
296
+ return String(BUNDLED_INSTALLED_VERSION);
297
+ }
298
+ try {
299
+ return require(path.join(__dirname, '..', '..', 'package.json')).version;
300
+ } catch (_) {
301
+ return null;
302
+ }
303
+ }
304
+
305
+ // ---------------------------------------------------------------------------
306
+ // Emit helpers
307
+ // ---------------------------------------------------------------------------
308
+
309
+ function emit(args, kind, payload) {
310
+ if (args.json) {
311
+ process.stdout.write(JSON.stringify({ status: kind, ...payload }) + '\n');
312
+ return;
313
+ }
314
+ if (kind === 'UPTODATE' && args.silentIfUptodate) return;
315
+ if (kind === 'SNOOZED' && args.silentIfSnoozed) return;
316
+
317
+ if (kind === 'UPTODATE') process.stdout.write('UPTODATE\n');
318
+ else if (kind === 'UPDATE_AVAILABLE')
319
+ process.stdout.write(`UPDATE_AVAILABLE ${payload.installed} ${payload.latest}\n`);
320
+ else if (kind === 'SNOOZED') process.stdout.write(`SNOOZED ${payload.until}\n`);
321
+ }
322
+
323
+ // ---------------------------------------------------------------------------
324
+ // main
325
+ // ---------------------------------------------------------------------------
326
+
327
+ async function main() {
328
+ const args = parseArgs(process.argv.slice(2));
329
+ if (args.help) {
330
+ help();
331
+ return;
332
+ }
333
+
334
+ const stateDir = args.stateDir || defaultStateDir();
335
+ const packageName = args.packageName || PACKAGE_NAME;
336
+
337
+ if (args.reset) {
338
+ resetState(stateDir);
339
+ return;
340
+ }
341
+
342
+ if (args.snooze) {
343
+ const now = Date.now();
344
+ const prior = readState(stateDir) || {};
345
+ const parsed = parseSnoozeArg(args.snooze, now, prior.snoozeLevel || 0);
346
+ if (parsed.clear) {
347
+ writeState(stateDir, { ...prior, snoozeUntil: null, snoozeLevel: 0 });
348
+ } else {
349
+ writeState(stateDir, {
350
+ ...prior,
351
+ snoozeUntil: parsed.until,
352
+ snoozeLevel: parsed.level,
353
+ });
354
+ }
355
+ return;
356
+ }
357
+
358
+ const installed = readInstalledVersion(args.installedVersion);
359
+ if (!installed) {
360
+ // Installed version undetermined — nothing useful to report.
361
+ return;
362
+ }
363
+
364
+ const now = Date.now();
365
+ let state = readState(stateDir);
366
+
367
+ // Snooze short-circuits everything except --force.
368
+ if (!args.force && isSnoozed(state, now)) {
369
+ emit(args, 'SNOOZED', { until: state.snoozeUntil });
370
+ return;
371
+ }
372
+
373
+ // Use cached `latest` when the cache is fresh (unless --force).
374
+ let latest = state && state.latest;
375
+ if (args.force || !isCacheFresh(state, now, CACHE_TTL_MS)) {
376
+ const fetched = await fetchLatestVersion(packageName);
377
+ if (fetched) {
378
+ latest = fetched;
379
+ const nextState = {
380
+ installed,
381
+ latest,
382
+ checkedAt: new Date(now).toISOString(),
383
+ snoozeUntil: (state && state.snoozeUntil) || null,
384
+ snoozeLevel: (state && state.snoozeLevel) || 0,
385
+ };
386
+ writeState(stateDir, nextState);
387
+ state = nextState;
388
+ }
389
+ // If fetched is null (network fail), we keep using the previous cache
390
+ // — or emit nothing if there's no cache at all.
391
+ }
392
+
393
+ if (!latest) {
394
+ // No cached value and no fetch — nothing to say.
395
+ return;
396
+ }
397
+
398
+ if (compareVersions(installed, latest) < 0) {
399
+ emit(args, 'UPDATE_AVAILABLE', { installed, latest });
400
+ } else {
401
+ emit(args, 'UPTODATE', { installed, latest });
402
+ }
403
+ }
404
+
405
+ module.exports = {
406
+ parseArgs,
407
+ compareVersions,
408
+ isCacheFresh,
409
+ isSnoozed,
410
+ computeNextSnoozeUntil,
411
+ parseSnoozeArg,
412
+ readState,
413
+ writeState,
414
+ resetState,
415
+ fetchLatestVersion,
416
+ readInstalledVersion,
417
+ CACHE_TTL_MS,
418
+ PACKAGE_NAME,
419
+ };
420
+
421
+ if (require.main === module) {
422
+ main().catch((err) => {
423
+ // Never throw out of the CLI — the preamble must not break skill invocation.
424
+ process.stderr.write(`update-check: ${err.message}\n`);
425
+ process.exit(0);
426
+ });
427
+ }