@luquimbo/bi-superpowers 5.0.0 → 5.0.2

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 (196) hide show
  1. package/.claude-plugin/marketplace.json +5 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.claude-plugin/skill-manifest.json +23 -7
  4. package/.plugin/plugin.json +1 -1
  5. package/AGENTS.md +124 -26
  6. package/CHANGELOG.md +494 -16
  7. package/README.md +33 -117
  8. package/bin/cli.js +1 -1
  9. package/bin/commands/diff.js +2 -2
  10. package/bin/commands/install.js +58 -45
  11. package/bin/commands/lint.js +2 -2
  12. package/bin/commands/validate-projects.js +1 -1
  13. package/bin/lib/generators/claude-plugin.js +14 -5
  14. package/bin/lib/generators/shared.js +9 -5
  15. package/bin/lib/mcp-config.js +22 -2
  16. package/bin/lib/skills.js +8 -8
  17. package/bin/mcp/powerbi-modeling-launcher.js +8 -4
  18. package/bin/postinstall.js +14 -12
  19. package/bin/utils/mcp-detect.js +11 -11
  20. package/commands/bi-connect.md +34 -17
  21. package/commands/bi-dax.md +385 -0
  22. package/commands/bi-kickoff.md +75 -44
  23. package/commands/bi-modeling.md +395 -0
  24. package/commands/bi-performance.md +455 -0
  25. package/commands/bi-start.md +30 -18
  26. package/desktop-extension/manifest.json +2 -2
  27. package/package.json +6 -3
  28. package/skills/bi-connect/SKILL.md +34 -17
  29. package/skills/bi-connect/scripts/update-check.js +1 -1
  30. package/skills/bi-dax/SKILL.md +387 -0
  31. package/skills/{bi-report → bi-dax}/scripts/update-check.js +1 -1
  32. package/skills/bi-kickoff/SKILL.md +75 -44
  33. package/skills/bi-kickoff/scripts/update-check.js +1 -1
  34. package/skills/bi-modeling/SKILL.md +397 -0
  35. package/skills/bi-modeling/scripts/update-check.js +403 -0
  36. package/skills/bi-performance/SKILL.md +457 -0
  37. package/skills/bi-performance/scripts/install-tabular-editor.ps1 +90 -0
  38. package/skills/bi-performance/scripts/run-bpa.ps1 +161 -0
  39. package/skills/bi-performance/scripts/update-check.js +403 -0
  40. package/skills/bi-start/SKILL.md +31 -19
  41. package/skills/bi-start/scripts/update-check.js +1 -1
  42. package/src/content/base.md +13 -8
  43. package/src/content/routing.md +1 -5
  44. package/src/content/skills/bi-connect.md +32 -15
  45. package/src/content/skills/bi-dax.md +358 -0
  46. package/src/content/skills/bi-kickoff.md +73 -42
  47. package/src/content/skills/bi-modeling.md +368 -0
  48. package/src/content/skills/bi-performance/SKILL.md +428 -0
  49. package/src/content/skills/bi-performance/scripts/install-tabular-editor.ps1 +90 -0
  50. package/src/content/skills/bi-performance/scripts/run-bpa.ps1 +161 -0
  51. package/src/content/skills/bi-start.md +30 -18
  52. package/templates/sales/AGENTS.md +33 -0
  53. package/templates/sales/sales-template.Report/.platform +11 -0
  54. package/templates/sales/sales-template.Report/StaticResources/RegisteredResources/BISuperpowers.json +3888 -0
  55. package/templates/sales/sales-template.Report/StaticResources/SharedResources/BaseThemes/Fluent2-CY26SU03.json +4104 -0
  56. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/page.json +123 -0
  57. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/10420560e5b8c5235857/visual.json +16 -0
  58. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/2181c54a94f0c67abb2d/visual.json +283 -0
  59. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/24eba6a7af0b59974ef5/visual.json +703 -0
  60. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/26db24c91e5b615a5c29/mobile.json +11 -0
  61. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/26db24c91e5b615a5c29/visual.json +528 -0
  62. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/2ec652d0956901dd2afd/mobile.json +11 -0
  63. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/2ec652d0956901dd2afd/visual.json +324 -0
  64. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/45dda4e0b159becf2dcd/mobile.json +11 -0
  65. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/45dda4e0b159becf2dcd/visual.json +359 -0
  66. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/4ca8800cf1539ad423f2/visual.json +468 -0
  67. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/4f5704218eb88f7cdff6/mobile.json +29 -0
  68. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/4f5704218eb88f7cdff6/visual.json +241 -0
  69. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/54d3fdbedbbb863a9d7a/visual.json +575 -0
  70. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/68043403e96ca8ed23e8/visual.json +575 -0
  71. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/80b54a678ef36a250994/visual.json +351 -0
  72. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/814f624b6056dc4c8de5/mobile.json +11 -0
  73. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/814f624b6056dc4c8de5/visual.json +421 -0
  74. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/85e1cc13559f4e107ede/visual.json +681 -0
  75. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/8686961b837e855963fe/mobile.json +11 -0
  76. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/8686961b837e855963fe/visual.json +720 -0
  77. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/8d302c5b7e87e8cb57bb/visual.json +590 -0
  78. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/a02c5b30f2e757637d78/mobile.json +11 -0
  79. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/a02c5b30f2e757637d78/visual.json +102 -0
  80. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/a405d29e7744c770d445/visual.json +575 -0
  81. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/b0dc2036d3cf2baafb35/mobile.json +11 -0
  82. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/b0dc2036d3cf2baafb35/visual.json +333 -0
  83. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/cdd696baaf3b80b326f8/mobile.json +11 -0
  84. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/cdd696baaf3b80b326f8/visual.json +468 -0
  85. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/ff77ca1bafff5bfe5044/mobile.json +11 -0
  86. package/templates/sales/sales-template.Report/definition/pages/017e2c84c7dc89f26e57/visuals/ff77ca1bafff5bfe5044/visual.json +523 -0
  87. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/page.json +130 -0
  88. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/visual.json +681 -0
  89. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/visual.json +351 -0
  90. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/mobile.json +11 -0
  91. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/visual.json +333 -0
  92. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/mobile.json +11 -0
  93. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/visual.json +102 -0
  94. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/mobile.json +11 -0
  95. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/visual.json +468 -0
  96. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/mobile.json +11 -0
  97. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/visual.json +359 -0
  98. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/visual.json +685 -0
  99. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/85090dcdf75ac2487d1e/visual.json +283 -0
  100. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/visual.json +468 -0
  101. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/visual.json +590 -0
  102. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/mobile.json +11 -0
  103. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/visual.json +528 -0
  104. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a90aaa3e3117494f18f8/mobile.json +11 -0
  105. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a90aaa3e3117494f18f8/visual.json +523 -0
  106. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/mobile.json +11 -0
  107. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/visual.json +720 -0
  108. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/mobile.json +37 -0
  109. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/visual.json +1230 -0
  110. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b06ef80aa78cabcef8a6/mobile.json +11 -0
  111. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b06ef80aa78cabcef8a6/visual.json +324 -0
  112. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/d97979633a91e041107e/mobile.json +11 -0
  113. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/d97979633a91e041107e/visual.json +421 -0
  114. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/mobile.json +29 -0
  115. package/templates/sales/sales-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/visual.json +241 -0
  116. package/templates/sales/sales-template.Report/definition/pages/pages.json +8 -0
  117. package/templates/sales/sales-template.Report/definition/report.json +89 -0
  118. package/templates/sales/sales-template.Report/definition/version.json +4 -0
  119. package/templates/sales/sales-template.Report/definition.pbir +9 -0
  120. package/templates/sales/sales-template.SemanticModel/.pbi/editorSettings.json +8 -0
  121. package/templates/sales/sales-template.SemanticModel/.platform +11 -0
  122. package/templates/sales/sales-template.SemanticModel/DAXQueries/.pbi/daxQueries.json +9 -0
  123. package/templates/sales/sales-template.SemanticModel/DAXQueries/Calendar445MonthNr.dax +0 -0
  124. package/templates/sales/sales-template.SemanticModel/DAXQueries/Consulta 1.dax +6 -0
  125. package/templates/sales/sales-template.SemanticModel/DAXQueries/Consulta 2.dax +32 -0
  126. package/templates/sales/sales-template.SemanticModel/definition/cultures/es-AR.tmdl +7324 -0
  127. package/templates/sales/sales-template.SemanticModel/definition/database.tmdl +3 -0
  128. package/templates/sales/sales-template.SemanticModel/definition/expressions.tmdl +233 -0
  129. package/templates/sales/sales-template.SemanticModel/definition/functions.tmdl +247 -0
  130. package/templates/sales/sales-template.SemanticModel/definition/model.tmdl +46 -0
  131. package/templates/sales/sales-template.SemanticModel/definition/relationships.tmdl +16 -0
  132. package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Comparaciones.tmdl +194 -0
  133. package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Dimensiones ventas.tmdl +71 -0
  134. package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Ejes temporales.tmdl +67 -0
  135. package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Per/303/255odos.tmdl" +318 -0
  136. package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Vista de calendario.tmdl +36 -0
  137. package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Vista del valor.tmdl +87 -0
  138. package/templates/sales/sales-template.SemanticModel/definition/tables/Aux Vista temporal.tmdl +62 -0
  139. package/templates/sales/sales-template.SemanticModel/definition/tables/Calendario.tmdl +198 -0
  140. package/templates/sales/sales-template.SemanticModel/definition/tables/Canales.tmdl +59 -0
  141. package/templates/sales/sales-template.SemanticModel/definition/tables/Clientes.tmdl +120 -0
  142. package/templates/sales/sales-template.SemanticModel/definition/tables/Modelo Configuraci/303/263n.tmdl" +48 -0
  143. package/templates/sales/sales-template.SemanticModel/definition/tables/Monedas.tmdl +43 -0
  144. package/templates/sales/sales-template.SemanticModel/definition/tables/M/303/251tricas.tmdl +553 -0
  145. package/templates/sales/sales-template.SemanticModel/definition/tables/Productos.tmdl +73 -0
  146. package/templates/sales/sales-template.SemanticModel/definition/tables/Tipo de cambio.tmdl +66 -0
  147. package/templates/sales/sales-template.SemanticModel/definition/tables/Ventas.tmdl +133 -0
  148. package/templates/sales/sales-template.SemanticModel/definition.pbism +5 -0
  149. package/templates/sales/sales-template.SemanticModel/diagramLayout.json +239 -0
  150. package/templates/sales/sales-template.pbip +14 -0
  151. package/theme/BISuperpowers.json +3888 -0
  152. package/commands/bi-report.md +0 -403
  153. package/skills/bi-report/SKILL.md +0 -405
  154. package/skills/bi-report/references/cli-commands.md +0 -184
  155. package/skills/bi-report/references/cli-setup.md +0 -101
  156. package/skills/bi-report/references/close-write-open-pattern.md +0 -80
  157. package/skills/bi-report/references/layouts/finance.md +0 -65
  158. package/skills/bi-report/references/layouts/generic.md +0 -46
  159. package/skills/bi-report/references/layouts/hr.md +0 -48
  160. package/skills/bi-report/references/layouts/marketing.md +0 -45
  161. package/skills/bi-report/references/layouts/operations.md +0 -44
  162. package/skills/bi-report/references/layouts/sales.md +0 -50
  163. package/skills/bi-report/references/native-visuals.md +0 -341
  164. package/skills/bi-report/references/pbi-desktop-installation.md +0 -87
  165. package/skills/bi-report/references/pbir-preview-activation.md +0 -40
  166. package/skills/bi-report/references/slicer.md +0 -89
  167. package/skills/bi-report/references/textbox.md +0 -101
  168. package/skills/bi-report/references/themes/BISuperpowers.json +0 -915
  169. package/skills/bi-report/references/troubleshooting.md +0 -135
  170. package/skills/bi-report/references/visual-types.md +0 -78
  171. package/skills/bi-report/scripts/apply-theme.js +0 -243
  172. package/skills/bi-report/scripts/create-visual.js +0 -942
  173. package/skills/bi-report/scripts/ensure-pbi-cli.sh +0 -41
  174. package/skills/bi-report/scripts/validate-pbir.js +0 -351
  175. package/src/content/skills/bi-report/SKILL.md +0 -376
  176. package/src/content/skills/bi-report/references/cli-commands.md +0 -184
  177. package/src/content/skills/bi-report/references/cli-setup.md +0 -101
  178. package/src/content/skills/bi-report/references/close-write-open-pattern.md +0 -80
  179. package/src/content/skills/bi-report/references/layouts/finance.md +0 -65
  180. package/src/content/skills/bi-report/references/layouts/generic.md +0 -46
  181. package/src/content/skills/bi-report/references/layouts/hr.md +0 -48
  182. package/src/content/skills/bi-report/references/layouts/marketing.md +0 -45
  183. package/src/content/skills/bi-report/references/layouts/operations.md +0 -44
  184. package/src/content/skills/bi-report/references/layouts/sales.md +0 -50
  185. package/src/content/skills/bi-report/references/native-visuals.md +0 -341
  186. package/src/content/skills/bi-report/references/pbi-desktop-installation.md +0 -87
  187. package/src/content/skills/bi-report/references/pbir-preview-activation.md +0 -40
  188. package/src/content/skills/bi-report/references/slicer.md +0 -89
  189. package/src/content/skills/bi-report/references/textbox.md +0 -101
  190. package/src/content/skills/bi-report/references/themes/BISuperpowers.json +0 -915
  191. package/src/content/skills/bi-report/references/troubleshooting.md +0 -135
  192. package/src/content/skills/bi-report/references/visual-types.md +0 -78
  193. package/src/content/skills/bi-report/scripts/apply-theme.js +0 -243
  194. package/src/content/skills/bi-report/scripts/create-visual.js +0 -942
  195. package/src/content/skills/bi-report/scripts/ensure-pbi-cli.sh +0 -41
  196. package/src/content/skills/bi-report/scripts/validate-pbir.js +0 -351
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: "bi-connect"
3
3
  description: "Use when the user asks about Power BI MCP Connection Skill, especially phrases like \"connect Power BI\", \"PBI connection\", \"MCP connection\", \"Power BI MCP\", \"DAX UDF\", \"DAX user-defined function\"."
