@luquimbo/bi-superpowers 3.1.0 → 3.2.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 (110) 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/README.md +2 -2
  6. package/bin/build-plugin.js +6 -6
  7. package/bin/cli.js +169 -310
  8. package/bin/commands/install.js +87 -70
  9. package/bin/commands/install.test.js +2 -2
  10. package/bin/lib/agents.js +21 -2
  11. package/bin/lib/mcp-config.js +27 -5
  12. package/bin/lib/mcp-config.test.js +1 -1
  13. package/desktop-extension/manifest.json +4 -11
  14. package/desktop-extension/server.js +34 -25
  15. package/package.json +3 -9
  16. package/skills/pbi-connect/SKILL.md +1 -1
  17. package/skills/project-kickoff/SKILL.md +1 -1
  18. package/bin/commands/add.js +0 -533
  19. package/bin/commands/add.test.js +0 -77
  20. package/bin/commands/changelog.js +0 -443
  21. package/bin/commands/pull.js +0 -287
  22. package/bin/commands/pull.test.js +0 -36
  23. package/bin/commands/push.js +0 -231
  24. package/bin/commands/push.test.js +0 -14
  25. package/bin/commands/search.js +0 -344
  26. package/bin/commands/search.test.js +0 -115
  27. package/bin/commands/setup.js +0 -545
  28. package/bin/commands/setup.test.js +0 -46
  29. package/bin/commands/sync-profile.js +0 -405
  30. package/bin/commands/sync-profile.test.js +0 -14
  31. package/bin/commands/sync-source.js +0 -418
  32. package/bin/commands/sync-source.test.js +0 -14
  33. package/bin/utils/errors.js +0 -159
  34. package/bin/utils/git.js +0 -298
  35. package/bin/utils/logger.js +0 -142
  36. package/bin/utils/pbix.js +0 -305
  37. package/bin/utils/pbix.test.js +0 -37
  38. package/bin/utils/profiles.js +0 -312
  39. package/bin/utils/projects.js +0 -169
  40. package/bin/utils/readline.js +0 -206
  41. package/bin/utils/readline.test.js +0 -47
  42. package/docs/openrouter-free-models.md +0 -92
  43. package/library/examples/README.md +0 -151
  44. package/library/examples/finance-reporting/README.md +0 -351
  45. package/library/examples/finance-reporting/data-model.md +0 -267
  46. package/library/examples/finance-reporting/measures.dax +0 -557
  47. package/library/examples/hr-analytics/README.md +0 -371
  48. package/library/examples/hr-analytics/data-model.md +0 -315
  49. package/library/examples/hr-analytics/measures.dax +0 -460
  50. package/library/examples/marketing-analytics/README.md +0 -37
  51. package/library/examples/marketing-analytics/data-model.md +0 -62
  52. package/library/examples/marketing-analytics/measures.dax +0 -110
  53. package/library/examples/retail-analytics/README.md +0 -439
  54. package/library/examples/retail-analytics/data-model.md +0 -288
  55. package/library/examples/retail-analytics/measures.dax +0 -481
  56. package/library/examples/supply-chain/README.md +0 -37
  57. package/library/examples/supply-chain/data-model.md +0 -69
  58. package/library/examples/supply-chain/measures.dax +0 -77
  59. package/library/examples/udf-library/README.md +0 -228
  60. package/library/examples/udf-library/functions.dax +0 -571
  61. package/library/snippets/dax/README.md +0 -292
  62. package/library/snippets/dax/business-domains.md +0 -576
  63. package/library/snippets/dax/calculate-patterns.md +0 -276
  64. package/library/snippets/dax/calculation-groups.md +0 -489
  65. package/library/snippets/dax/error-handling.md +0 -495
  66. package/library/snippets/dax/iterators-and-aggregations.md +0 -474
  67. package/library/snippets/dax/kpis-and-metrics.md +0 -293
  68. package/library/snippets/dax/rankings-and-topn.md +0 -235
  69. package/library/snippets/dax/security-patterns.md +0 -413
  70. package/library/snippets/dax/text-and-formatting.md +0 -316
  71. package/library/snippets/dax/time-intelligence.md +0 -196
  72. package/library/snippets/dax/user-defined-functions.md +0 -477
  73. package/library/snippets/dax/virtual-tables.md +0 -546
  74. package/library/snippets/excel-formulas/README.md +0 -84
  75. package/library/snippets/excel-formulas/aggregations.md +0 -330
  76. package/library/snippets/excel-formulas/dates-and-times.md +0 -361
  77. package/library/snippets/excel-formulas/dynamic-arrays.md +0 -314
  78. package/library/snippets/excel-formulas/lookups.md +0 -169
  79. package/library/snippets/excel-formulas/text-functions.md +0 -363
  80. package/library/snippets/governance/naming-conventions.md +0 -97
  81. package/library/snippets/governance/review-checklists.md +0 -107
  82. package/library/snippets/power-query/README.md +0 -389
  83. package/library/snippets/power-query/api-integration.md +0 -707
  84. package/library/snippets/power-query/connections.md +0 -434
  85. package/library/snippets/power-query/data-cleaning.md +0 -298
  86. package/library/snippets/power-query/error-handling.md +0 -526
  87. package/library/snippets/power-query/parameters.md +0 -350
  88. package/library/snippets/power-query/performance.md +0 -506
  89. package/library/snippets/power-query/transformations.md +0 -330
  90. package/library/snippets/report-design/accessibility.md +0 -78
  91. package/library/snippets/report-design/chart-selection.md +0 -54
  92. package/library/snippets/report-design/layout-patterns.md +0 -87
  93. package/library/templates/data-models/README.md +0 -93
  94. package/library/templates/data-models/finance-model.md +0 -627
  95. package/library/templates/data-models/retail-star-schema.md +0 -473
  96. package/library/templates/excel/README.md +0 -83
  97. package/library/templates/excel/budget-tracker.md +0 -432
  98. package/library/templates/excel/data-entry-form.md +0 -533
  99. package/library/templates/power-bi/README.md +0 -72
  100. package/library/templates/power-bi/finance-report.md +0 -449
  101. package/library/templates/power-bi/kpi-scorecard.md +0 -461
  102. package/library/templates/power-bi/sales-dashboard.md +0 -281
  103. package/library/themes/excel/README.md +0 -436
  104. package/library/themes/power-bi/README.md +0 -271
  105. package/library/themes/power-bi/accessible.json +0 -307
  106. package/library/themes/power-bi/bi-superpowers-default.json +0 -858
  107. package/library/themes/power-bi/corporate-blue.json +0 -291
  108. package/library/themes/power-bi/dark-mode.json +0 -291
  109. package/library/themes/power-bi/minimal.json +0 -292
  110. package/library/themes/power-bi/print-friendly.json +0 -309
