@luquimbo/bi-superpowers 4.1.2 → 4.1.4

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 (44) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.claude-plugin/skill-manifest.json +1 -1
  4. package/.plugin/plugin.json +1 -1
  5. package/AGENTS.md +9 -7
  6. package/CHANGELOG.md +40 -0
  7. package/README.md +637 -96
  8. package/bin/cli.js +76 -61
  9. package/bin/commands/build-desktop.js +60 -6
  10. package/bin/commands/diff.js +86 -1
  11. package/bin/commands/mcp-setup.js +26 -3
  12. package/bin/commands/watch.js +50 -5
  13. package/bin/postinstall.js +1 -1
  14. package/bin/utils/mcp-detect.js +1 -1
  15. package/commands/bi-start.md +3 -3
  16. package/commands/pbi-connect.md +60 -24
  17. package/commands/report-design.md +1 -1
  18. package/desktop-extension/server.js +43 -10
  19. package/package.json +3 -4
  20. package/skills/bi-start/SKILL.md +4 -4
  21. package/skills/bi-start/scripts/update-check.js +1 -1
  22. package/skills/pbi-connect/SKILL.md +61 -25
  23. package/skills/pbi-connect/scripts/update-check.js +1 -1
  24. package/skills/project-kickoff/SKILL.md +1 -1
  25. package/skills/project-kickoff/scripts/update-check.js +1 -1
  26. package/skills/report-design/SKILL.md +2 -2
  27. package/skills/report-design/references/layouts/finance.md +2 -2
  28. package/skills/report-design/references/native-visuals.md +2 -2
  29. package/skills/report-design/references/slicer.md +1 -1
  30. package/skills/report-design/references/textbox.md +1 -1
  31. package/skills/report-design/scripts/create-visual.js +65 -1
  32. package/skills/report-design/scripts/update-check.js +1 -1
  33. package/skills/report-design/scripts/validate-pbir.js +29 -0
  34. package/src/content/base.md +1 -1
  35. package/src/content/routing.md +1 -1
  36. package/src/content/skills/bi-start.md +3 -3
  37. package/src/content/skills/pbi-connect.md +60 -24
  38. package/src/content/skills/report-design/SKILL.md +1 -1
  39. package/src/content/skills/report-design/references/layouts/finance.md +2 -2
  40. package/src/content/skills/report-design/references/native-visuals.md +2 -2
  41. package/src/content/skills/report-design/references/slicer.md +1 -1
  42. package/src/content/skills/report-design/references/textbox.md +1 -1
  43. package/src/content/skills/report-design/scripts/create-visual.js +65 -1
  44. package/src/content/skills/report-design/scripts/validate-pbir.js +29 -0
package/bin/cli.js CHANGED
@@ -11,9 +11,9 @@
11
11
  * Architecture:
12
12
  * - Skills are authored once in src/content/skills/ and copied out to
13
13
  * each supported agent by `super install`.
14
- * - `super kickoff` generates a full Claude Code plugin tree in a
14
+ * - `super kickoff` optionally generates a local Claude Code plugin tree in a
15
15
  * user project (skills + commands + MCP config).
16
- * - `super recharge` regenerates that plugin after local edits.
16
+ * - `super recharge` regenerates an existing local Claude Code plugin after edits.
17
17
  *
18
18
  * Supported agents: Claude Code, GitHub Copilot, Codex, Gemini CLI, Kilo Code.
19
19
  * License: MIT. This project is fully open source — no activation, no keys.
@@ -28,34 +28,6 @@ const path = require('path');
28
28
  const { execSync } = require('child_process');
29
29
  const { loadSkills } = require('./lib/skills');
30
30
 
