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.
- package/.claude-plugin/marketplace.json +31 -0
- package/.claude-plugin/plugin.json +34 -0
- package/.claude-plugin/skill-manifest.json +79 -0
- package/.mcp.json +13 -0
- package/.plugin/plugin.json +14 -0
- package/LICENSE +21 -0
- package/README.md +849 -0
- package/bin/build-plugin.js +97 -0
- package/bin/cli.js +891 -0
- package/bin/commands/autoupdate.js +128 -0
- package/bin/commands/build-desktop.js +368 -0
- package/bin/commands/create-from-template.js +165 -0
- package/bin/commands/diff.js +435 -0
- package/bin/commands/install.js +542 -0
- package/bin/commands/lint.js +441 -0
- package/bin/commands/mcp-setup.js +255 -0
- package/bin/commands/session-update.js +204 -0
- package/bin/commands/smoke-test.js +20 -0
- package/bin/commands/uninstall.js +611 -0
- package/bin/commands/update-check.js +427 -0
- package/bin/commands/validate-cases.js +264 -0
- package/bin/commands/validate-projects.js +426 -0
- package/bin/commands/watch.js +251 -0
- package/bin/lib/agents.js +62 -0
- package/bin/lib/base-template-smoke.js +299 -0
- package/bin/lib/claude-hooks.js +160 -0
- package/bin/lib/generators/claude-plugin.js +529 -0
- package/bin/lib/generators/index.js +116 -0
- package/bin/lib/generators/shared.js +257 -0
- package/bin/lib/mcp-config.js +835 -0
- package/bin/lib/microsoft-mcp.js +206 -0
- package/bin/lib/powerbi-mcp-session.js +140 -0
- package/bin/lib/skills.js +164 -0
- package/bin/lib/template-scaffold.js +366 -0
- package/bin/mcp/powerbi-modeling-launcher.js +42 -0
- package/bin/postinstall.js +50 -0
- package/bin/utils/mcp-detect.js +346 -0
- package/bin/utils/tui.js +314 -0
- package/commands/bi-connect.md +520 -0
- package/commands/bi-dax.md +464 -0
- package/commands/bi-kickoff.md +550 -0
- package/commands/bi-modeling.md +485 -0
- package/commands/bi-performance.md +521 -0
- package/commands/bi-powerquery.md +229 -0
- package/commands/bi-refactor.md +249 -0
- package/commands/bi-scorecard.md +268 -0
- package/commands/bi-start.md +272 -0
- package/config.example.json +23 -0
- package/config.json +23 -0
- package/desktop-extension/manifest.json +30 -0
- package/desktop-extension/package.json +10 -0
- package/desktop-extension/server.js +137 -0
- package/package.json +94 -0
- package/skills/bi-connect/SKILL.md +522 -0
- package/skills/bi-connect/scripts/update-check.js +427 -0
- package/skills/bi-dax/SKILL.md +466 -0
- package/skills/bi-dax/scripts/update-check.js +427 -0
- package/skills/bi-kickoff/SKILL.md +552 -0
- package/skills/bi-kickoff/references/flow.html +78 -0
- package/skills/bi-kickoff/references/flow.md +62 -0
- package/skills/bi-kickoff/scripts/update-check.js +427 -0
- package/skills/bi-modeling/SKILL.md +487 -0
- package/skills/bi-modeling/scripts/update-check.js +427 -0
- package/skills/bi-performance/SKILL.md +523 -0
- package/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
- package/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
- package/skills/bi-performance/scripts/update-check.js +427 -0
- package/skills/bi-powerquery/SKILL.md +231 -0
- package/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
- package/skills/bi-powerquery/references/power-query-standards.md +74 -0
- package/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
- package/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
- package/skills/bi-powerquery/scripts/update-check.js +427 -0
- package/skills/bi-refactor/SKILL.md +251 -0
- package/skills/bi-refactor/references/flow.md +27 -0
- package/skills/bi-refactor/scripts/update-check.js +427 -0
- package/skills/bi-scorecard/SKILL.md +270 -0
- package/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
- package/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
- package/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
- package/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
- package/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
- package/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
- package/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
- package/skills/bi-scorecard/scripts/update-check.js +427 -0
- package/skills/bi-start/SKILL.md +274 -0
- package/skills/bi-start/scripts/update-check.js +427 -0
- package/src/content/base.md +197 -0
- package/src/content/mcp-requirements.json +57 -0
- package/src/content/routing.md +201 -0
- package/src/content/skills/bi-connect.md +493 -0
- package/src/content/skills/bi-dax.md +437 -0
- package/src/content/skills/bi-kickoff/SKILL.md +523 -0
- package/src/content/skills/bi-kickoff/references/flow.html +78 -0
- package/src/content/skills/bi-kickoff/references/flow.md +62 -0
- package/src/content/skills/bi-modeling.md +458 -0
- package/src/content/skills/bi-performance/SKILL.md +494 -0
- package/src/content/skills/bi-performance/scripts/install-tabular-editor.ps1 +159 -0
- package/src/content/skills/bi-performance/scripts/run-bpa.ps1 +265 -0
- package/src/content/skills/bi-powerquery/SKILL.md +202 -0
- package/src/content/skills/bi-powerquery/references/base-template-data-contract.md +323 -0
- package/src/content/skills/bi-powerquery/references/power-query-standards.md +74 -0
- package/src/content/skills/bi-powerquery/scripts/new-powerquery-staging.ps1 +371 -0
- package/src/content/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +225 -0
- package/src/content/skills/bi-refactor/SKILL.md +222 -0
- package/src/content/skills/bi-refactor/references/flow.md +27 -0
- package/src/content/skills/bi-scorecard/SKILL.md +241 -0
- package/src/content/skills/bi-scorecard/examples/base-template-scorecard-blueprint.expected.json +105 -0
- package/src/content/skills/bi-scorecard/examples/base-template-scorecard-overlay.json +82 -0
- package/src/content/skills/bi-scorecard/scripts/new-scorecard-blueprint-from-base-template.ps1 +124 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goal-status-rules-api.ps1 +39 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goal-values-api.ps1 +48 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-goals-api.ps1 +68 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-rest-common.ps1 +197 -0
- package/src/content/skills/bi-scorecard/scripts/powerbi-scorecards-api.ps1 +53 -0
- package/src/content/skills/bi-start.md +266 -0
- package/templates/base-template/AGENTS.md +33 -0
- package/templates/base-template/base-template.Report/.platform +11 -0
- package/templates/base-template/base-template.Report/StaticResources/RegisteredResources/BISuperpowers.json +3888 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/CY18SU07.json +177 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/Fluent2-CY26SU03.json +4104 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleCityPark.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleDefault.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleNeutral.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleOrchid.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleTidal.json +26 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Bloom.json +139 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CityPark.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Classroom.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/ColorblindSafe.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CopilotDefault.json +1861 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Divergent.json +127 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Electric.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Frontier.json +136 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/HighContrast.json +40 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Highrise.json +41 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Innovate.json +227 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/NewExecutive.json +41 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Solar.json +33 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Storm.json +25 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Sunset.json +48 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Temperature.json +33 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Tidal.json +100 -0
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Twilight.json +40 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/1d40d43c7ade66e8603c.bookmark.json +2297 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/af068ff51c0ca3089ea7.bookmark.json +2300 -0
- package/templates/base-template/base-template.Report/definition/bookmarks/bookmarks.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/page.json +130 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/visual.json +669 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/visual.json +723 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/visual.json +333 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/visual.json +109 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/mobile.json +31 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/visual.json +378 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/visual.json +175 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/visual.json +359 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/visual.json +690 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/90677f13cea5d1275990/visual.json +17 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/mobile.json +10 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/visual.json +328 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/visual.json +578 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/visual.json +432 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/visual.json +801 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/mobile.json +37 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/visual.json +1318 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b529688fe5a226643322/visual.json +209 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/visual.json +174 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/mobile.json +29 -0
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/visual.json +241 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/page.json +130 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/visual.json +690 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/visual.json +359 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/visual.json +669 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/visual.json +109 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/31c21f8cbeb3b208940a/visual.json +209 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/3ab72c25062437149b03/visual.json +17 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/visual.json +788 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/visual.json +592 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/visual.json +468 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/visual.json +1310 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/visual.json +175 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/visual.json +516 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d1e86f213a3841d12e20/visual.json +328 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/visual.json +432 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/visual.json +241 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/visual.json +174 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/mobile.json +11 -0
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/visual.json +333 -0
- package/templates/base-template/base-template.Report/definition/pages/pages.json +8 -0
- package/templates/base-template/base-template.Report/definition/report.json +89 -0
- package/templates/base-template/base-template.Report/definition/version.json +4 -0
- package/templates/base-template/base-template.Report/definition.pbir +9 -0
- package/templates/base-template/base-template.SemanticModel/.platform +11 -0
- package/templates/base-template/base-template.SemanticModel/definition/cultures/es-AR.tmdl +11185 -0
- package/templates/base-template/base-template.SemanticModel/definition/database.tmdl +3 -0
- package/templates/base-template/base-template.SemanticModel/definition/expressions.tmdl +234 -0
- package/templates/base-template/base-template.SemanticModel/definition/functions.tmdl +637 -0
- package/templates/base-template/base-template.SemanticModel/definition/model.tmdl +82 -0
- package/templates/base-template/base-template.SemanticModel/definition/relationships.tmdl +271 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Calendario.tmdl +200 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Campa/303/261as.tmdl +75 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Canales.tmdl +84 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Clientes.tmdl +143 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Devoluciones.tmdl +95 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ejecuci/303/263n proyectos.tmdl" +130 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Entregas.tmdl +122 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos m/303/251tricas.tmdl" +40 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos.tmdl +73 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Horas.tmdl +122 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Interacciones clientes.tmdl +146 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Leads.tmdl +119 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Monedas.tmdl +44 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Movimientos financieros.tmdl +145 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/M/303/251tricas.tmdl +1294 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/N/303/263mina.tmdl +110 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Oportunidades.tmdl +135 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Presupuesto.tmdl +125 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Productos.tmdl +98 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Proyectos.tmdl +77 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Servicios.tmdl +75 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tareas proyecto.tmdl +102 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tipo de cambio.tmdl +67 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ventas.tmdl +180 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux An/303/241lisis dimensiones.tmdl" +38 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Comparaciones.tmdl +227 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Compatibilidad m/303/251trica-dimensi/303/263n.tmdl" +68 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modelo configuraci/303/263n.tmdl" +44 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modo fechas.tmdl +36 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux M/303/251trica-Equipo.tmdl" +102 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Overrides m/303/251trica-dimensi/303/263n.tmdl" +54 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Per/303/255odos.tmdl" +182 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas modo.tmdl +36 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas.tmdl +27 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Vista de calendario.tmdl +30 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC C/303/241lculo.tmdl" +70 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Eje X.tmdl +63 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC M/303/251trica.tmdl" +374 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Tipo c/303/241lculo.tmdl" +223 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Dimensi/303/263n.tmdl" +98 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Eje X.tmdl +68 -0
- package/templates/base-template/base-template.SemanticModel/definition/tables//303/223rdenes servicio.tmdl" +151 -0
- package/templates/base-template/base-template.SemanticModel/definition.pbism +5 -0
- package/templates/base-template/base-template.SemanticModel/diagramLayout.json +568 -0
- package/templates/base-template/base-template.pbip +14 -0
- package/templates/base-template/template.manifest.json +41 -0
- package/theme/BISuperpowers.json +3888 -0
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* update-check — cross-agent version-check helper for bi-superpowers.
|
|
4
|
+
*
|
|
5
|
+
* The SKILL.md preamble (see lib/generators/claude-plugin.js) invokes this
|
|
6
|
+
* script at the start of every skill so the agent can surface an update
|
|
7
|
+
* notice to the user when a newer version is on npm — without hitting the
|
|
8
|
+
* network on every invocation. Cache TTL is 24h; repeated calls inside
|
|
9
|
+
* that window are served from `~/.bi-superpowers/update-state.json`.
|
|
10
|
+
*
|
|
11
|
+
* Output (stdout, one line):
|
|
12
|
+
* UPTODATE when installed >= latest
|
|
13
|
+
* UPDATE_AVAILABLE <installed> <latest> when installed < latest
|
|
14
|
+
* SNOOZED <iso> when user deferred the notice
|
|
15
|
+
*
|
|
16
|
+
* Flags:
|
|
17
|
+
* --force bypass cache (re-fetch npm, ignore snooze TTL)
|
|
18
|
+
* --silent-if-uptodate suppress UPTODATE line (used by the preamble)
|
|
19
|
+
* --silent-if-snoozed suppress SNOOZED line (used by the preamble)
|
|
20
|
+
* --json emit JSON instead of text
|
|
21
|
+
* --snooze 24h|48h|7d|clear set (or clear) the snooze state and exit
|
|
22
|
+
* --reset delete the state file and exit (used post-upgrade)
|
|
23
|
+
* --state-dir <path> override ~/.bi-superpowers/ (for tests)
|
|
24
|
+
* --package-name <name> override the package name (for tests)
|
|
25
|
+
* -h, --help show this help
|
|
26
|
+
*
|
|
27
|
+
* Exit code is always 0 when the script itself ran — errors during the
|
|
28
|
+
* network fetch degrade to "no output" so the caller never blocks. A
|
|
29
|
+
* non-zero exit means a user error (bad flags).
|
|
30
|
+
*
|
|
31
|
+
* Pure helpers (compareVersions, isCacheFresh, isSnoozed,
|
|
32
|
+
* computeNextSnoozeUntil, readState, writeState, fetchLatestVersion) are
|
|
33
|
+
* exported so unit tests can exercise them without spawning child
|
|
34
|
+
* processes or hitting the network.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
'use strict';
|
|
38
|
+
|
|
39
|
+
const fs = require('fs');
|
|
40
|
+
const os = require('os');
|
|
41
|
+
const path = require('path');
|
|
42
|
+
const https = require('https');
|
|
43
|
+
|
|
44
|
+
const PACKAGE_NAME = 'bi-superpowers';
|
|
45
|
+
const CACHE_TTL_MS = 1000 * 60 * 60 * 24; // 24 hours
|
|
46
|
+
const HTTPS_TIMEOUT_MS = 5000;
|
|
47
|
+
// Rewritten at generation time when this helper is copied into
|
|
48
|
+
// `skills/<name>/scripts/update-check.js`. In the canonical source under
|
|
49
|
+
// `bin/commands/`, it stays null and we fall back to package.json.
|
|
50
|
+
const BUNDLED_INSTALLED_VERSION = "1.0.0";
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Argument parsing
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
function parseArgs(argv) {
|
|
57
|
+
const out = {
|
|
58
|
+
force: false,
|
|
59
|
+
silentIfUptodate: false,
|
|
60
|
+
silentIfSnoozed: false,
|
|
61
|
+
json: false,
|
|
62
|
+
snooze: null,
|
|
63
|
+
reset: false,
|
|
64
|
+
help: false,
|
|
65
|
+
stateDir: null,
|
|
66
|
+
packageName: null,
|
|
67
|
+
installedVersion: null,
|
|
68
|
+
};
|
|
69
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
70
|
+
const a = argv[i];
|
|
71
|
+
if (a === '--force') out.force = true;
|
|
72
|
+
else if (a === '--silent-if-uptodate') out.silentIfUptodate = true;
|
|
73
|
+
else if (a === '--silent-if-snoozed') out.silentIfSnoozed = true;
|
|
74
|
+
else if (a === '--json') out.json = true;
|
|
75
|
+
else if (a === '--snooze') {
|
|
76
|
+
out.snooze = argv[++i];
|
|
77
|
+
if (out.snooze === undefined) {
|
|
78
|
+
process.stderr.write(
|
|
79
|
+
'update-check: --snooze requires a value (e.g. 24h, 48h, 7d, auto, clear)\n'
|
|
80
|
+
);
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
83
|
+
} else if (a === '--reset') out.reset = true;
|
|
84
|
+
else if (a === '--state-dir') out.stateDir = argv[++i];
|
|
85
|
+
else if (a === '--package-name') out.packageName = argv[++i];
|
|
86
|
+
else if (a === '--installed-version') out.installedVersion = argv[++i];
|
|
87
|
+
else if (a === '-h' || a === '--help') out.help = true;
|
|
88
|
+
else {
|
|
89
|
+
process.stderr.write(`update-check: unknown flag: ${a}\n`);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function help() {
|
|
97
|
+
process.stdout.write(
|
|
98
|
+
[
|
|
99
|
+
'Usage: update-check [options]',
|
|
100
|
+
'',
|
|
101
|
+
'Prints one of: UPTODATE, UPDATE_AVAILABLE <installed> <latest>, SNOOZED <iso>.',
|
|
102
|
+
'',
|
|
103
|
+
'Options:',
|
|
104
|
+
' --force Bypass cache and snooze TTL',
|
|
105
|
+
' --silent-if-uptodate Skip the UPTODATE line',
|
|
106
|
+
' --silent-if-snoozed Skip the SNOOZED line',
|
|
107
|
+
' --json Emit JSON',
|
|
108
|
+
' --snooze <dur> Set snooze state (24h|48h|7d) or "clear" to reset snooze',
|
|
109
|
+
' --reset Delete the state file (used after a successful upgrade)',
|
|
110
|
+
' --state-dir <path> Override ~/.bi-superpowers/ (tests)',
|
|
111
|
+
' --package-name <name> Override the package name (tests)',
|
|
112
|
+
' --installed-version <v> Override the installed version (generated skill bundles)',
|
|
113
|
+
' -h, --help Show this help',
|
|
114
|
+
'',
|
|
115
|
+
].join('\n')
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
// Version comparison (semver-ish: MAJOR.MINOR.PATCH with optional -prerelease)
|
|
121
|
+
// No deps; handles the shapes bi-superpowers uses today.
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Compare two semver strings.
|
|
126
|
+
* Returns -1 if a < b, 0 if equal, 1 if a > b.
|
|
127
|
+
* Pre-release tags (`-alpha.1`) sort before the release per semver.
|
|
128
|
+
*/
|
|
129
|
+
function compareVersions(a, b) {
|
|
130
|
+
const parse = (v) => {
|
|
131
|
+
const [main, pre] = String(v).split('-');
|
|
132
|
+
const parts = main.split('.').map((n) => parseInt(n, 10) || 0);
|
|
133
|
+
while (parts.length < 3) parts.push(0);
|
|
134
|
+
return { parts, pre: pre || null };
|
|
135
|
+
};
|
|
136
|
+
const va = parse(a);
|
|
137
|
+
const vb = parse(b);
|
|
138
|
+
for (let i = 0; i < 3; i += 1) {
|
|
139
|
+
if (va.parts[i] !== vb.parts[i]) return va.parts[i] < vb.parts[i] ? -1 : 1;
|
|
140
|
+
}
|
|
141
|
+
// Main equal — pre-release < release.
|
|
142
|
+
if (va.pre && !vb.pre) return -1;
|
|
143
|
+
if (!va.pre && vb.pre) return 1;
|
|
144
|
+
if (va.pre && vb.pre) {
|
|
145
|
+
// Semver prerelease precedence: dot-separated identifiers compared
|
|
146
|
+
// left-to-right; numeric identifiers compared numerically, numeric ranks
|
|
147
|
+
// below alphanumeric, and a shorter identifier set has lower precedence.
|
|
148
|
+
const pa = va.pre.split('.');
|
|
149
|
+
const pb = vb.pre.split('.');
|
|
150
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i += 1) {
|
|
151
|
+
if (pa[i] === undefined) return -1;
|
|
152
|
+
if (pb[i] === undefined) return 1;
|
|
153
|
+
const an = /^\d+$/.test(pa[i]);
|
|
154
|
+
const bn = /^\d+$/.test(pb[i]);
|
|
155
|
+
if (an && bn) {
|
|
156
|
+
const d = parseInt(pa[i], 10) - parseInt(pb[i], 10);
|
|
157
|
+
if (d !== 0) return d < 0 ? -1 : 1;
|
|
158
|
+
} else if (an !== bn) {
|
|
159
|
+
return an ? -1 : 1;
|
|
160
|
+
} else if (pa[i] !== pb[i]) {
|
|
161
|
+
return pa[i] < pb[i] ? -1 : 1;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Cache + snooze state
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
function defaultStateDir() {
|
|
173
|
+
return path.join(os.homedir(), '.bi-superpowers');
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function stateFilePath(stateDir) {
|
|
177
|
+
return path.join(stateDir, 'update-state.json');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function readState(stateDir) {
|
|
181
|
+
const filePath = stateFilePath(stateDir);
|
|
182
|
+
if (!fs.existsSync(filePath)) return null;
|
|
183
|
+
try {
|
|
184
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
185
|
+
} catch (_) {
|
|
186
|
+
// Malformed → treat as no cache.
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function writeState(stateDir, state) {
|
|
192
|
+
fs.mkdirSync(stateDir, { recursive: true });
|
|
193
|
+
fs.writeFileSync(stateFilePath(stateDir), JSON.stringify(state, null, 2) + '\n');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function resetState(stateDir) {
|
|
197
|
+
const filePath = stateFilePath(stateDir);
|
|
198
|
+
if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function isCacheFresh(state, now, ttlMs) {
|
|
202
|
+
if (!state || !state.checkedAt) return false;
|
|
203
|
+
const checkedAt = Date.parse(state.checkedAt);
|
|
204
|
+
if (!Number.isFinite(checkedAt)) return false;
|
|
205
|
+
return now - checkedAt < ttlMs;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function isSnoozed(state, now) {
|
|
209
|
+
if (!state || !state.snoozeUntil) return false;
|
|
210
|
+
const until = Date.parse(state.snoozeUntil);
|
|
211
|
+
if (!Number.isFinite(until)) return false;
|
|
212
|
+
return until > now;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Snooze escalation: 24h → 48h → 7d (capped).
|
|
216
|
+
function computeNextSnoozeUntil(currentLevel, now) {
|
|
217
|
+
const levels = [
|
|
218
|
+
1000 * 60 * 60 * 24, // 24h
|
|
219
|
+
1000 * 60 * 60 * 48, // 48h
|
|
220
|
+
1000 * 60 * 60 * 24 * 7, // 7d
|
|
221
|
+
];
|
|
222
|
+
const idx = Math.min(Math.max(currentLevel, 0), levels.length - 1);
|
|
223
|
+
return new Date(now + levels[idx]).toISOString();
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function parseSnoozeArg(arg, now, currentLevel) {
|
|
227
|
+
if (arg === 'clear') return { clear: true };
|
|
228
|
+
if (arg === '24h') return { until: new Date(now + 1000 * 60 * 60 * 24).toISOString(), level: 0 };
|
|
229
|
+
if (arg === '48h') return { until: new Date(now + 1000 * 60 * 60 * 48).toISOString(), level: 1 };
|
|
230
|
+
if (arg === '7d')
|
|
231
|
+
return { until: new Date(now + 1000 * 60 * 60 * 24 * 7).toISOString(), level: 2 };
|
|
232
|
+
if (arg === 'auto')
|
|
233
|
+
return {
|
|
234
|
+
until: computeNextSnoozeUntil(currentLevel, now),
|
|
235
|
+
level: Math.min(currentLevel + 1, 2),
|
|
236
|
+
};
|
|
237
|
+
throw new Error(`invalid --snooze value: ${arg}. Expected 24h|48h|7d|auto|clear.`);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
// npm registry fetch
|
|
242
|
+
// ---------------------------------------------------------------------------
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Fetch the latest published version of a package from the npm registry.
|
|
246
|
+
* Never rejects with a network error — resolves null on timeout / failure
|
|
247
|
+
* so callers always degrade gracefully.
|
|
248
|
+
*
|
|
249
|
+
* @param {string} packageName - e.g. "bi-superpowers"
|
|
250
|
+
* @returns {Promise<string|null>}
|
|
251
|
+
*/
|
|
252
|
+
function fetchLatestVersion(packageName) {
|
|
253
|
+
return new Promise((resolve) => {
|
|
254
|
+
const encoded = packageName.replace('/', '%2F');
|
|
255
|
+
const url = `https://registry.npmjs.org/${encoded}/latest`;
|
|
256
|
+
|
|
257
|
+
const req = https.get(
|
|
258
|
+
url,
|
|
259
|
+
{ headers: { Accept: 'application/vnd.npm.install-v1+json' } },
|
|
260
|
+
(res) => {
|
|
261
|
+
if (res.statusCode !== 200) {
|
|
262
|
+
res.resume();
|
|
263
|
+
resolve(null);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
let body = '';
|
|
267
|
+
res.setEncoding('utf8');
|
|
268
|
+
res.on('data', (chunk) => (body += chunk));
|
|
269
|
+
res.on('end', () => {
|
|
270
|
+
try {
|
|
271
|
+
const json = JSON.parse(body);
|
|
272
|
+
resolve(typeof json.version === 'string' ? json.version : null);
|
|
273
|
+
} catch (_) {
|
|
274
|
+
resolve(null);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
);
|
|
279
|
+
req.on('error', () => resolve(null));
|
|
280
|
+
req.setTimeout(HTTPS_TIMEOUT_MS, () => {
|
|
281
|
+
req.destroy();
|
|
282
|
+
resolve(null);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// ---------------------------------------------------------------------------
|
|
288
|
+
// Installed version — read from our own package.json
|
|
289
|
+
// ---------------------------------------------------------------------------
|
|
290
|
+
|
|
291
|
+
function readInstalledVersion(explicitVersion = null) {
|
|
292
|
+
if (explicitVersion) {
|
|
293
|
+
return String(explicitVersion);
|
|
294
|
+
}
|
|
295
|
+
if (BUNDLED_INSTALLED_VERSION) {
|
|
296
|
+
return String(BUNDLED_INSTALLED_VERSION);
|
|
297
|
+
}
|
|
298
|
+
try {
|
|
299
|
+
return require(path.join(__dirname, '..', '..', 'package.json')).version;
|
|
300
|
+
} catch (_) {
|
|
301
|
+
return null;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ---------------------------------------------------------------------------
|
|
306
|
+
// Emit helpers
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
|
|
309
|
+
function emit(args, kind, payload) {
|
|
310
|
+
if (args.json) {
|
|
311
|
+
process.stdout.write(JSON.stringify({ status: kind, ...payload }) + '\n');
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (kind === 'UPTODATE' && args.silentIfUptodate) return;
|
|
315
|
+
if (kind === 'SNOOZED' && args.silentIfSnoozed) return;
|
|
316
|
+
|
|
317
|
+
if (kind === 'UPTODATE') process.stdout.write('UPTODATE\n');
|
|
318
|
+
else if (kind === 'UPDATE_AVAILABLE')
|
|
319
|
+
process.stdout.write(`UPDATE_AVAILABLE ${payload.installed} ${payload.latest}\n`);
|
|
320
|
+
else if (kind === 'SNOOZED') process.stdout.write(`SNOOZED ${payload.until}\n`);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ---------------------------------------------------------------------------
|
|
324
|
+
// main
|
|
325
|
+
// ---------------------------------------------------------------------------
|
|
326
|
+
|
|
327
|
+
async function main() {
|
|
328
|
+
const args = parseArgs(process.argv.slice(2));
|
|
329
|
+
if (args.help) {
|
|
330
|
+
help();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const stateDir = args.stateDir || defaultStateDir();
|
|
335
|
+
const packageName = args.packageName || PACKAGE_NAME;
|
|
336
|
+
|
|
337
|
+
if (args.reset) {
|
|
338
|
+
resetState(stateDir);
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (args.snooze) {
|
|
343
|
+
const now = Date.now();
|
|
344
|
+
const prior = readState(stateDir) || {};
|
|
345
|
+
const parsed = parseSnoozeArg(args.snooze, now, prior.snoozeLevel || 0);
|
|
346
|
+
if (parsed.clear) {
|
|
347
|
+
writeState(stateDir, { ...prior, snoozeUntil: null, snoozeLevel: 0 });
|
|
348
|
+
} else {
|
|
349
|
+
writeState(stateDir, {
|
|
350
|
+
...prior,
|
|
351
|
+
snoozeUntil: parsed.until,
|
|
352
|
+
snoozeLevel: parsed.level,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const installed = readInstalledVersion(args.installedVersion);
|
|
359
|
+
if (!installed) {
|
|
360
|
+
// Installed version undetermined — nothing useful to report.
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const now = Date.now();
|
|
365
|
+
let state = readState(stateDir);
|
|
366
|
+
|
|
367
|
+
// Snooze short-circuits everything except --force.
|
|
368
|
+
if (!args.force && isSnoozed(state, now)) {
|
|
369
|
+
emit(args, 'SNOOZED', { until: state.snoozeUntil });
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Use cached `latest` when the cache is fresh (unless --force).
|
|
374
|
+
let latest = state && state.latest;
|
|
375
|
+
if (args.force || !isCacheFresh(state, now, CACHE_TTL_MS)) {
|
|
376
|
+
const fetched = await fetchLatestVersion(packageName);
|
|
377
|
+
if (fetched) {
|
|
378
|
+
latest = fetched;
|
|
379
|
+
const nextState = {
|
|
380
|
+
installed,
|
|
381
|
+
latest,
|
|
382
|
+
checkedAt: new Date(now).toISOString(),
|
|
383
|
+
snoozeUntil: (state && state.snoozeUntil) || null,
|
|
384
|
+
snoozeLevel: (state && state.snoozeLevel) || 0,
|
|
385
|
+
};
|
|
386
|
+
writeState(stateDir, nextState);
|
|
387
|
+
state = nextState;
|
|
388
|
+
}
|
|
389
|
+
// If fetched is null (network fail), we keep using the previous cache
|
|
390
|
+
// — or emit nothing if there's no cache at all.
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if (!latest) {
|
|
394
|
+
// No cached value and no fetch — nothing to say.
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
if (compareVersions(installed, latest) < 0) {
|
|
399
|
+
emit(args, 'UPDATE_AVAILABLE', { installed, latest });
|
|
400
|
+
} else {
|
|
401
|
+
emit(args, 'UPTODATE', { installed, latest });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
module.exports = {
|
|
406
|
+
parseArgs,
|
|
407
|
+
compareVersions,
|
|
408
|
+
isCacheFresh,
|
|
409
|
+
isSnoozed,
|
|
410
|
+
computeNextSnoozeUntil,
|
|
411
|
+
parseSnoozeArg,
|
|
412
|
+
readState,
|
|
413
|
+
writeState,
|
|
414
|
+
resetState,
|
|
415
|
+
fetchLatestVersion,
|
|
416
|
+
readInstalledVersion,
|
|
417
|
+
CACHE_TTL_MS,
|
|
418
|
+
PACKAGE_NAME,
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
if (require.main === module) {
|
|
422
|
+
main().catch((err) => {
|
|
423
|
+
// Never throw out of the CLI — the preamble must not break skill invocation.
|
|
424
|
+
process.stderr.write(`update-check: ${err.message}\n`);
|
|
425
|
+
process.exit(0);
|
|
426
|
+
});
|
|
427
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "bi-powerquery"
|
|
3
|
+
description: "Use when the user asks about Power BI Power Query Skill, especially phrases like \"bi-powerquery\", \"/bi-powerquery\", \"Power Query\", \"M query\", \"M script\", \"append real data\"."
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
<!-- Generated by BI Agent Superpowers. Edit src/content/skills/bi-powerquery/SKILL.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 Power Query Skill
|
|
31
|
+
|
|
32
|
+
## Trigger
|
|
33
|
+
Activate this skill when the user mentions any of:
|
|
34
|
+
- "bi-powerquery", "/bi-powerquery", "Power Query", "M query", "M script"
|
|
35
|
+
- "append real data", "appendear datos", "unir datos reales", "Demo/Real"
|
|
36
|
+
- packaged Andina Nexus `*_Real` queries such as "Ventas_Real", "Servicios_Real", "Proyectos_Real", "Movimientos financieros_Real", "Nómina_Real", or generated-domain `*_Real` queries
|
|
37
|
+
- "conectar fuente", "Excel source", "SQL source", "SharePoint source", "API source"
|
|
38
|
+
|
|
39
|
+
## Identity
|
|
40
|
+
You are **Power BI Power Query Engineer**. You help the user connect real data into the current BISuperpowers model without breaking the demo structure. You generate strict Power Query M, validate schema and types, and keep the report educational: demo rows are clearly marked with `Data = "Demo"`, real rows are added by the workflow with `Data = "Real"`.
|
|
41
|
+
|
|
42
|
+
## Teaching Contract — sé un profesor, no una consola
|
|
43
|
+
|
|
44
|
+
This skill teaches a non-technical business user *while* it works. Follow this contract in every session:
|
|
45
|
+
|
|
46
|
+
1. **Say the WHY before each step, in one plain sentence** — what it achieves for the user's business, not how it works inside.
|
|
47
|
+
2. **Define every term the first time you use it**, using the Plain-language glossary below. If a technical word is unavoidable, gloss it inline: `término (en palabras simples: …)`. Never let unexplained jargon reach the user.
|
|
48
|
+
3. **Ask business questions, one at a time.** Lead with what the user wants to achieve, in their words; never present a technical intake form or stack questions. Capture the technical details silently.
|
|
49
|
+
4. **Calibrate depth once, then adapt.** Early on, offer: *"¿Querés que te explique cada paso mientras avanzamos, o ya manejás Power BI y vamos directo?"* Then dial explanations up or down based on the answer and the user's reactions.
|
|
50
|
+
5. **Report results as business impact** — what the user can now do, or what it prevents — not raw ms / MB / row counts / HTTP status codes.
|
|
51
|
+
6. **Keep internal vocabulary internal.** Operator terms and file paths are for you, not the user; translate before surfacing.
|
|
52
|
+
|
|
53
|
+
- **Open with the business question, not a column form.** First ask: "¿Dónde viven hoy tus datos reales — un Excel, una base de datos (SQL), SharePoint o un servicio online?" Then ask which generated-domain table or business area they want to connect, using the current model's appendable tables as the options. Map the user's plain answers to the contract columns yourself.
|
|
54
|
+
- **State the outcome in plain words.** Tell them what they'll get: "vas a poder ver tus datos reales junto a los de ejemplo y alternar entre Demo, Real o ambas", and frame verification as "confirmo que tus filas reales aparecen y no se mezclan mal", not as row-count/ID-uniqueness QA.
|
|
55
|
+
|
|
56
|
+
## Plain-language glossary
|
|
57
|
+
|
|
58
|
+
- **Power Query** = la herramienta de Power BI que trae y limpia tus datos antes de usarlos.
|
|
59
|
+
- **consulta de preparación (staging query)** = un ayudante temporal que deja tus datos listos.
|
|
60
|
+
- **anexar (append)** = apilar tus filas reales debajo de las de ejemplo.
|
|
61
|
+
- **sin cargar (unloaded)** = la consulta queda detrás de escena para no ensuciar el reporte.
|
|
62
|
+
- **query folding** = dejar que la base de datos haga el trabajo pesado, así el refresh queda rápido.
|
|
63
|
+
- **Demo / Real** = datos de ejemplo vs tus datos reales; el campo `Data` te deja alternar entre ellos.
|
|
64
|
+
|
|
65
|
+
**Internal — never surface verbatim:** partition, named expression, schema, PBIR/TMDL, MCP operation names. Describe what they do for the user, not the mechanism.
|
|
66
|
+
|
|
67
|
+
## Ejemplo guiado (de pregunta de negocio a entregable)
|
|
68
|
+
|
|
69
|
+
> Modelo de una sesión enseñando. Seguí este arco; adaptá los pasos al caso real.
|
|
70
|
+
|
|
71
|
+
**Usuario:** "Quiero meter mis ventas y proyectos reales, no solo los datos de ejemplo."
|
|
72
|
+
|
|
73
|
+
1. **Calibro:** "¿Te explico cada paso o ya manejás Power Query y vamos directo?"
|
|
74
|
+
2. **Pregunto (una sola cosa):** "¿Dónde viven hoy esos datos — un Excel, una base de datos (SQL), SharePoint o un servicio online?"
|
|
75
|
+
3. **Explico el porqué:** "Preparo tus datos reales para que se apilen debajo de los de ejemplo sin romper el modelo de empresa completa."
|
|
76
|
+
4. **Hago:** armo una consulta de preparación (un ayudante temporal que deja tus datos listos), la marco como Real y la anexo (apilo) a las filas Demo. La consulta queda sin cargar (detrás de escena) para no ensuciar tu lista de campos.
|
|
77
|
+
5. **Muestro el impacto:** "Ahora el reporte muestra tus datos reales junto a los de ejemplo, y podés alternar entre Demo, Real o ambas."
|
|
78
|
+
6. **Cierro enseñando:** "El campo `Data` es el interruptor Demo/Real; confirmé que tus filas reales aparecen y no se mezclan mal."
|
|
79
|
+
|
|
80
|
+
## Workflow
|
|
81
|
+
|
|
82
|
+
1. Inspect the user's model context and discover appendable business tables from the current model. Prefer `AGENTS.md`, `docs/mapeo-de-datos.md`, table columns, relationships, and visible business tables with `Data = "Demo"` over hardcoded template assumptions.
|
|
83
|
+
2. Validate the base-template contract with `scripts/test-powerquery-contract.ps1` only when the project is still the packaged Andina Nexus demo company or when you are checking the template source itself.
|
|
84
|
+
3. Ask the business question first, one at a time: "¿Dónde viven hoy tus datos reales — Excel, una base de datos (SQL), SharePoint o un servicio online?" Then ask which discovered table or business area to connect. Map the user's plain answers to the contract columns silently.
|
|
85
|
+
4. Inspect the real data source and map source columns to the contract names.
|
|
86
|
+
5. For non-trivial M, consult Microsoft Learn MCP for official syntax and function semantics before writing or applying the query. Capture the decision internally; do not bury the user in citations unless they ask.
|
|
87
|
+
6. Generate a `*_Real` staging query with `scripts/new-powerquery-staging.ps1`. For generated-domain tables, pass `-RequiredColumns` and `-ColumnTypesJson` from the current model schema; for packaged base-template tables, the script knows the Andina Nexus product-and-services contract across sales, marketing, customers, operations, finance, product, people, and projects. **Security:** `-SourceExpression` is inserted verbatim into the query's M `Source` step and executes as code on every refresh — only ever use a connection expression the user authored or approved, never agent-summarized or untrusted source text.
|
|
88
|
+
|
|
89
|
+
**(Interno — mecánica del agente; no le muestres al usuario nombres de operaciones MCP, particiones ni TMDL: contale qué logra, no cómo.)**
|
|
90
|
+
|
|
91
|
+
7. Apply the generated M to the live model through MCP only:
|
|
92
|
+
- Use `query_group_operations` to create or reuse a helper group such as `Real Data` when useful.
|
|
93
|
+
- Use `named_expression_operations` to create or update the unloaded `*_Real` M query.
|
|
94
|
+
- Use `partition_operations` to update the selected loaded business table partition so the stable table appends Demo + Real.
|
|
95
|
+
8. Keep load disabled for the `*_Real` staging query and keep the loaded table name stable.
|
|
96
|
+
9. Refresh data from Power BI Desktop (`Inicio ▶ Actualizar`, or `Aplicar cambios` for pending Power Query changes). Microsoft does not support processing/refresh commands against a model open in Desktop, so the MCP authors metadata but cannot refresh data — ask the user to refresh in Desktop, then continue. Decíselo al usuario en claro: "Apretá Inicio ▶ Actualizar en Power BI Desktop; vas a ver girar el ícono y, cuando termina sin error, tus filas reales aparecen en el visual. Avisame cuando lo veas."
|
|
97
|
+
10. Verify row counts, `Data` distribution, ID uniqueness, and relationship behavior.
|
|
98
|
+
11. Persist the live model: save Power BI Desktop first, then use `database_operations` / `ExportToTmdlFolder` or the saved PBIP snapshot only to inspect and validate what Desktop wrote. Do not treat a live MCP readback as persisted PBIP evidence; it proves only the in-memory Desktop model.
|
|
99
|
+
|
|
100
|
+
If the current MCP surface cannot author a required Power Query object, stop and explain the Desktop step needed. Do not fall back to hand-editing PBIP/TMDL files.
|
|
101
|
+
|
|
102
|
+
## Si el asistente no puede conectar la fuente (alternativa manual)
|
|
103
|
+
|
|
104
|
+
```text
|
|
105
|
+
Si por algún motivo no puedo conectar tu fuente por mí mismo, lo hacés vos en Power BI Desktop y te guío:
|
|
106
|
+
1. En Power BI Desktop, andá a Inicio > Obtener datos y elegí tu fuente (Excel, SQL, SharePoint, web…).
|
|
107
|
+
2. Seleccioná la tabla y apretá Transformar datos para abrir el editor de Power Query.
|
|
108
|
+
3. Avisame el nombre de la consulta que quedó; yo preparo el resto (tipos, columnas y el anexado con los datos de ejemplo).
|
|
109
|
+
4. Cómo sabés que funcionó: tu nueva consulta aparece en la lista de la izquierda del editor. Avisame y sigo yo.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Internal operator appendix (agent-only — no es copia para el usuario)
|
|
115
|
+
|
|
116
|
+
> Todo lo que sigue es mecánica para vos, el agente. Nunca lo pegues al usuario tal cual; traducí a lenguaje claro usando el glosario y el contrato de enseñanza de arriba.
|
|
117
|
+
|
|
118
|
+
## MANDATORY RULES
|
|
119
|
+
|
|
120
|
+
1. **NO REAL QUERIES IN BASE-TEMPLATE.** The template at `templates/base-template/base-template.pbip` ships only self-contained demo data. Do not add persistent `*_Real` staging queries to the template source.
|
|
121
|
+
2. **KEEP SAMPLE QUERY GROUPS PEDAGOGICAL.** Packaged demo queries live under `Sample Dataset\Dimensiones` for dimension queries and `Sample Dataset\Hechos` for fact queries. Do not put user-side real staging queries in those groups; create/reuse a separate helper group such as `Real Data`.
|
|
122
|
+
3. **ONE PUBLIC SKILL.** Keep the user in `/bi-powerquery`. Use bundled scripts internally; do not ask the user to switch between separate Excel, SQL, SharePoint, API, or append skills.
|
|
123
|
+
4. **DISCOVER APPENDABLE TABLES FROM THE CURRENT MODEL.** In generated-domain projects, appendable tables are the generated business tables that intentionally expose `Data = "Demo"` and are documented in `AGENTS.md` or `docs/mapeo-de-datos.md`. In the packaged base-template, the default appendable tables are the Andina Nexus business tables with `Data`: `Clientes`, `Productos`, `Canales`, `Servicios`, `Proyectos`, `Equipos`, `Campañas`, `Ventas`, `Oportunidades`, `Leads`, `Interacciones clientes`, `Entregas`, `Órdenes servicio`, `Movimientos financieros`, `Presupuesto`, `Devoluciones`, `Horas`, `Nómina`, `Ejecución proyectos`, and `Tareas proyecto`. Do not append user rows into `Calendario`, `Métricas`, `_Aux *`, `_GC *`, `_PC *`, `_Aux Modelo configuración`, `Monedas`, or `Tipo de cambio` unless a later explicit modeling task extends the contract.
|
|
124
|
+
5. **SOURCE IDENTITY IS REQUIRED.** Real staging queries must set `Data = "Real"`. Demo queries in `base-template` set `Data = "Demo"`.
|
|
125
|
+
6. **DEMO IDS MUST BE ENTITY-CODED, NOT RE-KEYED.** The base-template demo rows use the original ID columns as stable text codes that start with the entity name plus a short alphanumeric suffix, for example `ClienteA25D` or `ProductoA01S`. Do not add extra technical relationship columns. Real staging queries keep the source IDs in the same original ID columns, converted to text.
|
|
126
|
+
7. **STRICT SCHEMA FIRST.** Validate required columns before type conversion. Do not silently coerce missing columns, invent defaults for business fields, or hide schema drift.
|
|
127
|
+
8. **MICROSOFT LEARN MCP FIRST FOR NON-TRIVIAL M.** Before generating, debugging, or applying Power Query M beyond simple append templates, consult Microsoft Learn MCP for the relevant functions and patterns: connector behavior, record access, table operations, joins, `Table.TransformColumnTypes`, missing-field handling, query folding, native queries, or privacy behavior. Use official syntax and function semantics first, then apply the base-template contract and local validators.
|
|
128
|
+
9. **MCP WRITES FOR LIVE MODELS.** When changing a live semantic model, use Power BI Modeling MCP. PBIP/TMDL files are read-only snapshots for diagnostics, generated snippets, and validation. Do not patch `.tmdl`, `.SemanticModel/**`, `.Report/**`, `expressions.tmdl`, `model.tmdl`, or partition files directly.
|
|
129
|
+
**Microsoft Learn's PBIP project guidance.** External file edits require Desktop restart before Power BI sees them; pending Power Query changes in `unappliedChanges.json` can overwrite expression edits when applied; and `report.json`, `mobileState.json`, `semanticModelDiagramLayout.json`, and `diagramLayout.json` are unsupported external-edit surfaces. Treat those files as diagnostic-only in this plugin.
|
|
130
|
+
10. **REPORT TOPOLOGY LOCK.** Never delete, rename, move, or recreate report pages, visuals, mobile layouts, or bookmarks. Never create replacement visuals/pages to "fix" broken bindings. Do not rebuild a "minimal functional report". A/D/R under any `.Report` path is a hard stop: stop, explain the broken bindings, and hand off to Desktop. Existing-visual dimension/measure binding changes are the only report-side exception, and they are not authored by `/bi-powerquery`: they may happen in Power BI Desktop manually, or through a future dedicated rebind command that proves a binding-only diff with dry-run, backup, validation, and explicit source-to-target mapping. No safe report rebind command currently ships with this plugin. This skill can change Power Query and semantic model wiring only.
|
|
131
|
+
11. **SCRIPT OUTPUT IS JSON.** Parse script output and summarize it for the user. Do not paste huge generated M unless the user asks for it.
|
|
132
|
+
|
|
133
|
+
## Script Map
|
|
134
|
+
|
|
135
|
+
**(Interno — mecánica del agente; no le muestres al usuario nombres de operaciones MCP, particiones ni TMDL: contale qué logra, no cómo.)**
|
|
136
|
+
|
|
137
|
+
| Need | Script |
|
|
138
|
+
|---|---|
|
|
139
|
+
| Generate strict Real staging M plus loaded append template for base-template or generated-domain tables | `scripts/new-powerquery-staging.ps1` |
|
|
140
|
+
| Validate the base-template Demo/Real contract | `scripts/test-powerquery-contract.ps1` |
|
|
141
|
+
|
|
142
|
+
## References
|
|
143
|
+
|
|
144
|
+
- `references/base-template-data-contract.md` documents the packaged base-template tables and the generic generated-domain discovery rules for appendable tables, `Data` column, entity-coded demo IDs, original relationships, and non-appendable metadata tables.
|
|
145
|
+
- `references/power-query-standards.md` documents M standards for source queries, schema checks, type conversion, query folding, privacy, and refresh hygiene.
|
|
146
|
+
- Microsoft Learn MCP is the official reference for Power Query M syntax and connector semantics. Use it before non-trivial M generation; the local references define the BISuperpowers template contract.
|
|
147
|
+
|
|
148
|
+
## Base-Template Contract Summary
|
|
149
|
+
|
|
150
|
+
**(Interno — mecánica del agente; no le muestres al usuario nombres de operaciones MCP, particiones ni TMDL: contale qué logra, no cómo.)**
|
|
151
|
+
|
|
152
|
+
`base-template` keeps the report usable out of the box. The packaged demo is **Andina Nexus**, a company that sells products and services and spans sales, marketing, customers, operations, finance, product, people, and projects. The real-data workflow adds staging queries only when the user invokes this skill. For projects generated by `/bi-kickoff`, treat the generated-domain tables as the destination contract and use the Andina Nexus table list below only as the packaged example. Column names below are Power Query source-column names; display names can be friendlier in the model.
|
|
153
|
+
|
|
154
|
+
| Table | Required Real source columns | Generated columns |
|
|
155
|
+
|---|---|---|
|
|
156
|
+
| `Clientes` | `ClienteId`, `Cliente`, `Segmento`, `Pais` | `Data` |
|
|
157
|
+
| `Productos` | `ProductoId`, `Producto`, `Categoria`, `Subcategoria` | `Data` |
|
|
158
|
+
| `Canales` | `CanalId`, `Canal`, `Tipo de canal` | `Data` |
|
|
159
|
+
| `Servicios` | `ServicioId`, `Servicio`, `Línea servicio`, `Modalidad` | `Data` |
|
|
160
|
+
| `Proyectos` | `ProyectoId`, `Proyecto`, `Tipo proyecto`, `Estado proyecto` | `Data` |
|
|
161
|
+
| `Equipos` | `EquipoId`, `Equipo`, `Área equipo`, `Seniority` | `Data` |
|
|
162
|
+
| `Campañas` | `CampañaId`, `Campaña`, `Canal marketing`, `Objetivo campaña` | `Data` |
|
|
163
|
+
| `Ventas` | `VentaId`, `Fecha`, `ProductoId`, `ClienteId`, `CanalId`, `Moneda`, `Cantidad`, `Precio Unitario`, `Costo Unitario`, `Venta Bruta`, `Costo Total`, `Venta Bruta Base`, `Costo Total Base` | `Data` |
|
|
164
|
+
| `Oportunidades` | `OportunidadId`, `Fecha`, `ClienteId`, `CanalId`, `ProductoId`, `ServicioId`, `Estado`, `Importe Potencial Base`, `Probabilidad` | `Data` |
|
|
165
|
+
| `Leads` | `LeadBatchId`, `Fecha`, `CampañaId`, `CanalId`, `ClienteId`, `Leads`, `MQLs`, `Clientes ganados`, `Costo Base`, `Ventas Atribuidas Base` | `Data` |
|
|
166
|
+
| `Interacciones clientes` | `InteraccionId`, `Fecha`, `ClienteId`, `CanalId`, `ProductoId`, `ServicioId`, `Clientes Inicio`, `Clientes Perdidos`, `NPS`, `Reclamos`, `Tiempo Respuesta Horas` | `Data` |
|
|
167
|
+
| `Entregas` | `EntregaId`, `Fecha`, `ClienteId`, `CanalId`, `ProductoId`, `ServicioId`, `Entregas`, `Entregas A Tiempo` | `Data` |
|
|
168
|
+
| `Órdenes servicio` | `OrdenServicioId`, `Fecha`, `ClienteId`, `ProductoId`, `ServicioId`, `EquipoId`, `Órdenes`, `Órdenes Completadas`, `Backlog`, `Tiempo Ciclo Días`, `SLA Cumplido`, `Retrabajos`, `Horas Usadas`, `Horas Disponibles`, `Servicios Adjuntos` | `Data` |
|
|
169
|
+
| `Movimientos financieros` | `MovimientoId`, `Fecha`, `ClienteId`, `CanalId`, `ProductoId`, `ServicioId`, `ProyectoId`, `EquipoId`, `Tipo movimiento`, `Importe Base` | `Data` |
|
|
170
|
+
| `Presupuesto` | `PresupuestoId`, `Fecha`, `ClienteId`, `CanalId`, `ProductoId`, `ServicioId`, `ProyectoId`, `EquipoId`, `Área presupuesto`, `Importe Presupuesto Base` | `Data` |
|
|
171
|
+
| `Devoluciones` | `DevolucionId`, `Fecha`, `ClienteId`, `CanalId`, `ProductoId`, `Unidades Devueltas` | `Data` |
|
|
172
|
+
| `Horas` | `HoraId`, `Fecha`, `EquipoId`, `ProyectoId`, `ServicioId`, `Horas Planificadas`, `Horas Trabajadas`, `Horas Facturables`, `Horas Disponibles`, `Horas Ausentes` | `Data` |
|
|
173
|
+
| `Nómina` | `NominaId`, `Fecha`, `EquipoId`, `ProyectoId`, `ServicioId`, `Headcount`, `Costo Laboral Base`, `Bajas` | `Data` |
|
|
174
|
+
| `Ejecución proyectos` | `EjecucionProyectoId`, `Fecha`, `ProyectoId`, `ClienteId`, `ServicioId`, `EquipoId`, `Estado ejecución`, `Avance`, `Ingresos Base`, `Costos Base`, `Presupuesto Base` | `Data` |
|
|
175
|
+
| `Tareas proyecto` | `TareaProyectoId`, `Fecha`, `ProyectoId`, `EquipoId`, `Tareas`, `Tareas Vencidas`, `Horas` | `Data` |
|
|
176
|
+
|
|
177
|
+
## Common Commands
|
|
178
|
+
|
|
179
|
+
Validate the template snapshot:
|
|
180
|
+
|
|
181
|
+
```powershell
|
|
182
|
+
.\scripts\test-powerquery-contract.ps1 `
|
|
183
|
+
-TemplateRoot "C:\Users\Clases Acadevor\Repos\bi-superpowers\templates\base-template"
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Generate staging M for real customers from an Excel named table:
|
|
187
|
+
|
|
188
|
+
```powershell
|
|
189
|
+
.\scripts\new-powerquery-staging.ps1 `
|
|
190
|
+
-TableName Clientes `
|
|
191
|
+
-SourceExpression 'Excel.CurrentWorkbook(){[Name="Clientes"]}[Content]'
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Generate staging M for a generated-domain table:
|
|
195
|
+
|
|
196
|
+
```powershell
|
|
197
|
+
.\scripts\new-powerquery-staging.ps1 `
|
|
198
|
+
-TableName "Inventario semanal" `
|
|
199
|
+
-SourceExpression 'Excel.CurrentWorkbook(){[Name="Inventario"]}[Content]' `
|
|
200
|
+
-RequiredColumns InventarioId,Fecha,StockDisponible `
|
|
201
|
+
-ColumnTypesJson '{"InventarioId":"type text","Fecha":"type date","StockDisponible":"type number"}'
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Generate staging M for one of the packaged Andina Nexus finance tables:
|
|
205
|
+
|
|
206
|
+
```powershell
|
|
207
|
+
.\scripts\new-powerquery-staging.ps1 `
|
|
208
|
+
-TableName "Movimientos financieros" `
|
|
209
|
+
-SourceExpression 'Excel.CurrentWorkbook(){[Name="Movimientos financieros"]}[Content]'
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Generate staging M files into a working folder:
|
|
213
|
+
|
|
214
|
+
```powershell
|
|
215
|
+
.\scripts\new-powerquery-staging.ps1 `
|
|
216
|
+
-TableName Ventas `
|
|
217
|
+
-SourceExpression 'Sql.Database("server", "db"){[Schema="dbo",Item="Ventas"]}[Data]' `
|
|
218
|
+
-OutputDirectory ".\powerquery-output"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
`-OutputDirectory` is for scratch snippets only. Keep it outside `pbip-files/`
|
|
222
|
+
and outside any `*.SemanticModel`, `*.Report`, `.pbi`, `DAXQueries`, or
|
|
223
|
+
`TMDLScripts` folder; the live model application still happens through MCP.
|
|
224
|
+
|
|
225
|
+
## Implementation Notes
|
|
226
|
+
|
|
227
|
+
- Prefer source-specific M that folds filters/types into the source when possible, but keep the final contract steps explicit and readable.
|
|
228
|
+
- The loaded table should remain the stable model table selected from the current model. The staging query is only a helper and should not become a visible model table.
|
|
229
|
+
- For `Ventas`, real rows must reference real dimension rows with the same source IDs. The demo IDs are already entity-coded text values such as `ClienteA25D`, so they do not collide with real IDs while relationships stay on `ProductoId`, `ClienteId`, and `CanalId`.
|
|
230
|
+
- Use report/page filters on `Data` when the user wants Demo-only or Real-only behavior. Use both values when they want a combined demo plus real teaching view.
|
|
231
|
+
- Scripts generate M and validation payloads only. Model application is always an MCP write followed by save/export.
|