@@ -3,10 +3,11 @@
3
3
  /**
4
4
  * BI Agent Superpowers — MCP Server for Claude Desktop
5
5
  *
6
- * Lightweight MCP server that exposes all 24 BI skills as prompts.
7
- * Bundled into a .mcpb extension via `super build-desktop`.
6
+ * Lightweight MCP server that exposes each bi-superpowers skill as a
7
+ * Claude Desktop prompt. Bundled into a .mcpb extension via
8
+ * `super build-desktop`.
8
9
  *
9
- * Skills are loaded from the ./skills/ directory (copied at build time).
10
+ * Skills are loaded from the ./skills/ directory (copied in at build time).
10
11
  */
11
12
 
12
13
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
@@ -18,29 +19,25 @@ import { fileURLToPath } from 'url';
18
19
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
19
20
  const skillsDir = path.join(__dirname, 'skills');
20
21
 
21
- // Create the MCP server instance
22
+ // Create the MCP server instance.
22
23
  const server = new McpServer({
23
24
  name: 'bi-superpowers',
24
25
  version: '0.0.0-template',
25
26
  });
26
27
 
27
- // Load all skill markdown files from the bundled skills/ directory
28
+ // Load all skill markdown files from the bundled skills/ directory.
28
29
  const skillFiles = fs.existsSync(skillsDir)
