bi-superpowers 1.0.0 → 1.1.1
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 +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.claude-plugin/skill-manifest.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/LICENSE +21 -21
- package/README.md +16 -6
- package/bin/cli.js +8 -1
- package/bin/commands/create-from-template.js +5 -0
- package/bin/commands/install.js +100 -15
- package/bin/commands/session-update.js +33 -3
- package/bin/commands/template-path.js +62 -0
- package/bin/commands/uninstall.js +76 -16
- package/bin/commands/update-check.js +29 -18
- package/bin/lib/base-template-smoke.js +80 -40
- package/bin/lib/install-manifest.js +198 -0
- package/bin/lib/powerbi-mcp-session.js +63 -17
- package/bin/lib/template-scaffold.js +40 -5
- package/bin/postinstall.js +0 -0
- package/commands/bi-powerquery.md +2 -1
- package/config.example.json +23 -23
- package/config.json +23 -23
- package/desktop-extension/manifest.json +30 -30
- package/desktop-extension/package.json +10 -10
- package/desktop-extension/server.js +76 -76
- package/package.json +1 -1
- package/skills/bi-connect/SKILL.md +1 -1
- package/skills/bi-connect/scripts/update-check.js +30 -19
- package/skills/bi-dax/SKILL.md +1 -1
- package/skills/bi-dax/scripts/update-check.js +30 -19
- package/skills/bi-kickoff/SKILL.md +1 -1
- package/skills/bi-kickoff/scripts/update-check.js +30 -19
- package/skills/bi-modeling/SKILL.md +1 -1
- package/skills/bi-modeling/scripts/update-check.js +30 -19
- package/skills/bi-performance/SKILL.md +1 -1
- package/skills/bi-performance/scripts/update-check.js +30 -19
- package/skills/bi-powerquery/SKILL.md +3 -2
- package/skills/bi-powerquery/references/base-template-data-contract.md +5 -2
- package/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +24 -2
- package/skills/bi-powerquery/scripts/update-check.js +30 -19
- package/skills/bi-refactor/SKILL.md +1 -1
- package/skills/bi-refactor/scripts/update-check.js +30 -19
- package/skills/bi-scorecard/SKILL.md +1 -1
- package/skills/bi-scorecard/scripts/update-check.js +30 -19
- package/skills/bi-start/SKILL.md +1 -1
- package/skills/bi-start/scripts/update-check.js +30 -19
- package/src/content/mcp-requirements.json +57 -57
- package/src/content/skills/bi-powerquery/SKILL.md +2 -1
- package/src/content/skills/bi-powerquery/references/base-template-data-contract.md +5 -2
- package/src/content/skills/bi-powerquery/scripts/test-powerquery-contract.ps1 +24 -2
- package/templates/base-template/base-template.Report/.platform +10 -10
- package/templates/base-template/base-template.Report/StaticResources/RegisteredResources/BISuperpowers.json +3887 -3887
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/CY18SU07.json +176 -176
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BaseThemes/Fluent2-CY26SU03.json +4103 -4103
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleCityPark.json +25 -25
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleDefault.json +25 -25
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleNeutral.json +25 -25
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleOrchid.json +25 -25
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/AccessibleTidal.json +25 -25
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Bloom.json +138 -138
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CityPark.json +39 -39
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Classroom.json +39 -39
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/ColorblindSafe.json +47 -47
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/CopilotDefault.json +1860 -1860
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Divergent.json +126 -126
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Electric.json +47 -47
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Frontier.json +135 -135
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/HighContrast.json +39 -39
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Highrise.json +40 -40
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Innovate.json +226 -226
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/NewExecutive.json +40 -40
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Solar.json +32 -32
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Storm.json +24 -24
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Sunset.json +47 -47
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Temperature.json +32 -32
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Tidal.json +99 -99
- package/templates/base-template/base-template.Report/StaticResources/SharedResources/BuiltInThemes/Twilight.json +39 -39
- package/templates/base-template/base-template.Report/definition/bookmarks/1d40d43c7ade66e8603c.bookmark.json +2296 -2296
- package/templates/base-template/base-template.Report/definition/bookmarks/af068ff51c0ca3089ea7.bookmark.json +2299 -2299
- package/templates/base-template/base-template.Report/definition/bookmarks/bookmarks.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/page.json +129 -129
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/0352fd80d074693a65db/visual.json +668 -668
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/1c5a14bf493697344b68/visual.json +722 -722
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/3486cf7624c5b109b4e5/visual.json +332 -332
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/4d8b989008edc0db28d1/visual.json +108 -108
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/mobile.json +30 -30
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/55e10ac7d76a1954f94f/visual.json +377 -377
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/57f52ecf4490f70e4da1/visual.json +174 -174
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/5f4d76bbc870118e9840/visual.json +467 -467
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/73629e1abebb7a444b59/visual.json +359 -358
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/749cb1388c7e0a88161c/visual.json +689 -689
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/90677f13cea5d1275990/visual.json +15 -16
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/92cf92e3da10493adb78/visual.json +467 -467
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/mobile.json +9 -9
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/9fe17b1971f68443fc15/visual.json +327 -327
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a30bd0950630ed94e8a3/visual.json +577 -577
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/a56e91d9400a835e4814/visual.json +431 -431
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/aded24cd205c0b528642/visual.json +800 -800
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/mobile.json +36 -36
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/af34b26f14a8a724c9a9/visual.json +1317 -1317
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/b529688fe5a226643322/visual.json +208 -208
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/c4c6f332d05e72e2eb06/visual.json +173 -173
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/mobile.json +28 -28
- package/templates/base-template/base-template.Report/definition/pages/6a4808bb8bb9166f49ff/visuals/fa81f184e2cb0e8b087c/visual.json +240 -240
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/page.json +129 -129
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/07e9c4302e29029c5462/visual.json +689 -689
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/109ceede4bc015b0c006/visual.json +467 -467
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/118257e006d472277e10/visual.json +358 -358
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/2caf02e0137c4a1280cc/visual.json +668 -668
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/311e76fe3c9edad68204/visual.json +108 -108
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/31c21f8cbeb3b208940a/visual.json +208 -208
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/3ab72c25062437149b03/visual.json +16 -16
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5959867442abcb0ce2b3/visual.json +787 -787
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/5b96e0f88d192b044a13/visual.json +591 -591
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/64e749a63d0786000e22/visual.json +467 -467
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/7ae1ca604edac6586ad0/visual.json +1309 -1309
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/840300733885141a6603/visual.json +174 -174
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/a38448cdb203279273d2/visual.json +515 -515
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d1e86f213a3841d12e20/visual.json +327 -327
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d4a484c1bcc8ee3075e2/visual.json +431 -431
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/d87cb5cf06acca19bbb5/visual.json +240 -240
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/e243da2677209ed69408/visual.json +173 -173
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/mobile.json +10 -10
- package/templates/base-template/base-template.Report/definition/pages/9a5b670b015cab882629/visuals/f3aaf24f5b22b67573b0/visual.json +332 -332
- package/templates/base-template/base-template.Report/definition/pages/pages.json +7 -7
- package/templates/base-template/base-template.Report/definition/report.json +88 -88
- package/templates/base-template/base-template.Report/definition/version.json +3 -3
- package/templates/base-template/base-template.Report/definition.pbir +8 -8
- package/templates/base-template/base-template.SemanticModel/.platform +10 -10
- package/templates/base-template/base-template.SemanticModel/definition/cultures/es-AR.tmdl +11185 -11185
- package/templates/base-template/base-template.SemanticModel/definition/database.tmdl +5 -3
- package/templates/base-template/base-template.SemanticModel/definition/expressions.tmdl +340 -234
- package/templates/base-template/base-template.SemanticModel/definition/functions.tmdl +637 -637
- package/templates/base-template/base-template.SemanticModel/definition/model.tmdl +85 -82
- package/templates/base-template/base-template.SemanticModel/definition/relationships.tmdl +263 -271
- package/templates/base-template/base-template.SemanticModel/definition/tables/Calendario.tmdl +200 -200
- package/templates/base-template/base-template.SemanticModel/definition/tables/Campa/303/261as.tmdl +75 -75
- package/templates/base-template/base-template.SemanticModel/definition/tables/Canales.tmdl +84 -84
- package/templates/base-template/base-template.SemanticModel/definition/tables/Clientes.tmdl +126 -143
- package/templates/base-template/base-template.SemanticModel/definition/tables/Devoluciones.tmdl +64 -95
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ejecuci/303/263n proyectos.tmdl" +98 -130
- package/templates/base-template/base-template.SemanticModel/definition/tables/Entregas.tmdl +77 -122
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos m/303/251tricas.tmdl" +40 -40
- package/templates/base-template/base-template.SemanticModel/definition/tables/Equipos.tmdl +47 -73
- package/templates/base-template/base-template.SemanticModel/definition/tables/Horas.tmdl +91 -122
- package/templates/base-template/base-template.SemanticModel/definition/tables/Interacciones clientes.tmdl +95 -146
- package/templates/base-template/base-template.SemanticModel/definition/tables/Leads.tmdl +90 -119
- package/templates/base-template/base-template.SemanticModel/definition/tables/Monedas.tmdl +44 -44
- package/templates/base-template/base-template.SemanticModel/definition/tables/Movimientos financieros.tmdl +146 -145
- package/templates/base-template/base-template.SemanticModel/definition/tables/M/303/251tricas.tmdl +1324 -1294
- package/templates/base-template/base-template.SemanticModel/definition/tables/N/303/263mina.tmdl +82 -110
- package/templates/base-template/base-template.SemanticModel/definition/tables/Oportunidades.tmdl +83 -135
- package/templates/base-template/base-template.SemanticModel/definition/tables/Presupuesto.tmdl +101 -125
- package/templates/base-template/base-template.SemanticModel/definition/tables/Productos.tmdl +98 -98
- package/templates/base-template/base-template.SemanticModel/definition/tables/Proyectos.tmdl +77 -77
- package/templates/base-template/base-template.SemanticModel/definition/tables/Servicios.tmdl +75 -75
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tareas proyecto.tmdl +73 -102
- package/templates/base-template/base-template.SemanticModel/definition/tables/Tipo de cambio.tmdl +67 -67
- package/templates/base-template/base-template.SemanticModel/definition/tables/Ventas.tmdl +142 -180
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux An/303/241lisis dimensiones.tmdl" +38 -38
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Comparaciones.tmdl +227 -227
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Compatibilidad m/303/251trica-dimensi/303/263n.tmdl" +68 -68
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modelo configuraci/303/263n.tmdl" +44 -44
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Modo fechas.tmdl +36 -36
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux M/303/251trica-Equipo.tmdl" +101 -102
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Overrides m/303/251trica-dimensi/303/263n.tmdl" +57 -54
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Per/303/255odos.tmdl" +182 -182
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas modo.tmdl +36 -36
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Rango fechas.tmdl +27 -27
- package/templates/base-template/base-template.SemanticModel/definition/tables/_Aux Vista de calendario.tmdl +30 -30
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC C/303/241lculo.tmdl" +70 -70
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Eje X.tmdl +63 -63
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC M/303/251trica.tmdl" +374 -374
- package/templates/base-template/base-template.SemanticModel/definition/tables/_GC Tipo c/303/241lculo.tmdl" +223 -223
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Dimensi/303/263n.tmdl" +98 -98
- package/templates/base-template/base-template.SemanticModel/definition/tables/_PC Eje X.tmdl +68 -68
- package/templates/base-template/base-template.SemanticModel/definition/tables//303/223rdenes servicio.tmdl" +121 -151
- package/templates/base-template/base-template.SemanticModel/definition.pbism +4 -4
- package/templates/base-template/base-template.SemanticModel/diagramLayout.json +567 -567
- package/templates/base-template/base-template.pbip +13 -13
- package/theme/BISuperpowers.json +3887 -3887
|
@@ -40,6 +40,15 @@ const os = require('os');
|
|
|
40
40
|
const readline = require('readline');
|
|
41
41
|
const { AGENTS, UNIVERSAL_DIR } = require('../lib/agents');
|
|
42
42
|
const { removeMcpConfigForAgent } = require('../lib/mcp-config');
|
|
43
|
+
const {
|
|
44
|
+
readInstallManifest,
|
|
45
|
+
removeInstallManifest,
|
|
46
|
+
getAgentSkillRecord,
|
|
47
|
+
isManifestOwnedSymlink,
|
|
48
|
+
samePath,
|
|
49
|
+
packageKey,
|
|
50
|
+
} = require('../lib/install-manifest');
|
|
51
|
+
const { disableAutoupdate } = require('./autoupdate');
|
|
43
52
|
|
|
44
53
|
const LEGACY_SESSION_DIR = '.bi-superpowers';
|
|
45
54
|
|
|
@@ -281,7 +290,7 @@ function removeIfEmpty(dir) {
|
|
|
281
290
|
*
|
|
282
291
|
* @returns {{ action: string, dir?: string, count?: number }}
|
|
283
292
|
*/
|
|
284
|
-
function removeAgentSkills(baseDir, agentId, skillNames, dryRun, removeEmpty) {
|
|
293
|
+
function removeAgentSkills(baseDir, agentId, skillNames, dryRun, removeEmpty, manifest = null) {
|
|
285
294
|
const agent = AGENTS[agentId];
|
|
286
295
|
if (agent.dir === UNIVERSAL_DIR) {
|
|
287
296
|
return { action: 'universal' };
|
|
@@ -294,14 +303,23 @@ function removeAgentSkills(baseDir, agentId, skillNames, dryRun, removeEmpty) {
|
|
|
294
303
|
}
|
|
295
304
|
|
|
296
305
|
if (st.isSymbolicLink()) {
|
|
306
|
+
const universalTarget = path.join(baseDir, UNIVERSAL_DIR);
|
|
307
|
+
if (!isManifestOwnedSymlink(manifest, agentId, dir, universalTarget)) {
|
|
308
|
+
return { action: 'preserved-symlink', dir: agent.dir };
|
|
309
|
+
}
|
|
297
310
|
if (!dryRun) fs.unlinkSync(dir);
|
|
298
311
|
if (removeEmpty && !dryRun) removeIfEmpty(path.dirname(dir));
|
|
299
312
|
return { action: 'unlinked', dir: agent.dir };
|
|
300
313
|
}
|
|
301
314
|
|
|
302
315
|
// Real directory (copy fallback or user-managed): remove only our subdirs.
|
|
316
|
+
const record = getAgentSkillRecord(manifest, agentId);
|
|
317
|
+
if (!record || record.method !== 'copied' || !samePath(record.path, dir)) {
|
|
318
|
+
return { action: 'unmanaged-directory', dir: agent.dir, count: 0 };
|
|
319
|
+
}
|
|
303
320
|
let count = 0;
|
|
304
|
-
|
|
321
|
+
const ownedSkills = Array.isArray(record.skills) ? record.skills : skillNames;
|
|
322
|
+
for (const name of ownedSkills) {
|
|
305
323
|
const sub = path.join(dir, name);
|
|
306
324
|
if (fs.existsSync(sub)) {
|
|
307
325
|
if (!dryRun) fs.rmSync(sub, { recursive: true, force: true });
|
|
@@ -321,7 +339,7 @@ function removeAgentSkills(baseDir, agentId, skillNames, dryRun, removeEmpty) {
|
|
|
321
339
|
*
|
|
322
340
|
* @returns {{ action: string, count?: number }}
|
|
323
341
|
*/
|
|
324
|
-
function removeUniversalSkills(baseDir, skillNames, dryRun, removeEmpty) {
|
|
342
|
+
function removeUniversalSkills(baseDir, skillNames, dryRun, removeEmpty, manifest = null) {
|
|
325
343
|
const universal = path.join(baseDir, UNIVERSAL_DIR);
|
|
326
344
|
const st = fs.lstatSync(universal, { throwIfNoEntry: false });
|
|
327
345
|
if (!st) {
|
|
@@ -329,12 +347,17 @@ function removeUniversalSkills(baseDir, skillNames, dryRun, removeEmpty) {
|
|
|
329
347
|
}
|
|
330
348
|
|
|
331
349
|
if (st.isSymbolicLink()) {
|
|
332
|
-
|
|
333
|
-
|
|
350
|
+
return { action: 'preserved-symlink' };
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const record = manifest && manifest.skills && manifest.skills.universal;
|
|
354
|
+
if (!record || !samePath(record.path, universal)) {
|
|
355
|
+
return { action: 'unmanaged-directory', count: 0 };
|
|
334
356
|
}
|
|
335
357
|
|
|
336
358
|
let count = 0;
|
|
337
|
-
|
|
359
|
+
const ownedSkills = Array.isArray(record.skills) ? record.skills : skillNames;
|
|
360
|
+
for (const name of ownedSkills) {
|
|
338
361
|
const sub = path.join(universal, name);
|
|
339
362
|
if (fs.existsSync(sub)) {
|
|
340
363
|
if (!dryRun) fs.rmSync(sub, { recursive: true, force: true });
|
|
@@ -374,13 +397,23 @@ function universalIsFullyReleased(baseDir, selectedAgents) {
|
|
|
374
397
|
*
|
|
375
398
|
* @returns {{ existed: boolean, path: string }}
|
|
376
399
|
*/
|
|
377
|
-
function cleanLegacySessionDir(baseDir, dryRun) {
|
|
400
|
+
function cleanLegacySessionDir(baseDir, dryRun, packageName = 'bi-superpowers') {
|
|
378
401
|
const dir = path.join(baseDir, LEGACY_SESSION_DIR);
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
402
|
+
const candidates = [
|
|
403
|
+
'auth.json',
|
|
404
|
+
'session.json',
|
|
405
|
+
'update-state.json',
|
|
406
|
+
'autoupdate-state.json',
|
|
407
|
+
`update-state-${packageKey(packageName)}.json`,
|
|
408
|
+
`autoupdate-state-${packageKey(packageName)}.json`,
|
|
409
|
+
`install-manifest-${packageKey(packageName)}.json`,
|
|
410
|
+
].map((name) => path.join(dir, name));
|
|
411
|
+
const existing = candidates.filter((file) => fs.existsSync(file));
|
|
412
|
+
if (!dryRun) {
|
|
413
|
+
for (const file of existing) fs.rmSync(file, { force: true });
|
|
414
|
+
removeIfEmpty(dir);
|
|
415
|
+
}
|
|
416
|
+
return { existed: existing.length > 0, path: dir, removed: existing };
|
|
384
417
|
}
|
|
385
418
|
|
|
386
419
|
/**
|
|
@@ -395,7 +428,12 @@ async function uninstallCommand(args, config) {
|
|
|
395
428
|
const opts = parseArgs(args);
|
|
396
429
|
const baseDir = os.homedir();
|
|
397
430
|
const packageDir = config.packageDir || path.dirname(path.dirname(__dirname));
|
|
398
|
-
const
|
|
431
|
+
const packageName = config.packageName || 'bi-superpowers';
|
|
432
|
+
const manifest = readInstallManifest(baseDir, packageName);
|
|
433
|
+
const skillNames =
|
|
434
|
+
manifest && manifest.skills && Array.isArray(manifest.skills.names)
|
|
435
|
+
? manifest.skills.names
|
|
436
|
+
: getManagedSkillNames(packageDir);
|
|
399
437
|
|
|
400
438
|
console.log(
|
|
401
439
|
boxen(
|
|
@@ -448,12 +486,29 @@ async function uninstallCommand(args, config) {
|
|
|
448
486
|
)
|
|
449
487
|
);
|
|
450
488
|
|
|
489
|
+
// Uninstall always disables the Claude Code auto-update hook so a removed
|
|
490
|
+
// package cannot keep reinstalling itself in future sessions.
|
|
491
|
+
try {
|
|
492
|
+
if (dry) {
|
|
493
|
+
console.log(chalk.gray(' · Claude Code auto-update hook would be disabled'));
|
|
494
|
+
} else {
|
|
495
|
+
const hook = disableAutoupdate();
|
|
496
|
+
console.log(
|
|
497
|
+
hook.removed
|
|
498
|
+
? chalk.green(' ✓ Claude Code auto-update hook disabled')
|
|
499
|
+
: chalk.gray(' – Claude Code auto-update hook was not enabled')
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
} catch (err) {
|
|
503
|
+
console.log(chalk.red(` ✗ Could not disable Claude Code auto-update: ${err.message}`));
|
|
504
|
+
}
|
|
505
|
+
|
|
451
506
|
// Phase 1: skills.
|
|
452
507
|
const skillResults = [];
|
|
453
508
|
if (doSkills) {
|
|
454
509
|
for (const agentId of selectedAgents) {
|
|
455
510
|
try {
|
|
456
|
-
const result = removeAgentSkills(baseDir, agentId, skillNames, dry, true);
|
|
511
|
+
const result = removeAgentSkills(baseDir, agentId, skillNames, dry, true, manifest);
|
|
457
512
|
skillResults.push({ agent: AGENTS[agentId].name, ...result });
|
|
458
513
|
} catch (err) {
|
|
459
514
|
skillResults.push({ agent: AGENTS[agentId].name, action: 'error', error: err.message });
|
|
@@ -462,7 +517,7 @@ async function uninstallCommand(args, config) {
|
|
|
462
517
|
|
|
463
518
|
if (releaseUniversal) {
|
|
464
519
|
try {
|
|
465
|
-
const uni = removeUniversalSkills(baseDir, skillNames, dry, true);
|
|
520
|
+
const uni = removeUniversalSkills(baseDir, skillNames, dry, true, manifest);
|
|
466
521
|
skillResults.push({ agent: `${UNIVERSAL_DIR}`, ...uni });
|
|
467
522
|
} catch (err) {
|
|
468
523
|
skillResults.push({ agent: UNIVERSAL_DIR, action: 'error', error: err.message });
|
|
@@ -480,6 +535,10 @@ async function uninstallCommand(args, config) {
|
|
|
480
535
|
console.log(chalk.green(` ${dry ? '·' : '✓'} ${r.agent}/ (${r.count} skills removed)`));
|
|
481
536
|
} else if (r.action === 'absent') {
|
|
482
537
|
console.log(chalk.gray(` – ${r.agent}: no managed skills found`));
|
|
538
|
+
} else if (r.action === 'preserved-symlink') {
|
|
539
|
+
console.log(chalk.yellow(` ⚠ ${r.dir || r.agent}: foreign symlink preserved`));
|
|
540
|
+
} else if (r.action === 'unmanaged-directory') {
|
|
541
|
+
console.log(chalk.yellow(` ⚠ ${r.dir || r.agent}: unowned directory preserved`));
|
|
483
542
|
} else if (r.action === 'error') {
|
|
484
543
|
console.log(chalk.red(` ✗ ${r.agent}: ${r.error}`));
|
|
485
544
|
}
|
|
@@ -522,7 +581,7 @@ async function uninstallCommand(args, config) {
|
|
|
522
581
|
// Phase 3: legacy session dir.
|
|
523
582
|
let legacy = { existed: false };
|
|
524
583
|
if (doExtras) {
|
|
525
|
-
legacy = cleanLegacySessionDir(baseDir, dry);
|
|
584
|
+
legacy = cleanLegacySessionDir(baseDir, dry, packageName);
|
|
526
585
|
if (legacy.existed) {
|
|
527
586
|
console.log(
|
|
528
587
|
chalk.green(
|
|
@@ -530,6 +589,7 @@ async function uninstallCommand(args, config) {
|
|
|
530
589
|
)
|
|
531
590
|
);
|
|
532
591
|
}
|
|
592
|
+
if (!dry) removeInstallManifest(baseDir, packageName);
|
|
533
593
|
}
|
|
534
594
|
|
|
535
595
|
// Summary.
|
|
@@ -49,6 +49,12 @@ const HTTPS_TIMEOUT_MS = 5000;
|
|
|
49
49
|
// `bin/commands/`, it stays null and we fall back to package.json.
|
|
50
50
|
const BUNDLED_INSTALLED_VERSION = null;
|
|
51
51
|
|
|
52
|
+
// Keep this helper dependency-free because the generator copies this script
|
|
53
|
+
// into every installed skill as a standalone update checker.
|
|
54
|
+
function packageKey(packageName) {
|
|
55
|
+
return Buffer.from(String(packageName || PACKAGE_NAME), 'utf8').toString('base64url');
|
|
56
|
+
}
|
|
57
|
+
|
|
52
58
|
// ---------------------------------------------------------------------------
|
|
53
59
|
// Argument parsing
|
|
54
60
|
// ---------------------------------------------------------------------------
|
|
@@ -173,12 +179,12 @@ function defaultStateDir() {
|
|
|
173
179
|
return path.join(os.homedir(), '.bi-superpowers');
|
|
174
180
|
}
|
|
175
181
|
|
|
176
|
-
function stateFilePath(stateDir) {
|
|
177
|
-
return path.join(stateDir,
|
|
182
|
+
function stateFilePath(stateDir, packageName = PACKAGE_NAME) {
|
|
183
|
+
return path.join(stateDir, `update-state-${packageKey(packageName)}.json`);
|
|
178
184
|
}
|
|
179
185
|
|
|
180
|
-
function readState(stateDir) {
|
|
181
|
-
const filePath = stateFilePath(stateDir);
|
|
186
|
+
function readState(stateDir, packageName = PACKAGE_NAME) {
|
|
187
|
+
const filePath = stateFilePath(stateDir, packageName);
|
|
182
188
|
if (!fs.existsSync(filePath)) return null;
|
|
183
189
|
try {
|
|
184
190
|
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
@@ -188,13 +194,13 @@ function readState(stateDir) {
|
|
|
188
194
|
}
|
|
189
195
|
}
|
|
190
196
|
|
|
191
|
-
function writeState(stateDir, state) {
|
|
197
|
+
function writeState(stateDir, state, packageName = PACKAGE_NAME) {
|
|
192
198
|
fs.mkdirSync(stateDir, { recursive: true });
|
|
193
|
-
fs.writeFileSync(stateFilePath(stateDir), JSON.stringify(state, null, 2) + '\n');
|
|
199
|
+
fs.writeFileSync(stateFilePath(stateDir, packageName), JSON.stringify(state, null, 2) + '\n');
|
|
194
200
|
}
|
|
195
201
|
|
|
196
|
-
function resetState(stateDir) {
|
|
197
|
-
const filePath = stateFilePath(stateDir);
|
|
202
|
+
function resetState(stateDir, packageName = PACKAGE_NAME) {
|
|
203
|
+
const filePath = stateFilePath(stateDir, packageName);
|
|
198
204
|
if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
|
|
199
205
|
}
|
|
200
206
|
|
|
@@ -335,22 +341,26 @@ async function main() {
|
|
|
335
341
|
const packageName = args.packageName || PACKAGE_NAME;
|
|
336
342
|
|
|
337
343
|
if (args.reset) {
|
|
338
|
-
resetState(stateDir);
|
|
344
|
+
resetState(stateDir, packageName);
|
|
339
345
|
return;
|
|
340
346
|
}
|
|
341
347
|
|
|
342
348
|
if (args.snooze) {
|
|
343
349
|
const now = Date.now();
|
|
344
|
-
const prior = readState(stateDir) || {};
|
|
350
|
+
const prior = readState(stateDir, packageName) || {};
|
|
345
351
|
const parsed = parseSnoozeArg(args.snooze, now, prior.snoozeLevel || 0);
|
|
346
352
|
if (parsed.clear) {
|
|
347
|
-
writeState(stateDir, { ...prior, snoozeUntil: null, snoozeLevel: 0 });
|
|
353
|
+
writeState(stateDir, { ...prior, snoozeUntil: null, snoozeLevel: 0 }, packageName);
|
|
348
354
|
} else {
|
|
349
|
-
writeState(
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
355
|
+
writeState(
|
|
356
|
+
stateDir,
|
|
357
|
+
{
|
|
358
|
+
...prior,
|
|
359
|
+
snoozeUntil: parsed.until,
|
|
360
|
+
snoozeLevel: parsed.level,
|
|
361
|
+
},
|
|
362
|
+
packageName
|
|
363
|
+
);
|
|
354
364
|
}
|
|
355
365
|
return;
|
|
356
366
|
}
|
|
@@ -362,7 +372,7 @@ async function main() {
|
|
|
362
372
|
}
|
|
363
373
|
|
|
364
374
|
const now = Date.now();
|
|
365
|
-
let state = readState(stateDir);
|
|
375
|
+
let state = readState(stateDir, packageName);
|
|
366
376
|
|
|
367
377
|
// Snooze short-circuits everything except --force.
|
|
368
378
|
if (!args.force && isSnoozed(state, now)) {
|
|
@@ -383,7 +393,7 @@ async function main() {
|
|
|
383
393
|
snoozeUntil: (state && state.snoozeUntil) || null,
|
|
384
394
|
snoozeLevel: (state && state.snoozeLevel) || 0,
|
|
385
395
|
};
|
|
386
|
-
writeState(stateDir, nextState);
|
|
396
|
+
writeState(stateDir, nextState, packageName);
|
|
387
397
|
state = nextState;
|
|
388
398
|
}
|
|
389
399
|
// If fetched is null (network fail), we keep using the previous cache
|
|
@@ -412,6 +422,7 @@ module.exports = {
|
|
|
412
422
|
readState,
|
|
413
423
|
writeState,
|
|
414
424
|
resetState,
|
|
425
|
+
stateFilePath,
|
|
415
426
|
fetchLatestVersion,
|
|
416
427
|
readInstalledVersion,
|
|
417
428
|
CACHE_TTL_MS,
|
|
@@ -27,6 +27,8 @@ const SMOKE_QUERY_PATTERN = /## Smoke Query\s+```DAX\s+([\s\S]*?)```/i;
|
|
|
27
27
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
28
28
|
const WEEK_MS = 7 * DAY_MS;
|
|
29
29
|
const DEMO_CUSTOMER_COUNT = 210;
|
|
30
|
+
const DEMO_INITIAL_CUSTOMER_COUNT = 90;
|
|
31
|
+
const DEFAULT_START_DATE = new Date(2023, 0, 1);
|
|
30
32
|
|
|
31
33
|
function extractSmokeQuery(caseMarkdown) {
|
|
32
34
|
const match = caseMarkdown.match(SMOKE_QUERY_PATTERN);
|
|
@@ -44,12 +46,6 @@ function formatLocalDate(date) {
|
|
|
44
46
|
return `${year}-${month}-${day}`;
|
|
45
47
|
}
|
|
46
48
|
|
|
47
|
-
function addLocalDays(date, days) {
|
|
48
|
-
const result = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
49
|
-
result.setDate(result.getDate() + days);
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
49
|
function startOfMondayWeek(date) {
|
|
54
50
|
const result = new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
55
51
|
const mondayOffset = (result.getDay() + 6) % 7;
|
|
@@ -63,11 +59,25 @@ function countMondayWeeks(startDate, endDate) {
|
|
|
63
59
|
return Math.floor((lastWeek.getTime() - firstWeek.getTime()) / WEEK_MS) + 1;
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
function estimateVentasRows(
|
|
62
|
+
function estimateVentasRows(
|
|
63
|
+
weekCount,
|
|
64
|
+
customerCount = DEMO_CUSTOMER_COUNT,
|
|
65
|
+
initialCustomerCount = DEMO_INITIAL_CUSTOMER_COUNT
|
|
66
|
+
) {
|
|
67
|
+
const initial = Math.min(initialCustomerCount, Math.max(0, customerCount - 1));
|
|
68
|
+
const remaining = customerCount - initial;
|
|
67
69
|
let rows = 0;
|
|
68
70
|
|
|
69
|
-
for (let
|
|
70
|
-
|
|
71
|
+
for (let weekIndex = 0; weekIndex < weekCount; weekIndex++) {
|
|
72
|
+
let active = initial;
|
|
73
|
+
for (let customerIndex = 0; customerIndex < remaining; customerIndex++) {
|
|
74
|
+
const acquisitionWeek =
|
|
75
|
+
remaining <= 1 || weekCount <= 1
|
|
76
|
+
? 0
|
|
77
|
+
: Math.floor((customerIndex * (weekCount - 1)) / (remaining - 1));
|
|
78
|
+
if (acquisitionWeek <= weekIndex) active++;
|
|
79
|
+
}
|
|
80
|
+
rows += active;
|
|
71
81
|
}
|
|
72
82
|
|
|
73
83
|
return rows;
|
|
@@ -79,10 +89,13 @@ function getExpectedSmokeEvidence(referenceDate = new Date()) {
|
|
|
79
89
|
referenceDate.getMonth(),
|
|
80
90
|
referenceDate.getDate()
|
|
81
91
|
);
|
|
82
|
-
const minDate =
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
92
|
+
const minDate = new Date(
|
|
93
|
+
DEFAULT_START_DATE.getFullYear(),
|
|
94
|
+
DEFAULT_START_DATE.getMonth(),
|
|
95
|
+
DEFAULT_START_DATE.getDate()
|
|
96
|
+
);
|
|
97
|
+
const maxFactDate = startOfMondayWeek(currentDate);
|
|
98
|
+
const validationWeeks = countMondayWeeks(minDate, currentDate);
|
|
86
99
|
|
|
87
100
|
return {
|
|
88
101
|
Metricas: '56',
|
|
@@ -93,11 +106,19 @@ function getExpectedSmokeEvidence(referenceDate = new Date()) {
|
|
|
93
106
|
WindowWeeks: String(validationWeeks),
|
|
94
107
|
FactTablesWithFullWeeks: '13',
|
|
95
108
|
MetricCoverageFailures: '0',
|
|
96
|
-
MetricDimensionPairs: '
|
|
109
|
+
MetricDimensionPairs: '415',
|
|
97
110
|
MetricDimensionFailures: '0',
|
|
98
|
-
|
|
111
|
+
VisibleDimensionFailures: '0',
|
|
112
|
+
MaxVisibleDimensionValues: '13',
|
|
113
|
+
BusinessInvariantFailures: '0',
|
|
114
|
+
YearRangeFailures: '0',
|
|
115
|
+
TeamRangeFailures: '0',
|
|
116
|
+
Last365RangeFailures: '0',
|
|
117
|
+
VentasRows: String(estimateVentasRows(validationWeeks)),
|
|
99
118
|
MinFecha: formatLocalDate(minDate),
|
|
100
|
-
MaxFecha: formatLocalDate(
|
|
119
|
+
MaxFecha: formatLocalDate(maxFactDate),
|
|
120
|
+
MaxCalendario: formatLocalDate(currentDate),
|
|
121
|
+
UltimoClienteNuevo: formatLocalDate(maxFactDate),
|
|
101
122
|
};
|
|
102
123
|
}
|
|
103
124
|
|
|
@@ -196,15 +217,22 @@ async function runBaseTemplateLiveSmokeTest(options = {}) {
|
|
|
196
217
|
const expected = getExpectedSmokeEvidence(referenceDate);
|
|
197
218
|
const session = sessionFactory(serverPath);
|
|
198
219
|
const attempts = [];
|
|
220
|
+
const connectionTimeoutMs = options.connectionTimeoutMs || 30_000;
|
|
221
|
+
const daxTimeoutMs = options.daxTimeoutMs || 210_000;
|
|
222
|
+
const signal = options.signal;
|
|
199
223
|
|
|
200
224
|
try {
|
|
201
|
-
await session.initialize(options.clientInfo);
|
|
202
|
-
|
|
203
|
-
const localInstancesResult = await session.callTool(
|
|
204
|
-
|
|
205
|
-
|
|
225
|
+
await session.initialize(options.clientInfo, { timeoutMs: connectionTimeoutMs, signal });
|
|
226
|
+
|
|
227
|
+
const localInstancesResult = await session.callTool(
|
|
228
|
+
'connection_operations',
|
|
229
|
+
{
|
|
230
|
+
request: {
|
|
231
|
+
operation: 'ListLocalInstances',
|
|
232
|
+
},
|
|
206
233
|
},
|
|
207
|
-
|
|
234
|
+
{ timeoutMs: connectionTimeoutMs, signal }
|
|
235
|
+
);
|
|
208
236
|
const localInstances = normalizeMcpJsonResult(localInstancesResult).data || [];
|
|
209
237
|
|
|
210
238
|
for (const instance of localInstances) {
|
|
@@ -218,31 +246,43 @@ async function runBaseTemplateLiveSmokeTest(options = {}) {
|
|
|
218
246
|
};
|
|
219
247
|
|
|
220
248
|
try {
|
|
221
|
-
await session.callTool(
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
249
|
+
await session.callTool(
|
|
250
|
+
'connection_operations',
|
|
251
|
+
{
|
|
252
|
+
request: {
|
|
253
|
+
operation: 'Connect',
|
|
254
|
+
connectionString: `Provider=MSOLAP;Data Source=localhost:${instance.port};Application Name=MCP-PBIModeling`,
|
|
255
|
+
},
|
|
225
256
|
},
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
257
|
+
{ timeoutMs: connectionTimeoutMs, signal }
|
|
258
|
+
);
|
|
259
|
+
|
|
260
|
+
const connectionsResult = await session.callTool(
|
|
261
|
+
'connection_operations',
|
|
262
|
+
{
|
|
263
|
+
request: {
|
|
264
|
+
operation: 'ListConnections',
|
|
265
|
+
},
|
|
231
266
|
},
|
|
232
|
-
|
|
267
|
+
{ timeoutMs: connectionTimeoutMs, signal }
|
|
268
|
+
);
|
|
233
269
|
const connections = normalizeMcpJsonResult(connectionsResult).data || [];
|
|
234
270
|
const selectedConnection = selectConnectionForPort(connections, instance.port);
|
|
235
271
|
attempt.connectionName = selectedConnection ? selectedConnection.connectionName : null;
|
|
236
272
|
|
|
237
|
-
const daxResult = await session.callTool(
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
273
|
+
const daxResult = await session.callTool(
|
|
274
|
+
'dax_query_operations',
|
|
275
|
+
{
|
|
276
|
+
request: {
|
|
277
|
+
operation: 'Execute',
|
|
278
|
+
connectionName: attempt.connectionName || undefined,
|
|
279
|
+
timeoutSeconds: 180,
|
|
280
|
+
maxRows: 1,
|
|
281
|
+
query: smokeQuery,
|
|
282
|
+
},
|
|
244
283
|
},
|
|
245
|
-
|
|
284
|
+
{ timeoutMs: daxTimeoutMs, signal }
|
|
285
|
+
);
|
|
246
286
|
|
|
247
287
|
const observed = parseSingleRowCsv(extractCsvText(daxResult));
|
|
248
288
|
attempt.observed = observed;
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install Ownership Manifest
|
|
3
|
+
* ==========================
|
|
4
|
+
*
|
|
5
|
+
* Records the user-level files and links created by `super install`.
|
|
6
|
+
* Uninstall and future upgrades use this file as proof of ownership instead
|
|
7
|
+
* of assuming that every similarly named path belongs to bi-superpowers.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const fs = require('fs');
|
|
11
|
+
const path = require('path');
|
|
12
|
+
|
|
13
|
+
const MANIFEST_SCHEMA_VERSION = 1;
|
|
14
|
+
const STATE_DIR = '.bi-superpowers';
|
|
15
|
+
|
|
16
|
+
function packageKey(packageName) {
|
|
17
|
+
return Buffer.from(String(packageName || 'bi-superpowers'), 'utf8').toString('base64url');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function manifestFilePath(homeDir, packageName = 'bi-superpowers') {
|
|
21
|
+
return path.join(homeDir, STATE_DIR, `install-manifest-${packageKey(packageName)}.json`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function readInstallManifest(homeDir, packageName = 'bi-superpowers') {
|
|
25
|
+
const file = manifestFilePath(homeDir, packageName);
|
|
26
|
+
if (!fs.existsSync(file)) return null;
|
|
27
|
+
try {
|
|
28
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
29
|
+
if (
|
|
30
|
+
!parsed ||
|
|
31
|
+
parsed.schemaVersion !== MANIFEST_SCHEMA_VERSION ||
|
|
32
|
+
parsed.packageName !== packageName
|
|
33
|
+
) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return parsed;
|
|
37
|
+
} catch (_) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function writeInstallManifest(homeDir, manifest) {
|
|
43
|
+
const packageName = manifest.packageName || 'bi-superpowers';
|
|
44
|
+
const file = manifestFilePath(homeDir, packageName);
|
|
45
|
+
const parent = path.dirname(file);
|
|
46
|
+
fs.mkdirSync(parent, { recursive: true });
|
|
47
|
+
|
|
48
|
+
const leaf = fs.lstatSync(file, { throwIfNoEntry: false });
|
|
49
|
+
if (leaf && leaf.isSymbolicLink()) {
|
|
50
|
+
throw new Error(`Refusing to overwrite symlinked install manifest: ${file}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const temp = `${file}.tmp`;
|
|
54
|
+
const tempLeaf = fs.lstatSync(temp, { throwIfNoEntry: false });
|
|
55
|
+
if (tempLeaf && tempLeaf.isSymbolicLink()) {
|
|
56
|
+
throw new Error(`Refusing to overwrite symlinked temporary manifest: ${temp}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
fs.writeFileSync(temp, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
|
|
60
|
+
try {
|
|
61
|
+
fs.renameSync(temp, file);
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// Windows cannot always atomically replace an existing file. The content
|
|
64
|
+
// is already complete in the sibling temp file, so replace in two steps.
|
|
65
|
+
if (!['EEXIST', 'EPERM'].includes(error.code)) throw error;
|
|
66
|
+
fs.rmSync(file, { force: true });
|
|
67
|
+
fs.renameSync(temp, file);
|
|
68
|
+
}
|
|
69
|
+
return file;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function removeInstallManifest(homeDir, packageName = 'bi-superpowers') {
|
|
73
|
+
const file = manifestFilePath(homeDir, packageName);
|
|
74
|
+
if (fs.existsSync(file)) fs.unlinkSync(file);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function normalizeForComparison(value) {
|
|
78
|
+
const resolved = path.resolve(String(value));
|
|
79
|
+
return process.platform === 'win32' ? resolved.toLowerCase() : resolved;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function samePath(left, right) {
|
|
83
|
+
if (!left || !right) return false;
|
|
84
|
+
return normalizeForComparison(left) === normalizeForComparison(right);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function resolveSymlinkTarget(linkPath) {
|
|
88
|
+
const stat = fs.lstatSync(linkPath, { throwIfNoEntry: false });
|
|
89
|
+
if (!stat || !stat.isSymbolicLink()) return null;
|
|
90
|
+
try {
|
|
91
|
+
const rawTarget = fs.readlinkSync(linkPath);
|
|
92
|
+
return path.resolve(path.dirname(linkPath), rawTarget);
|
|
93
|
+
} catch (_) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function getAgentSkillRecord(manifest, agentId) {
|
|
99
|
+
return manifest && manifest.skills && manifest.skills.agents
|
|
100
|
+
? manifest.skills.agents[agentId] || null
|
|
101
|
+
: null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function isManifestOwnedSymlink(manifest, agentId, linkPath, expectedTarget) {
|
|
105
|
+
const record = getAgentSkillRecord(manifest, agentId);
|
|
106
|
+
if (!record || record.method !== 'symlinked') return false;
|
|
107
|
+
const actualTarget = resolveSymlinkTarget(linkPath);
|
|
108
|
+
return (
|
|
109
|
+
samePath(record.path, linkPath) &&
|
|
110
|
+
samePath(record.target, expectedTarget) &&
|
|
111
|
+
samePath(actualTarget, expectedTarget)
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* One-time migration proof for installs created before manifests existed.
|
|
117
|
+
* The link must point exactly at the universal directory and that directory
|
|
118
|
+
* must contain every skill shipped by the package being installed.
|
|
119
|
+
*/
|
|
120
|
+
function isVerifiedLegacyManagedSymlink(linkPath, universalTarget, skillNames) {
|
|
121
|
+
const actualTarget = resolveSymlinkTarget(linkPath);
|
|
122
|
+
if (!samePath(actualTarget, universalTarget) || skillNames.length === 0) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
return skillNames.every((skillName) => {
|
|
126
|
+
const skillFile = path.join(universalTarget, skillName, 'SKILL.md');
|
|
127
|
+
if (!fs.existsSync(skillFile)) return false;
|
|
128
|
+
try {
|
|
129
|
+
return fs.readFileSync(skillFile, 'utf8').includes(`name: ${skillName}`);
|
|
130
|
+
} catch (_) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function createInstallManifest({
|
|
137
|
+
packageName,
|
|
138
|
+
packageVersion,
|
|
139
|
+
skillNames,
|
|
140
|
+
universalTarget,
|
|
141
|
+
agentResults,
|
|
142
|
+
mcpResults,
|
|
143
|
+
autoUpdateEnabled,
|
|
144
|
+
}) {
|
|
145
|
+
const agents = {};
|
|
146
|
+
for (const result of agentResults) {
|
|
147
|
+
if (!result.agentId || result.method === 'preserved-foreign') continue;
|
|
148
|
+
agents[result.agentId] = {
|
|
149
|
+
method: result.method,
|
|
150
|
+
path: result.path,
|
|
151
|
+
target: result.target || null,
|
|
152
|
+
skills: [...skillNames],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return {
|
|
157
|
+
schemaVersion: MANIFEST_SCHEMA_VERSION,
|
|
158
|
+
packageName,
|
|
159
|
+
packageVersion,
|
|
160
|
+
installedAt: new Date().toISOString(),
|
|
161
|
+
skills: {
|
|
162
|
+
names: [...skillNames],
|
|
163
|
+
universal: {
|
|
164
|
+
path: universalTarget,
|
|
165
|
+
skills: [...skillNames],
|
|
166
|
+
},
|
|
167
|
+
agents,
|
|
168
|
+
},
|
|
169
|
+
mcp: {
|
|
170
|
+
servers: ['powerbi-modeling-mcp', 'microsoft-learn'],
|
|
171
|
+
agents: mcpResults
|
|
172
|
+
.filter((result) => result.success && result.configPath)
|
|
173
|
+
.map((result) => ({
|
|
174
|
+
agentId: result.agentId,
|
|
175
|
+
configPath: result.configPath,
|
|
176
|
+
})),
|
|
177
|
+
},
|
|
178
|
+
autoUpdate: {
|
|
179
|
+
enabled: Boolean(autoUpdateEnabled),
|
|
180
|
+
},
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
module.exports = {
|
|
185
|
+
MANIFEST_SCHEMA_VERSION,
|
|
186
|
+
STATE_DIR,
|
|
187
|
+
packageKey,
|
|
188
|
+
manifestFilePath,
|
|
189
|
+
readInstallManifest,
|
|
190
|
+
writeInstallManifest,
|
|
191
|
+
removeInstallManifest,
|
|
192
|
+
samePath,
|
|
193
|
+
resolveSymlinkTarget,
|
|
194
|
+
getAgentSkillRecord,
|
|
195
|
+
isManifestOwnedSymlink,
|
|
196
|
+
isVerifiedLegacyManagedSymlink,
|
|
197
|
+
createInstallManifest,
|
|
198
|
+
};
|