@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.
- package/.claude-plugin/plugin.json +8 -0
- package/.mcp.json +25 -0
- package/AGENTS.md +244 -0
- package/CHANGELOG.md +265 -0
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/bin/build-plugin.js +30 -0
- package/bin/cli.js +1064 -0
- package/bin/commands/add.js +533 -0
- package/bin/commands/add.test.js +77 -0
- package/bin/commands/build-desktop.js +166 -0
- package/bin/commands/changelog.js +443 -0
- package/bin/commands/diff.js +325 -0
- package/bin/commands/lint.js +419 -0
- package/bin/commands/lint.test.js +103 -0
- package/bin/commands/mcp-setup.js +246 -0
- package/bin/commands/pull.js +287 -0
- package/bin/commands/pull.test.js +36 -0
- package/bin/commands/push.js +231 -0
- package/bin/commands/push.test.js +14 -0
- package/bin/commands/search.js +344 -0
- package/bin/commands/search.test.js +115 -0
- package/bin/commands/setup.js +545 -0
- package/bin/commands/setup.test.js +46 -0
- package/bin/commands/sync-profile.js +405 -0
- package/bin/commands/sync-profile.test.js +14 -0
- package/bin/commands/sync-source.js +418 -0
- package/bin/commands/sync-source.test.js +14 -0
- package/bin/commands/watch.js +206 -0
- package/bin/lib/generators/claude-plugin.js +266 -0
- package/bin/lib/generators/claude-plugin.test.js +110 -0
- package/bin/lib/generators/index.js +116 -0
- package/bin/lib/generators/shared.js +282 -0
- package/bin/lib/licensing/index.js +35 -0
- package/bin/lib/licensing/storage.js +364 -0
- package/bin/lib/licensing/storage.test.js +55 -0
- package/bin/lib/licensing/validator.js +213 -0
- package/bin/lib/licensing/validator.test.js +137 -0
- package/bin/lib/microsoft-mcp.js +176 -0
- package/bin/lib/microsoft-mcp.test.js +106 -0
- package/bin/lib/skills.js +84 -0
- package/bin/mcp/powerbi-modeling-launcher.js +38 -0
- package/bin/postinstall.js +44 -0
- package/bin/utils/errors.js +159 -0
- package/bin/utils/git.js +298 -0
- package/bin/utils/logger.js +142 -0
- package/bin/utils/mcp-detect.js +274 -0
- package/bin/utils/mcp-detect.test.js +105 -0
- package/bin/utils/pbix.js +305 -0
- package/bin/utils/pbix.test.js +37 -0
- package/bin/utils/profiles.js +312 -0
- package/bin/utils/projects.js +168 -0
- package/bin/utils/readline.js +206 -0
- package/bin/utils/readline.test.js +47 -0
- package/bin/utils/tui.js +314 -0
- package/bin/utils/tui.test.js +127 -0
- package/commands/contributions.md +265 -0
- package/commands/data-model-design.md +468 -0
- package/commands/dax-doctor.md +248 -0
- package/commands/fabric-scripts.md +452 -0
- package/commands/migration-assistant.md +290 -0
- package/commands/model-documenter.md +242 -0
- package/commands/pbi-connect.md +239 -0
- package/commands/project-kickoff.md +905 -0
- package/commands/report-layout.md +296 -0
- package/commands/rls-design.md +533 -0
- package/commands/theme-tweaker.md +624 -0
- package/config.example.json +23 -0
- package/config.json +23 -0
- package/desktop-extension/manifest.json +37 -0
- package/desktop-extension/package.json +10 -0
- package/desktop-extension/server.js +95 -0
- package/docs/openrouter-free-models.md +92 -0
- package/library/examples/README.md +151 -0
- package/library/examples/finance-reporting/README.md +351 -0
- package/library/examples/finance-reporting/data-model.md +267 -0
- package/library/examples/finance-reporting/measures.dax +557 -0
- package/library/examples/hr-analytics/README.md +371 -0
- package/library/examples/hr-analytics/data-model.md +315 -0
- package/library/examples/hr-analytics/measures.dax +460 -0
- package/library/examples/marketing-analytics/README.md +37 -0
- package/library/examples/marketing-analytics/data-model.md +62 -0
- package/library/examples/marketing-analytics/measures.dax +110 -0
- package/library/examples/retail-analytics/README.md +439 -0
- package/library/examples/retail-analytics/data-model.md +288 -0
- package/library/examples/retail-analytics/measures.dax +481 -0
- package/library/examples/supply-chain/README.md +37 -0
- package/library/examples/supply-chain/data-model.md +69 -0
- package/library/examples/supply-chain/measures.dax +77 -0
- package/library/examples/udf-library/README.md +228 -0
- package/library/examples/udf-library/functions.dax +571 -0
- package/library/snippets/dax/README.md +292 -0
- package/library/snippets/dax/business-domains.md +576 -0
- package/library/snippets/dax/calculate-patterns.md +276 -0
- package/library/snippets/dax/calculation-groups.md +489 -0
- package/library/snippets/dax/error-handling.md +495 -0
- package/library/snippets/dax/iterators-and-aggregations.md +474 -0
- package/library/snippets/dax/kpis-and-metrics.md +293 -0
- package/library/snippets/dax/rankings-and-topn.md +235 -0
- package/library/snippets/dax/security-patterns.md +413 -0
- package/library/snippets/dax/text-and-formatting.md +316 -0
- package/library/snippets/dax/time-intelligence.md +196 -0
- package/library/snippets/dax/user-defined-functions.md +477 -0
- package/library/snippets/dax/virtual-tables.md +546 -0
- package/library/snippets/excel-formulas/README.md +84 -0
- package/library/snippets/excel-formulas/aggregations.md +330 -0
- package/library/snippets/excel-formulas/dates-and-times.md +361 -0
- package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
- package/library/snippets/excel-formulas/lookups.md +169 -0
- package/library/snippets/excel-formulas/text-functions.md +363 -0
- package/library/snippets/governance/naming-conventions.md +97 -0
- package/library/snippets/governance/review-checklists.md +107 -0
- package/library/snippets/power-query/README.md +389 -0
- package/library/snippets/power-query/api-integration.md +707 -0
- package/library/snippets/power-query/connections.md +434 -0
- package/library/snippets/power-query/data-cleaning.md +298 -0
- package/library/snippets/power-query/error-handling.md +526 -0
- package/library/snippets/power-query/parameters.md +350 -0
- package/library/snippets/power-query/performance.md +506 -0
- package/library/snippets/power-query/transformations.md +330 -0
- package/library/snippets/report-design/accessibility.md +78 -0
- package/library/snippets/report-design/chart-selection.md +54 -0
- package/library/snippets/report-design/layout-patterns.md +87 -0
- package/library/templates/data-models/README.md +93 -0
- package/library/templates/data-models/finance-model.md +627 -0
- package/library/templates/data-models/retail-star-schema.md +473 -0
- package/library/templates/excel/README.md +83 -0
- package/library/templates/excel/budget-tracker.md +432 -0
- package/library/templates/excel/data-entry-form.md +533 -0
- package/library/templates/power-bi/README.md +72 -0
- package/library/templates/power-bi/finance-report.md +449 -0
- package/library/templates/power-bi/kpi-scorecard.md +461 -0
- package/library/templates/power-bi/sales-dashboard.md +281 -0
- package/library/themes/excel/README.md +436 -0
- package/library/themes/power-bi/README.md +271 -0
- package/library/themes/power-bi/accessible.json +307 -0
- package/library/themes/power-bi/bi-superpowers-default.json +858 -0
- package/library/themes/power-bi/corporate-blue.json +291 -0
- package/library/themes/power-bi/dark-mode.json +291 -0
- package/library/themes/power-bi/minimal.json +292 -0
- package/library/themes/power-bi/print-friendly.json +309 -0
- package/package.json +93 -0
- package/skills/contributions/SKILL.md +267 -0
- package/skills/data-model-design/SKILL.md +470 -0
- package/skills/data-modeling/SKILL.md +254 -0
- package/skills/data-quality/SKILL.md +664 -0
- package/skills/dax/SKILL.md +708 -0
- package/skills/dax-doctor/SKILL.md +250 -0
- package/skills/dax-udf/SKILL.md +489 -0
- package/skills/deployment/SKILL.md +320 -0
- package/skills/excel-formulas/SKILL.md +463 -0
- package/skills/fabric-scripts/SKILL.md +454 -0
- package/skills/fast-standard/SKILL.md +509 -0
- package/skills/governance/SKILL.md +205 -0
- package/skills/migration-assistant/SKILL.md +292 -0
- package/skills/model-documenter/SKILL.md +244 -0
- package/skills/pbi-connect/SKILL.md +241 -0
- package/skills/power-query/SKILL.md +406 -0
- package/skills/project-kickoff/SKILL.md +907 -0
- package/skills/query-performance/SKILL.md +480 -0
- package/skills/report-design/SKILL.md +207 -0
- package/skills/report-layout/SKILL.md +298 -0
- package/skills/rls-design/SKILL.md +535 -0
- package/skills/semantic-model/SKILL.md +237 -0
- package/skills/testing-validation/SKILL.md +643 -0
- package/skills/theme-tweaker/SKILL.md +626 -0
- package/src/content/base.md +237 -0
- package/src/content/mcp-requirements.json +69 -0
- package/src/content/routing.md +203 -0
- package/src/content/skills/contributions.md +259 -0
- package/src/content/skills/data-model-design.md +462 -0
- package/src/content/skills/data-modeling.md +246 -0
- package/src/content/skills/data-quality.md +656 -0
- package/src/content/skills/dax-doctor.md +242 -0
- package/src/content/skills/dax-udf.md +481 -0
- package/src/content/skills/dax.md +700 -0
- package/src/content/skills/deployment.md +312 -0
- package/src/content/skills/excel-formulas.md +455 -0
- package/src/content/skills/fabric-scripts.md +446 -0
- package/src/content/skills/fast-standard.md +501 -0
- package/src/content/skills/governance.md +197 -0
- package/src/content/skills/migration-assistant.md +284 -0
- package/src/content/skills/model-documenter.md +236 -0
- package/src/content/skills/pbi-connect.md +233 -0
- package/src/content/skills/power-query.md +398 -0
- package/src/content/skills/project-kickoff.md +899 -0
- package/src/content/skills/query-performance.md +472 -0
- package/src/content/skills/report-design.md +199 -0
- package/src/content/skills/report-layout.md +290 -0
- package/src/content/skills/rls-design.md +527 -0
- package/src/content/skills/semantic-model.md +229 -0
- package/src/content/skills/testing-validation.md +635 -0
- 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
|
+
});
|