@luquimbo/bi-superpowers 1.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 (193) hide show
  1. package/.claude-plugin/plugin.json +8 -0
  2. package/.mcp.json +25 -0
  3. package/AGENTS.md +244 -0
  4. package/CHANGELOG.md +265 -0
  5. package/LICENSE +21 -0
  6. package/README.md +211 -0
  7. package/bin/build-plugin.js +30 -0
  8. package/bin/cli.js +1064 -0
  9. package/bin/commands/add.js +533 -0
  10. package/bin/commands/add.test.js +77 -0
  11. package/bin/commands/build-desktop.js +166 -0
  12. package/bin/commands/changelog.js +443 -0
  13. package/bin/commands/diff.js +325 -0
  14. package/bin/commands/lint.js +419 -0
  15. package/bin/commands/lint.test.js +103 -0
  16. package/bin/commands/mcp-setup.js +246 -0
  17. package/bin/commands/pull.js +287 -0
  18. package/bin/commands/pull.test.js +36 -0
  19. package/bin/commands/push.js +231 -0
  20. package/bin/commands/push.test.js +14 -0
  21. package/bin/commands/search.js +344 -0
  22. package/bin/commands/search.test.js +115 -0
  23. package/bin/commands/setup.js +545 -0
  24. package/bin/commands/setup.test.js +46 -0
  25. package/bin/commands/sync-profile.js +405 -0
  26. package/bin/commands/sync-profile.test.js +14 -0
  27. package/bin/commands/sync-source.js +418 -0
  28. package/bin/commands/sync-source.test.js +14 -0
  29. package/bin/commands/watch.js +206 -0
  30. package/bin/lib/generators/claude-plugin.js +266 -0
  31. package/bin/lib/generators/claude-plugin.test.js +110 -0
  32. package/bin/lib/generators/index.js +116 -0
  33. package/bin/lib/generators/shared.js +282 -0
  34. package/bin/lib/licensing/index.js +35 -0
  35. package/bin/lib/licensing/storage.js +364 -0
  36. package/bin/lib/licensing/storage.test.js +55 -0
  37. package/bin/lib/licensing/validator.js +213 -0
  38. package/bin/lib/licensing/validator.test.js +137 -0
  39. package/bin/lib/microsoft-mcp.js +176 -0
  40. package/bin/lib/microsoft-mcp.test.js +106 -0
  41. package/bin/lib/skills.js +84 -0
  42. package/bin/mcp/powerbi-modeling-launcher.js +38 -0
  43. package/bin/postinstall.js +44 -0
  44. package/bin/utils/errors.js +159 -0
  45. package/bin/utils/git.js +298 -0
  46. package/bin/utils/logger.js +142 -0
  47. package/bin/utils/mcp-detect.js +274 -0
  48. package/bin/utils/mcp-detect.test.js +105 -0
  49. package/bin/utils/pbix.js +305 -0
  50. package/bin/utils/pbix.test.js +37 -0
  51. package/bin/utils/profiles.js +312 -0
  52. package/bin/utils/projects.js +168 -0
  53. package/bin/utils/readline.js +206 -0
  54. package/bin/utils/readline.test.js +47 -0
  55. package/bin/utils/tui.js +314 -0
  56. package/bin/utils/tui.test.js +127 -0
  57. package/commands/contributions.md +265 -0
  58. package/commands/data-model-design.md +468 -0
  59. package/commands/dax-doctor.md +248 -0
  60. package/commands/fabric-scripts.md +452 -0
  61. package/commands/migration-assistant.md +290 -0
  62. package/commands/model-documenter.md +242 -0
  63. package/commands/pbi-connect.md +239 -0
  64. package/commands/project-kickoff.md +905 -0
  65. package/commands/report-layout.md +296 -0
  66. package/commands/rls-design.md +533 -0
  67. package/commands/theme-tweaker.md +624 -0
  68. package/config.example.json +23 -0
  69. package/config.json +23 -0
  70. package/desktop-extension/manifest.json +37 -0
  71. package/desktop-extension/package.json +10 -0
  72. package/desktop-extension/server.js +95 -0
  73. package/docs/openrouter-free-models.md +92 -0
  74. package/library/examples/README.md +151 -0
  75. package/library/examples/finance-reporting/README.md +351 -0
  76. package/library/examples/finance-reporting/data-model.md +267 -0
  77. package/library/examples/finance-reporting/measures.dax +557 -0
  78. package/library/examples/hr-analytics/README.md +371 -0
  79. package/library/examples/hr-analytics/data-model.md +315 -0
  80. package/library/examples/hr-analytics/measures.dax +460 -0
  81. package/library/examples/marketing-analytics/README.md +37 -0
  82. package/library/examples/marketing-analytics/data-model.md +62 -0
  83. package/library/examples/marketing-analytics/measures.dax +110 -0
  84. package/library/examples/retail-analytics/README.md +439 -0
  85. package/library/examples/retail-analytics/data-model.md +288 -0
  86. package/library/examples/retail-analytics/measures.dax +481 -0
  87. package/library/examples/supply-chain/README.md +37 -0
  88. package/library/examples/supply-chain/data-model.md +69 -0
  89. package/library/examples/supply-chain/measures.dax +77 -0
  90. package/library/examples/udf-library/README.md +228 -0
  91. package/library/examples/udf-library/functions.dax +571 -0
  92. package/library/snippets/dax/README.md +292 -0
  93. package/library/snippets/dax/business-domains.md +576 -0
  94. package/library/snippets/dax/calculate-patterns.md +276 -0
  95. package/library/snippets/dax/calculation-groups.md +489 -0
  96. package/library/snippets/dax/error-handling.md +495 -0
  97. package/library/snippets/dax/iterators-and-aggregations.md +474 -0
  98. package/library/snippets/dax/kpis-and-metrics.md +293 -0
  99. package/library/snippets/dax/rankings-and-topn.md +235 -0
  100. package/library/snippets/dax/security-patterns.md +413 -0
  101. package/library/snippets/dax/text-and-formatting.md +316 -0
  102. package/library/snippets/dax/time-intelligence.md +196 -0
  103. package/library/snippets/dax/user-defined-functions.md +477 -0
  104. package/library/snippets/dax/virtual-tables.md +546 -0
  105. package/library/snippets/excel-formulas/README.md +84 -0
  106. package/library/snippets/excel-formulas/aggregations.md +330 -0
  107. package/library/snippets/excel-formulas/dates-and-times.md +361 -0
  108. package/library/snippets/excel-formulas/dynamic-arrays.md +314 -0
  109. package/library/snippets/excel-formulas/lookups.md +169 -0
  110. package/library/snippets/excel-formulas/text-functions.md +363 -0
  111. package/library/snippets/governance/naming-conventions.md +97 -0
  112. package/library/snippets/governance/review-checklists.md +107 -0
  113. package/library/snippets/power-query/README.md +389 -0
  114. package/library/snippets/power-query/api-integration.md +707 -0
  115. package/library/snippets/power-query/connections.md +434 -0
  116. package/library/snippets/power-query/data-cleaning.md +298 -0
  117. package/library/snippets/power-query/error-handling.md +526 -0
  118. package/library/snippets/power-query/parameters.md +350 -0
  119. package/library/snippets/power-query/performance.md +506 -0
  120. package/library/snippets/power-query/transformations.md +330 -0
  121. package/library/snippets/report-design/accessibility.md +78 -0
  122. package/library/snippets/report-design/chart-selection.md +54 -0
  123. package/library/snippets/report-design/layout-patterns.md +87 -0
  124. package/library/templates/data-models/README.md +93 -0
  125. package/library/templates/data-models/finance-model.md +627 -0
  126. package/library/templates/data-models/retail-star-schema.md +473 -0
  127. package/library/templates/excel/README.md +83 -0
  128. package/library/templates/excel/budget-tracker.md +432 -0
  129. package/library/templates/excel/data-entry-form.md +533 -0
  130. package/library/templates/power-bi/README.md +72 -0
  131. package/library/templates/power-bi/finance-report.md +449 -0
  132. package/library/templates/power-bi/kpi-scorecard.md +461 -0
  133. package/library/templates/power-bi/sales-dashboard.md +281 -0
  134. package/library/themes/excel/README.md +436 -0
  135. package/library/themes/power-bi/README.md +271 -0
  136. package/library/themes/power-bi/accessible.json +307 -0
  137. package/library/themes/power-bi/bi-superpowers-default.json +858 -0
  138. package/library/themes/power-bi/corporate-blue.json +291 -0
  139. package/library/themes/power-bi/dark-mode.json +291 -0
  140. package/library/themes/power-bi/minimal.json +292 -0
  141. package/library/themes/power-bi/print-friendly.json +309 -0
  142. package/package.json +93 -0
  143. package/skills/contributions/SKILL.md +267 -0
  144. package/skills/data-model-design/SKILL.md +470 -0
  145. package/skills/data-modeling/SKILL.md +254 -0
  146. package/skills/data-quality/SKILL.md +664 -0
  147. package/skills/dax/SKILL.md +708 -0
  148. package/skills/dax-doctor/SKILL.md +250 -0
  149. package/skills/dax-udf/SKILL.md +489 -0
  150. package/skills/deployment/SKILL.md +320 -0
  151. package/skills/excel-formulas/SKILL.md +463 -0
  152. package/skills/fabric-scripts/SKILL.md +454 -0
  153. package/skills/fast-standard/SKILL.md +509 -0
  154. package/skills/governance/SKILL.md +205 -0
  155. package/skills/migration-assistant/SKILL.md +292 -0
  156. package/skills/model-documenter/SKILL.md +244 -0
  157. package/skills/pbi-connect/SKILL.md +241 -0
  158. package/skills/power-query/SKILL.md +406 -0
  159. package/skills/project-kickoff/SKILL.md +907 -0
  160. package/skills/query-performance/SKILL.md +480 -0
  161. package/skills/report-design/SKILL.md +207 -0
  162. package/skills/report-layout/SKILL.md +298 -0
  163. package/skills/rls-design/SKILL.md +535 -0
  164. package/skills/semantic-model/SKILL.md +237 -0
  165. package/skills/testing-validation/SKILL.md +643 -0
  166. package/skills/theme-tweaker/SKILL.md +626 -0
  167. package/src/content/base.md +237 -0
  168. package/src/content/mcp-requirements.json +69 -0
  169. package/src/content/routing.md +203 -0
  170. package/src/content/skills/contributions.md +259 -0
  171. package/src/content/skills/data-model-design.md +462 -0
  172. package/src/content/skills/data-modeling.md +246 -0
  173. package/src/content/skills/data-quality.md +656 -0
  174. package/src/content/skills/dax-doctor.md +242 -0
  175. package/src/content/skills/dax-udf.md +481 -0
  176. package/src/content/skills/dax.md +700 -0
  177. package/src/content/skills/deployment.md +312 -0
  178. package/src/content/skills/excel-formulas.md +455 -0
  179. package/src/content/skills/fabric-scripts.md +446 -0
  180. package/src/content/skills/fast-standard.md +501 -0
  181. package/src/content/skills/governance.md +197 -0
  182. package/src/content/skills/migration-assistant.md +284 -0
  183. package/src/content/skills/model-documenter.md +236 -0
  184. package/src/content/skills/pbi-connect.md +233 -0
  185. package/src/content/skills/power-query.md +398 -0
  186. package/src/content/skills/project-kickoff.md +899 -0
  187. package/src/content/skills/query-performance.md +472 -0
  188. package/src/content/skills/report-design.md +199 -0
  189. package/src/content/skills/report-layout.md +290 -0
  190. package/src/content/skills/rls-design.md +527 -0
  191. package/src/content/skills/semantic-model.md +229 -0
  192. package/src/content/skills/testing-validation.md +635 -0
  193. package/src/content/skills/theme-tweaker.md +618 -0
