@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,314 @@
1
+ /**
2
+ * TUI Utilities - Rich terminal UI helpers
3
+ * =========================================
4
+ * Provides consistent styling and formatting for CLI output.
5
+ */
6
+
7
+ const chalk = require('chalk');
8
+ const boxen = require('boxen');
9
+ const Table = require('cli-table3');
10
+
11
+ // Color scheme
12
+ const colors = {
13
+ primary: chalk.cyan,
14
+ success: chalk.green,
15
+ error: chalk.red,
16
+ warning: chalk.yellow,
17
+ info: chalk.blue,
18
+ muted: chalk.gray,
19
+ highlight: chalk.bold.white,
20
+ code: chalk.magenta,
21
+ };
22
+
23
+ // Icons
24
+ const icons = {
25
+ success: chalk.green('✓'),
26
+ error: chalk.red('✗'),
27
+ warning: chalk.yellow('⚠'),
28
+ info: chalk.blue('ℹ'),
29
+ bullet: chalk.cyan('•'),
30
+ arrow: chalk.cyan('→'),
31
+ skill: '📚',
32
+ snippet: '📝',
33
+ theme: '🎨',
34
+ search: '🔍',
35
+ lint: '🔬',
36
+ diff: '📊',
37
+ watch: '👁',
38
+ };
39
+
40
+ /**
41
+ * Print a success message
42
+ * @param {string} message - Message to display
43
+ */
44
+ function success(message) {
45
+ console.log(`${icons.success} ${message}`);
46
+ }
47
+
48
+ /**
49
+ * Print an error message
50
+ * @param {string} message - Message to display
51
+ */
52
+ function error(message) {
53
+ console.log(`${icons.error} ${colors.error(message)}`);
54
+ }
55
+
56
+ /**
57
+ * Print a warning message
58
+ * @param {string} message - Message to display
59
+ */
60
+ function warning(message) {
61
+ console.log(`${icons.warning} ${colors.warning(message)}`);
62
+ }
63
+
64
+ /**
65
+ * Print an info message
66
+ * @param {string} message - Message to display
67
+ */
68
+ function info(message) {
69
+ console.log(`${icons.info} ${colors.info(message)}`);
70
+ }
71
+
72
+ /**
73
+ * Print a muted message
74
+ * @param {string} message - Message to display
75
+ */
76
+ function muted(message) {
77
+ console.log(colors.muted(message));
78
+ }
79
+
80
+ /**
81
+ * Print a header box
82
+ * @param {string} title - Title text
83
+ * @param {string} [subtitle] - Optional subtitle
84
+ */
85
+ function header(title, subtitle) {
86
+ const content = subtitle
87
+ ? `${colors.highlight(title)}\n${colors.muted(subtitle)}`
88
+ : colors.highlight(title);
89
+
90
+ console.log(
91
+ boxen(content, {
92
+ padding: 1,
93
+ margin: { top: 1, bottom: 1 },
94
+ borderStyle: 'round',
95
+ borderColor: 'cyan',
96
+ })
97
+ );
98
+ }
99
+
100
+ /**
101
+ * Print a section header
102
+ * @param {string} title - Section title
103
+ */
104
+ function section(title) {
105
+ console.log(`\n${colors.primary(title)}`);
106
+ console.log(colors.muted('─'.repeat(title.length + 4)));
107
+ }
108
+
109
+ /**
110
+ * Create a table for displaying data
111
+ * @param {string[]} headers - Table headers
112
+ * @param {string[][]} rows - Table rows
113
+ * @param {Object} [options] - Additional options
114
+ * @returns {string} Formatted table string
115
+ */
116
+ function createTable(headers, rows, options = {}) {
117
+ const table = new Table({
118
+ head: headers.map((h) => colors.primary(h)),
119
+ style: {
120
+ head: [],
121
+ border: ['gray'],
122
+ },
123
+ ...options,
124
+ });
125
+
126
+ rows.forEach((row) => table.push(row));
127
+ return table.toString();
128
+ }
129
+
130
+ /**
131
+ * Format a file path for display
132
+ * @param {string} filePath - File path to format
133
+ * @returns {string} Formatted path
134
+ */
135
+ function formatPath(filePath) {
136
+ return colors.code(filePath);
137
+ }
138
+
139
+ /**
140
+ * Format a code snippet for display
141
+ * @param {string} code - Code to format
142
+ * @param {string} [language] - Optional language hint
143
+ * @returns {string} Formatted code
144
+ */
145
+ function formatCode(code, language) {
146
+ const prefix = language ? colors.muted(`[${language}] `) : '';
147
+ return `${prefix}${colors.code(code)}`;
148
+ }
149
+
150
+ /**
151
+ * Print a key-value pair
152
+ * @param {string} key - Key/label
153
+ * @param {string} value - Value
154
+ */
155
+ function keyValue(key, value) {
156
+ console.log(` ${colors.muted(key + ':')} ${value}`);
157
+ }
158
+
159
+ /**
160
+ * Print a list item
161
+ * @param {string} text - Item text
162
+ * @param {number} [indent=0] - Indentation level
163
+ */
164
+ function listItem(text, indent = 0) {
165
+ const padding = ' '.repeat(indent);
166
+ console.log(`${padding}${icons.bullet} ${text}`);
167
+ }
168
+
169
+ /**
170
+ * Print a diff line (addition)
171
+ * @param {string} text - Line text
172
+ */
173
+ function diffAdd(text) {
174
+ console.log(colors.success(`+ ${text}`));
175
+ }
176
+
177
+ /**
178
+ * Print a diff line (deletion)
179
+ * @param {string} text - Line text
180
+ */
181
+ function diffRemove(text) {
182
+ console.log(colors.error(`- ${text}`));
183
+ }
184
+
185
+ /**
186
+ * Print a diff line (unchanged)
187
+ * @param {string} text - Line text
188
+ */
189
+ function diffUnchanged(text) {
190
+ console.log(colors.muted(` ${text}`));
191
+ }
192
+
193
+ /**
194
+ * Print search result
195
+ * @param {Object} result - Search result object
196
+ * @param {string} result.title - Result title
197
+ * @param {string} result.path - File path
198
+ * @param {string} result.preview - Preview text
199
+ * @param {number} result.score - Match score
200
+ */
201
+ function searchResult(result) {
202
+ console.log(`\n${icons.search} ${colors.highlight(result.title)}`);
203
+ console.log(` ${colors.muted(result.path)}`);
204
+ if (result.preview) {
205
+ console.log(` ${colors.muted(result.preview.substring(0, 100))}...`);
206
+ }
207
+ if (result.score !== undefined) {
208
+ console.log(` ${colors.muted('Score:')} ${result.score.toFixed(2)}`);
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Print lint result
214
+ * @param {Object} result - Lint result
215
+ * @param {string} result.file - File name
216
+ * @param {Object[]} result.errors - Array of errors
217
+ * @param {Object[]} result.warnings - Array of warnings
218
+ */
219
+ function lintResult(result) {
220
+ const hasIssues = result.errors.length > 0 || result.warnings.length > 0;
221
+
222
+ if (!hasIssues) {
223
+ console.log(`${icons.success} ${formatPath(result.file)}`);
224
+ return;
225
+ }
226
+
227
+ console.log(`\n${formatPath(result.file)}`);
228
+
229
+ result.errors.forEach((err) => {
230
+ console.log(` ${icons.error} ${colors.error(err.message)}`);
231
+ if (err.line) {
232
+ console.log(` ${colors.muted(`Line ${err.line}`)}`);
233
+ }
234
+ });
235
+
236
+ result.warnings.forEach((warn) => {
237
+ console.log(` ${icons.warning} ${colors.warning(warn.message)}`);
238
+ if (warn.line) {
239
+ console.log(` ${colors.muted(`Line ${warn.line}`)}`);
240
+ }
241
+ });
242
+ }
243
+
244
+ /**
245
+ * Print a summary box
246
+ * @param {Object} summary - Summary data
247
+ * @param {string} summary.title - Summary title
248
+ * @param {Object} summary.stats - Key-value stats
249
+ */
250
+ function summaryBox(summary) {
251
+ let content = colors.highlight(summary.title) + '\n\n';
252
+
253
+ Object.entries(summary.stats).forEach(([key, value]) => {
254
+ content += `${colors.muted(key + ':')} ${value}\n`;
255
+ });
256
+
257
+ console.log(
258
+ boxen(content.trim(), {
259
+ padding: 1,
260
+ margin: { top: 1, bottom: 1 },
261
+ borderStyle: 'round',
262
+ borderColor: 'green',
263
+ })
264
+ );
265
+ }
266
+
267
+ /**
268
+ * Print dry-run notice
269
+ */
270
+ function dryRunNotice() {
271
+ console.log(
272
+ boxen(colors.warning('DRY RUN MODE\n') + colors.muted('No files will be created or modified'), {
273
+ padding: 1,
274
+ borderStyle: 'round',
275
+ borderColor: 'yellow',
276
+ })
277
+ );
278
+ }
279
+
280
+ /**
281
+ * Truncate text with ellipsis
282
+ * @param {string} text - Text to truncate
283
+ * @param {number} maxLength - Maximum length
284
+ * @returns {string} Truncated text
285
+ */
286
+ function truncate(text, maxLength) {
287
+ if (text.length <= maxLength) return text;
288
+ return text.substring(0, maxLength - 3) + '...';
289
+ }
290
+
291
+ module.exports = {
292
+ colors,
293
+ icons,
294
+ success,
295
+ error,
296
+ warning,
297
+ info,
298
+ muted,
299
+ header,
300
+ section,
301
+ createTable,
302
+ formatPath,
303
+ formatCode,
304
+ keyValue,
305
+ listItem,
306
+ diffAdd,
307
+ diffRemove,
308
+ diffUnchanged,
309
+ searchResult,
310
+ lintResult,
311
+ summaryBox,
312
+ dryRunNotice,
313
+ truncate,
314
+ };
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Unit tests for the TUI (Terminal UI) utilities
3
+ *
4
+ * Run with: npm test
5
+ */
6
+
7
+ const { test, describe } = require('node:test');
8
+ const assert = require('node:assert');
9
+
10
+ // Import TUI module if available
11
+ let tui;
12
+ try {
13
+ tui = require('./tui');
14
+ } catch (e) {
15
+ // TUI module may not be available in all environments
16
+ tui = null;
17
+ }
18
+
19
+ describe('TUI Utilities', () => {
20
+ test('truncate should limit string length', () => {
21
+ // Basic truncation logic
22
+ const truncate = (str, maxLen) => {
23
+ if (str.length <= maxLen) return str;
24
+ return str.substring(0, maxLen - 3) + '...';
25
+ };
26
+
27
+ const longText = 'This is a very long text that should be truncated';
28
+ const truncated = truncate(longText, 20);
29
+
30
+ assert.ok(truncated.length <= 20, 'Truncated text should not exceed max length');
31
+ assert.ok(truncated.endsWith('...'), 'Truncated text should end with ellipsis');
32
+ });
33
+
34
+ test('formatPath should handle library paths', () => {
35
+ // Basic path formatting logic
36
+ const formatPath = (filePath) => {
37
+ const libraryIndex = filePath.indexOf('library');
38
+ if (libraryIndex !== -1) {
39
+ return filePath.substring(libraryIndex);
40
+ }
41
+ return filePath;
42
+ };
43
+
44
+ const fullPath = '/Users/test/.bi-superpowers/library/snippets/dax/time-intelligence.md';
45
+ const formatted = formatPath(fullPath);
46
+
47
+ assert.ok(formatted.startsWith('library'), 'Should start with library');
48
+ assert.ok(!formatted.includes('/Users/'), 'Should not include user path');
49
+ });
50
+
51
+ test('icons object should have required icons', () => {
52
+ const requiredIcons = ['success', 'error', 'warning', 'info', 'bullet'];
53
+
54
+ // Mock icons object
55
+ const icons = {
56
+ success: '✓',
57
+ error: '✗',
58
+ warning: '⚠',
59
+ info: 'ℹ',
60
+ bullet: '•',
61
+ watch: '👁',
62
+ };
63
+
64
+ requiredIcons.forEach((icon) => {
65
+ assert.ok(icons[icon], `Should have ${icon} icon`);
66
+ });
67
+ });
68
+ });
69
+
70
+ describe('Table Formatting', () => {
71
+ test('table should have headers and rows', () => {
72
+ const headers = ['Metric', 'Count'];
73
+ const rows = [
74
+ ['Files checked', '10'],
75
+ ['Errors', '0'],
76
+ ['Warnings', '2'],
77
+ ];
78
+
79
+ assert.strictEqual(headers.length, 2, 'Should have 2 headers');
80
+ assert.strictEqual(rows.length, 3, 'Should have 3 rows');
81
+ assert.strictEqual(rows[0].length, headers.length, 'Rows should match header count');
82
+ });
83
+ });
84
+
85
+ describe('Color Functions', () => {
86
+ test('color names should be defined', () => {
87
+ const colorNames = ['primary', 'success', 'error', 'warning', 'info', 'muted', 'highlight'];
88
+
89
+ // Mock colors object
90
+ const colors = {
91
+ primary: (s) => s,
92
+ success: (s) => s,
93
+ error: (s) => s,
94
+ warning: (s) => s,
95
+ info: (s) => s,
96
+ muted: (s) => s,
97
+ highlight: (s) => s,
98
+ };
99
+
100
+ colorNames.forEach((color) => {
101
+ assert.ok(typeof colors[color] === 'function', `${color} should be a function`);
102
+ });
103
+ });
104
+
105
+ test('color functions should return strings', () => {
106
+ // Mock color function
107
+ const colorFn = (str) => `\x1b[32m${str}\x1b[0m`;
108
+ const result = colorFn('test');
109
+
110
+ assert.strictEqual(typeof result, 'string', 'Color function should return string');
111
+ assert.ok(result.includes('test'), 'Result should include original text');
112
+ });
113
+ });
114
+
115
+ describe('Diff Display', () => {
116
+ test('diff add should format additions', () => {
117
+ const formatAdd = (line) => `+ ${line}`;
118
+ const result = formatAdd('new line');
119
+ assert.ok(result.startsWith('+'), 'Addition should start with +');
120
+ });
121
+
122
+ test('diff remove should format deletions', () => {
123
+ const formatRemove = (line) => `- ${line}`;
124
+ const result = formatRemove('old line');
125
+ assert.ok(result.startsWith('-'), 'Deletion should start with -');
126
+ });
127
+ });
@@ -0,0 +1,265 @@
1
+ ---
2
+ description: "Contribution validation"
3
+ ---
4
+
5
+ <!-- Generated by BI Agent Superpowers. Edit src/content/skills/contributions.md instead. -->
6
+
7
+ # Contributions Validation Skill
8
+
9
+ ## Trigger
10
+ Activate this skill when:
11
+ - Reviewing a pull request or contribution
12
+ - User mentions: "review contribution", "validate PR", "check submission"
13
+ - User mentions: "contribution guidelines", "review checklist"
14
+ - Evaluating code quality for DAX, Power Query, Excel, or themes
15
+
16
+ ## Identity
17
+ You are a **Contribution Reviewer** who validates community submissions against BI Agent Superpowers quality standards. You provide constructive feedback and help contributors improve their submissions.
18
+
19
+ ---
20
+
21
+ ## Review Checklist
22
+
23
+ ### General Quality
24
+ - [ ] Follows naming conventions for the content type
25
+ - [ ] Includes clear comments/documentation
26
+ - [ ] No hardcoded sensitive data (passwords, API keys, server names)
27
+ - [ ] Tested and verified working
28
+ - [ ] No duplicate of existing content
29
+
30
+ ### Documentation Requirements
31
+ - [ ] Clear description of purpose/use case
32
+ - [ ] Usage examples provided
33
+ - [ ] Parameters/inputs documented
34
+ - [ ] Expected output described
35
+ - [ ] Edge cases mentioned (if applicable)
36
+
37
+ ### File Structure
38
+ - [ ] Placed in correct folder
39
+ - [ ] File naming follows conventions
40
+ - [ ] Markdown formatting is correct
41
+ - [ ] Code blocks have proper language tags
42
+
43
+ ---
44
+
45
+ ## Content-Specific Criteria
46
+
47
+ ### DAX Snippets
48
+ ```
49
+ Location: library/snippets/dax/
50
+ Naming: kebab-case.md (e.g., time-intelligence.md)
51
+ ```
52
+
53
+ **Required sections:**
54
+ - Title and description
55
+ - Basic pattern with explanation
56
+ - Variations/advanced usage
57
+ - When to use / when not to use
58
+
59
+ **Quality checks:**
60
+ - [ ] Uses VAR/RETURN pattern
61
+ - [ ] Uses DIVIDE() instead of division operator
62
+ - [ ] No hardcoded values (dates, numbers)
63
+ - [ ] Follows naming conventions (measures: PascalCase, variables: _PascalCase)
64
+ - [ ] Comments explain non-obvious logic
65
+
66
+ ### Power Query Snippets
67
+ ```
68
+ Location: library/snippets/power-query/
69
+ Naming: kebab-case.md
70
+ ```
71
+
72
+ **Required sections:**
73
+ - Title and description
74
+ - M code with step-by-step explanation
75
+ - Parameters (if applicable)
76
+ - Performance notes (query folding)
77
+
78
+ **Quality checks:**
79
+ - [ ] Query folding preserved where possible
80
+ - [ ] Error handling included
81
+ - [ ] Uses parameters instead of hardcoded values
82
+ - [ ] Step names are descriptive
83
+ - [ ] Follows naming conventions (queries, parameters, functions)
84
+
85
+ ### Excel Formula Snippets
86
+ ```
87
+ Location: library/snippets/excel-formulas/
88
+ Naming: kebab-case.md
89
+ ```
90
+
91
+ **Required sections:**
92
+ - Title and description
93
+ - Formula with explanation
94
+ - Variations for different scenarios
95
+ - Compatibility notes (Excel version requirements)
96
+
97
+ **Quality checks:**
98
+ - [ ] Uses modern functions where appropriate (XLOOKUP > VLOOKUP)
99
+ - [ ] Includes error handling
100
+ - [ ] Uses structured references with tables
101
+ - [ ] Notes if formula requires Excel 365/2021+
102
+ - [ ] Avoids volatile functions without justification
103
+
104
+ ### Power BI Themes
105
+ ```
106
+ Location: library/themes/power-bi/
107
+ Naming: kebab-case.json
108
+ ```
109
+
110
+ **Required elements:**
111
+ - Valid JSON structure
112
+ - `name` property
113
+ - `dataColors` array (6-12 colors)
114
+ - `background`, `foreground` colors
115
+ - `good`, `bad`, `neutral` sentiment colors
116
+
117
+ **Quality checks:**
118
+ - [ ] JSON is valid (no syntax errors)
119
+ - [ ] Colors are accessible (sufficient contrast)
120
+ - [ ] Consistent visual style across properties
121
+ - [ ] Includes textClasses definitions
122
+ - [ ] Covers common visual types
123
+ - [ ] README update with theme description
124
+
125
+ ### Skills
126
+ ```
127
+ Location: src/content/skills/
128
+ Files: [skill-name].md
129
+ ```
130
+
131
+ **Required sections:**
132
+ - Trigger keywords
133
+ - Identity/persona description
134
+ - Naming conventions (if applicable)
135
+ - Best practices
136
+ - Common patterns with examples
137
+ - Anti-patterns to avoid
138
+
139
+ **Quality checks:**
140
+ - [ ] Comprehensive trigger keywords
141
+ - [ ] Clear identity statement
142
+ - [ ] Actionable best practices
143
+ - [ ] Real, working code examples
144
+ - [ ] Links to related resources
145
+
146
+ ### Templates
147
+ ```
148
+ Location: library/templates/[type]/
149
+ Files: descriptive-name.md or folder
150
+ ```
151
+
152
+ **Required elements:**
153
+ - Purpose description
154
+ - Structure overview
155
+ - Usage instructions
156
+ - Customization guide
157
+
158
+ ---
159
+
160
+ ## Feedback Guidelines
161
+
162
+ ### Be Constructive
163
+ ```
164
+ BAD: "This code is wrong."
165
+ GOOD: "This pattern could cause performance issues because... Consider using..."
166
+ ```
167
+
168
+ ### Be Specific
169
+ ```
170
+ BAD: "Naming is inconsistent."
171
+ GOOD: "Line 15 uses snake_case but line 23 uses PascalCase. Please standardize to PascalCase per our conventions."
172
+ ```
173
+
174
+ ### Acknowledge Good Work
175
+ ```
176
+ "Nice use of the VAR/RETURN pattern! One suggestion to make it even better..."
177
+ ```
178
+
179
+ ### Offer Help
180
+ ```
181
+ "If you'd like, I can help you refactor this section to improve query folding."
182
+ ```
183
+
184
+ ### Prioritize Feedback
185
+ ```
186
+ 1. MUST FIX: Security issues, broken code, major errors
187
+ 2. SHOULD FIX: Best practice violations, performance issues
188
+ 3. CONSIDER: Style preferences, minor improvements
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Common Issues and Solutions
194
+
195
+ ### DAX Issues
196
+ | Issue | Solution |
197
+ |-------|----------|
198
+ | Division without DIVIDE | Replace `A/B` with `DIVIDE(A, B, 0)` |
199
+ | Repeated expressions | Use VAR to calculate once |
200
+ | FILTER instead of simple condition | Use `Column = Value` in CALCULATE |
201
+ | Hardcoded dates | Use dynamic expressions or parameters |
202
+
203
+ ### Power Query Issues
204
+ | Issue | Solution |
205
+ |-------|----------|
206
+ | Query folding broken | Move operations that fold before those that don't |
207
+ | No error handling | Add `try...otherwise` for conversions |
208
+ | Hardcoded connections | Use parameters |
209
+ | Poor step names | Rename to descriptive PascalCase |
210
+
211
+ ### Excel Formula Issues
212
+ | Issue | Solution |
213
+ |-------|----------|
214
+ | VLOOKUP used | Suggest XLOOKUP or INDEX/MATCH |
215
+ | No error handling | Add IFERROR or IFNA |
216
+ | Volatile functions | Suggest INDEX over OFFSET |
217
+ | Nested IFs | Suggest IFS or SWITCH |
218
+
219
+ ### Theme Issues
220
+ | Issue | Solution |
221
+ |-------|----------|
222
+ | Low contrast colors | Verify WCAG AA compliance |
223
+ | Missing properties | Check against default theme structure |
224
+ | Invalid JSON | Use JSON validator |
225
+ | No sentiment colors | Add good/bad/neutral properties |
226
+
227
+ ---
228
+
229
+ ## Approval Workflow
230
+
231
+ ### Ready to Merge
232
+ - All MUST FIX items resolved
233
+ - Documentation complete
234
+ - Code tested and working
235
+ - Follows all conventions
236
+
237
+ ### Request Changes
238
+ - MUST FIX items present
239
+ - Missing required sections
240
+ - Broken or untested code
241
+
242
+ ### Needs Discussion
243
+ - Architectural decisions
244
+ - New patterns that may set precedent
245
+ - Major additions requiring review
246
+
247
+ ## Complexity Adaptation
248
+
249
+ Adjust depth based on `config.json → experienceLevel`:
250
+ - **beginner**: Step-by-step with explanations, reference library examples
251
+ - **intermediate**: Standard depth, explain non-obvious decisions
252
+ - **advanced**: Concise, skip basics, focus on edge cases and optimization
253
+
254
+ ## Related Skills
255
+
256
+ - `/governance` — Code standards to follow when contributing
257
+
258
+ ---
259
+
260
+ ## Related Resources
261
+
262
+ - [CONTRIBUTING.md](../../../CONTRIBUTING.md) - Full contribution guidelines
263
+ - [DAX Skill](./dax.md) - DAX conventions
264
+ - [Power Query Skill](./power-query.md) - Power Query conventions
265
+ - [Excel Formulas Skill](./excel-formulas.md) - Excel conventions