@luquimbo/bi-superpowers 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/.claude-plugin/skill-manifest.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/README.md +19 -0
- package/bin/commands/install.js +39 -18
- package/bin/lib/generators/claude-plugin.js +10 -5
- package/bin/lib/mcp-config.js +103 -82
- package/bin/lib/mcp-config.test.js +37 -0
- package/package.json +1 -1
- package/skills/pbi-connect/SKILL.md +1 -1
- package/skills/project-kickoff/SKILL.md +1 -1
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
"url": "https://github.com/luquimbo"
|
|
6
6
|
},
|
|
7
7
|
"metadata": {
|
|
8
|
-
"description": "AI-powered skills for Power BI
|
|
9
|
-
"version": "3.0
|
|
8
|
+
"description": "AI-powered skills for Power BI Desktop development. Works with Claude Code, GitHub Copilot, Codex, Gemini CLI, and Kilo Code.",
|
|
9
|
+
"version": "3.1.0",
|
|
10
10
|
"repository": "https://github.com/luquimbo/bi-superpowers"
|
|
11
11
|
},
|
|
12
12
|
"plugins": [
|
|
13
13
|
{
|
|
14
14
|
"name": "bi-superpowers",
|
|
15
|
-
"description": "
|
|
15
|
+
"description": "2 AI skills + Power BI Modeling and Microsoft Learn MCP servers for local Power BI Desktop workflows across 5 AI agents.",
|
|
16
16
|
"source": "./",
|
|
17
17
|
"strict": false,
|
|
18
18
|
"skills": [
|
package/.plugin/plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"spec": "open-plugin-spec@1",
|
|
3
3
|
"name": "bi-superpowers",
|
|
4
|
-
"version": "3.0
|
|
4
|
+
"version": "3.1.0",
|
|
5
5
|
"description": "Claude Code plugin for Power BI, Microsoft Fabric, and semantic model workflows powered by the official Microsoft MCP servers.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Lucas Sanchez"
|
package/README.md
CHANGED
|
@@ -89,6 +89,25 @@ super install --all --yes
|
|
|
89
89
|
|
|
90
90
|
---
|
|
91
91
|
|
|
92
|
+
## Alternativas para instalar los MCPs
|
|
93
|
+
|
|
94
|
+
`super install` escribe automáticamente los 2 MCPs en el config file de cada agente. Pero hay otras formas de instalar los mismos MCPs — cualquiera de estas funciona igual de bien:
|
|
95
|
+
|
|
96
|
+
### Para Power BI Modeling MCP (local)
|
|
97
|
+
|
|
98
|
+
- **Extensión de VS Code** — Microsoft publica "Power BI Modeling MCP" en el VS Code Marketplace. Si la instalás, VS Code + Copilot lo descubren automáticamente sin tocar archivos de config.
|
|
99
|
+
- **Extensión de Cursor** — misma extensión, Cursor la detecta.
|
|
100
|
+
- **Manual** — descargá el binario `.exe` y configurá `BI_SUPERPOWERS_POWERBI_MODELING_MCP_PATH` apuntando al ejecutable.
|
|
101
|
+
|
|
102
|
+
### Para Microsoft Learn MCP (HTTP)
|
|
103
|
+
|
|
104
|
+
- **MCP marketplace oficial de Anthropic** — en Claude Code se puede hacer `/plugin marketplace add anthropic/mcp-registry` y después `/plugin install microsoft-learn` (según disponibilidad).
|
|
105
|
+
- **Agregarlo a mano** en el config file del agente con la URL `https://learn.microsoft.com/api/mcp`.
|
|
106
|
+
|
|
107
|
+
Si ya instalaste los MCPs por alguno de estos caminos, no necesitás correr `super install` — o, si lo corrés, los configs se mergean sin conflicto (cada agente tiene merge por clave, no por overwrite).
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
92
111
|
## Requisitos
|
|
93
112
|
|
|
94
113
|
- **Node.js ≥ 18**
|
package/bin/commands/install.js
CHANGED
|
@@ -276,6 +276,44 @@ function performInstall(skillsSourceDir, skillDirs, selectedAgents, baseDir) {
|
|
|
276
276
|
return { agentResults, copyFallbacks };
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
/**
|
|
280
|
+
* Configura los 2 MCP servers (powerbi-modeling + microsoft-learn)
|
|
281
|
+
* para cada agente seleccionado escribiendo el config file en el path
|
|
282
|
+
* y formato que cada agente espera.
|
|
283
|
+
*
|
|
284
|
+
* Los errores por agente no interrumpen el flujo: se recolectan en los
|
|
285
|
+
* resultados para mostrarlos al final y que el caller decida qué hacer
|
|
286
|
+
* con el exit code.
|
|
287
|
+
*
|
|
288
|
+
* @param {string[]} selectedAgents - IDs de agentes seleccionados
|
|
289
|
+
* @param {string} packageDir - Absolute path al paquete instalado
|
|
290
|
+
* @param {string} baseDir - Home directory del usuario (para display)
|
|
291
|
+
* @param {Object} chalk - chalk instance para colorear output
|
|
292
|
+
* @returns {Array<{agent: string, success: boolean, configPath?: string, error?: string}>}
|
|
293
|
+
*/
|
|
294
|
+
function configureMcpsForAgents(selectedAgents, packageDir, baseDir, chalk) {
|
|
295
|
+
console.log(
|
|
296
|
+
chalk.cyan('\n Configurando MCP servers (Power BI Modeling + Microsoft Learn)...\n')
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const results = [];
|
|
300
|
+
for (const agentId of selectedAgents) {
|
|
301
|
+
const agent = AGENTS[agentId];
|
|
302
|
+
try {
|
|
303
|
+
const configPath = writeMcpConfigForAgent(agentId, packageDir);
|
|
304
|
+
if (configPath) {
|
|
305
|
+
const relPath = configPath.replace(baseDir, '~');
|
|
306
|
+
console.log(chalk.green(` ✓ ${relPath} — ${agent.name}`));
|
|
307
|
+
results.push({ agent: agent.name, configPath, success: true });
|
|
308
|
+
}
|
|
309
|
+
} catch (err) {
|
|
310
|
+
console.log(chalk.red(` ✗ ${agent.name}: ${err.message}`));
|
|
311
|
+
results.push({ agent: agent.name, success: false, error: err.message });
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
return results;
|
|
315
|
+
}
|
|
316
|
+
|
|
279
317
|
/**
|
|
280
318
|
* Handler principal del comando install.
|
|
281
319
|
* @param {string[]} args - Argumentos CLI
|
|
@@ -386,24 +424,7 @@ async function installCommand(args, config) {
|
|
|
386
424
|
}
|
|
387
425
|
|
|
388
426
|
// Configurar MCPs para cada agente seleccionado
|
|
389
|
-
|
|
390
|
-
chalk.cyan('\n Configurando MCP servers (Power BI Modeling + Microsoft Learn)...\n')
|
|
391
|
-
);
|
|
392
|
-
const mcpResults = [];
|
|
393
|
-
for (const agentId of selectedAgents) {
|
|
394
|
-
const agent = AGENTS[agentId];
|
|
395
|
-
try {
|
|
396
|
-
const configPath = writeMcpConfigForAgent(agentId, packageDir);
|
|
397
|
-
if (configPath) {
|
|
398
|
-
const relPath = configPath.replace(baseDir, '~');
|
|
399
|
-
console.log(chalk.green(` ✓ ${relPath} — ${agent.name}`));
|
|
400
|
-
mcpResults.push({ agent: agent.name, configPath, success: true });
|
|
401
|
-
}
|
|
402
|
-
} catch (err) {
|
|
403
|
-
console.log(chalk.red(` ✗ ${agent.name}: ${err.message}`));
|
|
404
|
-
mcpResults.push({ agent: agent.name, success: false, error: err.message });
|
|
405
|
-
}
|
|
406
|
-
}
|
|
427
|
+
const mcpResults = configureMcpsForAgents(selectedAgents, packageDir, baseDir, chalk);
|
|
407
428
|
|
|
408
429
|
// Resumen
|
|
409
430
|
const totalAgents = agentResults.length + (universalAgents.length > 0 ? 1 : 0);
|
|
@@ -193,7 +193,14 @@ async function generate(targetDir, skills, options = {}) {
|
|
|
193
193
|
JSON.stringify(pluginManifest, null, 2) + '\n'
|
|
194
194
|
);
|
|
195
195
|
|
|
196
|
-
// Generate marketplace.json with all skills listed and synced version
|
|
196
|
+
// Generate marketplace.json with all skills listed and synced version.
|
|
197
|
+
// The descriptions are derived from the actual skill count so they never
|
|
198
|
+
// drift out of sync with the real plugin contents.
|
|
199
|
+
const skillCount = skills.length;
|
|
200
|
+
const skillsPlural = skillCount === 1 ? 'skill' : 'skills';
|
|
201
|
+
const metadataDescription = `AI-powered ${skillsPlural} for Power BI Desktop development. Works with Claude Code, GitHub Copilot, Codex, Gemini CLI, and Kilo Code.`;
|
|
202
|
+
const pluginDescription = `${skillCount} AI ${skillsPlural} + Power BI Modeling and Microsoft Learn MCP servers for local Power BI Desktop workflows across 5 AI agents.`;
|
|
203
|
+
|
|
197
204
|
const marketplaceManifest = {
|
|
198
205
|
name: 'bi-superpowers',
|
|
199
206
|
owner: {
|
|
@@ -201,16 +208,14 @@ async function generate(targetDir, skills, options = {}) {
|
|
|
201
208
|
url: 'https://github.com/luquimbo',
|
|
202
209
|
},
|
|
203
210
|
metadata: {
|
|
204
|
-
description:
|
|
205
|
-
'AI-powered skills for Power BI, Microsoft Fabric, and Excel development. 24 skills covering DAX, Power Query, data modeling, report design, governance, and more.',
|
|
211
|
+
description: metadataDescription,
|
|
206
212
|
version,
|
|
207
213
|
repository: 'https://github.com/luquimbo/bi-superpowers',
|
|
208
214
|
},
|
|
209
215
|
plugins: [
|
|
210
216
|
{
|
|
211
217
|
name: 'bi-superpowers',
|
|
212
|
-
description:
|
|
213
|
-
'24 AI skills for Power BI, Fabric & Excel — DAX, Power Query, data modeling, star schema design, report design, governance, deployment, and more.',
|
|
218
|
+
description: pluginDescription,
|
|
214
219
|
source: './',
|
|
215
220
|
strict: false,
|
|
216
221
|
skills: skills.map((skill) => `./skills/${skill.name}`).sort(),
|
package/bin/lib/mcp-config.js
CHANGED
|
@@ -111,50 +111,113 @@ function escapeRegex(str) {
|
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
// ============================================
|
|
114
|
-
//
|
|
114
|
+
// JSON AGENT CONFIGURATIONS
|
|
115
115
|
// ============================================
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
116
|
+
// The 4 JSON-based agents (Claude Code, GitHub Copilot, Gemini CLI,
|
|
117
|
+
// Kilo Code) all follow the same pattern: read existing JSON, merge
|
|
118
|
+
// our 2 servers into a wrapper key, write back. Each agent differs
|
|
119
|
+
// only in:
|
|
120
|
+
// - The config file path
|
|
121
|
+
// - The wrapper key (`mcpServers` vs `servers`)
|
|
122
|
+
// - Whether the stdio entry needs an explicit `type` field
|
|
123
|
+
// - The HTTP URL field name (`url` vs `httpUrl`)
|
|
124
|
+
//
|
|
125
|
+
// We describe each agent in a single table and build the writer functions
|
|
126
|
+
// from it so adding a new JSON agent is a one-line change.
|
|
122
127
|
|
|
123
|
-
|
|
128
|
+
const JSON_AGENT_CONFIGS = {
|
|
129
|
+
'claude-code': {
|
|
130
|
+
// Claude Code user-scope MCP config lives in ~/.claude.json under
|
|
131
|
+
// mcpServers. stdio entries omit `type`, HTTP entries include it.
|
|
132
|
+
configPath: () => path.join(os.homedir(), '.claude.json'),
|
|
133
|
+
wrapperKey: 'mcpServers',
|
|
134
|
+
stdioIncludesType: false,
|
|
135
|
+
httpIncludesType: true,
|
|
136
|
+
httpField: 'url',
|
|
137
|
+
},
|
|
138
|
+
'github-copilot': {
|
|
139
|
+
// Copilot CLI uses `servers` (NOT mcpServers) and every server needs
|
|
140
|
+
// an explicit `type` field.
|
|
141
|
+
configPath: () => path.join(os.homedir(), '.copilot', 'mcp-config.json'),
|
|
142
|
+
wrapperKey: 'servers',
|
|
143
|
+
stdioIncludesType: true,
|
|
144
|
+
httpIncludesType: true,
|
|
145
|
+
httpField: 'url',
|
|
146
|
+
},
|
|
147
|
+
'gemini-cli': {
|
|
148
|
+
// Gemini uses `httpUrl` (NOT `url`) for HTTP transports and omits
|
|
149
|
+
// `type` — it's inferred from which key is present.
|
|
150
|
+
configPath: () => path.join(os.homedir(), '.gemini', 'settings.json'),
|
|
151
|
+
wrapperKey: 'mcpServers',
|
|
152
|
+
stdioIncludesType: false,
|
|
153
|
+
httpIncludesType: false,
|
|
154
|
+
httpField: 'httpUrl',
|
|
155
|
+
},
|
|
156
|
+
kilo: {
|
|
157
|
+
// Kilo uses the canonical `mcpServers` with `url` for HTTP.
|
|
158
|
+
configPath: () => path.join(os.homedir(), '.kilocode', 'mcp_settings.json'),
|
|
159
|
+
wrapperKey: 'mcpServers',
|
|
160
|
+
stdioIncludesType: false,
|
|
161
|
+
httpIncludesType: false,
|
|
162
|
+
httpField: 'url',
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Build the two-server JSON payload for a JSON-format agent.
|
|
168
|
+
* Each agent differs in whether it wants `type` fields and which key
|
|
169
|
+
* holds the HTTP URL (`url` vs `httpUrl`).
|
|
170
|
+
*
|
|
171
|
+
* @param {Object} agentConfig - Descriptor from JSON_AGENT_CONFIGS
|
|
172
|
+
* @param {string} packageDir - Absolute path to the installed package
|
|
173
|
+
* @returns {Object} Map of server name → server config
|
|
174
|
+
*/
|
|
175
|
+
function buildJsonServers(agentConfig, packageDir) {
|
|
176
|
+
// Modeling (stdio local launcher)
|
|
177
|
+
const modelingEntry = {
|
|
124
178
|
command: 'node',
|
|
125
179
|
args: [getLauncherAbsolutePath(packageDir)],
|
|
126
180
|
};
|
|
127
|
-
|
|
128
|
-
type
|
|
129
|
-
|
|
130
|
-
|
|
181
|
+
if (agentConfig.stdioIncludesType) {
|
|
182
|
+
// Put type first for readability
|
|
183
|
+
const { command, args } = modelingEntry;
|
|
184
|
+
Object.keys(modelingEntry).forEach((k) => delete modelingEntry[k]);
|
|
185
|
+
modelingEntry.type = 'stdio';
|
|
186
|
+
modelingEntry.command = command;
|
|
187
|
+
modelingEntry.args = args;
|
|
188
|
+
}
|
|
131
189
|
|
|
132
|
-
|
|
133
|
-
|
|
190
|
+
// Microsoft Learn (HTTP)
|
|
191
|
+
const learnEntry = {};
|
|
192
|
+
if (agentConfig.httpIncludesType) {
|
|
193
|
+
learnEntry.type = 'http';
|
|
194
|
+
}
|
|
195
|
+
learnEntry[agentConfig.httpField] = MICROSOFT_LEARN_URL;
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
[MODELING_SERVER_NAME]: modelingEntry,
|
|
199
|
+
[LEARN_SERVER_NAME]: learnEntry,
|
|
200
|
+
};
|
|
134
201
|
}
|
|
135
202
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
function
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
203
|
+
/**
|
|
204
|
+
* Create a writer function for a JSON-format agent.
|
|
205
|
+
* The returned function reads the existing config (if any), merges in
|
|
206
|
+
* our 2 servers, and writes back, preserving all other fields.
|
|
207
|
+
*/
|
|
208
|
+
function makeJsonWriter(agentId) {
|
|
209
|
+
const agentConfig = JSON_AGENT_CONFIGS[agentId];
|
|
210
|
+
return function jsonWriter(packageDir) {
|
|
211
|
+
const configPath = agentConfig.configPath();
|
|
212
|
+
const existing = readJsonSafe(configPath) || {};
|
|
213
|
+
const wrapperKey = agentConfig.wrapperKey;
|
|
145
214
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
command: 'node',
|
|
149
|
-
args: [getLauncherAbsolutePath(packageDir)],
|
|
150
|
-
};
|
|
151
|
-
servers[LEARN_SERVER_NAME] = {
|
|
152
|
-
type: 'http',
|
|
153
|
-
url: MICROSOFT_LEARN_URL,
|
|
154
|
-
};
|
|
215
|
+
const newServers = buildJsonServers(agentConfig, packageDir);
|
|
216
|
+
const mergedServers = { ...(existing[wrapperKey] || {}), ...newServers };
|
|
155
217
|
|
|
156
|
-
|
|
157
|
-
|
|
218
|
+
writeJson(configPath, { ...existing, [wrapperKey]: mergedServers });
|
|
219
|
+
return configPath;
|
|
220
|
+
};
|
|
158
221
|
}
|
|
159
222
|
|
|
160
223
|
// ============================================
|
|
@@ -201,59 +264,17 @@ function writeCodexConfig(packageDir) {
|
|
|
201
264
|
return configPath;
|
|
202
265
|
}
|
|
203
266
|
|
|
204
|
-
// ============================================
|
|
205
|
-
// GEMINI CLI
|
|
206
|
-
// ============================================
|
|
207
|
-
// Writes ~/.gemini/settings.json. Gemini uses `mcpServers` and `httpUrl`
|
|
208
|
-
// (not `url`) for HTTP transports.
|
|
209
|
-
function writeGeminiConfig(packageDir) {
|
|
210
|
-
const configPath = path.join(os.homedir(), '.gemini', 'settings.json');
|
|
211
|
-
const existing = readJsonSafe(configPath) || {};
|
|
212
|
-
const mcpServers = { ...(existing.mcpServers || {}) };
|
|
213
|
-
|
|
214
|
-
mcpServers[MODELING_SERVER_NAME] = {
|
|
215
|
-
command: 'node',
|
|
216
|
-
args: [getLauncherAbsolutePath(packageDir)],
|
|
217
|
-
};
|
|
218
|
-
mcpServers[LEARN_SERVER_NAME] = {
|
|
219
|
-
httpUrl: MICROSOFT_LEARN_URL,
|
|
220
|
-
};
|
|
221
|
-
|
|
222
|
-
writeJson(configPath, { ...existing, mcpServers });
|
|
223
|
-
return configPath;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// ============================================
|
|
227
|
-
// KILO CODE
|
|
228
|
-
// ============================================
|
|
229
|
-
// Writes ~/.kilocode/mcp_settings.json. Kilo uses `mcpServers` and `url`
|
|
230
|
-
// for HTTP transports.
|
|
231
|
-
function writeKiloConfig(packageDir) {
|
|
232
|
-
const configPath = path.join(os.homedir(), '.kilocode', 'mcp_settings.json');
|
|
233
|
-
const existing = readJsonSafe(configPath) || {};
|
|
234
|
-
const mcpServers = { ...(existing.mcpServers || {}) };
|
|
235
|
-
|
|
236
|
-
mcpServers[MODELING_SERVER_NAME] = {
|
|
237
|
-
command: 'node',
|
|
238
|
-
args: [getLauncherAbsolutePath(packageDir)],
|
|
239
|
-
};
|
|
240
|
-
mcpServers[LEARN_SERVER_NAME] = {
|
|
241
|
-
url: MICROSOFT_LEARN_URL,
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
writeJson(configPath, { ...existing, mcpServers });
|
|
245
|
-
return configPath;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
267
|
/**
|
|
249
268
|
* Registry mapping agent IDs to their MCP config writers.
|
|
269
|
+
* JSON agents are generated from JSON_AGENT_CONFIGS via makeJsonWriter;
|
|
270
|
+
* Codex is the only TOML-based agent and has its own writer.
|
|
250
271
|
*/
|
|
251
272
|
const MCP_WRITERS = {
|
|
252
|
-
'claude-code':
|
|
253
|
-
'github-copilot':
|
|
273
|
+
'claude-code': makeJsonWriter('claude-code'),
|
|
274
|
+
'github-copilot': makeJsonWriter('github-copilot'),
|
|
254
275
|
codex: writeCodexConfig,
|
|
255
|
-
'gemini-cli':
|
|
256
|
-
kilo:
|
|
276
|
+
'gemini-cli': makeJsonWriter('gemini-cli'),
|
|
277
|
+
kilo: makeJsonWriter('kilo'),
|
|
257
278
|
};
|
|
258
279
|
|
|
259
280
|
/**
|
|
@@ -204,6 +204,43 @@ describe('MCP writers — JSON agents', () => {
|
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
+
// Cross-agent sanity check: verifies each JSON agent writes the HTTP
|
|
208
|
+
// URL under the correct key per its spec. Catches copy-paste errors
|
|
209
|
+
// where someone might accidentally use `url` for Gemini (which expects
|
|
210
|
+
// `httpUrl`) or vice versa.
|
|
211
|
+
test('each JSON agent uses the correct HTTP field name', () => {
|
|
212
|
+
const expectations = {
|
|
213
|
+
'claude-code': { key: 'url', wrapperKey: 'mcpServers' },
|
|
214
|
+
'github-copilot': { key: 'url', wrapperKey: 'servers' },
|
|
215
|
+
'gemini-cli': { key: 'httpUrl', wrapperKey: 'mcpServers' },
|
|
216
|
+
kilo: { key: 'url', wrapperKey: 'mcpServers' },
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
for (const [agentId, expected] of Object.entries(expectations)) {
|
|
220
|
+
// Reset home for each agent so configs don't leak between writes.
|
|
221
|
+
fs.rmSync(tempHome, { recursive: true, force: true });
|
|
222
|
+
fs.mkdirSync(tempHome, { recursive: true });
|
|
223
|
+
|
|
224
|
+
const configPath = MCP_WRITERS[agentId](fakePkgDir);
|
|
225
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
226
|
+
const learnEntry = config[expected.wrapperKey][LEARN_SERVER_NAME];
|
|
227
|
+
|
|
228
|
+
assert.strictEqual(
|
|
229
|
+
learnEntry[expected.key],
|
|
230
|
+
MICROSOFT_LEARN_URL,
|
|
231
|
+
`${agentId} should use "${expected.key}" for HTTP URL`
|
|
232
|
+
);
|
|
233
|
+
|
|
234
|
+
// And it should NOT use the wrong key (defensive check)
|
|
235
|
+
const wrongKey = expected.key === 'url' ? 'httpUrl' : 'url';
|
|
236
|
+
assert.strictEqual(
|
|
237
|
+
learnEntry[wrongKey],
|
|
238
|
+
undefined,
|
|
239
|
+
`${agentId} should NOT have "${wrongKey}"`
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
207
244
|
test('writeJson refuses to overwrite symlinked target', () => {
|
|
208
245
|
const realFile = path.join(tempHome, 'real-claude.json');
|
|
209
246
|
const linkFile = path.join(tempHome, '.claude.json');
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "pbi-connect"
|
|
3
3
|
description: "Use when the user asks about Power BI MCP Connection Skill, especially phrases like \"connect Power BI\", \"modeling mcp\", \"Power BI Desktop\", \"conectar Power BI\", \"can't connect to Power BI\"."
|
|
4
|
-
version: "3.0
|
|
4
|
+
version: "3.1.0"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<!-- Generated by BI Agent Superpowers. Edit src/content/skills/pbi-connect.md instead. -->
|