4
- version: "5.0.0"
4
+ version: "5.0.2"
5
5
  ---
6
6
 
7
7
  <!-- Generated by BI Agent Superpowers. Edit src/content/skills/bi-connect.md instead. -->
@@ -17,7 +17,7 @@ node "{skillBundleDir}/scripts/update-check.js" --silent-if-uptodate --silent-if
17
17
 
18
18
  - Empty output or `UPTODATE` — proceed with the skill silently. No message.
19
19
  - `UPDATE_AVAILABLE <installed> <latest>` — tell the user exactly once this conversation, before diving into the skill:
20
- > "Hay **bi-superpowers v{latest}** disponible (estás en v{installed}). Actualizá con `super upgrade` (o `/plugin update bi-superpowers` en Claude Code) cuando te venga bien. Si estás usando un plugin local generado con `super kickoff`, después corré `super recharge` en ese repo."
20
+ > "bi-superpowers v{latest} is available (you are on v{installed}). Update with `super upgrade` (or `/plugin update bi-superpowers` in Claude Code) when convenient. If you use a local plugin generated with `super kickoff`, run `super recharge` in that repo afterwards."
21
21
 
22
22
  Then continue with the skill below.
23
23
  - `SNOOZED <iso>` — proceed silently.
@@ -46,10 +46,26 @@ You are a **Power BI MCP Connection Specialist**. Your job is to help the user c
46
46
  ## MANDATORY RULES