31
- // Background update check. update-notifier spawns a detached child process
32
- // that fetches the latest version from npm and caches it; the banner that
33
- // `notify()` schedules is printed at process exit, so this is zero-latency
34
- // on the command path. Errors are swallowed silently — the CLI must not
35
- // break because of a failed update check.
36
- let _updateNotifierNotify = null;
37
- try {
38
- const updateNotifier = require('update-notifier');
39
- const pkg = require('../package.json');
40
- const notifier = updateNotifier({
41
- pkg,
42
- updateCheckInterval: 1000 * 60 * 60 * 24, // 24h
43
- shouldNotifyInNpmScript: false,
44
- });
45
- _updateNotifierNotify = () =>
46
- notifier.notify({
47
- defer: true,
48
- isGlobal: true,
49
- message:
50
- 'Update available {currentVersion} → {latestVersion}\n' +
51
- 'Run {updateCommand} to update,\n' +
52
- 'then refresh your install path (`/plugin update bi-superpowers`, `super install --yes`, or run `super recharge` inside each repo where you used `super kickoff`).',
53
- });
54
- } catch (_) {
55
- // update-notifier not available during npm install phase, or network
56
- // probe failed — skip silently.
57
- }
58
-
59
31
  // Optional lib import — may not be available during npm install phase.
60
32
  let generators;
