@luquimbo/bi-superpowers 3.1.1 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/.claude-plugin/marketplace.json +5 -3
  2. package/.claude-plugin/plugin.json +28 -2
  3. package/.claude-plugin/skill-manifest.json +22 -6
  4. package/.plugin/plugin.json +1 -1
  5. package/AGENTS.md +52 -36
  6. package/CHANGELOG.md +295 -0
  7. package/README.md +75 -26
  8. package/bin/build-plugin.js +17 -10
  9. package/bin/cli.js +278 -322
  10. package/bin/commands/build-desktop.js +35 -16
  11. package/bin/commands/diff.js +31 -13
  12. package/bin/commands/install.js +93 -72
  13. package/bin/commands/lint.js +40 -26
  14. package/bin/commands/mcp-setup.js +3 -10
  15. package/bin/commands/update-check.js +389 -0
  16. package/bin/lib/agents.js +19 -0
  17. package/bin/lib/generators/claude-plugin.js +144 -6
  18. package/bin/lib/generators/shared.js +29 -33
  19. package/bin/lib/mcp-config.js +191 -16
  20. package/bin/lib/skills.js +115 -27
  21. package/bin/postinstall.js +4 -2
  22. package/bin/utils/mcp-detect.js +2 -2
  23. package/commands/bi-start.md +218 -0
  24. package/commands/pbi-connect.md +43 -65
  25. package/commands/project-kickoff.md +393 -673
  26. package/commands/report-design.md +403 -0
  27. package/desktop-extension/manifest.json +5 -12
  28. package/desktop-extension/server.js +34 -25
  29. package/package.json +6 -10
  30. package/skills/bi-start/SKILL.md +220 -0
  31. package/skills/bi-start/scripts/update-check.js +389 -0
  32. package/skills/pbi-connect/SKILL.md +45 -67
  33. package/skills/pbi-connect/scripts/update-check.js +389 -0
  34. package/skills/project-kickoff/SKILL.md +395 -675
  35. package/skills/project-kickoff/scripts/update-check.js +389 -0
  36. package/skills/report-design/SKILL.md +405 -0
  37. package/skills/report-design/references/cli-commands.md +184 -0
  38. package/skills/report-design/references/cli-setup.md +101 -0
  39. package/skills/report-design/references/close-write-open-pattern.md +80 -0
  40. package/skills/report-design/references/layouts/finance.md +65 -0
  41. package/skills/report-design/references/layouts/generic.md +46 -0
  42. package/skills/report-design/references/layouts/hr.md +48 -0
  43. package/skills/report-design/references/layouts/marketing.md +45 -0
  44. package/skills/report-design/references/layouts/operations.md +44 -0
  45. package/skills/report-design/references/layouts/sales.md +50 -0
  46. package/skills/report-design/references/native-visuals.md +341 -0
  47. package/skills/report-design/references/pbi-desktop-installation.md +87 -0
  48. package/skills/report-design/references/pbir-preview-activation.md +40 -0
  49. package/skills/report-design/references/slicer.md +89 -0
  50. package/skills/report-design/references/textbox.md +101 -0
  51. package/skills/report-design/references/themes/BISuperpowers.json +915 -0
  52. package/skills/report-design/references/troubleshooting.md +135 -0
  53. package/skills/report-design/references/visual-types.md +78 -0
  54. package/skills/report-design/scripts/apply-theme.js +243 -0
  55. package/skills/report-design/scripts/create-visual.js +878 -0
  56. package/skills/report-design/scripts/ensure-pbi-cli.sh +41 -0
  57. package/skills/report-design/scripts/update-check.js +389 -0
  58. package/skills/report-design/scripts/validate-pbir.js +322 -0
  59. package/src/content/base.md +12 -68
  60. package/src/content/mcp-requirements.json +0 -25
  61. package/src/content/routing.md +19 -74
  62. package/src/content/skills/bi-start.md +191 -0
  63. package/src/content/skills/pbi-connect.md +22 -65
  64. package/src/content/skills/project-kickoff.md +372 -673
  65. package/src/content/skills/report-design/SKILL.md +376 -0
  66. package/src/content/skills/report-design/references/cli-commands.md +184 -0
  67. package/src/content/skills/report-design/references/cli-setup.md +101 -0
  68. package/src/content/skills/report-design/references/close-write-open-pattern.md +80 -0
  69. package/src/content/skills/report-design/references/layouts/finance.md +65 -0
  70. package/src/content/skills/report-design/references/layouts/generic.md +46 -0
  71. package/src/content/skills/report-design/references/layouts/hr.md +48 -0
  72. package/src/content/skills/report-design/references/layouts/marketing.md +45 -0
  73. package/src/content/skills/report-design/references/layouts/operations.md +44 -0
  74. package/src/content/skills/report-design/references/layouts/sales.md +50 -0
  75. package/src/content/skills/report-design/references/native-visuals.md +341 -0
  76. package/src/content/skills/report-design/references/pbi-desktop-installation.md +87 -0
  77. package/src/content/skills/report-design/references/pbir-preview-activation.md +40 -0
  78. package/src/content/skills/report-design/references/slicer.md +89 -0
  79. package/src/content/skills/report-design/references/textbox.md +101 -0
  80. package/src/content/skills/report-design/references/themes/BISuperpowers.json +915 -0
  81. package/src/content/skills/report-design/references/troubleshooting.md +135 -0
  82. package/src/content/skills/report-design/references/visual-types.md +78 -0
  83. package/src/content/skills/report-design/scripts/apply-theme.js +243 -0
  84. package/src/content/skills/report-design/scripts/create-visual.js +878 -0
  85. package/src/content/skills/report-design/scripts/ensure-pbi-cli.sh +41 -0
  86. package/src/content/skills/report-design/scripts/validate-pbir.js +322 -0
  87. package/bin/commands/add.js +0 -533
  88. package/bin/commands/add.test.js +0 -77
  89. package/bin/commands/changelog.js +0 -443
  90. package/bin/commands/install.test.js +0 -289
  91. package/bin/commands/lint.test.js +0 -103
  92. package/bin/commands/pull.js +0 -287
  93. package/bin/commands/pull.test.js +0 -36
  94. package/bin/commands/push.js +0 -231
  95. package/bin/commands/push.test.js +0 -14
  96. package/bin/commands/search.js +0 -344
  97. package/bin/commands/search.test.js +0 -115
  98. package/bin/commands/setup.js +0 -545
  99. package/bin/commands/setup.test.js +0 -46
  100. package/bin/commands/sync-profile.js +0 -405
  101. package/bin/commands/sync-profile.test.js +0 -14
  102. package/bin/commands/sync-source.js +0 -418
  103. package/bin/commands/sync-source.test.js +0 -14
  104. package/bin/lib/generators/claude-plugin.test.js +0 -111
  105. package/bin/lib/mcp-config.test.js +0 -310
  106. package/bin/lib/microsoft-mcp.test.js +0 -115
  107. package/bin/utils/errors.js +0 -159
  108. package/bin/utils/git.js +0 -298
  109. package/bin/utils/logger.js +0 -142
  110. package/bin/utils/mcp-detect.test.js +0 -81
  111. package/bin/utils/pbix.js +0 -305
  112. package/bin/utils/pbix.test.js +0 -37
  113. package/bin/utils/profiles.js +0 -312
  114. package/bin/utils/projects.js +0 -169
  115. package/bin/utils/readline.js +0 -206
  116. package/bin/utils/readline.test.js +0 -47
  117. package/bin/utils/tui.test.js +0 -127
  118. package/docs/openrouter-free-models.md +0 -92
  119. package/library/examples/README.md +0 -151
  120. package/library/examples/finance-reporting/README.md +0 -351
  121. package/library/examples/finance-reporting/data-model.md +0 -267
  122. package/library/examples/finance-reporting/measures.dax +0 -557
  123. package/library/examples/hr-analytics/README.md +0 -371
  124. package/library/examples/hr-analytics/data-model.md +0 -315
  125. package/library/examples/hr-analytics/measures.dax +0 -460
  126. package/library/examples/marketing-analytics/README.md +0 -37
  127. package/library/examples/marketing-analytics/data-model.md +0 -62
  128. package/library/examples/marketing-analytics/measures.dax +0 -110
  129. package/library/examples/retail-analytics/README.md +0 -439
  130. package/library/examples/retail-analytics/data-model.md +0 -288
  131. package/library/examples/retail-analytics/measures.dax +0 -481
  132. package/library/examples/supply-chain/README.md +0 -37
  133. package/library/examples/supply-chain/data-model.md +0 -69
  134. package/library/examples/supply-chain/measures.dax +0 -77
  135. package/library/examples/udf-library/README.md +0 -228
  136. package/library/examples/udf-library/functions.dax +0 -571
  137. package/library/snippets/dax/README.md +0 -292
  138. package/library/snippets/dax/business-domains.md +0 -576
  139. package/library/snippets/dax/calculate-patterns.md +0 -276
  140. package/library/snippets/dax/calculation-groups.md +0 -489
  141. package/library/snippets/dax/error-handling.md +0 -495
  142. package/library/snippets/dax/iterators-and-aggregations.md +0 -474
  143. package/library/snippets/dax/kpis-and-metrics.md +0 -293
  144. package/library/snippets/dax/rankings-and-topn.md +0 -235
  145. package/library/snippets/dax/security-patterns.md +0 -413
  146. package/library/snippets/dax/text-and-formatting.md +0 -316
  147. package/library/snippets/dax/time-intelligence.md +0 -196
  148. package/library/snippets/dax/user-defined-functions.md +0 -477
  149. package/library/snippets/dax/virtual-tables.md +0 -546
  150. package/library/snippets/excel-formulas/README.md +0 -84
  151. package/library/snippets/excel-formulas/aggregations.md +0 -330
  152. package/library/snippets/excel-formulas/dates-and-times.md +0 -361
  153. package/library/snippets/excel-formulas/dynamic-arrays.md +0 -314
  154. package/library/snippets/excel-formulas/lookups.md +0 -169
  155. package/library/snippets/excel-formulas/text-functions.md +0 -363
  156. package/library/snippets/governance/naming-conventions.md +0 -97
  157. package/library/snippets/governance/review-checklists.md +0 -107
  158. package/library/snippets/power-query/README.md +0 -389
  159. package/library/snippets/power-query/api-integration.md +0 -707
  160. package/library/snippets/power-query/connections.md +0 -434
  161. package/library/snippets/power-query/data-cleaning.md +0 -298
  162. package/library/snippets/power-query/error-handling.md +0 -526
  163. package/library/snippets/power-query/parameters.md +0 -350
  164. package/library/snippets/power-query/performance.md +0 -506
  165. package/library/snippets/power-query/transformations.md +0 -330
  166. package/library/snippets/report-design/accessibility.md +0 -78
  167. package/library/snippets/report-design/chart-selection.md +0 -54
  168. package/library/snippets/report-design/layout-patterns.md +0 -87
  169. package/library/templates/data-models/README.md +0 -93
  170. package/library/templates/data-models/finance-model.md +0 -627
  171. package/library/templates/data-models/retail-star-schema.md +0 -473
  172. package/library/templates/excel/README.md +0 -83
  173. package/library/templates/excel/budget-tracker.md +0 -432
  174. package/library/templates/excel/data-entry-form.md +0 -533
  175. package/library/templates/power-bi/README.md +0 -72
  176. package/library/templates/power-bi/finance-report.md +0 -449
  177. package/library/templates/power-bi/kpi-scorecard.md +0 -461
  178. package/library/templates/power-bi/sales-dashboard.md +0 -281
  179. package/library/themes/excel/README.md +0 -436
  180. package/library/themes/power-bi/README.md +0 -271
  181. package/library/themes/power-bi/accessible.json +0 -307
  182. package/library/themes/power-bi/bi-superpowers-default.json +0 -858
  183. package/library/themes/power-bi/corporate-blue.json +0 -291
  184. package/library/themes/power-bi/dark-mode.json +0 -291
  185. package/library/themes/power-bi/minimal.json +0 -292
  186. 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
- });