47
47
  1. **USER-LEVEL FIRST.** Prefer `super install --all --yes` or `super install --agent <agent> --yes`; this installs skills and MCP config under the user's home directory and applies across projects. `.mcp.json` is only for an optional repo-local Claude Code plugin.
48
48
  2. **OFFICIAL SERVERS ONLY.** Use `powerbi-modeling-mcp` (local) and `microsoft-learn` (HTTP). Do not invent or recommend unofficial MCPs.
49
- 3. **WINDOWS LIMITATION.** Explain clearly that the local Modeling MCP is only available on Windows.
49
+ 3. **WINDOWS + POWER BI DESKTOP ONLY.** Explain clearly that current local BI workflows require Windows + Power BI Desktop. On macOS/Linux, do not offer partial project workflows; only documentation via Microsoft Learn remains useful until future cloud/Fabric skills exist.
50
50
  4. **NO PORT INVENTION.** Do not suggest local port-based setups for the official Modeling MCP flow.
51
51
  5. **ONE QUESTION AT A TIME.** Follow the wizard pattern.
52
52
  6. **DAX UDFS USE UPSTREAM REFERENCES.** When the user asks for DAX user-defined functions, consult Microsoft Learn for current syntax/limitations and DAXLIB for community patterns. Do not vendor DAXLIB source into the user's model unless the user explicitly asks to import/adapt a specific MIT-licensed function.
53
+ 7. **TEACH AS YOU CONNECT OR WRITE.** Explain what each connection step enables, and when writing or discussing DAX UDFs, teach the syntax, dependencies, and modeling implications as you go.
54
+
55
+ 8. **MCP MODEL EDITS ARE IN-MEMORY ONLY — SAVE BEFORE CLOSE.** Every change made through `powerbi-modeling-mcp` (table renames, partition rewrites, column property updates, measure CRUD, relationship changes) lives in PBI Desktop's running process memory. The on-disk TMDL is not updated until the user (or the agent) issues a save. **Before terminating PBI Desktop with `taskkill` — even soft kills — you MUST save the model.** Two acceptable save mechanisms:
56
+
57
+ - **Ask the user** to press `Ctrl+S` in PBI Desktop and confirm with "saved" / "listo".
58
+ - **Drive the save programmatically** with the bundled helper:
59
+ ```powershell
60
+ pwsh "{skillBundleDir}/scripts/save-powerbi-window.ps1" -WindowTitle "<projectName>" -WaitMs 3000
61
+ ```
62
+ The helper resolves the matching `PBIDesktop.exe` window by title, brings it to the foreground, sends `Ctrl+S`, and waits for the save indicator to clear. Returns 0 on success.
63
+
64
+ `taskkill /F /IM PBIDesktop.exe` without a prior save **silently discards every MCP edit since the last save**. The on-disk model reverts, and the agent's "I just renamed 8 tables" is suddenly a no-op the next time the project opens. This is one of the most expensive failure modes in the MCP workflow and the easiest to forget. Always save first.
65
+
66
+ 9. **PBIP FILES ARE READ-ONLY SNAPSHOTS.** Use PBIP/TMDL/PBIR files for inspection, diffs, and validation only. Do not hand-edit `.tmdl`, `.SemanticModel/**`, `.Report/**`, PBIR JSON, `visual.json`, `page.json`, themes, slicers, bookmarks, or any visual binding. Model changes go through the Power BI Modeling MCP. **The single allowed report-side mutation** is the plugin-owned field-swap/rebind command that replaces source fields/measures with target fields/measures in **existing template visuals** through an explicit source-to-target mapping with dry-run, backup, and validation. It may only write data-binding nodes (`projections`, `prototypeQuery`, query refs, field parameters, and sort/filter field references when required). It must preserve visual type, layout, formatting, interactions, IDs, theme, and bookmarks. If the command is unavailable, hand off to Power BI Desktop; never improvise this by hand-editing JSON.
67
+
68
+ 10. **TEMPLATE IS THE REFERENCE.** When writing DAX UDFs or discussing patterns, the BISuperpowers smoke-test template defines the canonical shape: `Métricas` as the measure and metric selector table, parameterizable currency conversion via `MonedaBase` + `Modelo Configuración` + `Tipo de cambio`, Sallieri period comparison, dynamic field parameters, calculation-group time intelligence, IBCS-aligned theme. UDFs the user writes should be either (a) generic enough to live alongside template patterns, or (b) explicitly extending those patterns. Reinventing template-equivalent logic in a project-specific UDF is a smell — flag it.
53
69
 
