@luquimbo/bi-superpowers 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/.claude-plugin/plugin.json +8 -0
  2. package/.mcp.json +25 -0
  3. package/AGENTS.md +244 -0
  4. package/CHANGELOG.md +265 -0
  5. package/LICENSE +21 -0
  6. package/README.md +211 -0
  7. package/bin/build-plugin.js +30 -0
  8. package/bin/cli.js +1064 -0
  9. package/bin/commands/add.js +533 -0
  10. package/bin/commands/add.test.js +77 -0
  11. package/bin/commands/build-desktop.js +166 -0
  12. package/bin/commands/changelog.js +443 -0
  13. package/bin/commands/diff.js +325 -0
  14. package/bin/commands/lint.js +419 -0
  15. package/bin/commands/lint.test.js +103 -0
  16. package/bin/commands/mcp-setup.js +246 -0
  17. package/bin/commands/pull.js +287 -0
  18. package/bin/commands/pull.test.js +36 -0
  19. package/bin/commands/push.js +231 -0
  20. package/bin/commands/push.test.js +14 -0
  21. package/bin/commands/search.js +344 -0
  22. package/bin/commands/search.test.js +115 -0
  23. package/bin/commands/setup.js +545 -0
  24. package/bin/commands/setup.test.js +46 -0
  25. package/bin/commands/sync-profile.js +405 -0
  26. package/bin/commands/sync-profile.test.js +14 -0
  27. package/bin/commands/sync-source.js +418 -0
  28. package/bin/commands/sync-source.test.js +14 -0
  29. package/bin/commands/watch.js +206 -0
  30. package/bin/lib/generators/claude-plugin.js +266 -0
  31. package/bin/lib/generators/claude-plugin.test.js +110 -0
  32. package/bin/lib/generators/index.js +116 -0
  33. package/bin/lib/generators/shared.js +282 -0
  34. package/bin/lib/licensing/index.js +35 -0
  35. package/bin/lib/licensing/storage.js +364 -0
  36. package/bin/lib/licensing/storage.test.js +55 -0
  37. package/bin/lib/licensing/validator.js +213 -0
  38. package/bin/lib/licensing/validator.test.js +137 -0
  39. package/bin/lib/microsoft-mcp.js +176 -0
  40. package/bin/lib/microsoft-mcp.test.js +106 -0
  41. package/bin/lib/skills.js +84 -0
  42. package/bin/mcp/powerbi-modeling-launcher.js +38 -0
  43. package/bin/postinstall.js +44 -0
  44. package/bin/utils/errors.js +159 -0
  45. package/bin/utils/git.js +298 -0
  46. package/bin/utils/logger.js +142 -0
  47. package/bin/utils/mcp-detect.js +274 -0
  48. package/bin/utils/mcp-detect.test.js +105 -0
  49. package/bin/utils/pbix.js +305 -0
  50. package/bin/utils/pbix.test.js +37 -0
  51. package/bin/utils/profiles.js +312 -0
  52. package/bin/utils/projects.js +168 -0
  53. package/bin/utils/readline.js +206 -0
  54. package/bin/utils/readline.test.js +47 -0
  55. package/bin/utils/tui.js +314 -0
  56. package/bin/utils/tui.test.js +127 -0
  57. package/commands/contributions.md +265 -0
  58. package/commands/data-model-design.md +468 -0
  59. package/commands/dax-doctor.md +248 -0
  60. package/commands/fabric-scripts.md +452 -0
  61. package/commands/migration-assistant.md +290 -0
  62. package/commands/model-documenter.md +242 -0
  63. package/commands/pbi-connect.md +239 -0
  64. package/commands/project-kickoff.md +905 -0
  65. package/commands/report-layout.md +296 -0
  66. package/commands/rls-design.md +533 -0
  67. package/commands/theme-tweaker.md +624 -0
  68. package/config.example.json +23 -0
  69. package/config.json +23 -0
  70. package/desktop-extension/manifest.json +37 -0
  71. package/desktop-extension/package.json +10 -0
  72. package/desktop-extension/server.js +95 -0
  73. package/docs/openrouter-free-models.md +92 -0
  74. package/library/examples/README.md +151 -0
  75. package/library/examples/finance-reporting/README.md +351 -0
  76. package/library/examples/finance-reporting/data-model.md +267 -0
  77. package/library/examples/finance-reporting/measures.dax +557 -0
  78. package/library/examples/hr-analytics/README.md +371 -0
  79. package/library/examples/hr-analytics/data-model.md +315 -0
  80. package/library/examples/hr-analytics/measures.dax +460 -0
  81. package/library/examples/marketing-analytics/README.md +37 -0
  82. package/library/examples/marketing-analytics/data-model.md +62 -0
  83. package/library/examples/marketing-analytics/measures.dax +110 -0
  84. package/library/examples/retail-analytics/README.md +439 -0
  85. package/library/examples/retail-analytics/data-model.md +288 -0
  86. package/library/examples/retail-analytics/measures.dax +481 -0
  87. package/library/examples/supply-chain/README.md +37 -0
  88. package/library/examples/supply-chain/data-model.md +69 -0
  89. package/library/examples/supply-chain/measures.dax +77 -0
  90. package/library/examples/udf-library/README.md +228 -0
  91. package/library/examples/udf-library/functions.dax +571 -0
  92. package/library/snippets/dax/README.md +292 -0
  93. package/library/snippets/dax/business-domains.md +576 -0
  94. package/library/snippets/dax/calculate-patterns.md +276 -0
  95. package/library/snippets/dax/calculation-groups.md +489 -0
  96. package/library/snippets/dax/error-handling.md +495 -0
  97. package/library/snippets/dax/iterators-and-aggregations.md +474 -0
  98. package/library/snippets/dax/kpis-and-metrics.md +293 -0
  99. package/library/snippets/dax/rankings-and-topn.md +235 -0
  100. package/library/snippets/dax/security-patterns.md +413 -0
  101. package/library/snippets/dax/text-and-formatting.md +316 -0
  102. package/library/snippets/dax/time-intelligence.md +196 -0
  103. package/library/snippets/dax/user-defined-functions.md +477 -0
  104. package/library/snippets/dax/virtual-tables.md +546 -0
  105. package/library/snippets/excel-formulas/README.md +84 -0
  106. package/library/snippets/excel-formulas/aggregations.md +330 -0
  107. package/library/snippets/excel-formulas/dates-and-times.md +361 -0
  108. package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
  109. package/library/snippets/excel-formulas/lookups.md +169 -0
  110. package/library/snippets/excel-formulas/text-functions.md +363 -0
  111. package/library/snippets/governance/naming-conventions.md +97 -0
  112. package/library/snippets/governance/review-checklists.md +107 -0
  113. package/library/snippets/power-query/README.md +389 -0
  114. package/library/snippets/power-query/api-integration.md +707 -0
  115. package/library/snippets/power-query/connections.md +434 -0
  116. package/library/snippets/power-query/data-cleaning.md +298 -0
  117. package/library/snippets/power-query/error-handling.md +526 -0
  118. package/library/snippets/power-query/parameters.md +350 -0
  119. package/library/snippets/power-query/performance.md +506 -0
  120. package/library/snippets/power-query/transformations.md +330 -0
  121. package/library/snippets/report-design/accessibility.md +78 -0
  122. package/library/snippets/report-design/chart-selection.md +54 -0
  123. package/library/snippets/report-design/layout-patterns.md +87 -0
  124. package/library/templates/data-models/README.md +93 -0
  125. package/library/templates/data-models/finance-model.md +627 -0
  126. package/library/templates/data-models/retail-star-schema.md +473 -0
  127. package/library/templates/excel/README.md +83 -0
  128. package/library/templates/excel/budget-tracker.md +432 -0
  129. package/library/templates/excel/data-entry-form.md +533 -0
  130. package/library/templates/power-bi/README.md +72 -0
  131. package/library/templates/power-bi/finance-report.md +449 -0
  132. package/library/templates/power-bi/kpi-scorecard.md +461 -0
  133. package/library/templates/power-bi/sales-dashboard.md +281 -0
  134. package/library/themes/excel/README.md +436 -0
  135. package/library/themes/power-bi/README.md +271 -0
  136. package/library/themes/power-bi/accessible.json +307 -0
  137. package/library/themes/power-bi/bi-superpowers-default.json +858 -0
  138. package/library/themes/power-bi/corporate-blue.json +291 -0
  139. package/library/themes/power-bi/dark-mode.json +291 -0
  140. package/library/themes/power-bi/minimal.json +292 -0
  141. package/library/themes/power-bi/print-friendly.json +309 -0
  142. package/package.json +93 -0
  143. package/skills/contributions/SKILL.md +267 -0
  144. package/skills/data-model-design/SKILL.md +470 -0
  145. package/skills/data-modeling/SKILL.md +254 -0
  146. package/skills/data-quality/SKILL.md +664 -0
  147. package/skills/dax/SKILL.md +708 -0
  148. package/skills/dax-doctor/SKILL.md +250 -0
  149. package/skills/dax-udf/SKILL.md +489 -0
  150. package/skills/deployment/SKILL.md +320 -0
  151. package/skills/excel-formulas/SKILL.md +463 -0
  152. package/skills/fabric-scripts/SKILL.md +454 -0
  153. package/skills/fast-standard/SKILL.md +509 -0
  154. package/skills/governance/SKILL.md +205 -0
  155. package/skills/migration-assistant/SKILL.md +292 -0
  156. package/skills/model-documenter/SKILL.md +244 -0
  157. package/skills/pbi-connect/SKILL.md +241 -0
  158. package/skills/power-query/SKILL.md +406 -0
  159. package/skills/project-kickoff/SKILL.md +907 -0
  160. package/skills/query-performance/SKILL.md +480 -0
  161. package/skills/report-design/SKILL.md +207 -0
  162. package/skills/report-layout/SKILL.md +298 -0
  163. package/skills/rls-design/SKILL.md +535 -0
  164. package/skills/semantic-model/SKILL.md +237 -0
  165. package/skills/testing-validation/SKILL.md +643 -0
  166. package/skills/theme-tweaker/SKILL.md +626 -0
  167. package/src/content/base.md +237 -0
  168. package/src/content/mcp-requirements.json +69 -0
  169. package/src/content/routing.md +203 -0
  170. package/src/content/skills/contributions.md +259 -0
  171. package/src/content/skills/data-model-design.md +462 -0
  172. package/src/content/skills/data-modeling.md +246 -0
  173. package/src/content/skills/data-quality.md +656 -0
  174. package/src/content/skills/dax-doctor.md +242 -0
  175. package/src/content/skills/dax-udf.md +481 -0
  176. package/src/content/skills/dax.md +700 -0
  177. package/src/content/skills/deployment.md +312 -0
  178. package/src/content/skills/excel-formulas.md +455 -0
  179. package/src/content/skills/fabric-scripts.md +446 -0
  180. package/src/content/skills/fast-standard.md +501 -0
  181. package/src/content/skills/governance.md +197 -0
  182. package/src/content/skills/migration-assistant.md +284 -0
  183. package/src/content/skills/model-documenter.md +236 -0
  184. package/src/content/skills/pbi-connect.md +233 -0
  185. package/src/content/skills/power-query.md +398 -0
  186. package/src/content/skills/project-kickoff.md +899 -0
  187. package/src/content/skills/query-performance.md +472 -0
  188. package/src/content/skills/report-design.md +199 -0
  189. package/src/content/skills/report-layout.md +290 -0
  190. package/src/content/skills/rls-design.md +527 -0
  191. package/src/content/skills/semantic-model.md +229 -0
  192. package/src/content/skills/testing-validation.md +635 -0
  193. package/src/content/skills/theme-tweaker.md +618 -0
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Logger Utility
3
+ * ===============
4
+ *
5
+ * Standardized logging for the CLI with log levels.
6
+ * Respects LOG_LEVEL environment variable.
7
+ *
8
+ * Usage:
9
+ * const logger = require('./utils/logger');
10
+ * logger.debug('Debug message', { context: 'optional' });
11
+ * logger.info('Info message');
12
+ * logger.warn('Warning message');
13
+ * logger.error('Error message');
14
+ *
15
+ * Environment:
16
+ * LOG_LEVEL=debug|info|warn|error (default: info)
17
+ * DEBUG=true (shorthand for LOG_LEVEL=debug)
18
+ *
19
+ * @module utils/logger
20
+ */
21
+
22
+ const LOG_LEVELS = {
23
+ debug: 0,
24
+ info: 1,
25
+ warn: 2,
26
+ error: 3,
27
+ silent: 4,
28
+ };
29
+
30
+ /**
31
+ * Get current log level from environment
32
+ * @returns {string} Current log level
33
+ */
34
+ function getCurrentLevel() {
35
+ if (process.env.DEBUG === 'true') {
36
+ return 'debug';
37
+ }
38
+ return process.env.LOG_LEVEL || 'info';
39
+ }
40
+
41
+ /**
42
+ * Check if a log level should be shown
43
+ * @param {string} level - Level to check
44
+ * @returns {boolean} Whether to show this level
45
+ */
46
+ function shouldLog(level) {
47
+ const currentLevel = getCurrentLevel();
48
+ return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];
49
+ }
50
+
51
+ /**
52
+ * Format a log message with optional context
53
+ * @param {string} prefix - Log level prefix
54
+ * @param {string} message - Log message
55
+ * @param {Object|null} context - Optional context object
56
+ * @returns {string} Formatted message
57
+ */
58
+ function formatMessage(prefix, message, context) {
59
+ let formatted = `[${prefix}] ${message}`;
60
+ if (context !== null && context !== undefined) {
61
+ if (typeof context === 'object') {
62
+ formatted += ` ${JSON.stringify(context)}`;
63
+ } else {
64
+ formatted += ` ${context}`;
65
+ }
66
+ }
67
+ return formatted;
68
+ }
69
+
70
+ /**
71
+ * Debug level logging
72
+ * Only shown when LOG_LEVEL=debug or DEBUG=true
73
+ * @param {string} message - Log message
74
+ * @param {Object|null} context - Optional context
75
+ */
76
+ function debug(message, context = null) {
77
+ if (shouldLog('debug')) {
78
+ console.log(formatMessage('DEBUG', message, context));
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Info level logging
84
+ * Standard informational messages
85
+ * @param {string} message - Log message
86
+ * @param {Object|null} context - Optional context
87
+ */
88
+ function info(message, context = null) {
89
+ if (shouldLog('info')) {
90
+ console.log(formatMessage('INFO', message, context));
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Warning level logging
96
+ * Non-critical issues that should be noticed
97
+ * @param {string} message - Log message
98
+ * @param {Object|null} context - Optional context
99
+ */
100
+ function warn(message, context = null) {
101
+ if (shouldLog('warn')) {
102
+ console.warn(formatMessage('WARN', message, context));
103
+ }
104
+ }
105
+
106
+ /**
107
+ * Error level logging
108
+ * Critical errors that affect operation
109
+ * @param {string} message - Log message
110
+ * @param {Object|null} context - Optional context
111
+ */
112
+ function error(message, context = null) {
113
+ if (shouldLog('error')) {
114
+ console.error(formatMessage('ERROR', message, context));
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Create a child logger with a prefix
120
+ * Useful for module-specific logging
121
+ * @param {string} prefix - Prefix for all messages
122
+ * @returns {Object} Logger instance with prefix
123
+ */
124
+ function createLogger(prefix) {
125
+ return {
126
+ debug: (msg, ctx) => debug(`[${prefix}] ${msg}`, ctx),
127
+ info: (msg, ctx) => info(`[${prefix}] ${msg}`, ctx),
128
+ warn: (msg, ctx) => warn(`[${prefix}] ${msg}`, ctx),
129
+ error: (msg, ctx) => error(`[${prefix}] ${msg}`, ctx),
130
+ };
131
+ }
132
+
133
+ module.exports = {
134
+ LOG_LEVELS,
135
+ debug,
136
+ info,
137
+ warn,
138
+ error,
139
+ createLogger,
140
+ getCurrentLevel,
141
+ shouldLog,
142
+ };
@@ -0,0 +1,274 @@
1
+ /**
2
+ * MCP Detection Utilities for BI Agent Superpowers
3
+ * =================================================
4
+ *
5
+ * Detects installed MCP servers (Microsoft Power BI Modeling MCP).
6
+ * Supports both local (VS Code extension) and remote (Fabric) MCPs.
7
+ *
8
+ * @module utils/mcp-detect
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const os = require('os');
14
+ const { spawnSync } = require('child_process');
15
+ const {
16
+ PLUGIN_ROOT_LAUNCHER_MODE,
17
+ REMOTE_POWERBI_URL,
18
+ createMcpConfigForFormat,
19
+ } = require('../lib/microsoft-mcp');
20
+
21
+ /**
22
+ * Common installation paths for the Power BI Modeling MCP
23
+ */
24
+ const EXTENSION_PATTERNS = [
25
+ // VS Code extensions folder
26
+ path.join(os.homedir(), '.vscode', 'extensions'),
27
+ // Cursor extensions folder
28
+ path.join(os.homedir(), '.cursor', 'extensions'),
29
+ // VS Code Insiders
30
+ path.join(os.homedir(), '.vscode-insiders', 'extensions'),
31
+ // Manual installation path we suggest
32
+ path.join(os.homedir(), '.bi-superpowers', 'mcp'),
33
+ ];
34
+
35
+ /**
36
+ * Extension name pattern to search for
37
+ */
38
+ const EXTENSION_NAME_PATTERN = /^analysis-services\.powerbi-modeling-mcp-/;
39
+
40
+ const MODELING_MCP_ENV_VARS = [
41
+ 'BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH',
42
+ 'POWERBI_MODELING_MCP_PATH',
43
+ 'PBI_MODELING_MCP_PATH',
44
+ ];
45
+
46
+ /**
47
+ * Resolve an explicitly configured MCP executable path, if any.
48
+ *
49
+ * @returns {string|null} Existing executable path
50
+ */
51
+ function getExplicitMcpPath() {
52
+ for (const envVar of MODELING_MCP_ENV_VARS) {
53
+ const configuredPath = process.env[envVar];
54
+ if (configuredPath && fs.existsSync(configuredPath)) {
55
+ return configuredPath;
56
+ }
57
+ }
58
+
59
+ return null;
60
+ }
61
+
62
+ /**
63
+ * Find the Power BI Modeling MCP executable
64
+ * @returns {string|null} Path to the executable or null if not found
65
+ */
66
+ function findLocalMcp() {
67
+ const explicitPath = getExplicitMcpPath();
68
+ if (explicitPath) {
69
+ return explicitPath;
70
+ }
71
+
72
+ if (os.platform() !== 'win32') {
73
+ return null;
74
+ }
75
+
76
+ for (const extensionsDir of EXTENSION_PATTERNS) {
77
+ if (!fs.existsSync(extensionsDir)) {
78
+ continue;
79
+ }
80
+
81
+ try {
82
+ const entries = fs.readdirSync(extensionsDir);
83
+
84
+ for (const entry of entries) {
85
+ if (EXTENSION_NAME_PATTERN.test(entry)) {
86
+ // Found the extension folder
87
+ const exePath = path.join(extensionsDir, entry, 'server', 'powerbi-modeling-mcp.exe');
88
+
89
+ if (fs.existsSync(exePath)) {
90
+ return exePath;
91
+ }
92
+
93
+ // Alternative path structure
94
+ const altExePath = path.join(
95
+ extensionsDir,
96
+ entry,
97
+ 'extension',
98
+ 'server',
99
+ 'powerbi-modeling-mcp.exe'
100
+ );
101
+
102
+ if (fs.existsSync(altExePath)) {
103
+ return altExePath;
104
+ }
105
+ }
106
+ }
107
+ } catch (e) {
108
+ // Ignore read errors
109
+ }
110
+ }
111
+
112
+ // Check if it's in PATH
113
+ try {
114
+ const result = spawnSync('where', ['powerbi-modeling-mcp.exe'], {
115
+ encoding: 'utf8',
116
+ shell: true,
117
+ });
118
+
119
+ if (result.status === 0 && result.stdout) {
120
+ const firstLine = result.stdout.trim().split('\n')[0];
121
+ if (firstLine && fs.existsSync(firstLine)) {
122
+ return firstLine;
123
+ }
124
+ }
125
+ } catch (e) {
126
+ // Ignore errors
127
+ }
128
+
129
+ return null;
130
+ }
131
+
132
+ /**
133
+ * Get version from MCP executable
134
+ * @param {string} exePath - Path to the executable
135
+ * @returns {string|null} Version string or null
136
+ */
137
+ function getMcpVersion(exePath) {
138
+ if (!exePath || !fs.existsSync(exePath)) {
139
+ return null;
140
+ }
141
+
142
+ try {
143
+ const result = spawnSync(exePath, ['--version'], {
144
+ encoding: 'utf8',
145
+ timeout: 5000,
146
+ });
147
+
148
+ if (result.stdout) {
149
+ const match = result.stdout.match(/\d+\.\d+\.\d+/);
150
+ return match ? match[0] : null;
151
+ }
152
+ } catch (e) {
153
+ // Ignore errors
154
+ }
155
+
156
+ // Try to extract version from path
157
+ const match = exePath.match(/powerbi-modeling-mcp-(\d+\.\d+\.\d+)/);
158
+ return match ? match[1] : null;
159
+ }
160
+
161
+ /**
162
+ * Get full MCP status
163
+ * @returns {Object} Status object with local and remote info
164
+ */
165
+ function getMcpStatus() {
166
+ const localPath = findLocalMcp();
167
+
168
+ return {
169
+ local: {
170
+ installed: !!localPath,
171
+ path: localPath,
172
+ version: getMcpVersion(localPath),
173
+ platform: os.platform(),
174
+ available: os.platform() === 'win32',
175
+ envVars: MODELING_MCP_ENV_VARS,
176
+ },
177
+ remote: {
178
+ available: true, // Always available (requires auth)
179
+ url: REMOTE_POWERBI_URL,
180
+ requiresAuth: true,
181
+ description: 'Power BI Remote MCP (Fabric)',
182
+ },
183
+ fabric: {
184
+ available: true,
185
+ package: '@microsoft/fabric-mcp@latest',
186
+ description: 'Microsoft Fabric MCP Server',
187
+ },
188
+ };
189
+ }
190
+
191
+ /**
192
+ * Get installation instructions for local MCP
193
+ * @returns {Object} Installation instructions
194
+ */
195
+ function getInstallInstructions() {
196
+ return {
197
+ title: 'Power BI Modeling MCP no detectado',
198
+ options: [
199
+ {
200
+ name: 'VS Code / Cursor',
201
+ steps: [
202
+ 'Abrir VS Code o Cursor',
203
+ 'Ir a Extensions (Ctrl+Shift+X)',
204
+ 'Buscar "Power BI Modeling MCP"',
205
+ 'Instalar la extensión de Microsoft',
206
+ 'Ejecutar: super mcp-setup',
207
+ ],
208
+ link: 'https://aka.ms/powerbi-modeling-mcp-vscode',
209
+ },
210
+ {
211
+ name: 'Manual',
212
+ steps: [
213
+ 'Descargar VSIX desde VS Code Marketplace',
214
+ 'Renombrar .vsix a .zip',
215
+ `Extraer a ${path.join(os.homedir(), '.bi-superpowers', 'mcp')}`,
216
+ 'Configurar BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH con la ruta al .exe',
217
+ ],
218
+ link: 'https://marketplace.visualstudio.com/items?itemName=analysis-services.powerbi-modeling-mcp',
219
+ },
220
+ ],
221
+ note:
222
+ os.platform() !== 'win32'
223
+ ? 'El MCP local solo está disponible en Windows. Puedes usar el MCP Remoto de Fabric en Mac/Linux.'
224
+ : null,
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Build an actionable error for environments where the local Modeling MCP
230
+ * executable isn't available.
231
+ *
232
+ * @returns {string} Human-friendly error message
233
+ */
234
+ function getModelingMcpError() {
235
+ if (os.platform() !== 'win32') {
236
+ return [
237
+ 'Power BI Modeling MCP is only available on Windows.',
238
+ 'You can still use the official powerbi-remote and fabric-mcp-server entries on macOS/Linux.',
239
+ 'If you are on Windows and extracted the server manually, set BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH.',
240
+ ].join('\n');
241
+ }
242
+
243
+ return [
244
+ 'Unable to locate the official Microsoft Power BI Modeling MCP executable.',
245
+ 'Install the "Power BI Modeling MCP" extension in VS Code or Cursor, or set BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH to powerbi-modeling-mcp.exe.',
246
+ ].join('\n');
247
+ }
248
+
249
+ /**
250
+ * Backward-compatible config generator retained for legacy callers/tests.
251
+ *
252
+ * @param {Object} _status - Unused, kept for compatibility
253
+ * @param {string} format - Config format (cursor, claude, vscode, etc.)
254
+ * @param {Object} [options] - Additional generation options
255
+ * @returns {Object} Configuration object
256
+ */
257
+ function generateMcpConfig(_status, format, options = {}) {
258
+ return createMcpConfigForFormat(format, {
259
+ packageDir: options.packageDir,
260
+ launcherMode: options.launcherMode || PLUGIN_ROOT_LAUNCHER_MODE,
261
+ });
262
+ }
263
+
264
+ module.exports = {
265
+ findLocalMcp,
266
+ getMcpVersion,
267
+ getMcpStatus,
268
+ getInstallInstructions,
269
+ generateMcpConfig,
270
+ getExplicitMcpPath,
271
+ getModelingMcpError,
272
+ MODELING_MCP_ENV_VARS,
273
+ REMOTE_POWERBI_URL,
274
+ };
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Tests for MCP Detection Utilities
3
+ * @module utils/mcp-detect.test
4
+ */
5
+
6
+ const { test, describe } = require('node:test');
7
+ const assert = require('node:assert');
8
+
9
+ const mcpDetect = require('./mcp-detect');
10
+
11
+ describe('MCP Detection Utilities', () => {
12
+ test('exports expected functions', () => {
13
+ assert.strictEqual(typeof mcpDetect.findLocalMcp, 'function');
14
+ assert.strictEqual(typeof mcpDetect.getMcpVersion, 'function');
15
+ assert.strictEqual(typeof mcpDetect.getMcpStatus, 'function');
16
+ assert.strictEqual(typeof mcpDetect.getInstallInstructions, 'function');
17
+ assert.strictEqual(typeof mcpDetect.generateMcpConfig, 'function');
18
+ assert.strictEqual(typeof mcpDetect.getExplicitMcpPath, 'function');
19
+ assert.strictEqual(typeof mcpDetect.getModelingMcpError, 'function');
20
+ });
21
+
22
+ test('exports official remote url and env vars', () => {
23
+ assert.strictEqual(typeof mcpDetect.REMOTE_POWERBI_URL, 'string');
24
+ assert.strictEqual(
25
+ mcpDetect.REMOTE_POWERBI_URL,
26
+ 'https://api.fabric.microsoft.com/v1/mcp/powerbi'
27
+ );
28
+ assert.ok(Array.isArray(mcpDetect.MODELING_MCP_ENV_VARS));
29
+ assert.ok(mcpDetect.MODELING_MCP_ENV_VARS.includes('BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH'));
30
+ });
31
+ });
32
+
33
+ describe('getMcpStatus', () => {
34
+ test('returns expected structure', () => {
35
+ const status = mcpDetect.getMcpStatus();
36
+
37
+ assert.ok(status.local);
38
+ assert.ok(status.remote);
39
+ assert.ok(status.fabric);
40
+
41
+ assert.ok('installed' in status.local);
42
+ assert.ok('path' in status.local);
43
+ assert.ok('version' in status.local);
44
+ assert.ok('platform' in status.local);
45
+ assert.ok('available' in status.local);
46
+ assert.ok(Array.isArray(status.local.envVars));
47
+
48
+ assert.strictEqual(status.remote.available, true);
49
+ assert.strictEqual(status.remote.url, mcpDetect.REMOTE_POWERBI_URL);
50
+ assert.strictEqual(status.remote.requiresAuth, true);
51
+
52
+ assert.strictEqual(status.fabric.available, true);
53
+ assert.strictEqual(status.fabric.package, '@microsoft/fabric-mcp@latest');
54
+ });
55
+ });
56
+
57
+ describe('getInstallInstructions', () => {
58
+ test('returns expected structure', () => {
59
+ const instructions = mcpDetect.getInstallInstructions();
60
+
61
+ assert.ok(instructions.title);
62
+ assert.ok(Array.isArray(instructions.options));
63
+ assert.ok(instructions.options.length > 0);
64
+
65
+ instructions.options.forEach((option) => {
66
+ assert.ok(option.name);
67
+ assert.ok(Array.isArray(option.steps));
68
+ assert.ok(option.link);
69
+ });
70
+ });
71
+ });
72
+
73
+ describe('generateMcpConfig', () => {
74
+ test('generates plugin format with official Microsoft MCPs', () => {
75
+ const config = mcpDetect.generateMcpConfig({}, 'plugin');
76
+
77
+ assert.ok(config['powerbi-remote']);
78
+ assert.ok(config['fabric-mcp-server']);
79
+ assert.ok(config['powerbi-modeling-mcp']);
80
+
81
+ assert.strictEqual(config['powerbi-remote'].type, 'http');
82
+ assert.strictEqual(config['powerbi-remote'].url, mcpDetect.REMOTE_POWERBI_URL);
83
+ assert.strictEqual(config['fabric-mcp-server'].command, 'npx');
84
+ assert.deepStrictEqual(config['fabric-mcp-server'].args, [
85
+ '-y',
86
+ '@microsoft/fabric-mcp@latest',
87
+ 'server',
88
+ 'start',
89
+ '--mode',
90
+ 'all',
91
+ ]);
92
+ assert.strictEqual(config['powerbi-modeling-mcp'].type, 'stdio');
93
+ assert.strictEqual(config['powerbi-modeling-mcp'].command, 'node');
94
+ assert.ok(config['powerbi-modeling-mcp'].args[0].includes('powerbi-modeling-launcher.js'));
95
+ });
96
+
97
+ test('generates claude format with nested mcpServers object', () => {
98
+ const config = mcpDetect.generateMcpConfig({}, 'claude');
99
+
100
+ assert.ok(config.mcpServers);
101
+ assert.ok(config.mcpServers['powerbi-remote']);
102
+ assert.ok(config.mcpServers['fabric-mcp-server']);
103
+ assert.ok(config.mcpServers['powerbi-modeling-mcp']);
104
+ });
105
+ });