29
30
  ? fs.readdirSync(skillsDir).filter((f) => f.endsWith('.md'))
30
31
  : [];
31
32
 
32
- // Register each skill as an MCP prompt that Claude Desktop can invoke
33
+ // Register each skill as an MCP prompt that Claude Desktop can invoke.
33
34
  for (const file of skillFiles) {
34
35
  const name = path.basename(file, '.md');
35
36
  const content = fs.readFileSync(path.join(skillsDir, file), 'utf8');
36
37
 
37
- // Extract first line as description (skip markdown headers)
38
- const firstLine = content
39
- .split('\n')
40
- .find((l) => l.trim() && !l.startsWith('#'));
41
- const description = firstLine
42
- ? firstLine.slice(0, 120).trim()
43
- : `BI Superpowers: ${name}`;
38
+ // Use the first non-header line as a short description for the prompt.
39
+ const firstLine = content.split('\n').find((l) => l.trim() && !l.startsWith('#'));
40
+ const description = firstLine ? firstLine.slice(0, 120).trim() : `BI Superpowers: ${name}`;
44
41
 
45
42
  server.prompt(name, { description }, () => ({
46
43
  messages: [
@@ -52,10 +49,15 @@ for (const file of skillFiles) {
52
49
  }));
53
50
  }
54
51
 
55
- // Register a setup-mcp helper prompt with Power BI/Fabric/Excel MCP instructions
52
+ // Register a setup-mcp helper prompt that explains how to wire the
53
+ // official Microsoft MCP servers (Power BI Modeling + Microsoft Learn)
54
+ // into Claude Desktop.
56
55
  server.prompt(
57
56
  'setup-mcp',
58
- { description: 'Instructions to configure Power BI, Fabric & Excel MCP servers in Claude Desktop' },
57
+ {
58
+ description:
59
+ 'Instructions to configure the Power BI Modeling and Microsoft Learn MCP servers in Claude Desktop',
60
+ },
59
61
  () => ({
60
62
  messages: [
61
63
  {
@@ -64,25 +66,32 @@ server.prompt(
64
66
  type: 'text',
65
67
  text: `# Configure MCP Servers for Claude Desktop
66
68
 
67
- To connect Power BI, Fabric, and Excel to Claude Desktop, add the following
68
- to your \`claude_desktop_config.json\` (Settings > Developer > Edit Config):
69
+ bi-superpowers ships two official Microsoft MCP servers. To wire them
70
+ into Claude Desktop, add the following to your \`claude_desktop_config.json\`
71
+ (Settings → Developer → Edit Config):
69
72
 
70
73
  \`\`\`json
71
74
  {
72
75
  "mcpServers": {
73
- "powerbi-remote": {
74
- "command": "npx",
75
- "args": ["-y", "@anthropic-ai/mcp-remote", "https://mcp.powerbi.com/sse"]
76
+ "powerbi-modeling": {
77
+ "command": "node",
78
+ "args": ["<absolute path to powerbi-modeling-launcher.js>"]
76
79
  },
77
- "fabric-mcp-server": {
78
- "command": "npx",
79
- "args": ["-y", "@anthropic-ai/mcp-remote", "https://mcp.fabric.microsoft.com/v1/sse"]
80
+ "microsoft-learn": {
81
+ "type": "http",
82
+ "url": "https://learn.microsoft.com/api/mcp"
80
83
  }
81
84
  }
82
85
  }
83
86
  \`\`\`
84
87
 
85
- After saving, restart Claude Desktop. The MCP servers will appear in your tools.
88
+ The \`powerbi-modeling\` server requires Power BI Desktop on Windows
89
+ with a model open. If you prefer automated setup, run
90
+ \`super install\` from the bi-superpowers CLI — it configures both
91
+ servers across all 5 supported AI agents.
92
+
93
+ After saving, restart Claude Desktop. The MCP servers will appear in
94
+ your tools.
86
95
  `,
87
96
  },
88
97
  },
@@ -90,6 +99,6 @@ After saving, restart Claude Desktop. The MCP servers will appear in your tools.
90
99
  })
91
100
  );
92
101
 
93
- // Start the server with stdio transport
102
+ // Start the server with stdio transport.
94
103
  const transport = new StdioServerTransport();
95
104
  await server.connect(transport);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@luquimbo/bi-superpowers",
3
- "version": "3.1.0",
4
- "description": "Plugin-first Claude Code toolkit for Power BI, Microsoft Fabric, and Excel workflows powered by official Microsoft MCP servers.",
3
+ "version": "3.2.0",
4
+ "description": "Open-source Power BI Desktop toolkit for Claude Code, GitHub Copilot, Codex, Gemini CLI, and Kilo Code. Ships 2 skills and 2 official Microsoft MCP servers.",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
7
7
  "bi-superpowers": "bin/cli.js"
@@ -25,11 +25,7 @@
25
25
  "chalk": "^4.1.2",
26
26
  "chokidar": "^3.6.0",
27
27
  "cli-table3": "^0.6.5",
28
- "fuse.js": "^7.3.0",
29
- "gray-matter": "^4.0.3",
30
- "js-yaml": "^4.1.0",
31
- "ora": "^5.4.1",
32
- "simple-git": "^3.22.0"
28
+ "ora": "^5.4.1"
33
29
  },
34
30
  "devDependencies": {
35
31
  "@eslint/js": "^9.39.2",
@@ -81,9 +77,7 @@
81
77
  "commands/",
82
78
  "skills/",
83
79
  "src/content/",
84
- "library/",
85
80
  "desktop-extension/",
86
- "docs/",
87
81
  "config.json",
88
82
  "config.example.json",
89
83
  "README.md",
@@ -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.1.0"
4
+ version: "3.2.0"
5
5
  ---
6
6
 
7
7
  <!-- Generated by BI Agent Superpowers. Edit src/content/skills/pbi-connect.md instead. -->
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: "project-kickoff"
3
3
  description: "Project Kickoff Skill: Project analysis and planning."
4
- version: "3.1.0"
4
+ version: "3.2.0"
5
5
  ---
6
6
 
7
7
  <!-- Generated by BI Agent Superpowers. Edit src/content/skills/project-kickoff.md instead. -->
@@ -1,533 +0,0 @@
1
- /**
2
- * Add Command - Add Project to Repository
3
- * =========================================
4
- *
5
- * Adds a Power BI or Excel project to the bi-repo.
6
- * Extracts versionable content (TMDL, queries) and creates project config.
7
- *
8
- * Usage:
9
- * super add "C:/path/to/file.pbix"
10
- * super add "C:/path/to/file.pbix" --profile finance
11
- * super add "C:/path/to/file.xlsx" --name budget-2026
12
- *
13
- * @module commands/add
14
- */
15
-
16
- const fs = require('fs');
17
- const path = require('path');
18
-
19
- const git = require('../utils/git');
20
- const profiles = require('../utils/profiles');
21
- const pbix = require('../utils/pbix');
22
- const rl = require('../utils/readline');
23
-
24
- // Using shared readline utilities
25
- const { createReadline, prompt } = rl;
26
-
27
- /**
28
- * Parse command line arguments
29
- * @param {string[]} args - CLI arguments
30
- * @returns {Object} Parsed options
31
- */
32
- function parseArgs(args) {
33
- const options = {
34
- filePath: null,
35
- name: null,
36
- profile: null,
37
- help: false,
38
- };
39
-
40
- for (let i = 0; i < args.length; i++) {
41
- const arg = args[i];
42
-
43
- if (arg === '--name' || arg === '-n') {
44
- options.name = args[++i];
45
- } else if (arg === '--profile' || arg === '-p') {
46
- options.profile = args[++i];
47
- } else if (arg === '--help' || arg === '-h') {
48
- options.help = true;
49
- } else if (!arg.startsWith('-') && !options.filePath) {
50
- options.filePath = arg;
51
- }
52
- }
53
-
54
- return options;
55
- }
56
-
57
- // Readline functions imported from ../utils/readline.js
58
-
59
- /**
60
- * Show help message
61
- */
62
- function showHelp() {
63
- console.log(`
64
- super add - Añadir un proyecto BI al repositorio
65
-
66
- Uso:
67
- super add <archivo> Añadir un proyecto
68
- super add <archivo> --profile <nombre> Añadir con perfil específico
69
- super add <archivo> --name <nombre> Especificar nombre del proyecto
70
-
71
- Argumentos:
72
- <archivo> Ruta al archivo .pbix, .pbip o .xlsx
73
-
74
- Opciones:
75
- --name, -n <nombre> Nombre personalizado del proyecto (slug)
76
- --profile, -p <nombre> Perfil a usar (default, finance, retail, etc.)
77
- --help, -h Mostrar esta ayuda
78
-
79
- Ejemplos:
80
- super add "C:/Users/Juan/Documents/Sales.pbix"
81
- super add "./Dashboard.pbix" --profile finance
82
- super add "Budget.xlsx" --name budget-2026 --profile finance
83
- `);
84
- }
85
-
86
- /**
87
- * Get or create project name
88
- */
89
- async function getProjectName(rl, fileInfo, customName) {
90
- if (customName) {
91
- return pbix.generateSlug(customName);
92
- }
93
-
94
- const suggested = pbix.generateSlug(fileInfo.name);
95
- console.log(`\nNombre detectado: ${fileInfo.name}`);
96
- const input = await prompt(rl, `Nombre del proyecto [${suggested}]: `);
97
-
98
- return input ? pbix.generateSlug(input) : suggested;
99
- }
100
-
101
- /**
102
- * Select profile for the project
103
- */
104
- async function selectProfile(rl, customProfile) {
105
- if (customProfile) {
106
- // Validate profile exists or create it
107
- if (!profiles.profileExists(customProfile)) {
108
- console.log(`\nPerfil "${customProfile}" no existe. Creándolo...`);
109
- profiles.createProfile(customProfile, { inheritsFrom: 'default' });
110
- }
111
- return customProfile;
112
- }
113
-
114
- const availableProfiles = profiles.listProfiles();
115
-
116
- console.log('\nPerfil a usar:');
117
- availableProfiles.forEach((p, i) => {
118
- console.log(` ${i + 1}. ${p}`);
119
- });
120
-
121
- const choice = await prompt(rl, `\nSelecciona (1-${availableProfiles.length}): `);
122
- const choiceNum = parseInt(choice, 10);
123
-
124
- if (choiceNum >= 1 && choiceNum <= availableProfiles.length) {
125
- return availableProfiles[choiceNum - 1];
126
- }
127
-
128
- return 'default';
129
- }
130
-
131
- /**
132
- * Create project directory in repo
133
- */
134
- function createProjectDirectory(repoPath, projectName) {
135
- const projectDir = path.join(repoPath, 'projects', projectName);
136
-
137
- if (fs.existsSync(projectDir)) {
138
- return { exists: true, path: projectDir };
139
- }
140
-
141
- fs.mkdirSync(projectDir, { recursive: true });
142
- fs.mkdirSync(path.join(projectDir, 'definition'), { recursive: true });
143
- fs.mkdirSync(path.join(projectDir, 'queries'), { recursive: true });
144
-
145
- return { exists: false, path: projectDir };
146
- }
147
-
148
- /**
149
- * Extract content based on file type
150
- */
151
- function extractContent(fileInfo, projectDir) {
152
- const result = {
153
- success: false,
154
- files: [],
155
- message: '',
156
- };
157
-
158
- if (fileInfo.type === 'power-bi-project') {
159
- // PBIP - extract TMDL directly
160
- const extraction = pbix.extractPbipToRepo(fileInfo.path, projectDir);
161
- if (extraction.success) {
162
- result.success = true;
163
- result.files = extraction.files;
164
- result.message = `Extraídos ${extraction.files.length} archivos TMDL`;
165
- } else {
166
- result.message = extraction.error;
167
- }
168
- } else if (fileInfo.type === 'power-bi') {
169
- // PBIX - binary file, cannot extract directly
170
- // We'll create a placeholder and instruct user to save as PBIP
171
- result.success = true;
172
- result.message = `
173
- NOTA: Los archivos .pbix son binarios y no se pueden versionar directamente.
174
-
175
- Para versionar tu modelo, tienes dos opciones:
176
-
177
- 1. RECOMENDADO: Guarda como proyecto PBIP
178
- - En Power BI Desktop: File → Save as → Power BI Project (.pbip)
179
- - Luego ejecuta: super add "ruta/al/proyecto.pbip"
180
-
181
- 2. Usar el formato actual:
182
- - El proyecto se añadirá con referencia al .pbix
183
- - Los cambios se detectarán por fecha de modificación
184
- - No podrás ver diferencias detalladas en Git`;
185
-
186
- // Create a note file
187
- const noteContent = `# ${fileInfo.name}
188
-
189
- Este proyecto está vinculado a un archivo .pbix binario.
190
-
191
- ## Archivo Original
192
- - Ruta: ${fileInfo.path}
193
- - Tipo: Power BI Desktop (.pbix)
194
-
195
- ## Para mejor versionado
196
-
197
- Considera guardar como Power BI Project (.pbip):
198
- 1. Abre el archivo en Power BI Desktop
199
- 2. File → Save as → Power BI Project (.pbip)
200
- 3. Ejecuta: super add "ruta/al/proyecto.pbip"
201
-
202
- Los archivos .pbip contienen TMDL (texto) que Git puede versionar correctamente.
203
- `;
204
-
205
- fs.writeFileSync(path.join(projectDir, 'README.md'), noteContent);
206
- result.files = ['README.md'];
207
- } else if (fileInfo.type === 'excel' || fileInfo.type === 'excel-macro') {
208
- // Excel - create documentation placeholder
209
- result.success = true;
210
-
211
- const workbookDir = path.join(projectDir, 'workbook');
212
- if (!fs.existsSync(workbookDir)) {
213
- fs.mkdirSync(workbookDir, { recursive: true });
214
- }
215
-
216
- const structureContent = `# ${fileInfo.name}
217
-
218
- ## Estructura del Workbook
219
-
220
- Documenta aquí la estructura de tu workbook:
221
-
222
- ### Hojas
223
- -
224
-
225
- ### Tablas
226
- -
227
-
228
- ### Rangos Nombrados
229
- -
230
-
231
- ### Conexiones de Datos
232
- -
233
- `;
234
-
235
- fs.writeFileSync(path.join(workbookDir, 'structure.md'), structureContent);
236
-
237
- const formulasContent = `# Fórmulas Importantes
238
-
239
- Documenta aquí las fórmulas clave de tu workbook:
240
-
241
- ## Cálculos Principales
242
-
243
- \`\`\`excel
244
- =EXAMPLE_FORMULA()
245
- \`\`\`
246
-
247
- ## Lookups
248
-
249
- ## Agregaciones
250
- `;
251
-
252
- fs.writeFileSync(path.join(workbookDir, 'formulas.md'), formulasContent);
253
-
254
- result.files = ['workbook/structure.md', 'workbook/formulas.md'];
255
- result.message = 'Creada estructura para documentar el workbook Excel';
256
- } else {
257
- result.message = 'Tipo de archivo no soportado';
258
- }
259
-
260
- return result;
261
- }
262
-
263
- /**
264
- * Update repo config with new project
265
- */
266
- function updateRepoConfig(repoPath, projectName, projectConfig) {
267
- const configPath = path.join(repoPath, '.bi-superpowers.json');
268
-
269
- let config = { version: '3.0', projects: [] };
270
- if (fs.existsSync(configPath)) {
271
- try {
272
- config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
273
- } catch (e) {
274
- // Use default
275
- }
276
- }
277
-
278
- // Add or update project
279
- const existingIndex = config.projects.findIndex((p) => p.name === projectName);
280
- if (existingIndex >= 0) {
281
- config.projects[existingIndex] = projectConfig;
282
- } else {
283
- config.projects.push(projectConfig);
284
- }
285
-
286
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
287
- }
288
-
289
- /**
290
- * Main add command handler
291
- */
292
- async function addCommand(args, _config) {
293
- const options = parseArgs(args);
294
-
295
- if (options.help) {
296
- showHelp();
297
- return;
298
- }
299
-
300
- // Check if repo exists
301
- const repoPath = profiles.getRepoPath();
302
- if (!repoPath || !fs.existsSync(repoPath)) {
303
- console.log(`
304
- No se encontró el repositorio de BI.
305
-
306
- Ejecuta primero:
307
- super setup
308
-
309
- Para crear tu repositorio de proyectos.
310
- `);
311
- process.exit(1);
312
- }
313
-
314
- // Check if file path provided
315
- if (!options.filePath) {
316
- console.log(`
317
- Uso: super add <archivo>
318
-
319
- Ejemplo:
320
- super add "C:/Users/Juan/Documents/Sales.pbix"
321
- super add ./Dashboard.pbip --profile finance
322
- `);
323
- process.exit(1);
324
- }
325
-
326
- // Resolve and validate file path
327
- const filePath = path.resolve(options.filePath);
328
-
329
- // Security: Validate path to prevent path traversal attacks
330
- // Ensure the resolved path is within expected locations (user's folders, not system paths)
331
- const normalizedPath = path.normalize(filePath);
332
- const systemPaths = [
333
- path.normalize('C:\\Windows'),
334
- path.normalize('C:\\Program Files'),
335
- path.normalize('C:\\Program Files (x86)'),
336
- '/etc',
337
- '/usr',
338
- '/bin',
339
- '/sbin',
340
- '/var',
341
- '/root',
342
- ];
343
-
344
- const isSystemPath = systemPaths.some((sysPath) =>
345
- normalizedPath.toLowerCase().startsWith(sysPath.toLowerCase())
346
- );
347
-
348
- if (isSystemPath) {
349
- console.log('\n✗ Access denied: Cannot add files from system directories');
350
- console.log(' Please use files from your user directories.');
351
- process.exit(1);
352
- }
353
-
354
- const fileInfo = pbix.detectFileType(filePath);
355
-
356
- if (!fileInfo.exists) {
357
- console.log(`\n✗ Archivo no encontrado: ${filePath}`);
358
- process.exit(1);
359
- }
360
-
361
- if (fileInfo.type === 'unknown') {
362
- console.log(`\n✗ Tipo de archivo no soportado: ${fileInfo.extension}`);
363
- console.log(' Formatos soportados: .pbix, .pbip, .xlsx, .xlsm');
364
- process.exit(1);
365
- }
366
-
367
- console.log(`
368
- ════════════════════════════════════════════════════════════════
369
- Añadir Proyecto
370
- ════════════════════════════════════════════════════════════════
371
-
372
- Archivo: ${fileInfo.name}${fileInfo.extension}
373
- Tipo: ${fileInfo.type}
374
- Ruta: ${filePath}
375
- `);
376
-
377
- const rl = createReadline();
378
-
379
- try {
380
- // Get project name
381
- const projectName = await getProjectName(rl, fileInfo, options.name);
382
-
383
- // Select profile
384
- const profile = await selectProfile(rl, options.profile);
385
-
386
- // Create project directory
387
- const projectDir = createProjectDirectory(repoPath, projectName);
388
-
389
- if (projectDir.exists) {
390
- const overwrite = await prompt(
391
- rl,
392
- `\nEl proyecto "${projectName}" ya existe. ¿Sobrescribir? (s/n): `
393
- );
394
- if (overwrite.toLowerCase() !== 's' && overwrite.toLowerCase() !== 'y') {
395
- console.log('\nCancelado.');
396
- return;
397
- }
398
- }
399
-
400
- console.log(`\nCreando proyecto: ${projectName}`);
401
- console.log(` Directorio: ${projectDir.path}`);
402
- console.log(` Perfil: ${profile}`);
403
-
404
- // Extract content
405
- const extraction = extractContent(fileInfo, projectDir.path);
406
-
407
- if (extraction.success) {
408
- console.log(`\n ✓ ${extraction.message}`);
409
-
410
- if (extraction.files.length > 0) {
411
- console.log(' Archivos:');
412
- extraction.files.slice(0, 5).forEach((f) => {
413
- console.log(` - ${f}`);
414
- });
415
- if (extraction.files.length > 5) {
416
- console.log(` ... y ${extraction.files.length - 5} más`);
417
- }
418
- }
419
- } else if (extraction.message) {
420
- console.log(extraction.message);
421
- }
422
-
423
- // Create project.json (legacy, for backward compatibility)
424
- const projectConfig = pbix.createProjectConfig({
425
- name: projectName,
426
- displayName: fileInfo.name,
427
- type: fileInfo.type,
428
- profile: profile,
429
- sourcePath: filePath,
430
- });
431
-
432
- fs.writeFileSync(
433
- path.join(projectDir.path, 'project.json'),
434
- JSON.stringify(projectConfig, null, 2)
435
- );
436
- console.log(' ✓ Creado: project.json');
437
-
438
- // Create bi-project.json (versioned project config - NEW in v2.4)
439
- const biProjectConfig = {
440
- version: '1.0',
441
- name: projectName,
442
- displayName: fileInfo.name,
443
- type: fileInfo.type,
444
- profile: profile,
445
- sourcePath: filePath,
446
- created: new Date().toISOString(),
447
- mcpServers: {
448
- 'powerbi-modeling-mcp': {
449
- enabled: true,
450
- launcher: 'official-microsoft',
451
- },
452
- 'powerbi-remote': {
453
- enabled: false,
454
- semanticModelId: null,
455
- },
456
- 'fabric-mcp-server': {
457
- enabled: true,
458
- mode: 'all',
459
- },
460
- },
461
- changelog: {
462
- enabled: true,
463
- path: 'CHANGELOG.md',
464
- includeInAgentContext: true,
465
- recentChangesCount: 5,
466
- },
467
- agentContext: {
468
- includeRecentChanges: true,
469
- customInstructions: null,
470
- },
471
- };
472
-
473
- fs.writeFileSync(
474
- path.join(projectDir.path, 'bi-project.json'),
475
- JSON.stringify(biProjectConfig, null, 2)
476
- );
477
- console.log(' ✓ Creado: bi-project.json (configuración versionada)');
478
-
479
- // Create initial CHANGELOG.md
480
- const changelogContent = `# Changelog - ${fileInfo.name}
481
-
482
- All notable changes to this project will be documented in this file.
483
-
484
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
485
-
486
- ## [Unreleased]
487
-
488
- ### Added
489
- - Initial project setup with BI Agent Superpowers
490
-
491
- ---
492
- *Generated by [BI Agent Superpowers](https://github.com/luquimbo/bi-superpowers)*
493
- `;
494
-
495
- fs.writeFileSync(path.join(projectDir.path, 'CHANGELOG.md'), changelogContent);
496
- console.log(' ✓ Creado: CHANGELOG.md');
497
-
498
- // Update repo config
499
- updateRepoConfig(repoPath, projectName, {
500
- name: projectName,
501
- type: fileInfo.type,
502
- profile: profile,
503
- });
504
-
505
- // Git commit
506
- if (git.isGitRepo(repoPath)) {
507
- git.stageFiles(repoPath, '.');
508
- git.commit(repoPath, `Add project: ${projectName}`);
509
- console.log(` ✓ Commit: "Add project: ${projectName}"`);
510
- }
511
-
512
- console.log(`
513
- ════════════════════════════════════════════════════════════════
514
- ¡Proyecto añadido!
515
- ════════════════════════════════════════════════════════════════
516
-
517
- Los archivos originales permanecen en:
518
- ${filePath}
519
-
520
- Para traer cambios del original al repo:
521
- super pull ${projectName}
522
-
523
- Para ver el historial:
524
- cd "${repoPath}" && git log --oneline
525
-
526
- ════════════════════════════════════════════════════════════════
527
- `);
528
- } finally {
529
- rl.close();
530
- }
531
- }
532
-
533
- module.exports = addCommand;