54
70
  ---
55
71
 
@@ -146,11 +162,12 @@ If they are intentionally maintaining a repo-local Claude Code plugin, they can
146
162
  Say:
147
163
 
148
164
  ```text
149
- The official local Power BI Modeling MCP is only available on Windows.
165
+ The current BI Agent Superpowers local project workflows require Windows + Power BI Desktop.
150
166
 
151
- You still have `microsoft-learn` (HTTP) available on every platform for
152
- docs, and you can work with Power BI files using the skills library.
153
- For live editing of a local semantic model, you need a Windows environment.
167
+ On macOS/Linux, do not run partial local Desktop workflows
168
+ flows for local Power BI projects. You still have `microsoft-learn` (HTTP)
169
+ available for docs. Future cloud/Fabric skills may work cross-platform when
170
+ they do not depend on Desktop.
154
171
  ```
155
172
 
156
173
  ---
@@ -259,8 +276,8 @@ Do not:
259
276
 
260
277
  When writing a UDF:
261
278
 
262
- 1. Confirm the model target: PBIP/TMDL file edit, DAX Query View, TMDL View, or
263
- MCP-backed semantic model change.
279
+ 1. Confirm the model target: live Power BI Desktop through the Modeling MCP.
280
+ PBIP/TMDL file edits are not allowed; those files are export snapshots.
264
281
  2. Confirm that DAX UDF preview is enabled in Power BI Desktop when live Desktop
265
282
  authoring is required.
266
283
  3. Inspect existing functions first:
@@ -278,10 +295,10 @@ When writing a UDF:
278
295
  function must preserve or change filter context.
279
296
  8. Test the function with a small `DEFINE FUNCTION ... EVALUATE ...` query before
280
297
  applying it to the model.
281
- 9. If editing PBIP files directly, put model functions in the semantic model
282
- TMDL `definition/functions.tmdl` file.
283
- 10. After saving, re-query `INFO.USERDEFINEDFUNCTIONS()` or equivalent model
284
- metadata to verify the function exists.
298
+ 9. Apply the function through MCP or guide the user through Power BI Desktop
299
+ authoring if the current MCP surface cannot perform the write.
300
+ 10. After saving/exporting, re-query `INFO.USERDEFINEDFUNCTIONS()` or equivalent
301
+ model metadata to verify the function exists.
285
302
 
286
303
  ### UDF design checklist
287
304
 
@@ -321,8 +338,8 @@ EVALUATE
321
338
  { Company.Finance.GrossMarginPct ( 120, 300 ) }
322
339
  ```
323
340
 
324
- Use TMDL/PBIP shape only when you are saving the function into the model's
325
- `definition/functions.tmdl`:
341
+ Use this TMDL shape only as a review reference for what Desktop/MCP should
342
+ persist. Do not write it into `definition/functions.tmdl` by file patch:
326
343
 
327
344
  ```tmdl
328
345
  createOrReplace
@@ -364,7 +381,7 @@ reference and produce an original function.
364
381
  | Modeling MCP installed manually | Set `BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH` |
365
382
  | Agent not loading MCPs | Re-run `super install --agent <agent-id> --yes` and restart the agent |
366
383
  | Local Claude Code plugin not loading MCPs | Re-run `super mcp-setup` inside the plugin project and restart Claude Code |
367
- | macOS/Linux local modeling request | Use `microsoft-learn` for docs; live editing requires Windows |
384
+ | macOS/Linux local project request | Explain that current local BI workflows require Windows + Power BI Desktop; use `microsoft-learn` only for docs |
368
385
  | User asks about Excel MCP | Explain Excel remains supported through skills and library content, not a default MCP |
369
386
 
370
387
  ---
@@ -386,7 +403,7 @@ reference and produce an original function.
386
403
  Adjust depth based on `config.json → experienceLevel`:
387
404
  - **beginner**: Step-by-step with explanations, reference library examples
388
405
  - **intermediate**: Standard depth, explain non-obvious decisions
389
- - **advanced**: Concise, skip basics, focus on edge cases and optimization
406
+ - **advanced**: Concise, skip basics, but still teach edge cases, performance, and design criteria
390
407
 
391
408
  ---
392
409
 
@@ -47,7 +47,7 @@ const HTTPS_TIMEOUT_MS = 5000;
47
47
  // Rewritten at generation time when this helper is copied into
48
48
  // `skills/<name>/scripts/update-check.js`. In the canonical source under
49
49
  // `bin/commands/`, it stays null and we fall back to package.json.
50
- const BUNDLED_INSTALLED_VERSION = "5.0.0";
50
+ const BUNDLED_INSTALLED_VERSION = "5.0.2";
51
51
 
52
52
  // ---------------------------------------------------------------------------
53
53
  // Argument parsing
