@luquimbo/bi-superpowers 4.1.5 → 5.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 (81) hide show
  1. package/.claude-plugin/marketplace.json +5 -5
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.claude-plugin/skill-manifest.json +17 -17
  4. package/.plugin/plugin.json +1 -1
  5. package/AGENTS.md +50 -54
  6. package/CHANGELOG.md +67 -0
  7. package/README.md +103 -24
  8. package/bin/cli.js +12 -8
  9. package/bin/commands/build-desktop.js +37 -2
  10. package/bin/commands/diff.js +2 -2
  11. package/bin/commands/install.js +29 -7
  12. package/bin/commands/lint.js +2 -2
  13. package/bin/commands/mcp-setup.js +20 -30
  14. package/bin/commands/validate-projects.js +425 -0
  15. package/bin/commands/watch.js +1 -1
  16. package/bin/lib/generators/claude-plugin.js +20 -5
  17. package/bin/lib/generators/shared.js +8 -8
  18. package/bin/lib/skills.js +5 -5
  19. package/bin/postinstall.js +3 -3
  20. package/commands/{pbi-connect.md → bi-connect.md} +151 -3
  21. package/commands/{project-kickoff.md → bi-kickoff.md} +9 -9
  22. package/commands/{report-design.md → bi-report.md} +12 -12
  23. package/commands/bi-start.md +20 -20
  24. package/desktop-extension/manifest.json +1 -1
  25. package/package.json +1 -1
  26. package/skills/{pbi-connect → bi-connect}/SKILL.md +153 -5
  27. package/skills/{pbi-connect → bi-connect}/scripts/update-check.js +1 -1
  28. package/skills/{project-kickoff → bi-kickoff}/SKILL.md +11 -11
  29. package/skills/{report-design → bi-kickoff}/scripts/update-check.js +1 -1
  30. package/skills/{report-design → bi-report}/SKILL.md +14 -14
  31. package/skills/{report-design → bi-report}/references/layouts/hr.md +1 -1
  32. package/{src/content/skills/report-design → skills/bi-report}/references/native-visuals.md +1 -1
  33. package/{src/content/skills/report-design → skills/bi-report}/references/pbir-preview-activation.md +3 -3
  34. package/{src/content/skills/report-design → skills/bi-report}/references/troubleshooting.md +1 -1
  35. package/skills/{project-kickoff → bi-report}/scripts/update-check.js +1 -1
  36. package/skills/bi-start/SKILL.md +21 -21
  37. package/skills/bi-start/scripts/update-check.js +1 -1
  38. package/src/content/base.md +6 -5
  39. package/src/content/routing.md +22 -20
  40. package/src/content/skills/{pbi-connect.md → bi-connect.md} +149 -1
  41. package/src/content/skills/{project-kickoff.md → bi-kickoff.md} +8 -8
  42. package/src/content/skills/{report-design → bi-report}/SKILL.md +11 -11
  43. package/src/content/skills/{report-design → bi-report}/references/layouts/hr.md +1 -1
  44. package/{skills/report-design → src/content/skills/bi-report}/references/native-visuals.md +1 -1
  45. package/{skills/report-design → src/content/skills/bi-report}/references/pbir-preview-activation.md +3 -3
  46. package/{skills/report-design → src/content/skills/bi-report}/references/troubleshooting.md +1 -1
  47. package/src/content/skills/bi-start.md +20 -20
  48. /package/skills/{report-design → bi-report}/references/cli-commands.md +0 -0
  49. /package/skills/{report-design → bi-report}/references/cli-setup.md +0 -0
  50. /package/skills/{report-design → bi-report}/references/close-write-open-pattern.md +0 -0
  51. /package/skills/{report-design → bi-report}/references/layouts/finance.md +0 -0
  52. /package/skills/{report-design → bi-report}/references/layouts/generic.md +0 -0
  53. /package/skills/{report-design → bi-report}/references/layouts/marketing.md +0 -0
  54. /package/skills/{report-design → bi-report}/references/layouts/operations.md +0 -0
  55. /package/skills/{report-design → bi-report}/references/layouts/sales.md +0 -0
  56. /package/skills/{report-design → bi-report}/references/pbi-desktop-installation.md +0 -0
  57. /package/skills/{report-design → bi-report}/references/slicer.md +0 -0
  58. /package/skills/{report-design → bi-report}/references/textbox.md +0 -0
  59. /package/skills/{report-design → bi-report}/references/themes/BISuperpowers.json +0 -0
  60. /package/skills/{report-design → bi-report}/references/visual-types.md +0 -0
  61. /package/skills/{report-design → bi-report}/scripts/apply-theme.js +0 -0
  62. /package/skills/{report-design → bi-report}/scripts/create-visual.js +0 -0
  63. /package/skills/{report-design → bi-report}/scripts/ensure-pbi-cli.sh +0 -0
  64. /package/skills/{report-design → bi-report}/scripts/validate-pbir.js +0 -0
  65. /package/src/content/skills/{report-design → bi-report}/references/cli-commands.md +0 -0
  66. /package/src/content/skills/{report-design → bi-report}/references/cli-setup.md +0 -0
  67. /package/src/content/skills/{report-design → bi-report}/references/close-write-open-pattern.md +0 -0
  68. /package/src/content/skills/{report-design → bi-report}/references/layouts/finance.md +0 -0
  69. /package/src/content/skills/{report-design → bi-report}/references/layouts/generic.md +0 -0
  70. /package/src/content/skills/{report-design → bi-report}/references/layouts/marketing.md +0 -0
  71. /package/src/content/skills/{report-design → bi-report}/references/layouts/operations.md +0 -0
  72. /package/src/content/skills/{report-design → bi-report}/references/layouts/sales.md +0 -0
  73. /package/src/content/skills/{report-design → bi-report}/references/pbi-desktop-installation.md +0 -0
  74. /package/src/content/skills/{report-design → bi-report}/references/slicer.md +0 -0
  75. /package/src/content/skills/{report-design → bi-report}/references/textbox.md +0 -0
  76. /package/src/content/skills/{report-design → bi-report}/references/themes/BISuperpowers.json +0 -0
  77. /package/src/content/skills/{report-design → bi-report}/references/visual-types.md +0 -0
  78. /package/src/content/skills/{report-design → bi-report}/scripts/apply-theme.js +0 -0
  79. /package/src/content/skills/{report-design → bi-report}/scripts/create-visual.js +0 -0
  80. /package/src/content/skills/{report-design → bi-report}/scripts/ensure-pbi-cli.sh +0 -0
  81. /package/src/content/skills/{report-design → bi-report}/scripts/validate-pbir.js +0 -0