61
33
  try {
@@ -160,14 +132,6 @@ function main() {
160
132
  const args = process.argv.slice(2);
161
133
  const command = args[0] || 'help';
162
134
 
163
- // Schedule the update-notifier banner to print at process exit. Only fire
164
- // for "normal" commands — skipping machine-readable and ultra-hot paths so
165
- // tools that parse super output don't get surprised by the banner.
166
- const SKIP_NOTIFY_COMMANDS = new Set(['version', 'help', 'about', 'info']);
167
- if (_updateNotifierNotify && !SKIP_NOTIFY_COMMANDS.has(command)) {
168
- _updateNotifierNotify();
169
- }
170
-
171
135
  if (commands[command]) {
172
136
  commands[command](args.slice(1));
173
137
  } else {
@@ -186,18 +150,18 @@ Open-source toolkit for Power BI Desktop development across 5 AI coding agents:
186
150
  Claude Code · GitHub Copilot · Codex · Gemini CLI · Kilo Code.
187
151
 
188
152
  Quick Start:
189
- super install # Install skills + MCPs for all your AI agents
190
- super kickoff # Generate the Claude Code plugin in a project
153
+ super install --all --yes # Install skills + MCPs user-level for all agents
154
+ super powers # List the skills and MCPs available
191
155
 
192
156
  Usage:
193
157
  super <command> [options]
194
158
 
195
159
  Primary commands:
196
- install Install the 4 skills + 2 MCPs across your AI agents
197
- kickoff [path] Generate the full Claude Code plugin in a project
198
- recharge [path] Regenerate the plugin after editing source skills
160
+ install Install the 4 skills + 2 MCPs user-level across your AI agents
161
+ kickoff [path] Optional: generate a repo-local Claude Code plugin
162
+ recharge [path] Optional: regenerate an existing repo-local Claude Code plugin
199
163
  build-desktop Build the .mcpb extension for Claude Desktop
200
- mcp-setup Configure the official Microsoft MCP servers
164
+ mcp-setup Refresh MCP config for an existing Claude Code local plugin
201
165
  powers List available skills and MCPs
202
166
  upgrade Update to the latest version on npm
203
167
  about Show installation info
@@ -214,13 +178,14 @@ Options:
214
178
  Examples:
215
179
  super install # Interactive installer for all agents
216
180
  super install --all --yes # Non-interactive install for every agent
181
+ super install -a codex # Install user-level skills + MCPs for Codex
217
182
  super install -a claude-code # Install only for Claude Code
218
- super kickoff # Initialize plugin in current directory
219
- super kickoff ./my-project # Initialize in a specific directory
220
- super kickoff --dry-run # Preview what would be created
221
- super recharge # Regenerate plugin after editing skills
183
+ super kickoff # Claude Code only: create local plugin files
184
+ super kickoff ./my-project # Claude Code only: initialize in a repo
185
+ super kickoff --dry-run # Preview local Claude Code plugin files
186
+ super recharge # Regenerate existing local Claude Code plugin
222
187
  super build-desktop # Build .mcpb for Claude Desktop
223
- super mcp-setup # Configure the local Power BI Modeling MCP
188
+ super mcp-setup # Existing local Claude Code plugin only
224
189
 
225
190
  Open source — MIT licensed.
226
191
  Documentation: https://github.com/luquimbo/bi-superpowers
@@ -293,7 +258,7 @@ function parseSkillMetadata(content) {
293
258
  // ============================================
294
259
 
295
260
  /**
296
- * `super kickoff` — generate the Claude Code plugin in the target directory.
261
+ * `super kickoff` — generate an optional local Claude Code plugin in the target directory.
297
262
  *
298
263
  * What it does:
299
264
  * 1. Generates .claude-plugin/, .mcp.json, commands/, skills/ in the target.
@@ -314,10 +279,17 @@ async function initProject(args) {
314
279
  console.log(`
315
280
  BI Agent Superpowers v${VERSION}
316
281
  ================================
317
- Claude Code Plugin Setup
282
+ Claude Code local plugin setup
318
283
 
319
284
  Initializing in: ${targetDir}
320
285
  Skills available: ${skills.length}
286
+
287
+ This is not the multi-agent install path. For Codex, GitHub Copilot,
288
+ Gemini CLI, Kilo Code, and user-level Claude Code installs, run:
289
+
290
+ super install --all --yes
291
+
292
+ kickoff writes repo-local Claude Code plugin files only.
321
293
  `);
322
294
 
323
295
  if (dryRun) {
@@ -359,7 +331,7 @@ Skills available: ${skills.length}
359
331
  }
360
332
 
361
333
  /**
362
- * `super recharge` — regenerate the Claude Code plugin without prompts.
334
+ * `super recharge` — regenerate an existing local Claude Code plugin without prompts.
363
335
  *
364
336
  * Re-reads the saved tool preferences from .bi-superpowers.json (or falls
365
337
  * back to the default toolset) and regenerates everything. Useful after:
@@ -393,6 +365,23 @@ Regenerating configs from ${skills.length} skills...
393
365
  }
394
366
  }
395
367
 
368
+ if (!hasProjectLocalPlugin(targetDir)) {
369
+ console.log(`
370
+ This repo does not contain a local Claude Code plugin generated by super kickoff.
371
+
372
+ For Codex, GitHub Copilot, Gemini CLI, Kilo Code, and user-level Claude Code
373
+ installs, refresh the user-level install instead:
374
+
375
+ super install --all --yes
376
+
377
+ If you intentionally want repo-local Claude Code plugin files, run:
378
+
379
+ super kickoff
380
+ `);
381
+ process.exitCode = 2;
382
+ return;
383
+ }
384
+
396
385
  const config = loadToolConfig(targetDir);
397
386
  const selectedTools = ensurePluginTool(config.tools || [...DEFAULT_TOOLS]);
398
387
 
@@ -544,6 +533,13 @@ function loadToolConfig(targetDir) {
544
533
  };
545
534
  }
546
535
 
536
+ function hasProjectLocalPlugin(targetDir) {
537
+ return (
538
+ fs.existsSync(path.join(targetDir, CONFIG_FILE)) ||
539
+ fs.existsSync(path.join(targetDir, '.claude-plugin', 'plugin.json'))
540
+ );
541
+ }
542
+
547
543
  /**
548
544
  * Dispatch to the tool-specific generator.
549
545
  */
@@ -561,6 +557,10 @@ function showCompletionMessage(targetDir, tools, skillCount) {
561
557
 
562
558
  Skills: ${skillCount} skills generated
563
559
 
560
+ Note: this is a repo-local Claude Code plugin only.
561
+ Codex, GitHub Copilot, Gemini CLI, Kilo Code, and user-level Claude Code
562
+ installs use: super install --all --yes
563
+
564
564
  ────────────────────────────────────────────────────────────
565
565
  CLAUDE CODE
566
566
  ────────────────────────────────────────────────────────────
@@ -783,19 +783,32 @@ function runWatch(args) {
783
783
  process.exit(1);
784
784
  }
785
785
 
786
- const cliModule = {
787
- syncProjectInternal: (targetDir, tools) => {
788
- const skills = getSkillFiles();
786
+ watchCommand(args, getCommandConfig(), createWatchCliModule());
787
+ }
788
+
789
+ /**
790
+ * Build the tiny adapter used by `super sentinel`.
791
+ * It intentionally delegates through generateForTool(), the same path as
792
+ * kickoff/recharge, so regenerated plugin files keep the real package version,
793
+ * library prefix, and MCP launcher mode.
794
+ *
795
+ * @param {Object} [deps] - Test seams
796
+ * @param {Function} [deps.getSkillFilesFn] - Skill loader
797
+ * @param {Function} [deps.generateForToolFn] - Tool generator
798
+ * @returns {{syncProjectInternal: Function}} Watch command adapter
799
+ */
800
+ function createWatchCliModule(deps = {}) {
801
+ const getSkillFilesFn = deps.getSkillFilesFn || getSkillFiles;
802
+ const generateForToolFn = deps.generateForToolFn || generateForTool;
803
+
804
+ return {
805
+ syncProjectInternal: async (targetDir, tools) => {
806
+ const skills = getSkillFilesFn();
789
807
  for (const tool of tools) {
790
- const cfg = AI_TOOLS[tool];
791
- if (cfg && cfg.generate) {
792
- cfg.generate(targetDir, skills, { packageDir: PACKAGE_DIR });
793
- }
808
+ await generateForToolFn(tool, targetDir, skills);
794
809
  }
795
810
  },
796
811
  };
797
-
798
- watchCommand(args, getCommandConfig(), cliModule);
799
812
  }
800
813
 
801
814
  /**
@@ -823,6 +836,8 @@ module.exports = {
823
836
  getUpgradeCommand,
824
837
  getUpgradeRefreshSteps,
825
838
  resetUpdateCheckStateAfterUpgrade,
839
+ createWatchCliModule,
840
+ getGenerationOptions,
826
841
  AI_TOOLS,
827
842
  SKILLS_DIR,
828
843
  VERSION,
@@ -30,10 +30,10 @@ const DESKTOP_TEMPLATE_DIR = path.join(PACKAGE_DIR, 'desktop-extension');
30
30
  * Bundle skills into the Desktop extension's skills/ directory.
31
31
  *
32
32
  * Handles both flat `src/content/skills/<name>.md` and folder-based
33
- * `src/content/skills/<name>/SKILL.md` layouts by flattening each skill
34
- * to a single `<name>.md` file inside `skillsOutDir`. The Claude Desktop
35
- * MCP server loads those flat files as prompts `references/` and
36
- * `scripts/` are distributed through `super install`, not bundled here.
33
+ * `src/content/skills/<name>/SKILL.md` layouts by writing each skill as
34
+ * `<name>/SKILL.md`. Folder-based skills also get their runtime
35
+ * `references/` and `scripts/` subtrees copied into the MCPB, so prompts
36
+ * never point Claude Desktop at files missing from the installed extension.
37
37
  *
38
38
  * @param {string} skillsOutDir - Destination directory (created if missing)
39
39
  * @param {string} packageDir - npm package root containing src/content/skills/
@@ -43,11 +43,63 @@ function bundleSkills(skillsOutDir, packageDir) {
43
43
  fs.mkdirSync(skillsOutDir, { recursive: true });
44
44
  const skills = loadSkills({ packageDir });
45
45
  for (const skill of skills) {
46
- fs.writeFileSync(path.join(skillsOutDir, `${skill.name}.md`), skill.content);
46
+ const skillOutDir = path.join(skillsOutDir, skill.name);
47
+ fs.mkdirSync(skillOutDir, { recursive: true });
48
+ fs.writeFileSync(path.join(skillOutDir, 'SKILL.md'), skill.content);
49
+
50
+ if (skill.bundleDir) {
51
+ copyRuntimeTree(
52
+ path.join(skill.bundleDir, 'references'),
53
+ path.join(skillOutDir, 'references')
54
+ );
55
+ copyRuntimeTree(path.join(skill.bundleDir, 'scripts'), path.join(skillOutDir, 'scripts'));
56
+ }
47
57
  }
48
58
  return skills.map((s) => s.name);
49
59
  }
50
60
 
61
+ /**
62
+ * Copy runtime skill assets, excluding test/build/editor artifacts.
63
+ *
64
+ * @param {string} source - Source file or directory
65
+ * @param {string} target - Destination file or directory
66
+ */
67
+ function copyRuntimeTree(source, target) {
68
+ if (!fs.existsSync(source)) {
69
+ return;
70
+ }
71
+
72
+ const stat = fs.statSync(source);
73
+ if (stat.isDirectory()) {
74
+ fs.mkdirSync(target, { recursive: true });
75
+ for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
76
+ copyRuntimeTree(path.join(source, entry.name), path.join(target, entry.name));
77
+ }
78
+ return;
79
+ }
80
+
81
+ if (!stat.isFile() || shouldSkipRuntimeFile(source)) {
82
+ return;
83
+ }
84
+
85
+ fs.mkdirSync(path.dirname(target), { recursive: true });
86
+ fs.copyFileSync(source, target);
87
+ }
88
+
89
+ /**
90
+ * @param {string} filePath - Runtime asset path
91
+ * @returns {boolean} True if this file should not ship in the MCPB
92
+ */
93
+ function shouldSkipRuntimeFile(filePath) {
94
+ const base = path.basename(filePath);
95
+ return (
96
+ base.endsWith('.test.js') ||
97
+ base.endsWith('.spec.js') ||
98
+ base.endsWith('.bak') ||
99
+ base.endsWith('.tmp')
100
+ );
101
+ }
102
+
51
103
  /**
52
104
  * Build the .mcpb extension for Claude Desktop.
53
105
  *
@@ -94,7 +146,7 @@ BI Agent Superpowers — Build Desktop Extension
94
146
 
95
147
  // Bundle every skill (flat + folder-based) into temp/skills/
96
148
  const bundledNames = bundleSkills(path.join(tmpDir, 'skills'), PACKAGE_DIR);
97
- const skillFiles = bundledNames.map((n) => `${n}.md`);
149
+ const skillFiles = bundledNames.map((n) => `${n}/SKILL.md`);
98
150
  console.log(` Bundled ${bundledNames.length} skills`);
99
151
 
100
152
  // Patch template placeholder versions with the real package version
@@ -185,3 +237,5 @@ BI Agent Superpowers — Build Desktop Extension
185
237
 
186
238
  module.exports = buildDesktop;
187
239
  module.exports.bundleSkills = bundleSkills;
240
+ module.exports.copyRuntimeTree = copyRuntimeTree;
241
+ module.exports.shouldSkipRuntimeFile = shouldSkipRuntimeFile;
@@ -13,6 +13,7 @@ const fs = require('fs');
13
13
  const path = require('path');
14
14
  const tui = require('../utils/tui');
15
15
  const { readSkillDirectory, normalizeSkillName } = require('../lib/skills');
16
+ const { buildCommandMarkdown } = require('../lib/generators/claude-plugin');
16
17
 
17
18
  /**
18
19
  * Generate a simple diff between two strings
@@ -113,6 +114,71 @@ function compareFiles(skillPath, generatedPath) {
113
114
  };
114
115
  }
115
116
 
117
+ /**
118
+ * Compare a loaded skill against the content that should have been generated
119
+ * for a specific tool. This avoids false drift from generator-owned wrappers
120
+ * such as Claude command frontmatter, generated comments, and update-check
121
+ * preambles.
122
+ *
123
+ * @param {{name: string, path: string, content: string}} skill - Loaded source skill
124
+ * @param {string} generatedPath - Path to generated file
125
+ * @param {Object} [options] - Comparison options
126
+ * @param {string} [options.tool] - Tool id
127
+ * @param {string} [options.libraryPrefix] - Library prefix used by the generator
128
+ * @returns {Object} Comparison result
129
+ */
130
+ function compareSkillToGenerated(skill, generatedPath, options = {}) {
131
+ if (!skill || !fs.existsSync(skill.path)) {
132
+ return {
133
+ skill: skill && skill.name ? skill.name : 'unknown',
134
+ status: 'missing-source',
135
+ message: 'Source skill file not found',
136
+ };
137
+ }
138
+
139
+ if (!fs.existsSync(generatedPath)) {
140
+ return {
141
+ skill: skill.name,
142
+ status: 'not-generated',
143
+ message: 'Generated file does not exist (will be created on sync)',
144
+ };
145
+ }
146
+
147
+ const generatedContent = fs.readFileSync(generatedPath, 'utf8');
148
+ const expectedContent = buildExpectedGeneratedContent(skill, options);
149
+
150
+ if (expectedContent === generatedContent) {
151
+ return {
152
+ skill: skill.name,
153
+ status: 'unchanged',
154
+ message: 'No changes',
155
+ };
156
+ }
157
+
158
+ const diff = generateDiff(generatedContent, expectedContent);
159
+
160
+ return {
161
+ skill: skill.name,
162
+ status: 'changed',
163
+ diff,
164
+ sourcePath: skill.path,
165
+ generatedPath,
166
+ };
167
+ }
168
+
169
+ /**
170
+ * @param {{name: string, content: string}} skill - Loaded source skill
171
+ * @param {Object} options - Comparison options
172
+ * @returns {string} Expected generated output for the scan target
173
+ */
174
+ function buildExpectedGeneratedContent(skill, options = {}) {
175
+ if (options.tool === 'claude-code') {
176
+ return buildCommandMarkdown(skill, options.libraryPrefix || 'library');
177
+ }
178
+
179
+ return skill.content;
180
+ }
181
+
116
182
  /**
117
183
  * Get generated file path for a skill based on tool
118
184
  * @param {string} skillName - Skill name (without .md)
@@ -291,6 +357,7 @@ function diffCommand(args, config) {
291
357
  // and `path.basename(...)` would return `SKILL`, breaking the diff.
292
358
  const results = skillFiles.map((skillPath) => {
293
359
  const skillName = skillNameByPath.get(skillPath) || path.basename(skillPath, '.md');
360
+ const skill = skillsByName.get(skillName);
294
361
  const generatedPath = getGeneratedPath(skillName, options.tool, targetDir);
295
362
 
296
363
  if (!generatedPath) {
@@ -301,7 +368,10 @@ function diffCommand(args, config) {
301
368
  };
302
369
  }
303
370
 
304
- return compareFiles(skillPath, generatedPath);
371
+ return compareSkillToGenerated(skill, generatedPath, {
372
+ tool: options.tool,
373
+ libraryPrefix: getLibraryPrefix(targetDir, config.packageDir),
374
+ });
305
375
  });
306
376
 
307
377
  // Display results
@@ -340,6 +410,21 @@ function diffCommand(args, config) {
340
410
  module.exports = Object.assign(diffCommand, {
341
411
  generateDiff,
342
412
  compareFiles,
413
+ compareSkillToGenerated,
414
+ buildExpectedGeneratedContent,
343
415
  getGeneratedPath,
344
416
  parseArgs,
345
417
  });
418
+
419
+ /**
420
+ * Match the Claude plugin generator's library reference behavior.
421
+ *
422
+ * @param {string} targetDir - Target project directory
423
+ * @param {string} packageDir - Package root
424
+ * @returns {string} Library prefix used in generated markdown
425
+ */
426
+ function getLibraryPrefix(targetDir, packageDir) {
427
+ return fs.existsSync(path.join(targetDir, 'library'))
428
+ ? 'library'
429
+ : path.join(packageDir, 'library');
430
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * MCP Setup Command
3
3
  * =================
4
- * Configures the official Microsoft MCP servers for the Claude Code plugin
5
- * and legacy adapter formats.
4
+ * Configures the official Microsoft MCP servers for an existing project-local
5
+ * Claude Code plugin and legacy adapter formats.
6
6
  *
7
7
  * Usage:
8
8
  * super mcp-setup
@@ -103,6 +103,13 @@ function loadConfiguredTools(targetDir) {
103
103
  return ['claude-plugin'];
104
104
  }
105
105
 
106
+ function hasLocalPluginMarker(targetDir) {
107
+ return (
108
+ fs.existsSync(path.join(targetDir, '.bi-superpowers.json')) ||
109
+ fs.existsSync(path.join(targetDir, '.claude-plugin', 'plugin.json'))
110
+ );
111
+ }
112
+
106
113
  function readJson(filePath) {
107
114
  if (!fs.existsSync(filePath)) {
108
115
  return {};
@@ -157,8 +164,24 @@ function mcpSetupCommand(args, config) {
157
164
 
158
165
  if (options.deprecatedFlags.length > 0) {
159
166
  tui.warning(
160
- `Deprecated flags ignored: ${options.deprecatedFlags.join(', ')}. MCP setup is now plugin-first and uses the official Microsoft servers.`
167
+ `Deprecated flags ignored: ${options.deprecatedFlags.join(', ')}. MCP setup now targets local Claude Code plugin configs and uses the official Microsoft servers.`
168
+ );
169
+ }
170
+
171
+ if (!options.tool && !hasLocalPluginMarker(targetDir)) {
172
+ tui.warning('mcp-setup is only for project-local Claude Code plugin configs.');
173
+ tui.info(
174
+ 'For Codex, GitHub Copilot, Gemini CLI, Kilo Code, and Claude Code user-level installs, run:'
175
+ );
176
+ tui.listItem('super install --all --yes');
177
+ tui.info(
178
+ 'That writes user-level skills and MCP config under your home directory without creating files in this repo.'
179
+ );
180
+ tui.info(
181
+ 'If you intentionally need a local Claude Code plugin, run `super kickoff` first or pass `--tool claude-plugin`.'
161
182
  );
183
+ process.exitCode = 2;
184
+ return;
162
185
  }
163
186
 
164
187
  let configuredTools = loadConfiguredTools(targetDir);
@@ -48,6 +48,42 @@ function parseArgs(args) {
48
48
  return options;
49
49
  }
50
50
 
51
+ /**
52
+ * Chokidar v4 no longer supports glob paths. Watch the skill root and filter
53
+ * relevant runtime/source files in-process so folder-based skills are covered.
54
+ *
55
+ * @param {string} skillsDir - Directory containing skill sources
56
+ * @returns {string[]} Watch roots
57
+ */
58
+ function getWatchRoots(skillsDir) {
59
+ return [skillsDir];
60
+ }
61
+
62
+ /**
63
+ * @param {string} changedPath - Changed file path
64
+ * @param {string} skillsDir - Watched skill root
65
+ * @returns {boolean} Whether the changed file should trigger regeneration
66
+ */
67
+ function isRelevantSkillPath(changedPath, skillsDir) {
68
+ const relative = path.relative(skillsDir, changedPath);
69
+ if (!relative || relative.startsWith('..') || path.isAbsolute(relative)) {
70
+ return false;
71
+ }
72
+
73
+ const base = path.basename(changedPath);
74
+ if (
75
+ base.endsWith('.test.js') ||
76
+ base.endsWith('.spec.js') ||
77
+ base.endsWith('.bak') ||
78
+ base.endsWith('.tmp') ||
79
+ base.startsWith('.')
80
+ ) {
81
+ return false;
82
+ }
83
+
84
+ return ['.md', '.js', '.json', '.sh'].includes(path.extname(changedPath));
85
+ }
86
+
51
87
  /**
52
88
  * Main watch command handler
53
89
  * @param {string[]} args - Command arguments
@@ -91,7 +127,7 @@ function watchCommand(args, config, cliModule) {
91
127
  const pendingChanges = new Set();
92
128
 
93
129
  // Create watcher
94
- const watcher = chokidar.watch(path.join(skillsDir, '*.md'), {
130
+ const watcher = chokidar.watch(getWatchRoots(skillsDir), {
95
131
  persistent: true,
96
132
  ignoreInitial: true,
97
133
  awaitWriteFinish: {
@@ -106,7 +142,11 @@ function watchCommand(args, config, cliModule) {
106
142
  * @param {string} eventType - Type of event (add, change, unlink)
107
143
  */
108
144
  function handleChange(changedPath, _eventType) {
109
- const filename = path.basename(changedPath);
145
+ if (!isRelevantSkillPath(changedPath, skillsDir)) {
146
+ return;
147
+ }
148
+
149
+ const filename = path.relative(skillsDir, changedPath);
110
150
  pendingChanges.add(filename);
111
151
 
112
152
  // Clear existing timer
@@ -157,7 +197,7 @@ function watchCommand(args, config, cliModule) {
157
197
  * @param {string|null} specificTool - Specific tool or null for all
158
198
  * @param {Object} cliModule - CLI module reference
159
199
  */
160
- function regenerateConfigs(targetDir, specificTool, cliModule) {
200
+ async function regenerateConfigs(targetDir, specificTool, cliModule) {
161
201
  const ora = require('ora');
162
202
  const spinner = ora('Regenerating configs...').start();
163
203
 
@@ -193,7 +233,7 @@ function regenerateConfigs(targetDir, specificTool, cliModule) {
193
233
 
194
234
  // Call the sync logic from CLI module
195
235
  if (cliModule && typeof cliModule.syncProjectInternal === 'function') {
196
- cliModule.syncProjectInternal(targetDir, tools);
236
+ await cliModule.syncProjectInternal(targetDir, tools);
197
237
  spinner.succeed(`Regenerated configs for: ${tools.join(', ')}`);
198
238
  } else {
199
239
  // Fallback: just report what would be done
@@ -205,4 +245,9 @@ function regenerateConfigs(targetDir, specificTool, cliModule) {
205
245
  }
206
246
  }
207
247
 
208
- module.exports = watchCommand;
248
+ module.exports = Object.assign(watchCommand, {
249
+ parseArgs,
250
+ getWatchRoots,
251
+ isRelevantSkillPath,
252
+ regenerateConfigs,
253
+ });
@@ -36,7 +36,7 @@ Funciona con los 5 agentes:
36
36
  /report-design — Generá reportes PBIR para Power BI Desktop (Windows)
37
37
 
38
38
  2 MCP servers:
39
- powerbi-modeling — Conexión local a Power BI Desktop (XMLA)
39
+ powerbi-modeling-mcp — Conexión local a Power BI Desktop (XMLA)
40
40
  microsoft-learn — Docs de Microsoft Learn en contexto
41
41
 
42
42
  Documentation: https://github.com/luquimbo/bi-superpowers
@@ -188,7 +188,7 @@ function getInstallInstructions() {
188
188
  'Ir a Extensions (Ctrl+Shift+X)',
189
189
  'Buscar "Power BI Modeling MCP"',
190
190
  'Instalar la extensión de Microsoft',
191
- 'Ejecutar: super mcp-setup',
191
+ 'Ejecutar: super install --all --yes',
192
192
  ],
193
193
  link: 'https://aka.ms/powerbi-modeling-mcp-vscode',
194
194
  },
@@ -55,7 +55,7 @@ Interpret the single-line output:
55
55
  ```bash
56
56
  super upgrade
57
57
  ```
58
- After it finishes, remind: _"Si instalaste skills en el perfil del agente, corré `super install --yes`. Si además usás un plugin local generado con `super kickoff`, corré `super recharge` dentro de ese repo."_
58
+ After it finishes, remind: _"Corré `super install --all --yes` para refrescar la instalación user-level de todos los agentes. Solo si además mantenés un plugin local de Claude Code generado con `super kickoff`, corré `super recharge` dentro de ese repo."_
59
59
 
60
60
  On `no` — respect it, continue to PHASE 1 silently. The update-state.json already tracks the user's snooze per `update-check.js` semantics.
61
61
 
@@ -86,7 +86,7 @@ Do these detections in order:
86
86
  ```
87
87
  (or equivalent). `$pbiDesktopRunning = true` if present.
88
88
 
89
- 4. **MCP configured**: look for `.mcp.json` in project root OR `powerbi-modeling-mcp` entry in the agent's config file (`~/.claude.json`, `~/.codex/config.toml`, etc). Keep the check shallow — no need to deep-diff.
89
+ 4. **MCP configured**: look first for `powerbi-modeling-mcp` in the agent's user-level config file (`~/.claude.json`, `~/.codex/config.toml`, etc). Only check project-root `.mcp.json` when the user explicitly says they use a local Claude Code plugin. Keep the check shallow — no need to deep-diff.
90
90
 
91
91
  ### Emit the context in 3-4 lines max
92
92
 
@@ -180,7 +180,7 @@ Stop. Don't hover. The user will tell you what they want next.
180
180
  - **Project analysis or setup**: that's `/project-kickoff`. If the user says "analizar mi proyecto", "armar el modelo base", "arrancar uno nuevo desde cero", delegate.
181
181
  - **MCP wiring details**: that's `/pbi-connect`. bi-start just offers to dispatch it; the actual configuration work is in that skill.
182
182
  - **Report authoring**: that's `/report-design`. Same pattern.
183
- - **Running the update**: bi-start offers + dispatches `super upgrade`; the actual refresh path after eso (`/plugin update bi-superpowers`, `super install --yes`, o `super recharge`) is owned by `/bin/cli.js`.
183
+ - **Running the update**: bi-start offers + dispatches `super upgrade`; the actual refresh path after eso (`/plugin update bi-superpowers`, `super install --all --yes`, o `super recharge` only for local Claude Code plugins) is owned by `/bin/cli.js`.
184
184
 
185
185
  ## Related Skills
186
186