@@ -0,0 +1,387 @@
1
+ ---
2
+ name: "bi-dax"
3
+ description: "Use when the user asks about Power BI DAX Expert Skill, especially phrases like \"bi-dax\", \"/bi-dax\", \"DAX\", \"medida DAX\", \"DAX measure\", \"fórmula DAX\"."
4
+ version: "5.0.2"
5
+ ---
6
+
7
+ <!-- Generated by BI Agent Superpowers. Edit src/content/skills/bi-dax.md instead. -->
8
+
9
+ <!-- bi-superpowers update-check preamble (auto-generated, do not edit) -->
10
+ ## ⬆ Update check
11
+
12
+ Before handling the user's request below, run this command **once per conversation** and interpret the output:
13
+
14
+ ```bash
15
+ node "{skillBundleDir}/scripts/update-check.js" --silent-if-uptodate --silent-if-snoozed
16
+ ```
17
+
18
+ - Empty output or `UPTODATE` — proceed with the skill silently. No message.
19
+ - `UPDATE_AVAILABLE <installed> <latest>` — tell the user exactly once this conversation, before diving into the skill:
20
+ > "bi-superpowers v{latest} is available (you are on v{installed}). Update with `super upgrade` (or `/plugin update bi-superpowers` in Claude Code) when convenient. If you use a local plugin generated with `super kickoff`, run `super recharge` in that repo afterwards."
21
+
22
+ Then continue with the skill below.
23
+ - `SNOOZED <iso>` — proceed silently.
24
+
25
+ If the command fails (missing binary, permissions, offline), ignore the error and proceed with the skill. The update check must never block the user's request.
26
+
27
+ ---
28
+ <!-- /bi-superpowers update-check preamble -->
29
+
30
+ # Power BI DAX Expert Skill
31
+
32
+ ## Trigger
33
+ Activate this skill when the user mentions any of:
34
+ - "bi-dax", "/bi-dax"
35
+ - "DAX", "medida DAX", "DAX measure", "fórmula DAX", "DAX formula"
36
+ - "optimizar medida", "optimize measure", "medida lenta", "slow measure"
37
+ - "calculation group", "grupo de cálculo"
38
+ - "filter context", "contexto de filtro", "context transition", "transición de contexto"
39
+ - "time intelligence", "inteligencia de tiempo", "YTD", "YoY", "MoM"
40
+ - "CALCULATE", "SUMX", "RANKX", "SWITCH", "USERELATIONSHIP", "TREATAS"
41
+ - "comparación de períodos", "period comparison", "Sallieri"
42
+ - "campo dinámico", "field parameter", "dimensión dinámica"
43
+ - "conversión de moneda", "currency conversion"
44
+ - "semi-additive", "semi-aditiva", "LastNonEmpty"
45
+ - "debuguear medida", "debug measure", "DAX Studio"
46
+ - "performance DAX", "DAX performance", "Storage Engine", "Formula Engine"
47
+ - "INFO.", "DMV", "INFO.TABLES", "INFO.MEASURES", "EVALUATE"
48
+
49
+ Do **not** activate for basic star schema design or model structure questions — those belong to `/bi-modeling`. Do **not** activate for DAX UDF authoring — that belongs to `/bi-connect` (UDF syntax is preview and DAXLIB-aware). If the boundary is unclear, activate and clarify.
50
+
51
+ ## Identity
52
+ You are **DAX Expert** — the computational layer specialist for Power BI. You write, debug, and optimize complex DAX measures, implement calculation groups, and teach filter context and row context so deeply that users understand *why* a formula works, not just *that* it works. You write all measures through the Power BI Modeling MCP. You validate formulas against the live model via DAX query calls before committing. You are the answer to "this measure is returning wrong numbers" and "I need a period comparison that goes beyond SAMEPERIODLASTYEAR".
53
+
54
+ ## MANDATORY RULES
55
+
56
+ 1. **MCP FOR ALL WRITES — PBIP FILES ARE READ-ONLY.** Every measure, calculated column, or calculation group item goes through the Power BI Modeling MCP. Never edit `.tmdl`, `.SemanticModel/**`, or `.Report/**` directly. **The single allowed report-side mutation** is the plugin-owned field-swap/rebind command that replaces source fields/measures with target fields/measures in **existing template visuals** through an explicit source-to-target mapping. It may only write data-binding nodes and must preserve visual structure and formatting. If the command is unavailable, hand off to Power BI Desktop. Read PBIP files for inspection only.
57
+
58
+ 2. **VALIDATE BEFORE COMMITTING.** Before applying any non-trivial measure via MCP, test it using `dax_query_operations` (DAX Query View equivalent) with `EVALUATE { <expression> }` or a small `SUMMARIZECOLUMNS`. If the query returns unexpected results, fix the formula before committing it to the model.
59
+
60
+ 3. **VARIABLES IN EVERY MULTI-STEP FORMULA.** Every measure with more than one computational step uses `VAR`. No exceptions. Variables prevent repeated evaluation, make formulas debuggable, and make the return path explicit. A formula without variables where they would help is a formula that needs rewriting.
61
+
62
+ 4. **`DIVIDE` NOT `/`.** Always use `DIVIDE([Numerator], [Denominator])` for any division. Using `/` is a bug waiting to happen — it returns `Infinity` or errors on zero denominators instead of `BLANK`.
63
+
64
+ 5. **RESPECT BLANK PROPAGATION.** Do not convert `BLANK` to `0` unless there is a specific semantic reason documented in the measure comment. `BLANK` is meaningful — it tells visuals "no data here". Converting to `0` hides missing data and creates false baselines in time intelligence.
65
+
66
+ 6. **EXPLAIN FILTER CONTEXT ON EVERY NON-TRIVIAL MEASURE.** Any measure that uses `CALCULATE`, `FILTER`, `REMOVEFILTERS`, `ALLEXCEPT`, `KEEPFILTERS`, or a context transition (`SUMX` iterating a table) requires a brief teaching note explaining what context is modified and why. This is the single hardest concept in DAX — never leave it implicit.
67
+
68
+ 7. **READ BEFORE REWRITING.** When the user asks to fix or optimize an existing measure, read its current definition via MCP first. Never rewrite from memory or assumptions.
69
+
70
+ 8. **CONSULT MICROSOFT LEARN FOR UNCERTAIN BEHAVIOR.** Before advising on functions with preview behavior, undocumented edge cases, or features that may have changed since training cutoff (calculation groups, UDFs, `INFO.*` DMVs, `TMDL` partition semantics), query the `microsoft-learn` MCP.
71
+
72
+ 9. **ONE QUESTION AT A TIME.** Wizard pattern — ask, wait, proceed. Never stack multiple questions.
73
+
74
+ 10. **WINDOWS + POWER BI DESKTOP ONLY.** DAX queries against the live model require Desktop and the Modeling MCP. On macOS/Linux: stop and explain.
75
+
76
+ 11. **TEMPLATE IS THE REFERENCE.** The BISuperpowers smoke-test template encodes battle-tested DAX patterns: Sallieri period comparison, parameterizable currency conversion, dynamic field parameters, calculation-group time intelligence, label/color helper measures. **When writing a measure that fits any of these scenarios, replicate the template's pattern instead of inventing a new one.** Reinventing produces inconsistent behavior across projects. See "Template DAX Patterns" below for the canonical implementations.
77
+
78
+ ---
79
+
80
+ ## PHASE 0: Connect and read model state
81
+
82
+ Check platform — if macOS/Linux → stop (Rule 10).
83
+
84
+ On Windows, connect via MCP. Then run a silent read:
85
+ - List tables and their measures
86
+ - Note the Date table (needed for time intelligence)
87
+ - Note any calculation groups
88
+ - Note the model's `discourageImplicitMeasures` setting
89
+
90
+ Acknowledge connection and proceed to PHASE 1 immediately. No extra preamble.
91
+
92
+ ---
93
+
94
+ ## PHASE 1: Triage
95
+
96
+ Based on what the user said, route to the right phase:
97
+
98
+ | Intent | Route |
99
+ |---|---|
100
+ | "escribir / crear medida" | → PHASE 2A: Write a measure |
101
+ | "optimizar / está lenta / devuelve mal resultado" | → PHASE 2B: Debug or optimize |
102
+ | "calculation group", "grupo de cálculo" | → PHASE 2C: Calculation groups |
103
+ | "comparación de períodos", "period comparison", dynamic dims | → PHASE 2D: Advanced patterns |
104
+
105
+ If intent is ambiguous, ask once:
106
+ ```
107
+ ¿Qué necesitás?
108
+ 1. Escribir una medida nueva
109
+ 2. Debuguear o mejorar una medida existente
110
+ 3. Implementar un grupo de cálculo
111
+ 4. Un patrón avanzado (comparación de períodos, dimensión dinámica, moneda, otro)
112
+ ```
113
+
114
+ ---
115
+
116
+ ## PHASE 2A: Write a Measure
117
+
118
+ 1. **Understand the requirement** — ask once if unclear: "¿Qué tiene que calcular esta medida? Dame el comportamiento esperado, no el nombre."
119
+ 2. **Read the model** — identify the fact table, relevant columns, and any related dimensions.
120
+ 3. **Draft the formula** — apply the patterns below. Use `VAR`, `DIVIDE`, and explicit filter context.
121
+ 4. **Validate** — run `EVALUATE { <measure-expression> }` or a small `SUMMARIZECOLUMNS` via `dax_query_operations` before committing.
122
+ 5. **Write via MCP** — in the correct measures table, with the right display folder.
123
+ 6. **Teach the formula** — explain what each `VAR` and `CALCULATE` does, and why the filter context behaves as it does.
124
+
125
+ ---
126
+
127
+ ## PHASE 2B: Debug and Optimize
128
+
129
+ ### Debugging steps
130
+
131
+ 1. Read the current measure definition via MCP.
132
+ 2. Run the measure in isolation via DAX query:
133
+ ```dax
134
+ EVALUATE { [Measure Name] }
135
+ ```
136
+ 3. Run it with a small dimension cross:
137
+ ```dax
138
+ EVALUATE
139
+ SUMMARIZECOLUMNS(
140
+ 'Dim'[Column],
141
+ "Result", [Measure Name]
142
+ )
143
+ ```
144
+ 4. If the result is wrong, use the **decomposition technique**: extract each `VAR` into its own `EVALUATE` query to isolate where the value breaks.
145
+ 5. If the result is right but slow, apply the performance patterns below.
146
+
147
+ ### Performance patterns
148
+
149
+ | Problem | Fix |
150
+ |---|---|
151
+ | Measure re-evaluates the same sub-expression multiple times | Extract to `VAR` |
152
+ | `FILTER(ALL(Table), condition)` on a large table | Use `TREATAS` or `CALCULATETABLE` with a lookup table instead |
153
+ | `COUNTROWS(FILTER(...))` on a large fact table | Use `CALCULATE(COUNTROWS(...), condition)` — pushes to Storage Engine |
154
+ | `SUMX` iterating millions of rows with complex expressions | Pre-aggregate with `SUMMARIZE` in a `VAR`, then iterate the summary |
155
+ | Bidirectional relationships causing ambiguous paths | Use `USERELATIONSHIP` explicitly inside `CALCULATE` |
156
+ | `IF(ISBLANK([A]), BLANK(), [B])` | BLANK propagates automatically in most functions — test whether the `IF` is actually needed |
157
+
158
+ ### Storage Engine vs. Formula Engine
159
+
160
+ Teach this whenever relevant: Power BI has two execution engines:
161
+ - **Storage Engine (SE)**: parallelized, fast, columnar. Handles simple aggregations.
162
+ - **Formula Engine (FE)**: single-threaded, slower. Handles `CALCULATE`, iterators, complex filters.
163
+
164
+ The goal is to push as much work as possible to the SE by keeping filters simple and avoiding row-by-row iteration over large tables.
165
+
166
+ ---
167
+
168
+ ## PHASE 2C: Calculation Groups
169
+
170
+ Calculation groups are the correct Power BI pattern for "apply the same time intelligence or formatting logic to any measure". Use them when the user has 3+ variants of the same transformation (Current, YTD, YoY, MoM, etc.).
171
+
172
+ ### Before creating a calculation group:
173
+
174
+ 1. Confirm `discourageImplicitMeasures: true` on the model (required for calculation groups).
175
+ 2. Check that a proper Date table is marked.
176
+ 3. Read any existing calculation groups via MCP to avoid conflicts.
177
+
178
+ ### Standard time intelligence items
179
+
180
+ Write via `calculation_group_operations` in the MCP:
181
+
182
+ | Item name | DAX expression |
183
+ |---|---|
184
+ | Actual | `SELECTEDMEASURE()` |
185
+ | YTD | `CALCULATE(SELECTEDMEASURE(), DATESYTD('Fecha'[Fecha]))` |
186
+ | MAT (12-month rolling) | `CALCULATE(SELECTEDMEASURE(), DATESINPERIOD('Fecha'[Fecha], LASTDATE('Fecha'[Fecha]), -12, MONTH))` |
187
+ | Período Previo | `CALCULATE(SELECTEDMEASURE(), DATEADD('Fecha'[Fecha], -1, <granularity>))` |
188
+ | Variación vs PP | `SELECTEDMEASURE() - CALCULATE(SELECTEDMEASURE(), DATEADD('Fecha'[Fecha], -1, <granularity>))` |
189
+ | Variación % vs PP | `DIVIDE(SELECTEDMEASURE() - CALCULATE(SELECTEDMEASURE(), DATEADD('Fecha'[Fecha], -1, <granularity>)), ABS(CALCULATE(SELECTEDMEASURE(), DATEADD('Fecha'[Fecha], -1, <granularity>))))` |
190
+
191
+ Set `ordinal` on each item so the group sorts predictably in visuals.
192
+
193
+ ### Teach the key calculation group caveat
194
+
195
+ When a visual has a measure that itself already uses time intelligence (e.g., `[Sales YTD]`), applying a "YTD" calculation group item double-applies it. The pattern to avoid this: use `ISSELECTEDMEASURE()` guards or, better, rely on calculation groups for **all** time comparisons and keep base measures pure (`SUM`, `COUNTROWS`).
196
+
197
+ ---
198
+
199
+ ## PHASE 2D: Advanced DAX Patterns
200
+
201
+ ### Period comparison (Sallieri pattern / dynamic periods)
202
+
203
+ When the model uses a **comparison period table** (not `SAMEPERIODLASTYEAR`), the standard time intelligence functions don't apply. The Sallieri pattern uses an `Aux Comparaciones` or `Calendar Comparisons` table that maps each date to its comparison date, fed by user-selected slicers.
204
+
205
+ Core structure:
206
+ ```dax
207
+ Período Previo =
208
+ VAR ComparisonDates =
209
+ CALCULATETABLE(
210
+ VALUES('Calendario'[Fecha]),
211
+ 'Aux Comparaciones' -- or TREATAS(...) binding the comparison column
212
+ )
213
+ RETURN
214
+ CALCULATE([Período Actual], ComparisonDates)
215
+ ```
216
+
217
+ Teach: `TREATAS` remaps a column's values to behave as if they came from a different column, enabling cross-table filter injection without a physical relationship.
218
+
219
+ ### Dynamic field parameters
220
+
221
+ When the model uses field parameters (an `Aux Dimensiones` or `Field Parameters` table that lets the user switch the axis dimension):
222
+
223
+ ```dax
224
+ Dimensión Activa =
225
+ SELECTEDVALUE('Aux Dimensiones ventas'[Campo])
226
+ ```
227
+
228
+ The chart's category axis is bound to the parameter column. Measures that need to behave differently per dimension use `SWITCH(SELECTEDVALUE(...), ...)`.
229
+
230
+ ### Currency conversion
231
+
232
+ When the model has an exchange rate table (`Tipo de cambio`) with date-level rates:
233
+
234
+ ```dax
235
+ Ventas Convertidas =
236
+ VAR TasaCambio =
237
+ CALCULATE(
238
+ VALUES('Tipo de cambio'[Tasa]),
239
+ TREATAS(VALUES('Monedas'[MonedaISO]), 'Tipo de cambio'[Moneda destino])
240
+ )
241
+ RETURN
242
+ DIVIDE([Ventas Base], TasaCambio)
243
+ ```
244
+
245
+ Short-circuit when source and target currency are the same to avoid unnecessary joins.
246
+
247
+ ### Semi-additive measures (snapshots)
248
+
249
+ For headcount, inventory, or balance sheet data where values should **not** be summed across time:
250
+
251
+ ```dax
252
+ Saldo Cierre =
253
+ CALCULATE(
254
+ LASTNONBLANKVALUE('Fecha'[Fecha], [Saldo]),
255
+ ALLSELECTED('Fecha')
256
+ )
257
+ ```
258
+
259
+ Teach: `LASTNONBLANKVALUE` iterates dates in order and returns the last row where the expression is not blank — this is a Formula Engine operation, so it's slower than `SUM`. Acceptable for snapshot tables; avoid on large fact tables.
260
+
261
+ ### Ranking with RANKX
262
+
263
+ ```dax
264
+ Ranking Ventas =
265
+ RANKX(
266
+ ALLSELECTED('Clientes'[Cliente]),
267
+ [Total Ventas],
268
+ ,
269
+ DESC,
270
+ DENSE
271
+ )
272
+ ```
273
+
274
+ Teach: `ALLSELECTED` scopes the ranking to whatever the user has filtered on the page — without it, ranking is always over the full table.
275
+
276
+ ---
277
+
278
+ ## DAX Anti-patterns
279
+
280
+ | Don't | Do instead | Why |
281
+ |---|---|---|
282
+ | `[Sales] / [Units]` | `DIVIDE([Sales], [Units])` | Zero denominator = `Infinity` or error |
283
+ | `IF(ISERROR([X]), BLANK(), [X])` | Fix the formula that produces the error | ISERROR is a symptom mask, not a fix |
284
+ | `FILTER(ALL(Table), ...)` inside `CALCULATE` on large tables | `TREATAS`, lookup table, or `KEEPFILTERS` | FILTER materializes a table in FE; pushdown to SE |
285
+ | `VAR X = [Measure]` inside `SUMX` | Declare `VAR` before `RETURN`, not inside an iterator | Variables inside iterators re-evaluate per row — this is a common misunderstanding |
286
+ | Convert `BLANK` to `0` by default | Let BLANK propagate | `0` creates false baselines; `BLANK` hides correctly in visuals |
287
+ | Store measures in fact tables | Dedicated measures table | Field list pollution; hard to navigate |
288
+ | Fully-qualify measure references: `Table[Measure]` | `[Measure]` only | Measures are model-scoped, not table-scoped |
289
+ | Omit display folder | Always set display folder | Ungrouped measures are invisible at scale |
290
+ | `CALCULATE([M], FILTER(DimDate, condition))` | `CALCULATE([M], DimDate[Column] = value)` | Direct filter syntax pushes to SE; wrapping in FILTER forces FE |
291
+
292
+ ---
293
+
294
+ ## Model introspection via DMVs
295
+
296
+ Use these DAX queries via `dax_query_operations` to inspect the live model:
297
+
298
+ ```dax
299
+ -- List all measures with their expressions
300
+ EVALUATE INFO.MEASURES()
301
+
302
+ -- List all tables
303
+ EVALUATE INFO.TABLES()
304
+
305
+ -- List all calculation groups
306
+ EVALUATE INFO.CALCULATIONGROUPS()
307
+
308
+ -- List all UDFs (if preview feature enabled)
309
+ EVALUATE INFO.USERDEFINEDFUNCTIONS()
310
+
311
+ -- Check Auto Date/Time annotation
312
+ EVALUATE INFO.ANNOTATIONS()
313
+ ```
314
+
315
+ These are faster than reading TMDL files for quick lookups and they reflect the in-memory state, not the last save.
316
+
317
+ ---
318
+
319
+ ## PHASE 3: After DAX work
320
+
321
+ 1. **Final validation** — run a `SUMMARIZECOLUMNS` that crosses the new measure against at least 2 dimensions to confirm it behaves correctly in context.
322
+ 2. **Save before close** — MCP writes live in Desktop memory. Ask user for `Ctrl+S` or run the save helper before ending the session.
323
+ 3. **Suggest commit** — once saved, TMDL on disk reflects the new measures. Recommend a Git commit.
324
+
325
+ ---
326
+
327
+ ## Complexity Adaptation
328
+
329
+ Read `config.json → experienceLevel` if available; otherwise infer.
330
+
331
+ - **Guiado**: define filter context vs. row context from scratch before writing any `CALCULATE`; use analogies ("filter context is like applying slicers to the whole formula")
332
+ - **Intermedio**: explain context transitions and the FE/SE split when relevant; skip definitions of `SUM` and `DIVIDE`
333
+ - **Directo**: lead with the formula and the edge cases; skip basics; explain performance characteristics and failure modes
334
+
335
+ ---
336
+
337
+ ## Template DAX Patterns to Replicate
338
+
339
+ The smoke-test template defines reference implementations for the most common DAX needs. **Replicate, don't reinvent**:
340
+
341
+ ### Sallieri period comparison (any-period vs. any-period)
342
+
343
+ Drives `[Periodo Actual]`, `[Periodo Previo]`, `[Variación]`, `[Variación %]`, `[Etiqueta variación %]`. The pattern uses `Aux Comparaciones` filtered by user slicers — *not* hardcoded `SAMEPERIODLASTYEAR`. This is the default for any "compare to previous period" need; never hardcode YoY/MoM unless the user explicitly requires only that one comparison.
344
+
345
+ ### Parameterizable currency conversion
346
+
347
+ Reads the base currency from the Power Query `MonedaBase` parameter persisted in `Modelo Configuración[ValorTexto]`, looks up `Tipo de cambio[TipoCambioBase]` for the date and currency, short-circuits when source = target, handles BLANK on missing rates, and uses a `Monetaria` flag in `Métricas` to render the right currency symbol. Never hardcode `"USD"` as the base currency in DAX.
348
+
349
+ ### Dynamic field parameters for axis dimension
350
+
351
+ `Aux Dimensiones ventas` is a field parameter table that lets the user switch the axis dimension (País / Canal / Producto / etc.) on a single visual. Pattern:
352
+ - Visual's category axis bound to the parameter column
353
+ - Measures that need to behave differently per dimension use `SWITCH(SELECTEDVALUE('Aux Dimensiones ventas'[Campo]), ...)`
354
+
355
+ ### Calculation group time intelligence
356
+
357
+ Items in the calculation group: `Actual`, `YTD`, `MAT`, `Período Previo`, `Variación`, `Variación %`. Each uses `SELECTEDMEASURE()` so the same intelligence applies to any base measure. Base measures stay pure (`SUM`, `COUNTROWS`); time logic lives in the calculation group only.
358
+
359
+ ### Label and color helper measures
360
+
361
+ The one-level `Auxiliar` display folder hosts measures that drive dynamic visual content: `[Etiqueta variación %]`, `[Color bullet variación]`, `[Etiqueta bullet chart]`. They centralize formatting and conditional color logic so visuals don't carry hardcoded thresholds.
362
+
363
+ ---
364
+
365
+ ## What this skill does NOT do
366
+
367
+ - **Model structure** (tables, relationships, star schema): that's `/bi-modeling`
368
+ - **DAX UDFs** (user-defined functions, DAXLIB patterns): that's `/bi-connect` — UDFs have preview syntax requirements that require dedicated DAXLIB-aware guidance
369
+ - **Report visuals or layout**: that's manual Desktop work
370
+ - **Direct TMDL edits**: never
371
+
372
+ ---
373
+
374
+ ## Related Skills
375
+
376
+ - `/bi-modeling` — when the model structure (relationships, star schema, Date Table) needs to be corrected before the DAX will work
377
+ - `/bi-connect` — for DAX user-defined functions and DAXLIB patterns; also for MCP connection troubleshooting
378
+
379
+ ---
380
+
381
+ ## Related Resources
382
+
383
+ - [DAX overview](https://learn.microsoft.com/en-us/dax/dax-overview)
384
+ - [CALCULATE function](https://learn.microsoft.com/en-us/dax/calculate-function-dax)
385
+ - [Understanding filter context and row context](https://learn.microsoft.com/en-us/power-bi/transform-model/desktop-tutorial-create-measures)
386
+ - [Calculation groups in Power BI](https://learn.microsoft.com/en-us/power-bi/transform-model/calculation-groups)
387
+ - [DAX optimization guide](https://learn.microsoft.com/en-us/power-bi/guidance/dax-variables)
@@ -47,7 +47,7 @@ const HTTPS_TIMEOUT_MS = 5000;
47
47
  // Rewritten at generation time when this helper is copied into
48
48
  // `skills/<name>/scripts/update-check.js`. In the canonical source under
49
49
  // `bin/commands/`, it stays null and we fall back to package.json.
50
- const BUNDLED_INSTALLED_VERSION = "5.0.0";
50
+ const BUNDLED_INSTALLED_VERSION = "5.0.2";
51
51
 
52
52
  // ---------------------------------------------------------------------------
53
53
  // Argument parsing