package/bin/cli.js CHANGED
@@ -45,6 +45,7 @@ let watchCommand;
45
45
  let mcpSetupCommand;
46
46
  let buildDesktopCommand;
47
47
  let installCommand;
48
+ let validateProjectsCommand;
48
49
  let tui;
49
50
  try {
50
51
  lintCommand = require('./commands/lint'); // checkup: skill file validation
@@ -53,6 +54,7 @@ try {
53
54
  mcpSetupCommand = require('./commands/mcp-setup'); // MCP server configuration
54
55
  buildDesktopCommand = require('./commands/build-desktop'); // .mcpb for Claude Desktop
55
56
  installCommand = require('./commands/install'); // multi-agent skill + MCP installer
57
+ validateProjectsCommand = require('./commands/validate-projects'); // repo/project validation harness
56
58
  tui = require('./utils/tui'); // colors, tables, boxes for CLI output
57
59
  } catch (_) {
58
60
  // Expected during `npm install` — modules become available after deps are linked.
@@ -171,6 +173,7 @@ Developer tools:
171
173
  checkup [file] Lint/validate skill source files
172
174
  scan Diff between source skills and generated plugin
173
175
  sentinel Watch skill sources and auto-regenerate
176
+ validate-projects Validate public fixtures + local private project references
174
177
 
175
178
  Options:
176
179
  --dry-run Preview changes without writing files (kickoff, recharge)
@@ -185,7 +188,9 @@ Examples:
185
188
  super kickoff --dry-run # Preview local Claude Code plugin files
186
189
  super recharge # Regenerate existing local Claude Code plugin
187
190
  super build-desktop # Build .mcpb for Claude Desktop
191
+ super build-desktop --output dist
188
192
  super mcp-setup # Existing local Claude Code plugin only
193
+ super validate-projects # Developer QA against validation/ descriptors
189
194
 
190
195
  Open source — MIT licensed.
191
196
  Documentation: https://github.com/luquimbo/bi-superpowers
@@ -428,15 +433,12 @@ function ensurePluginTool(tools = []) {
428
433
 
429
434
  /**
430
435
  * Build the options object passed into individual generators.
431
- * If the target directory has its own local `library/` folder, skills
432
- * will reference that; otherwise they reference the library bundled
433
- * inside the installed npm package.
436
+ * `library/` is no longer shipped by this package. Keep local project
437
+ * library references unchanged only when the target repo provides them.
434
438
  */
435
439
  function getGenerationOptions(targetDir) {
436
440
  const usePluginRootLauncher = path.resolve(targetDir) === PACKAGE_DIR;
437
- const libraryPrefix = fs.existsSync(path.join(targetDir, 'library'))
438
- ? 'library'
439
- : path.join(PACKAGE_DIR, 'library');
441
+ const libraryPrefix = fs.existsSync(path.join(targetDir, 'library')) ? 'library' : null;
440
442
 
441
443
  return {
442
444
  packageDir: PACKAGE_DIR,
@@ -581,9 +583,9 @@ function showCompletionMessage(targetDir, tools, skillCount) {
581
583
 
582
584
  To build the Desktop extension:
583
585
 
584
- super build-desktop
586
+ super build-desktop --output dist
585
587
 
586
- Then double-click bi-superpowers.mcpb to install.
588
+ Then double-click dist/bi-superpowers.mcpb to install.
587
589
 
588
590
  ────────────────────────────────────────────────────────────
589
591
 
@@ -759,6 +761,7 @@ const runDiff = createCommandWrapper(diffCommand, 'Diff');
759
761
  const runMcpSetup = createCommandWrapper(mcpSetupCommand, 'MCP setup');
760
762
  const runBuildDesktop = createCommandWrapper(buildDesktopCommand, 'Build Desktop');
761
763
  const runInstall = createCommandWrapper(installCommand, 'Install');
764
+ const runValidateProjects = createCommandWrapper(validateProjectsCommand, 'Validate projects');
762
765
 
763
766
  // Register wrapper-based commands into the command map (phase 2).
764
767
  commands.install = runInstall;
@@ -768,6 +771,7 @@ commands.sentinel = runWatch;
768
771
  commands['mcp-setup'] = runMcpSetup;
769
772
  commands.mcp = runMcpSetup;
770
773
  commands['build-desktop'] = runBuildDesktop;
774
+ commands['validate-projects'] = runValidateProjects;
771
775
  commands.lint = runLint;
772
776
  commands.diff = runDiff;
773
777
  commands.watch = runWatch;
@@ -100,14 +100,48 @@ function shouldSkipRuntimeFile(filePath) {
100
100
  );
101
101
  }
102
102
 
103
+ /**
104
+ * Parse build-desktop CLI arguments.
105
+ *
106
+ * @param {string[]} args - CLI arguments after `build-desktop`
107
+ * @returns {{outputDir: string}} Build options
108
+ */
109
+ function parseArgs(args) {
110
+ const options = {
111
+ outputDir: process.cwd(),
112
+ };
113
+
114
+ for (let index = 0; index < args.length; index++) {
115
+ const arg = args[index];
116
+
117
+ if (arg === '--output' || arg === '-o') {
118
+ const value = args[++index];
119
+ if (!value || value.startsWith('-')) {
120
+ throw new Error(`${arg} requires a path`);
121
+ }
122
+ options.outputDir = path.resolve(value);
123
+ }
124
+ }
125
+
126
+ return options;
127
+ }
128
+
103
129
  /**
104
130
  * Build the .mcpb extension for Claude Desktop.
105
131
  *
106
132
  * @param {string[]} args - CLI arguments
107
133
  * @param {Object} config - Command config from CLI
108
134
  */
109
- function buildDesktop(_args, _config) {
110
- const outputDir = process.cwd();
135
+ function buildDesktop(args, _config) {
136
+ let options;
137
+ try {
138
+ options = parseArgs(args || []);
139
+ } catch (err) {
140
+ console.error(`Error: ${err.message}`);
141
+ process.exit(1);
142
+ }
143
+ const outputDir = options.outputDir;
144
+ fs.mkdirSync(outputDir, { recursive: true });
111
145
 
112
146
  console.log(`
113
147
  BI Agent Superpowers — Build Desktop Extension
@@ -239,3 +273,4 @@ module.exports = buildDesktop;
239
273
  module.exports.bundleSkills = bundleSkills;
240
274
  module.exports.copyRuntimeTree = copyRuntimeTree;
241
275
  module.exports.shouldSkipRuntimeFile = shouldSkipRuntimeFile;
276
+ module.exports.parseArgs = parseArgs;
@@ -331,8 +331,8 @@ function diffCommand(args, config) {
331
331
  let skillFiles = [];
332
332
 
333
333
  if (options.skill) {
334
- // normalizeSkillName accepts `dax`, `dax.md`, `report-design`, or
335
- // `report-design/SKILL.md` and returns the canonical skill name.
334
+ // normalizeSkillName accepts `dax`, `dax.md`, `bi-report`, or
335
+ // `bi-report/SKILL.md` and returns the canonical skill name.
336
336
  const skill = skillsByName.get(normalizeSkillName(options.skill));
337
337
  if (skill) {
338
338
  skillFiles = [skill.path];
@@ -13,7 +13,8 @@
13
13
  * Everything is installed at the user level (~/) so it applies across
14
14
  * all projects without polluting any specific repo. Skills land in
15
15
  * ~/.agents/skills/ (universal path) and each agent's own skill dir is
16
- * symlinked to that universal copy. MCPs are written to each agent's
16
+ * symlinked to that universal copy when possible. Copy fallback mirrors
17
+ * managed skill directories on every run. MCPs are written to each agent's
17
18
  * expected config file in the format that agent requires (JSON for
18
19
  * most, TOML for Codex) — see `lib/mcp-config.js` for details.
19
20
  *
@@ -116,10 +117,31 @@ async function selectMultiple(rl, items, preselected = []) {
116
117
  * @param {string} destDir - Destination directory
117
118
  */
118
119
  function copySkillDir(srcDir, destDir) {
119
- if (!fs.existsSync(destDir)) {
120
- fs.mkdirSync(destDir, { recursive: true });
120
+ const resolvedSrc = path.resolve(srcDir);
121
+ const resolvedDest = path.resolve(destDir);
122
+ const destRoot = path.parse(resolvedDest).root;
123
+
124
+ if (
125
+ resolvedSrc === resolvedDest ||
126
+ resolvedSrc.startsWith(`${resolvedDest}${path.sep}`) ||
127
+ resolvedDest === destRoot
128
+ ) {
129
+ throw new Error(`Refusing to mirror skill directory into unsafe target: ${destDir}`);
121
130
  }
122
131
 
132
+ // Skill directories are package-managed. Remove the old managed copy first
133
+ // so upgrades cannot leave deleted scripts or references behind.
134
+ const existingDest = fs.lstatSync(destDir, { throwIfNoEntry: false });
135
+ if (existingDest) {
136
+ if (existingDest.isSymbolicLink()) {
137
+ fs.unlinkSync(destDir);
138
+ } else {
139
+ fs.rmSync(destDir, { recursive: true, force: true });
140
+ }
141
+ }
142
+
143
+ fs.mkdirSync(destDir, { recursive: true });
144
+
123
145
  const entries = fs.readdirSync(srcDir, { withFileTypes: true });
124
146
  for (const entry of entries) {
125
147
  const srcPath = path.join(srcDir, entry.name);
@@ -435,7 +457,7 @@ async function installCommand(args, config) {
435
457
  chalk.yellow(
436
458
  `\n ⚠ ${copyFallbacks} agente(s) usaron copia en vez de symlink ` +
437
459
  '(probable Windows sin permisos de admin).\n' +
438
- " Re-ejecutá 'super install' tras cada upgrade para refrescar los archivos."
460
+ " Re-ejecutá 'super install' tras cada upgrade; la copia se espeja y elimina runtimes viejos."
439
461
  )
440
462
  );
441
463
  }
@@ -474,11 +496,11 @@ async function installCommand(args, config) {
474
496
  '\n' +
475
497
  chalk.gray(' /bi-start — Arrancar una sesión: menú + update + conexión') +
476
498
  '\n' +
477
- chalk.gray(' /project-kickoff — Analizá tu proyecto BI (proyecto nuevo)') +
499
+ chalk.gray(' /bi-kickoff — Analizá tu proyecto BI (proyecto nuevo)') +
478
500
  '\n' +
479
- chalk.gray(' /pbi-connect — Conectá tu agente a Power BI Desktop') +
501
+ chalk.gray(' /bi-connect — Conectá Power BI + guía UDF DAX') +
480
502
  '\n' +
481
- chalk.gray(' /report-design — Generá reportes PBIR para Power BI Desktop (Windows)'),
503
+ chalk.gray(' /bi-report — Generá reportes PBIR para Power BI Desktop (Windows)'),
482
504
  {
483
505
  padding: 1,
484
506
  margin: { top: 1 },
@@ -366,7 +366,7 @@ function lintCommand(args, config) {
366
366
  // Determine which files to lint. Use the shared skill loader so we
367
367
  // catch both flat (`<name>.md`) and folder-based (`<name>/SKILL.md`)
368
368
  // skills — a previous version filtered with `f.endsWith('.md')` and
369
- // silently skipped every folder-based skill (e.g. `report-design`).
369
+ // silently skipped every folder-based skill (e.g. `bi-report`).
370
370
  const allSkills = readSkillDirectory(skillsDir);
371
371
  const skillsByName = new Map(allSkills.map((s) => [s.name, s]));
372
372
  let filesToLint = [];
@@ -379,7 +379,7 @@ function lintCommand(args, config) {
379
379
  return f;
380
380
  }
381
381
  // Look up by skill name. normalizeSkillName accepts `dax`,
382
- // `dax.md`, `report-design`, or `report-design/SKILL.md`.
382
+ // `dax.md`, `bi-report`, or `bi-report/SKILL.md`.
383
383
  const skill = skillsByName.get(normalizeSkillName(f));
384
384
  if (skill) return skill.path;
385
385
 
@@ -2,7 +2,8 @@
2
2
  * MCP Setup Command
3
3
  * =================
4
4
  * Configures the official Microsoft MCP servers for an existing project-local
5
- * Claude Code plugin and legacy adapter formats.
5
+ * BI Superpowers plugin. Normal multi-agent setup is user-level via
6
+ * `super install --all --yes`; this command refuses arbitrary repo-local writes.
6
7
  *
7
8
  * Usage:
8
9
  * super mcp-setup
@@ -20,6 +21,7 @@ const {
20
21
  createMcpConfigForFormat,
21
22
  mergeMcpConfig,
22
23
  } = require('../lib/microsoft-mcp');
24
+ const { readJsonStrict, writeJson } = require('../lib/mcp-config');
23
25
 
24
26
  const MCP_CONFIGS = {
25
27
  'claude-plugin': {
@@ -110,21 +112,7 @@ function hasLocalPluginMarker(targetDir) {
110
112
  );
111
113
  }
112
114
 
113
- function readJson(filePath) {
114
- if (!fs.existsSync(filePath)) {
115
- return {};
116
- }
117
-
118
- try {
119
- return JSON.parse(fs.readFileSync(filePath, 'utf8'));
120
- } catch (error) {
121
- return {};
122
- }
123
- }
124
-
125
115
  function writeConfig(filePath, config, dryRun) {
126
- const directory = path.dirname(filePath);
127
-
128
116
  if (dryRun) {
129
117
  tui.info(`Would write: ${tui.formatPath(filePath)}`);
130
118
  tui.muted(JSON.stringify(config, null, 2).slice(0, 220) + '...');
@@ -132,11 +120,7 @@ function writeConfig(filePath, config, dryRun) {
132
120
  }
133
121
 
134
122
  try {
135
- if (!fs.existsSync(directory)) {
136
- fs.mkdirSync(directory, { recursive: true });
137
- }
138
-
139
- fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + '\n');
123
+ writeJson(filePath, config);
140
124
  return true;
141
125
  } catch (error) {
142
126
  tui.error(`Failed to write ${filePath}: ${error.message}`);
@@ -174,8 +158,8 @@ function mcpSetupCommand(args, config) {
174
158
  process.exit(1);
175
159
  }
176
160
 
177
- if ((!options.tool || options.tool === 'claude-plugin') && !hasLocalPluginMarker(targetDir)) {
178
- tui.warning('mcp-setup is only for project-local Claude Code plugin configs.');
161
+ if (!hasLocalPluginMarker(targetDir)) {
162
+ tui.warning('mcp-setup is only for existing project-local BI Superpowers plugin configs.');
179
163
  tui.info(
180
164
  'For Codex, GitHub Copilot, Gemini CLI, Kilo Code, and Claude Code user-level installs, run:'
181
165
  );
@@ -184,7 +168,7 @@ function mcpSetupCommand(args, config) {
184
168
  'That writes user-level skills and MCP config under your home directory without creating files in this repo.'
185
169
  );
186
170
  tui.info(
187
- 'If you intentionally need a local Claude Code plugin, run `super kickoff` first or pass `--tool claude-plugin`.'
171
+ 'If you intentionally need local Claude Code plugin files, run `super kickoff` first, then rerun `super mcp-setup` inside that initialized repo.'
188
172
  );
189
173
  process.exitCode = 2;
190
174
  return;
@@ -225,13 +209,19 @@ function mcpSetupCommand(args, config) {
225
209
  configuredTools.forEach((tool) => {
226
210
  const toolConfig = MCP_CONFIGS[tool];
227
211
  const filePath = path.join(targetDir, toolConfig.configPath);
228
- const existingConfig = readJson(filePath);
229
- const generatedConfig = createMcpConfigForFormat(toolConfig.format, {
230
- packageDir: config.packageDir,
231
- launcherMode: getLauncherMode(targetDir, config.packageDir, tool),
232
- });
233
- const mergedConfig = mergeMcpConfig(existingConfig, generatedConfig, toolConfig.format);
234
- const ok = writeConfig(filePath, mergedConfig, options.dryRun);
212
+ let ok = false;
213
+
214
+ try {
215
+ const existingConfig = readJsonStrict(filePath) || {};
216
+ const generatedConfig = createMcpConfigForFormat(toolConfig.format, {
217
+ packageDir: config.packageDir,
218
+ launcherMode: getLauncherMode(targetDir, config.packageDir, tool),
219
+ });
220
+ const mergedConfig = mergeMcpConfig(existingConfig, generatedConfig, toolConfig.format);
221
+ ok = writeConfig(filePath, mergedConfig, options.dryRun);
222
+ } catch (error) {
223
+ tui.error(`Failed to prepare ${filePath}: ${error.message}`);
224
+ }
235
225
 
236
226
  if (ok) {
237
227
  results.success.push(toolConfig.name);