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,82 @@
1
+ {
2
+ "scorecardName": "Dirección Andina Nexus",
3
+ "goals": [
4
+ {
5
+ "metricName": "Ventas",
6
+ "scorecardEnabled": true,
7
+ "goalName": "Ventas",
8
+ "owner": "direccion@example.com",
9
+ "cadence": "Monthly",
10
+ "startDate": "2026-01-01T00:00:00Z",
11
+ "dueDate": "2026-12-31T00:00:00Z",
12
+ "target": 12000000,
13
+ "statusRulePreset": "higher-is-better"
14
+ },
15
+ {
16
+ "metricName": "Margen %",
17
+ "scorecardEnabled": true,
18
+ "goalName": "Margen %",
19
+ "owner": "finance@example.com",
20
+ "cadence": "Quarterly",
21
+ "startDate": "2026-01-01T00:00:00Z",
22
+ "dueDate": "2026-12-31T00:00:00Z",
23
+ "target": 0.42,
24
+ "statusRulePreset": "higher-is-better"
25
+ },
26
+ {
27
+ "metricName": "EBITDA",
28
+ "scorecardEnabled": true,
29
+ "goalName": "EBITDA",
30
+ "owner": "finance@example.com",
31
+ "cadence": "Monthly",
32
+ "startDate": "2026-01-01T00:00:00Z",
33
+ "dueDate": "2026-12-31T00:00:00Z",
34
+ "target": 2800000,
35
+ "statusRulePreset": "higher-is-better"
36
+ },
37
+ {
38
+ "metricName": "Margen operativo %",
39
+ "scorecardEnabled": true,
40
+ "goalName": "Margen operativo %",
41
+ "owner": "finance@example.com",
42
+ "cadence": "Quarterly",
43
+ "startDate": "2026-01-01T00:00:00Z",
44
+ "dueDate": "2026-12-31T00:00:00Z",
45
+ "target": 0.24,
46
+ "statusRulePreset": "higher-is-better"
47
+ },
48
+ {
49
+ "metricName": "Cash collected",
50
+ "scorecardEnabled": true,
51
+ "goalName": "Cash collected",
52
+ "owner": "treasury@example.com",
53
+ "cadence": "Monthly",
54
+ "startDate": "2026-01-01T00:00:00Z",
55
+ "dueDate": "2026-12-31T00:00:00Z",
56
+ "target": 10500000,
57
+ "statusRulePreset": "higher-is-better"
58
+ },
59
+ {
60
+ "metricName": "Retención %",
61
+ "scorecardEnabled": true,
62
+ "goalName": "Retención %",
63
+ "owner": "clientes@example.com",
64
+ "cadence": "Monthly",
65
+ "startDate": "2026-01-01T00:00:00Z",
66
+ "dueDate": "2026-12-31T00:00:00Z",
67
+ "target": 0.9,
68
+ "statusRulePreset": "higher-is-better"
69
+ },
70
+ {
71
+ "metricName": "Rentabilidad de proyectos",
72
+ "scorecardEnabled": true,
73
+ "goalName": "Rentabilidad de proyectos",
74
+ "owner": "proyectos@example.com",
75
+ "cadence": "Monthly",
76
+ "startDate": "2026-01-01T00:00:00Z",
77
+ "dueDate": "2026-12-31T00:00:00Z",
78
+ "target": 1600000,
79
+ "statusRulePreset": "higher-is-better"
80
+ }
81
+ ]
82
+ }
@@ -0,0 +1,124 @@
1
+ #requires -Version 7.0
2
+
3
+ param(
4
+ [string] $TemplateRoot = 'templates/base-template',
5
+
6
+ [Parameter(Mandatory = $true)]
7
+ [string] $OverlayPath
8
+ )
9
+
10
+ Set-StrictMode -Version Latest
11
+ $ErrorActionPreference = 'Stop'
12
+ # Pin stdout to UTF-8 so the blueprint JSON keeps "Métricas"/"Descripción" intact
13
+ # when Node decodes the pipe as UTF-8, regardless of the host console codepage.
14
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
15
+
16
+ function Read-Overlay {
17
+ param([string] $Path)
18
+ return Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json -Depth 100
19
+ }
20
+
21
+ function Get-MetricsTmdlPath {
22
+ param([string] $Root)
23
+ $path = Join-Path $Root 'base-template.SemanticModel/definition/tables/Métricas.tmdl'
24
+ if (-not (Test-Path -LiteralPath $path)) {
25
+ throw "Métricas.tmdl not found under $Root"
26
+ }
27
+ return $path
28
+ }
29
+
30
+ function Convert-MetricRow {
31
+ param(
32
+ [string] $Row,
33
+ [string[]] $Columns
34
+ )
35
+
36
+ # Assumes the Métricas catalog uses uppercase TRUE/FALSE booleans and no
37
+ # embedded/doubled quotes ("") in text cells; a violating edit throws the
38
+ # "Unexpected ... row shape" error below rather than silently mis-parsing.
39
+ # Use a private name, not the automatic $matches variable (which any later
40
+ # -match would silently overwrite).
41
+ $tokenMatches = [regex]::Matches($Row, '"([^"]*)"|TRUE|FALSE|[-]?\d+(?:\.\d+)?')
42
+ $values = @($tokenMatches | ForEach-Object { $_.Value.Trim('"') })
43
+ if ($values.Count -ne $Columns.Count) {
44
+ throw "Unexpected Métricas DATATABLE row shape: $Row"
45
+ }
46
+
47
+ $rowByColumn = @{}
48
+ for ($i = 0; $i -lt $Columns.Count; $i++) {
49
+ $rowByColumn[$Columns[$i]] = $values[$i]
50
+ }
51
+
52
+ return [ordered]@{
53
+ metricName = $rowByColumn['Métrica']
54
+ format = $rowByColumn['Formato']
55
+ formatType = $rowByColumn['Tipo de formato']
56
+ trendDirection = $rowByColumn['Tendencia']
57
+ description = $rowByColumn['Descripción']
58
+ }
59
+ }
60
+
61
+ function Read-BaseTemplateMetrics {
62
+ param([string] $Path)
63
+
64
+ $content = Get-Content -LiteralPath $Path -Raw
65
+ $table = [regex]::Match(
66
+ $content,
67
+ 'DATATABLE\s*\((?<header>[\s\S]*?),\s*\{(?<rows>[\s\S]*?)\n\s*\}\s*\)\s*$'
68
+ )
69
+ if (-not $table.Success) {
70
+ throw 'Could not locate the Métricas DATATABLE rows.'
71
+ }
72
+
73
+ $columns = @(
74
+ [regex]::Matches($table.Groups['header'].Value, '"([^"]+)"\s*,\s*(?:STRING|INTEGER|BOOLEAN)') |
75
+ ForEach-Object { $_.Groups[1].Value }
76
+ )
77
+ if ($columns.Count -eq 0) {
78
+ throw 'Could not locate the Métricas DATATABLE columns.'
79
+ }
80
+
81
+ $rowOptions = [System.Text.RegularExpressions.RegexOptions]::Singleline
82
+ $rows = [regex]::Matches($table.Groups['rows'].Value, '\{\s*(?<row>[^{}]*?)\s*\}', $rowOptions)
83
+ return @($rows | ForEach-Object { Convert-MetricRow -Row $_.Groups['row'].Value -Columns $columns })
84
+ }
85
+
86
+ $overlay = Read-Overlay -Path $OverlayPath
87
+ $metrics = Read-BaseTemplateMetrics -Path (Get-MetricsTmdlPath -Root $TemplateRoot)
88
+ $metricByName = @{}
89
+ foreach ($metric in $metrics) {
90
+ $metricByName[$metric.metricName] = $metric
91
+ }
92
+
93
+ $goals = @()
94
+ foreach ($goal in $overlay.goals) {
95
+ if (-not $goal.scorecardEnabled) {
96
+ continue
97
+ }
98
+ if (-not $metricByName.ContainsKey($goal.metricName)) {
99
+ throw "Overlay references metric not found in base-template: $($goal.metricName)"
100
+ }
101
+
102
+ $metric = $metricByName[$goal.metricName]
103
+ $goals += [ordered]@{
104
+ metricName = $goal.metricName
105
+ goalName = $goal.goalName
106
+ description = $metric.description
107
+ format = $metric.format
108
+ formatType = $metric.formatType
109
+ trendDirection = $metric.trendDirection
110
+ owner = $goal.owner
111
+ cadence = $goal.cadence
112
+ startDate = $goal.startDate
113
+ dueDate = $goal.dueDate
114
+ target = $goal.target
115
+ statusRulePreset = $goal.statusRulePreset
116
+ }
117
+ }
118
+
119
+ [ordered]@{
120
+ sourceTemplate = 'templates/base-template/base-template.pbip'
121
+ metricsTable = 'Métricas'
122
+ scorecardName = $overlay.scorecardName
123
+ goals = $goals
124
+ } | ConvertTo-Json -Depth 100
@@ -0,0 +1,39 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [ValidateSet('Get', 'Upsert', 'Delete')]
4
+ [string] $Action,
5
+
6
+ [Parameter(Mandatory = $true)]
7
+ [string] $GroupId,
8
+
9
+ [Parameter(Mandatory = $true)]
10
+ [string] $ScorecardId,
11
+
12
+ [Parameter(Mandatory = $true)]
13
+ [string] $GoalId,
14
+
15
+ [string] $BodyPath,
16
+ [string] $AccessToken,
17
+ [switch] $ConfirmWrite
18
+ )
19
+
20
+ . "$PSScriptRoot/powerbi-rest-common.ps1"
21
+
22
+ $encodedGoalId = ConvertTo-PowerBiPathSegment -Name 'GoalId' -Value $GoalId
23
+ $goalPath = (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId -Suffix 'goals') + "($encodedGoalId)"
24
+ $statusRulesPath = "$goalPath/statusRules"
25
+
26
+ switch ($Action) {
27
+ 'Get' {
28
+ Invoke-PowerBiRest -Method GET -Path $statusRulesPath -AccessToken $AccessToken
29
+ }
30
+ 'Upsert' {
31
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
32
+ Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
33
+ Invoke-PowerBiRest -Method POST -Path $statusRulesPath -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
34
+ }
35
+ 'Delete' {
36
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
37
+ Invoke-PowerBiRest -Method DELETE -Path $statusRulesPath -AccessToken $AccessToken
38
+ }
39
+ }
@@ -0,0 +1,48 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [ValidateSet('List', 'Create', 'Delete')]
4
+ [string] $Action,
5
+
6
+ [Parameter(Mandatory = $true)]
7
+ [string] $GroupId,
8
+
9
+ [Parameter(Mandatory = $true)]
10
+ [string] $ScorecardId,
11
+
12
+ [Parameter(Mandatory = $true)]
13
+ [string] $GoalId,
14
+
15
+ [string] $Timestamp,
16
+ [string] $BodyPath,
17
+ [string] $AccessToken,
18
+ [switch] $ConfirmWrite
19
+ )
20
+
21
+ . "$PSScriptRoot/powerbi-rest-common.ps1"
22
+
23
+ $encodedGoalId = ConvertTo-PowerBiPathSegment -Name 'GoalId' -Value $GoalId
24
+ $goalPath = (New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId -Suffix 'goals') + "($encodedGoalId)"
25
+ $goalValuesPath = "$goalPath/goalValues"
26
+
27
+ switch ($Action) {
28
+ 'List' {
29
+ Invoke-PowerBiRest -Method GET -Path $goalValuesPath -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 $goalValuesPath -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
35
+ }
36
+ 'Delete' {
37
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
38
+ Assert-RequiredValue -Name 'Timestamp' -Value $Timestamp
39
+ # The timestamp is an OData datetime key and appears literally per the
40
+ # Power BI REST reference — goalValues(2021-12-14T00:00:00Z) — so do NOT
41
+ # percent-encode the colons (a strict OData parser rejects %3A). Validate
42
+ # the ISO-8601 instant instead, which also keeps the segment injection-safe.
43
+ if ($Timestamp -notmatch '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?Z$') {
44
+ throw "Timestamp must be an ISO-8601 UTC instant like 2026-01-01T00:00:00Z (got: $Timestamp)"
45
+ }
46
+ Invoke-PowerBiRest -Method DELETE -Path "$goalValuesPath($Timestamp)" -AccessToken $AccessToken
47
+ }
48
+ }
@@ -0,0 +1,68 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [ValidateSet('List', 'Get', 'Create', 'Update', 'Delete', 'GetRefreshHistory', 'RefreshCurrentValue', 'RefreshTargetValue', 'DeleteCurrentValueConnection', 'DeleteTargetValueConnection')]
4
+ [string] $Action,
5
+
6
+ [Parameter(Mandatory = $true)]
7
+ [string] $GroupId,
8
+
9
+ [Parameter(Mandatory = $true)]
10
+ [string] $ScorecardId,
11
+
12
+ [string] $GoalId,
13
+ [string] $BodyPath,
14
+ [string] $AccessToken,
15
+ [switch] $ConfirmWrite
16
+ )
17
+
18
+ . "$PSScriptRoot/powerbi-rest-common.ps1"
19
+
20
+ $goalsPath = New-PowerBiScorecardPath -GroupId $GroupId -ScorecardId $ScorecardId -Suffix 'goals'
21
+
22
+ function Get-GoalPath {
23
+ Assert-RequiredValue -Name 'GoalId' -Value $GoalId
24
+ $encodedGoalId = ConvertTo-PowerBiPathSegment -Name 'GoalId' -Value $GoalId
25
+ return "$goalsPath($encodedGoalId)"
26
+ }
27
+
28
+ switch ($Action) {
29
+ 'List' {
30
+ Invoke-PowerBiRest -Method GET -Path $goalsPath -AccessToken $AccessToken
31
+ }
32
+ 'Get' {
33
+ Invoke-PowerBiRest -Method GET -Path (Get-GoalPath) -AccessToken $AccessToken
34
+ }
35
+ 'Create' {
36
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
37
+ Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
38
+ Invoke-PowerBiRest -Method POST -Path $goalsPath -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
39
+ }
40
+ 'Update' {
41
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
42
+ Assert-RequiredValue -Name 'BodyPath' -Value $BodyPath
43
+ Invoke-PowerBiRest -Method PATCH -Path (Get-GoalPath) -Body (Read-JsonObject -Path $BodyPath) -AccessToken $AccessToken
44
+ }
45
+ 'Delete' {
46
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
47
+ Invoke-PowerBiRest -Method DELETE -Path (Get-GoalPath) -AccessToken $AccessToken
48
+ }
49
+ 'GetRefreshHistory' {
50
+ Invoke-PowerBiRest -Method GET -Path "$(Get-GoalPath)/GetRefreshHistory()" -AccessToken $AccessToken
51
+ }
52
+ 'RefreshCurrentValue' {
53
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
54
+ Invoke-PowerBiRest -Method POST -Path "$(Get-GoalPath)/RefreshGoalCurrentValue()" -AccessToken $AccessToken
55
+ }
56
+ 'RefreshTargetValue' {
57
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
58
+ Invoke-PowerBiRest -Method POST -Path "$(Get-GoalPath)/RefreshGoalTargetValue()" -AccessToken $AccessToken
59
+ }
60
+ 'DeleteCurrentValueConnection' {
61
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
62
+ Invoke-PowerBiRest -Method POST -Path "$(Get-GoalPath)/DeleteGoalCurrentValueConnection()" -AccessToken $AccessToken
63
+ }
64
+ 'DeleteTargetValueConnection' {
65
+ Assert-ConfirmedWrite -Action $Action -ConfirmWrite:$ConfirmWrite
66
+ Invoke-PowerBiRest -Method POST -Path "$(Get-GoalPath)/DeleteGoalTargetValueConnection()" -AccessToken $AccessToken
67
+ }
68
+ }
@@ -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
+ }