@@ -0,0 +1,325 @@
1
+ /**
2
+ * Diff Command (scan)
3
+ * ===================
4
+ * Shows differences between source skills and generated configs.
5
+ *
6
+ * Usage:
7
+ * super scan Show all pending changes
8
+ * super scan --skill dax Show changes for specific skill
9
+ * super scan --tool claude-code Show changes for specific tool
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const tui = require('../utils/tui');
15
+
16
+ /**
17
+ * Generate a simple diff between two strings
18
+ * @param {string} oldContent - Original content
19
+ * @param {string} newContent - New content
20
+ * @returns {Object} Diff result with lines and stats
21
+ */
22
+ function generateDiff(oldContent, newContent) {
23
+ const oldLines = oldContent.split('\n');
24
+ const newLines = newContent.split('\n');
25
+
26
+ const diff = {
27
+ lines: [],
28
+ additions: 0,
29
+ deletions: 0,
30
+ unchanged: 0,
31
+ };
32
+
33
+ // Simple line-by-line diff (not a full diff algorithm, but good for display)
34
+ // Create maps of line content to track changes
35
+ const oldSet = new Set(oldLines);
36
+ const newSet = new Set(newLines);
37
+
38
+ // Track which lines are in both
39
+ const inBoth = new Set();
40
+ oldLines.forEach((line) => {
41
+ if (newSet.has(line)) {
42
+ inBoth.add(line);
43
+ }
44
+ });
45
+
46
+ // Process old lines
47
+ const processedOld = new Set();
48
+ oldLines.forEach((line, index) => {
49
+ if (inBoth.has(line) && !processedOld.has(line)) {
50
+ diff.lines.push({ type: 'unchanged', content: line, lineNum: index + 1 });
51
+ diff.unchanged++;
52
+ processedOld.add(line);
53
+ } else if (!inBoth.has(line)) {
54
+ diff.lines.push({ type: 'removed', content: line, lineNum: index + 1 });
55
+ diff.deletions++;
56
+ }
57
+ });
58
+
59
+ // Process new lines (additions)
60
+ newLines.forEach((line, index) => {
61
+ if (!oldSet.has(line)) {
62
+ diff.lines.push({ type: 'added', content: line, lineNum: index + 1 });
63
+ diff.additions++;
64
+ }
65
+ });
66
+
67
+ return diff;
68
+ }
69
+
70
+ /**
71
+ * Compare a source skill with its generated output
72
+ * @param {string} skillPath - Path to source skill
73
+ * @param {string} generatedPath - Path to generated file
74
+ * @returns {Object|null} Comparison result or null if no difference
75
+ */
76
+ function compareFiles(skillPath, generatedPath) {
77
+ if (!fs.existsSync(skillPath)) {
78
+ return {
79
+ skill: path.basename(skillPath),
80
+ status: 'missing-source',
81
+ message: 'Source skill file not found',
82
+ };
83
+ }
84
+
85
+ if (!fs.existsSync(generatedPath)) {
86
+ return {
87
+ skill: path.basename(skillPath),
88
+ status: 'not-generated',
89
+ message: 'Generated file does not exist (will be created on sync)',
90
+ };
91
+ }
92
+
93
+ const sourceContent = fs.readFileSync(skillPath, 'utf8');
94
+ const generatedContent = fs.readFileSync(generatedPath, 'utf8');
95
+
96
+ if (sourceContent === generatedContent) {
97
+ return {
98
+ skill: path.basename(skillPath),
99
+ status: 'unchanged',
100
+ message: 'No changes',
101
+ };
102
+ }
103
+
104
+ const diff = generateDiff(generatedContent, sourceContent);
105
+
106
+ return {
107
+ skill: path.basename(skillPath),
108
+ status: 'changed',
109
+ diff,
110
+ sourcePath: skillPath,
111
+ generatedPath,
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Get generated file path for a skill based on tool
117
+ * @param {string} skillName - Skill name (without .md)
118
+ * @param {string} tool - AI tool name
119
+ * @param {string} targetDir - Target project directory
120
+ * @returns {string|null} Path to generated file or null
121
+ */
122
+ function getGeneratedPath(skillName, tool, targetDir) {
123
+ switch (tool) {
124
+ case 'claude-code':
125
+ return path.join(targetDir, '.claude', 'commands', `${skillName}.md`);
126
+ case 'cursor':
127
+ // Cursor uses a single file, can't diff per-skill
128
+ return null;
129
+ case 'copilot':
130
+ // Copilot uses a single file, can't diff per-skill
131
+ return null;
132
+ default:
133
+ return null;
134
+ }
135
+ }
136
+
137
+ /**
138
+ * Display diff for a single comparison
139
+ * @param {Object} comparison - Comparison result
140
+ * @param {boolean} verbose - Show full diff
141
+ */
142
+ function displayComparison(comparison, verbose = false) {
143
+ const { skill, status, diff } = comparison;
144
+
145
+ switch (status) {
146
+ case 'unchanged':
147
+ console.log(`${tui.icons.success} ${tui.colors.muted(skill)} - No changes`);
148
+ break;
149
+
150
+ case 'not-generated':
151
+ console.log(`${tui.icons.info} ${tui.colors.info(skill)} - Will be created`);
152
+ break;
153
+
154
+ case 'missing-source':
155
+ console.log(`${tui.icons.warning} ${tui.colors.warning(skill)} - Source missing`);
156
+ break;
157
+
158
+ case 'changed':
159
+ console.log(`\n${tui.icons.warning} ${tui.colors.highlight(skill)} - Changes detected`);
160
+ console.log(
161
+ ` ${tui.colors.success(`+${diff.additions}`)} additions, ${tui.colors.error(`-${diff.deletions}`)} deletions`
162
+ );
163
+
164
+ if (verbose && diff.lines) {
165
+ console.log('');
166
+ diff.lines.forEach((line) => {
167
+ if (line.type === 'added') {
168
+ tui.diffAdd(tui.truncate(line.content, 100));
169
+ } else if (line.type === 'removed') {
170
+ tui.diffRemove(tui.truncate(line.content, 100));
171
+ }
172
+ });
173
+ }
174
+ break;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Parse command line arguments
180
+ * @param {string[]} args - CLI arguments
181
+ * @returns {Object} Parsed options
182
+ */
183
+ function parseArgs(args) {
184
+ const options = {
185
+ skill: null,
186
+ tool: 'claude-code', // Default to claude-code as it supports per-skill diffs
187
+ verbose: false,
188
+ targetDir: process.cwd(),
189
+ };
190
+
191
+ for (let i = 0; i < args.length; i++) {
192
+ const arg = args[i];
193
+
194
+ if (arg === '--skill' || arg === '-s') {
195
+ options.skill = args[++i];
196
+ } else if (arg === '--tool' || arg === '-t') {
197
+ options.tool = args[++i];
198
+ } else if (arg === '--verbose' || arg === '-v') {
199
+ options.verbose = true;
200
+ } else if (!arg.startsWith('-')) {
201
+ options.targetDir = arg;
202
+ }
203
+ }
204
+
205
+ return options;
206
+ }
207
+
208
+ /**
209
+ * Main diff command handler
210
+ * @param {string[]} args - Command arguments
211
+ * @param {Object} config - CLI configuration with paths
212
+ */
213
+ function diffCommand(args, config) {
214
+ const options = parseArgs(args);
215
+ const targetDir = options.targetDir;
216
+
217
+ // Try cache directory first, fall back to local skills
218
+ let skillsDir = config.skillsDir;
219
+ const localSkills = path.join(config.packageDir, '.agents', 'prompts', 'skills');
220
+
221
+ if (!fs.existsSync(skillsDir)) {
222
+ if (fs.existsSync(localSkills)) {
223
+ skillsDir = localSkills;
224
+ } else {
225
+ tui.error('Skills directory not found. Run "bi-superpowers unlock" first.');
226
+ process.exit(1);
227
+ }
228
+ }
229
+
230
+ tui.header('BI Agent Superpowers', 'Diff: Source vs Generated');
231
+
232
+ // Check if tool supports per-skill diff
233
+ if (options.tool !== 'claude-code') {
234
+ tui.warning(`Tool "${options.tool}" uses a combined config file.`);
235
+ tui.info('Per-skill diff is only available for Claude Code.');
236
+ console.log('\nTo see changes, compare:');
237
+ console.log(` Source: ${skillsDir}`);
238
+
239
+ switch (options.tool) {
240
+ case 'cursor':
241
+ console.log(` Generated: ${path.join(targetDir, '.cursorrules')}`);
242
+ break;
243
+ case 'copilot':
244
+ console.log(` Generated: ${path.join(targetDir, '.github', 'copilot-instructions.md')}`);
245
+ break;
246
+ }
247
+ return;
248
+ }
249
+
250
+ // Get skill files to compare
251
+ let skillFiles = [];
252
+
253
+ if (options.skill) {
254
+ const skillName = options.skill.replace('.md', '');
255
+ const skillPath = path.join(skillsDir, `${skillName}.md`);
256
+ if (fs.existsSync(skillPath)) {
257
+ skillFiles = [skillPath];
258
+ } else {
259
+ tui.error(`Skill not found: ${options.skill}`);
260
+ process.exit(1);
261
+ }
262
+ } else {
263
+ skillFiles = fs
264
+ .readdirSync(skillsDir)
265
+ .filter((f) => f.endsWith('.md'))
266
+ .map((f) => path.join(skillsDir, f));
267
+ }
268
+
269
+ if (skillFiles.length === 0) {
270
+ tui.warning('No skill files found');
271
+ return;
272
+ }
273
+
274
+ tui.info(`Comparing ${skillFiles.length} skill(s) for ${options.tool}...`);
275
+ tui.section('Changes');
276
+
277
+ // Compare each skill
278
+ const results = skillFiles.map((skillPath) => {
279
+ const skillName = path.basename(skillPath, '.md');
280
+ const generatedPath = getGeneratedPath(skillName, options.tool, targetDir);
281
+
282
+ if (!generatedPath) {
283
+ return {
284
+ skill: skillName,
285
+ status: 'skipped',
286
+ message: 'Tool does not support per-skill diff',
287
+ };
288
+ }
289
+
290
+ return compareFiles(skillPath, generatedPath);
291
+ });
292
+
293
+ // Display results
294
+ results.forEach((result) => {
295
+ displayComparison(result, options.verbose);
296
+ });
297
+
298
+ // Summary
299
+ const changed = results.filter((r) => r.status === 'changed').length;
300
+ const unchanged = results.filter((r) => r.status === 'unchanged').length;
301
+ const notGenerated = results.filter((r) => r.status === 'not-generated').length;
302
+
303
+ console.log('');
304
+ tui.section('Summary');
305
+
306
+ const table = tui.createTable(
307
+ ['Status', 'Count'],
308
+ [
309
+ ['Unchanged', unchanged.toString()],
310
+ ['Changed', tui.colors.warning(changed.toString())],
311
+ ['New (will create)', tui.colors.info(notGenerated.toString())],
312
+ ]
313
+ );
314
+ console.log(table);
315
+
316
+ if (changed > 0 || notGenerated > 0) {
317
+ console.log(
318
+ `\n${tui.colors.muted('Run')} super recharge ${tui.colors.muted('to apply changes')}`
319
+ );
320
+ } else {
321
+ console.log(`\n${tui.icons.success} ${tui.colors.success('Everything is in sync!')}`);
322
+ }
323
+ }
324
+
325
+ module.exports = diffCommand;