@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,168 @@
1
+ /**
2
+ * Projects Utility
3
+ * =================
4
+ *
5
+ * Shared functions for working with bi-repo projects.
6
+ * Extracted from add.js, pull.js, push.js to reduce duplication.
7
+ *
8
+ * @module utils/projects
9
+ */
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+
14
+ /**
15
+ * Get a specific project by name
16
+ * @param {string} repoPath - Path to bi-repo
17
+ * @param {string} projectName - Name of the project
18
+ * @returns {Object|null} Project config with projectPath added, or null
19
+ */
20
+ function getProject(repoPath, projectName) {
21
+ const projectPath = path.join(repoPath, 'projects', projectName);
22
+ const configPath = path.join(projectPath, 'project.json');
23
+
24
+ if (!fs.existsSync(configPath)) {
25
+ return null;
26
+ }
27
+
28
+ try {
29
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
30
+ return {
31
+ ...config,
32
+ projectPath,
33
+ };
34
+ } catch (e) {
35
+ // Invalid JSON in config file
36
+ if (process.env.DEBUG === 'true') {
37
+ console.error(`[DEBUG] Failed to parse project config: ${configPath}`);
38
+ }
39
+ return null;
40
+ }
41
+ }
42
+
43
+ /**
44
+ * Get list of all projects in the repo
45
+ * @param {string} repoPath - Path to bi-repo
46
+ * @returns {Object[]} Array of project configs with projectPath added
47
+ */
48
+ function getAllProjects(repoPath) {
49
+ const projectsDir = path.join(repoPath, 'projects');
50
+
51
+ if (!fs.existsSync(projectsDir)) {
52
+ return [];
53
+ }
54
+
55
+ const projects = [];
56
+ const dirs = fs.readdirSync(projectsDir);
57
+
58
+ for (const dir of dirs) {
59
+ const projectPath = path.join(projectsDir, dir);
60
+
61
+ // Skip if not a directory
62
+ try {
63
+ if (!fs.statSync(projectPath).isDirectory()) {
64
+ continue;
65
+ }
66
+ } catch (e) {
67
+ continue;
68
+ }
69
+
70
+ const configPath = path.join(projectPath, 'project.json');
71
+
72
+ if (fs.existsSync(configPath)) {
73
+ try {
74
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
75
+ projects.push({
76
+ ...config,
77
+ projectPath,
78
+ });
79
+ } catch (e) {
80
+ // Skip invalid configs
81
+ if (process.env.DEBUG === 'true') {
82
+ console.error(`[DEBUG] Skipping invalid config: ${configPath}`);
83
+ }
84
+ }
85
+ }
86
+ }
87
+
88
+ return projects;
89
+ }
90
+
91
+ /**
92
+ * Detect current project based on working directory
93
+ * @param {string} repoPath - Path to bi-repo
94
+ * @returns {Object|null} Project config or null if not in a project folder
95
+ */
96
+ function detectCurrentProject(repoPath) {
97
+ const cwd = process.cwd();
98
+ const projectsBase = path.join(repoPath, 'projects');
99
+
100
+ // Check if we're inside a project folder
101
+ if (cwd.startsWith(projectsBase)) {
102
+ const relative = path.relative(projectsBase, cwd);
103
+ const projectName = relative.split(path.sep)[0];
104
+
105
+ if (projectName && projectName !== '..') {
106
+ return getProject(repoPath, projectName);
107
+ }
108
+ }
109
+
110
+ return null;
111
+ }
112
+
113
+ /**
114
+ * List project names
115
+ * @param {string} repoPath - Path to bi-repo
116
+ * @returns {string[]} Array of project names
117
+ */
118
+ function listProjectNames(repoPath) {
119
+ return getAllProjects(repoPath).map((p) => p.name);
120
+ }
121
+
122
+ /**
123
+ * Check if a project exists
124
+ * @param {string} repoPath - Path to bi-repo
125
+ * @param {string} projectName - Name of the project
126
+ * @returns {boolean} True if project exists
127
+ */
128
+ function projectExists(repoPath, projectName) {
129
+ const projectPath = path.join(repoPath, 'projects', projectName);
130
+ const configPath = path.join(projectPath, 'project.json');
131
+ return fs.existsSync(configPath);
132
+ }
133
+
134
+ /**
135
+ * Get project path
136
+ * @param {string} repoPath - Path to bi-repo
137
+ * @param {string} projectName - Name of the project
138
+ * @returns {string} Path to project directory
139
+ */
140
+ function getProjectPath(repoPath, projectName) {
141
+ return path.join(repoPath, 'projects', projectName);
142
+ }
143
+
144
+ /**
145
+ * Print available projects to console
146
+ * @param {string} repoPath - Path to bi-repo
147
+ * @param {string} prefix - Prefix for each line (default: ' - ')
148
+ */
149
+ function printAvailableProjects(repoPath, prefix = ' - ') {
150
+ const projects = getAllProjects(repoPath);
151
+ if (projects.length === 0) {
152
+ console.log(`${prefix}(no projects found)`);
153
+ } else {
154
+ projects.forEach((p) => {
155
+ console.log(`${prefix}${p.name}`);
156
+ });
157
+ }
158
+ }
159
+
160
+ module.exports = {
161
+ getProject,
162
+ getAllProjects,
163
+ detectCurrentProject,
164
+ listProjectNames,
165
+ projectExists,
166
+ getProjectPath,
167
+ printAvailableProjects,
168
+ };
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Readline Utilities for BI Agent Superpowers
3
+ * ============================================
4
+ *
5
+ * Shared readline functions for interactive CLI commands.
6
+ * Consolidates duplicated code from setup.js, add.js, sync-source.js, sync-profile.js
7
+ *
8
+ * @module utils/readline
9
+ */
10
+
11
+ const readline = require('readline');
12
+
13
+ /**
14
+ * Create a readline interface for interactive prompts
15
+ * @returns {readline.Interface} Readline interface
16
+ */
17
+ function createReadline() {
18
+ return readline.createInterface({
19
+ input: process.stdin,
20
+ output: process.stdout,
21
+ });
22
+ }
23
+
24
+ /**
25
+ * Prompt the user for input
26
+ * @param {readline.Interface} rl - Readline interface
27
+ * @param {string} question - Question to ask
28
+ * @returns {Promise<string>} User's answer (trimmed)
29
+ */
30
+ function prompt(rl, question) {
31
+ return new Promise((resolve) => {
32
+ rl.question(question, (answer) => {
33
+ resolve(answer.trim());
34
+ });
35
+ });
36
+ }
37
+
38
+ /**
39
+ * Ask for yes/no confirmation
40
+ * @param {readline.Interface} rl - Readline interface
41
+ * @param {string} question - Question to ask (without y/n suffix)
42
+ * @param {boolean} defaultValue - Default value if user just presses Enter
43
+ * @returns {Promise<boolean>} True if confirmed, false otherwise
44
+ */
45
+ function confirm(rl, question, defaultValue = false) {
46
+ const suffix = defaultValue ? ' (S/n): ' : ' (s/N): ';
47
+ return new Promise((resolve) => {
48
+ rl.question(question + suffix, (answer) => {
49
+ const trimmed = answer.trim().toLowerCase();
50
+ if (trimmed === '') {
51
+ resolve(defaultValue);
52
+ } else {
53
+ resolve(trimmed === 's' || trimmed === 'y' || trimmed === 'si' || trimmed === 'yes');
54
+ }
55
+ });
56
+ });
57
+ }
58
+
59
+ /**
60
+ * Ask user to select from a list of options
61
+ * @param {readline.Interface} rl - Readline interface
62
+ * @param {string} question - Question to ask
63
+ * @param {string[]} options - Array of option strings
64
+ * @param {number} defaultIndex - Default option index (0-based)
65
+ * @returns {Promise<{index: number, value: string}>} Selected option
66
+ */
67
+ async function select(rl, question, options, defaultIndex = 0) {
68
+ console.log(`\n${question}\n`);
69
+
70
+ options.forEach((option, i) => {
71
+ const marker = i === defaultIndex ? '>' : ' ';
72
+ console.log(` ${marker} ${i + 1}. ${option}`);
73
+ });
74
+
75
+ console.log('');
76
+
77
+ const answer = await prompt(rl, `Elige una opción (1-${options.length}) [${defaultIndex + 1}]: `);
78
+
79
+ if (answer === '') {
80
+ return { index: defaultIndex, value: options[defaultIndex] };
81
+ }
82
+
83
+ const num = parseInt(answer, 10);
84
+ if (isNaN(num) || num < 1 || num > options.length) {
85
+ console.log('Opción no válida, usando la predeterminada.');
86
+ return { index: defaultIndex, value: options[defaultIndex] };
87
+ }
88
+
89
+ return { index: num - 1, value: options[num - 1] };
90
+ }
91
+
92
+ /**
93
+ * Ask user to select multiple options from a list
94
+ * @param {readline.Interface} rl - Readline interface
95
+ * @param {string} question - Question to ask
96
+ * @param {Array<{label: string, value: any, selected?: boolean}>} options - Options with labels and values
97
+ * @returns {Promise<any[]>} Array of selected values
98
+ */
99
+ async function multiSelect(rl, question, options) {
100
+ console.log(`\n${question}\n`);
101
+ console.log(' Instrucciones:');
102
+ console.log(' - Escribe números separados por comas (ej: 1,3,5)');
103
+ console.log(' - "a" para seleccionar todos');
104
+ console.log(' - "n" para deseleccionar todos');
105
+ console.log(' - Enter para confirmar selección actual\n');
106
+
107
+ // Show options with current selection
108
+ options.forEach((option, i) => {
109
+ const marker = option.selected ? '[x]' : '[ ]';
110
+ console.log(` ${marker} ${i + 1}. ${option.label}`);
111
+ });
112
+
113
+ console.log('');
114
+
115
+ const answer = await prompt(rl, 'Selección: ');
116
+
117
+ if (answer.toLowerCase() === 'a') {
118
+ return options.map((o) => o.value);
119
+ }
120
+
121
+ if (answer.toLowerCase() === 'n' || answer === '') {
122
+ return options.filter((o) => o.selected).map((o) => o.value);
123
+ }
124
+
125
+ // Parse comma-separated numbers
126
+ const indices = answer
127
+ .split(',')
128
+ .map((s) => parseInt(s.trim(), 10) - 1)
129
+ .filter((n) => !isNaN(n) && n >= 0 && n < options.length);
130
+
131
+ return indices.map((i) => options[i].value);
132
+ }
133
+
134
+ /**
135
+ * Show a spinner while executing an async operation
136
+ * @param {string} message - Message to show
137
+ * @param {Promise} promise - Promise to wait for
138
+ * @returns {Promise} Result of the promise
139
+ */
140
+ async function withSpinner(message, promise) {
141
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
142
+ let i = 0;
143
+
144
+ const interval = setInterval(() => {
145
+ process.stdout.write(`\r${frames[i]} ${message}`);
146
+ i = (i + 1) % frames.length;
147
+ }, 80);
148
+
149
+ try {
150
+ const result = await promise;
151
+ clearInterval(interval);
152
+ process.stdout.write(`\r✓ ${message}\n`);
153
+ return result;
154
+ } catch (error) {
155
+ clearInterval(interval);
156
+ process.stdout.write(`\r✗ ${message}\n`);
157
+ throw error;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Exit with error message
163
+ * @param {string} message - Error message
164
+ * @param {number} code - Exit code (default 1)
165
+ */
166
+ function exitWithError(message, code = 1) {
167
+ console.error(`\n✗ ${message}\n`);
168
+ process.exit(code);
169
+ }
170
+
171
+ /**
172
+ * Show success message
173
+ * @param {string} message - Success message
174
+ */
175
+ function showSuccess(message) {
176
+ console.log(`✓ ${message}`);
177
+ }
178
+
179
+ /**
180
+ * Show warning message
181
+ * @param {string} message - Warning message
182
+ */
183
+ function showWarning(message) {
184
+ console.log(`⚠ ${message}`);
185
+ }
186
+
187
+ /**
188
+ * Show info message
189
+ * @param {string} message - Info message
190
+ */
191
+ function showInfo(message) {
192
+ console.log(`ℹ ${message}`);
193
+ }
194
+
195
+ module.exports = {
196
+ createReadline,
197
+ prompt,
198
+ confirm,
199
+ select,
200
+ multiSelect,
201
+ withSpinner,
202
+ exitWithError,
203
+ showSuccess,
204
+ showWarning,
205
+ showInfo,
206
+ };
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Tests for Readline Utilities
3
+ * @module utils/readline.test
4
+ */
5
+
6
+ const { test, describe } = require('node:test');
7
+ const assert = require('node:assert');
8
+
9
+ const readline = require('./readline');
10
+
11
+ describe('Readline Utilities', () => {
12
+ test('exports createReadline function', () => {
13
+ assert.strictEqual(typeof readline.createReadline, 'function');
14
+ });
15
+
16
+ test('exports prompt function', () => {
17
+ assert.strictEqual(typeof readline.prompt, 'function');
18
+ });
19
+
20
+ test('exports confirm function', () => {
21
+ assert.strictEqual(typeof readline.confirm, 'function');
22
+ });
23
+
24
+ test('exports select function', () => {
25
+ assert.strictEqual(typeof readline.select, 'function');
26
+ });
27
+
28
+ test('exports multiSelect function', () => {
29
+ assert.strictEqual(typeof readline.multiSelect, 'function');
30
+ });
31
+
32
+ test('exports exitWithError function', () => {
33
+ assert.strictEqual(typeof readline.exitWithError, 'function');
34
+ });
35
+
36
+ test('exports showSuccess function', () => {
37
+ assert.strictEqual(typeof readline.showSuccess, 'function');
38
+ });
39
+
40
+ test('exports showWarning function', () => {
41
+ assert.strictEqual(typeof readline.showWarning, 'function');
42
+ });
43
+
44
+ test('exports showInfo function', () => {
45
+ assert.strictEqual(typeof readline.showInfo, 'function');
46
+ });
47
+ });