@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
@@ -1,405 +0,0 @@
1
- /**
2
- * Sync Profile Command
3
- * =====================
4
- *
5
- * Syncs snippets/standards from a project to a base profile.
6
- * Allows users to save their custom patterns for reuse across projects.
7
- *
8
- * Usage:
9
- * super sync-profile Interactive mode
10
- * super sync-profile --profile finance Sync to specific profile
11
- * super sync-profile --new healthcare Create new profile and sync
12
- * super sync-profile --all Sync all snippets
13
- *
14
- * @module commands/sync-profile
15
- */
16
-
17
- const fs = require('fs');
18
- const path = require('path');
19
-
20
- const profiles = require('../utils/profiles');
21
- const rl = require('../utils/readline');
22
-
23
- // Using shared readline utilities
24
- const { createReadline, prompt } = rl;
25
-
26
- /**
27
- * Parse command line arguments
28
- * @param {string[]} args - CLI arguments
29
- * @returns {Object} Parsed options
30
- */
31
- function parseArgs(args) {
32
- const options = {
33
- profile: null,
34
- newProfile: null,
35
- all: false,
36
- overwrite: false,
37
- help: false,
38
- };
39
-
40
- for (let i = 0; i < args.length; i++) {
41
- const arg = args[i];
42
-
43
- if (arg === '--profile' || arg === '-p') {
44
- options.profile = args[++i];
45
- } else if (arg === '--new' || arg === '-n') {
46
- options.newProfile = args[++i];
47
- } else if (arg === '--all' || arg === '-a') {
48
- options.all = true;
49
- } else if (arg === '--overwrite' || arg === '-o') {
50
- options.overwrite = true;
51
- } else if (arg === '--help' || arg === '-h') {
52
- options.help = true;
53
- }
54
- }
55
-
56
- return options;
57
- }
58
-
59
- // Readline functions imported from ../utils/readline.js
60
-
61
- /**
62
- * Show help message
63
- */
64
- function showHelp() {
65
- console.log(`
66
- super sync-profile - Sync snippets to a base profile
67
-
68
- Usage:
69
- super sync-profile Interactive mode
70
- super sync-profile --profile <name> Sync to specific profile
71
- super sync-profile --new <name> Create new profile and sync
72
-
73
- Options:
74
- --profile, -p <name> Target profile name
75
- --new, -n <name> Create a new profile
76
- --all, -a Sync all snippets without selecting
77
- --overwrite, -o Overwrite existing files without prompting
78
- --help, -h Show this help message
79
-
80
- Examples:
81
- super sync-profile
82
- super sync-profile --profile finance
83
- super sync-profile --new healthcare --all
84
- `);
85
- }
86
-
87
- /**
88
- * Get snippets from the current repo
89
- * @param {string} repoPath - Path to bi-repo
90
- * @returns {Object[]} Array of snippet objects
91
- */
92
- function getRepoSnippets(repoPath) {
93
- const snippetsDir = path.join(repoPath, 'snippets');
94
- const standardsDir = path.join(repoPath, 'standards');
95
-
96
- const snippets = [];
97
-
98
- // Get snippets
99
- if (fs.existsSync(snippetsDir)) {
100
- const files = profiles.findMdFiles(snippetsDir);
101
- for (const file of files) {
102
- snippets.push({
103
- path: file,
104
- relativePath: path.relative(snippetsDir, file),
105
- type: 'snippet',
106
- });
107
- }
108
- }
109
-
110
- // Get standards
111
- if (fs.existsSync(standardsDir)) {
112
- const files = profiles.findMdFiles(standardsDir);
113
- for (const file of files) {
114
- snippets.push({
115
- path: file,
116
- relativePath: path.relative(standardsDir, file),
117
- type: 'standard',
118
- });
119
- }
120
- }
121
-
122
- return snippets;
123
- }
124
-
125
- /**
126
- * Select target profile interactively
127
- */
128
- async function selectProfile(rl, options) {
129
- // If new profile specified, create it
130
- if (options.newProfile) {
131
- const name = options.newProfile;
132
-
133
- if (profiles.profileExists(name)) {
134
- console.log(`\n⚠ El perfil "${name}" ya existe.`);
135
- const useExisting = await prompt(rl, '¿Usar perfil existente? (s/n): ');
136
- if (useExisting.toLowerCase() !== 's' && useExisting.toLowerCase() !== 'y') {
137
- return null;
138
- }
139
- } else {
140
- console.log(`\nCreando perfil: ${name}`);
141
- profiles.createProfile(name, { inheritsFrom: 'default' });
142
- console.log(' ✓ Perfil creado');
143
- }
144
-
145
- return name;
146
- }
147
-
148
- // If profile specified, validate it
149
- if (options.profile) {
150
- if (!profiles.profileExists(options.profile)) {
151
- console.log(`\n⚠ Perfil "${options.profile}" no existe.`);
152
- const create = await prompt(rl, '¿Crear perfil? (s/n): ');
153
- if (create.toLowerCase() === 's' || create.toLowerCase() === 'y') {
154
- profiles.createProfile(options.profile, { inheritsFrom: 'default' });
155
- console.log(' ✓ Perfil creado');
156
- } else {
157
- return null;
158
- }
159
- }
160
- return options.profile;
161
- }
162
-
163
- // Interactive selection
164
- const availableProfiles = profiles.listProfiles();
165
-
166
- console.log('\nPerfiles disponibles:');
167
- availableProfiles.forEach((p, i) => {
168
- console.log(` ${i + 1}. ${p}`);
169
- });
170
- console.log(` ${availableProfiles.length + 1}. [Crear nuevo perfil]`);
171
-
172
- const choice = await prompt(rl, `\nSelecciona (1-${availableProfiles.length + 1}): `);
173
- const choiceNum = parseInt(choice, 10);
174
-
175
- if (choiceNum === availableProfiles.length + 1) {
176
- // Create new profile
177
- const name = await prompt(rl, 'Nombre del nuevo perfil: ');
178
- if (!name) {
179
- console.log('Nombre requerido.');
180
- return null;
181
- }
182
-
183
- profiles.createProfile(name, { inheritsFrom: 'default' });
184
- console.log(' ✓ Perfil creado');
185
- return name;
186
- } else if (choiceNum >= 1 && choiceNum <= availableProfiles.length) {
187
- return availableProfiles[choiceNum - 1];
188
- }
189
-
190
- return 'default';
191
- }
192
-
193
- /**
194
- * Select snippets to sync
195
- */
196
- async function selectSnippets(rl, snippets, options) {
197
- if (options.all) {
198
- return snippets;
199
- }
200
-
201
- if (snippets.length === 0) {
202
- return [];
203
- }
204
-
205
- console.log('\nArchivos disponibles para sincronizar:\n');
206
-
207
- const selected = new Array(snippets.length).fill(true);
208
-
209
- snippets.forEach((s, i) => {
210
- const type = s.type === 'snippet' ? '📝' : '📋';
211
- console.log(` ${i + 1}. [x] ${type} ${s.relativePath}`);
212
- });
213
-
214
- console.log(`
215
- Opciones:
216
- - Número para toggle (ej: 1)
217
- - 'a' para seleccionar todos
218
- - 'n' para deseleccionar todos
219
- - 'd' para continuar
220
- `);
221
-
222
- while (true) {
223
- const input = await prompt(rl, 'Toggle (1-N), a, n, o d: ');
224
-
225
- if (input.toLowerCase() === 'd') {
226
- break;
227
- } else if (input.toLowerCase() === 'a') {
228
- selected.fill(true);
229
- console.log(' ✓ Todos seleccionados');
230
- } else if (input.toLowerCase() === 'n') {
231
- selected.fill(false);
232
- console.log(' ✓ Ninguno seleccionado');
233
- } else {
234
- const num = parseInt(input, 10);
235
- if (num >= 1 && num <= snippets.length) {
236
- selected[num - 1] = !selected[num - 1];
237
- const status = selected[num - 1] ? '✓' : '✗';
238
- console.log(` ${status} ${snippets[num - 1].relativePath}`);
239
- }
240
- }
241
- }
242
-
243
- return snippets.filter((_, i) => selected[i]);
244
- }
245
-
246
- /**
247
- * Sync snippets to profile
248
- */
249
- function syncToProfile(snippets, profileName, overwrite) {
250
- const results = {
251
- copied: 0,
252
- skipped: 0,
253
- errors: [],
254
- };
255
-
256
- const profileSnippetsDir = path.join(profiles.PROFILES_DIR, profileName, 'snippets');
257
-
258
- for (const snippet of snippets) {
259
- const targetPath = path.join(profileSnippetsDir, snippet.relativePath);
260
- const targetDir = path.dirname(targetPath);
261
-
262
- // Check if file exists
263
- if (fs.existsSync(targetPath) && !overwrite) {
264
- results.skipped++;
265
- continue;
266
- }
267
-
268
- try {
269
- // Create directory if needed
270
- if (!fs.existsSync(targetDir)) {
271
- fs.mkdirSync(targetDir, { recursive: true });
272
- }
273
-
274
- // Copy file
275
- fs.copyFileSync(snippet.path, targetPath);
276
- results.copied++;
277
- } catch (e) {
278
- results.errors.push({
279
- file: snippet.relativePath,
280
- error: e.message,
281
- });
282
- }
283
- }
284
-
285
- return results;
286
- }
287
-
288
- /**
289
- * Main sync-profile command handler
290
- */
291
- async function syncProfileCommand(args, _config) {
292
- const options = parseArgs(args);
293
-
294
- if (options.help) {
295
- showHelp();
296
- return;
297
- }
298
-
299
- // Check if repo exists
300
- const repoPath = profiles.getRepoPath();
301
- if (!repoPath || !fs.existsSync(repoPath)) {
302
- console.log(`
303
- No se encontró el repositorio de BI.
304
-
305
- Ejecuta primero:
306
- super setup
307
- `);
308
- process.exit(1);
309
- }
310
-
311
- console.log(`
312
- ════════════════════════════════════════════════════════════════
313
- Sync Profile - Guardar snippets al perfil base
314
- ════════════════════════════════════════════════════════════════
315
- `);
316
-
317
- // Get snippets from repo
318
- const snippets = getRepoSnippets(repoPath);
319
-
320
- if (snippets.length === 0) {
321
- console.log('No hay snippets o standards para sincronizar.');
322
- console.log('\nCrea archivos .md en:');
323
- console.log(` ${path.join(repoPath, 'snippets')}/`);
324
- console.log(` ${path.join(repoPath, 'standards')}/`);
325
- return;
326
- }
327
-
328
- console.log(`Encontrados: ${snippets.length} archivos\n`);
329
-
330
- const rl = createReadline();
331
-
332
- try {
333
- // Select profile
334
- const targetProfile = await selectProfile(rl, options);
335
-
336
- if (!targetProfile) {
337
- console.log('\nCancelado.');
338
- return;
339
- }
340
-
341
- console.log(`\nPerfil destino: ${targetProfile}`);
342
-
343
- // Select snippets
344
- const selectedSnippets = await selectSnippets(rl, snippets, options);
345
-
346
- if (selectedSnippets.length === 0) {
347
- console.log('\nNo hay archivos seleccionados.');
348
- return;
349
- }
350
-
351
- console.log(`\nSincronizando ${selectedSnippets.length} archivos...`);
352
-
353
- // Check for conflicts if not overwrite mode
354
- if (!options.overwrite) {
355
- const profileSnippetsDir = path.join(profiles.PROFILES_DIR, targetProfile, 'snippets');
356
- const conflicts = selectedSnippets.filter((s) =>
357
- fs.existsSync(path.join(profileSnippetsDir, s.relativePath))
358
- );
359
-
360
- if (conflicts.length > 0) {
361
- console.log(`\n⚠ ${conflicts.length} archivo(s) ya existen en el perfil:`);
362
- conflicts.slice(0, 5).forEach((c) => {
363
- console.log(` - ${c.relativePath}`);
364
- });
365
- if (conflicts.length > 5) {
366
- console.log(` ... y ${conflicts.length - 5} más`);
367
- }
368
-
369
- const overwriteChoice = await prompt(rl, '\n¿Sobrescribir existentes? (s/n): ');
370
- options.overwrite =
371
- overwriteChoice.toLowerCase() === 's' || overwriteChoice.toLowerCase() === 'y';
372
- }
373
- }
374
-
375
- // Sync
376
- const results = syncToProfile(selectedSnippets, targetProfile, options.overwrite);
377
-
378
- console.log(`
379
- ════════════════════════════════════════════════════════════════
380
- Resumen
381
- ════════════════════════════════════════════════════════════════
382
-
383
- Perfil: ${targetProfile}
384
- Copiados: ${results.copied}
385
- Omitidos: ${results.skipped}
386
- Errores: ${results.errors.length}
387
-
388
- Los snippets estarán disponibles en proyectos que usen
389
- el perfil "${targetProfile}".
390
-
391
- ════════════════════════════════════════════════════════════════
392
- `);
393
-
394
- if (results.errors.length > 0) {
395
- console.log('Errores:');
396
- results.errors.forEach((e) => {
397
- console.log(` ✗ ${e.file}: ${e.error}`);
398
- });
399
- }
400
- } finally {
401
- rl.close();
402
- }
403
- }
404
-
405
- module.exports = syncProfileCommand;
@@ -1,14 +0,0 @@
1
- /**
2
- * Tests for Sync Profile Command
3
- * @module commands/sync-profile.test
4
- */
5
-
6
- const { test, describe } = require('node:test');
7
- const assert = require('node:assert');
8
-
9
- describe('Sync Profile Command', () => {
10
- test('module exports a function', () => {
11
- const syncProfileCommand = require('./sync-profile');
12
- assert.strictEqual(typeof syncProfileCommand, 'function');
13
- });
14
- });