@luquimbo/bi-superpowers 3.1.1 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.claude-plugin/skill-manifest.json +1 -1
- package/.plugin/plugin.json +1 -1
- package/bin/build-plugin.js +6 -6
- package/bin/cli.js +169 -310
- package/bin/commands/install.js +87 -70
- package/bin/lib/agents.js +19 -0
- package/bin/lib/mcp-config.js +23 -4
- package/desktop-extension/manifest.json +4 -11
- package/desktop-extension/server.js +34 -25
- package/package.json +3 -9
- package/skills/pbi-connect/SKILL.md +1 -1
- package/skills/project-kickoff/SKILL.md +1 -1
- package/bin/commands/add.js +0 -533
- package/bin/commands/add.test.js +0 -77
- package/bin/commands/changelog.js +0 -443
- package/bin/commands/pull.js +0 -287
- package/bin/commands/pull.test.js +0 -36
- package/bin/commands/push.js +0 -231
- package/bin/commands/push.test.js +0 -14
- package/bin/commands/search.js +0 -344
- package/bin/commands/search.test.js +0 -115
- package/bin/commands/setup.js +0 -545
- package/bin/commands/setup.test.js +0 -46
- package/bin/commands/sync-profile.js +0 -405
- package/bin/commands/sync-profile.test.js +0 -14
- package/bin/commands/sync-source.js +0 -418
- package/bin/commands/sync-source.test.js +0 -14
- package/bin/utils/errors.js +0 -159
- package/bin/utils/git.js +0 -298
- package/bin/utils/logger.js +0 -142
- package/bin/utils/pbix.js +0 -305
- package/bin/utils/pbix.test.js +0 -37
- package/bin/utils/profiles.js +0 -312
- package/bin/utils/projects.js +0 -169
- package/bin/utils/readline.js +0 -206
- package/bin/utils/readline.test.js +0 -47
- package/docs/openrouter-free-models.md +0 -92
- package/library/examples/README.md +0 -151
- package/library/examples/finance-reporting/README.md +0 -351
- package/library/examples/finance-reporting/data-model.md +0 -267
- package/library/examples/finance-reporting/measures.dax +0 -557
- package/library/examples/hr-analytics/README.md +0 -371
- package/library/examples/hr-analytics/data-model.md +0 -315
- package/library/examples/hr-analytics/measures.dax +0 -460
- package/library/examples/marketing-analytics/README.md +0 -37
- package/library/examples/marketing-analytics/data-model.md +0 -62
- package/library/examples/marketing-analytics/measures.dax +0 -110
- package/library/examples/retail-analytics/README.md +0 -439
- package/library/examples/retail-analytics/data-model.md +0 -288
- package/library/examples/retail-analytics/measures.dax +0 -481
- package/library/examples/supply-chain/README.md +0 -37
- package/library/examples/supply-chain/data-model.md +0 -69
- package/library/examples/supply-chain/measures.dax +0 -77
- package/library/examples/udf-library/README.md +0 -228
- package/library/examples/udf-library/functions.dax +0 -571
- package/library/snippets/dax/README.md +0 -292
- package/library/snippets/dax/business-domains.md +0 -576
- package/library/snippets/dax/calculate-patterns.md +0 -276
- package/library/snippets/dax/calculation-groups.md +0 -489
- package/library/snippets/dax/error-handling.md +0 -495
- package/library/snippets/dax/iterators-and-aggregations.md +0 -474
- package/library/snippets/dax/kpis-and-metrics.md +0 -293
- package/library/snippets/dax/rankings-and-topn.md +0 -235
- package/library/snippets/dax/security-patterns.md +0 -413
- package/library/snippets/dax/text-and-formatting.md +0 -316
- package/library/snippets/dax/time-intelligence.md +0 -196
- package/library/snippets/dax/user-defined-functions.md +0 -477
- package/library/snippets/dax/virtual-tables.md +0 -546
- package/library/snippets/excel-formulas/README.md +0 -84
- package/library/snippets/excel-formulas/aggregations.md +0 -330
- package/library/snippets/excel-formulas/dates-and-times.md +0 -361
- package/library/snippets/excel-formulas/dynamic-arrays.md +0 -314
- package/library/snippets/excel-formulas/lookups.md +0 -169
- package/library/snippets/excel-formulas/text-functions.md +0 -363
- package/library/snippets/governance/naming-conventions.md +0 -97
- package/library/snippets/governance/review-checklists.md +0 -107
- package/library/snippets/power-query/README.md +0 -389
- package/library/snippets/power-query/api-integration.md +0 -707
- package/library/snippets/power-query/connections.md +0 -434
- package/library/snippets/power-query/data-cleaning.md +0 -298
- package/library/snippets/power-query/error-handling.md +0 -526
- package/library/snippets/power-query/parameters.md +0 -350
- package/library/snippets/power-query/performance.md +0 -506
- package/library/snippets/power-query/transformations.md +0 -330
- package/library/snippets/report-design/accessibility.md +0 -78
- package/library/snippets/report-design/chart-selection.md +0 -54
- package/library/snippets/report-design/layout-patterns.md +0 -87
- package/library/templates/data-models/README.md +0 -93
- package/library/templates/data-models/finance-model.md +0 -627
- package/library/templates/data-models/retail-star-schema.md +0 -473
- package/library/templates/excel/README.md +0 -83
- package/library/templates/excel/budget-tracker.md +0 -432
- package/library/templates/excel/data-entry-form.md +0 -533
- package/library/templates/power-bi/README.md +0 -72
- package/library/templates/power-bi/finance-report.md +0 -449
- package/library/templates/power-bi/kpi-scorecard.md +0 -461
- package/library/templates/power-bi/sales-dashboard.md +0 -281
- package/library/themes/excel/README.md +0 -436
- package/library/themes/power-bi/README.md +0 -271
- package/library/themes/power-bi/accessible.json +0 -307
- package/library/themes/power-bi/bi-superpowers-default.json +0 -858
- package/library/themes/power-bi/corporate-blue.json +0 -291
- package/library/themes/power-bi/dark-mode.json +0 -291
- package/library/themes/power-bi/minimal.json +0 -292
- package/library/themes/power-bi/print-friendly.json +0 -309
package/bin/utils/projects.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
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
|
-
// Warn user about broken config so they can fix it
|
|
81
|
-
console.warn(`⚠ Config de proyecto inválido en ${configPath}: ${e.message}`);
|
|
82
|
-
if (process.env.DEBUG === 'true') {
|
|
83
|
-
console.error('[DEBUG] Full error:', e);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return projects;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Detect current project based on working directory
|
|
94
|
-
* @param {string} repoPath - Path to bi-repo
|
|
95
|
-
* @returns {Object|null} Project config or null if not in a project folder
|
|
96
|
-
*/
|
|
97
|
-
function detectCurrentProject(repoPath) {
|
|
98
|
-
const cwd = process.cwd();
|
|
99
|
-
const projectsBase = path.join(repoPath, 'projects');
|
|
100
|
-
|
|
101
|
-
// Check if we're inside a project folder
|
|
102
|
-
if (cwd.startsWith(projectsBase)) {
|
|
103
|
-
const relative = path.relative(projectsBase, cwd);
|
|
104
|
-
const projectName = relative.split(path.sep)[0];
|
|
105
|
-
|
|
106
|
-
if (projectName && projectName !== '..') {
|
|
107
|
-
return getProject(repoPath, projectName);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return null;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* List project names
|
|
116
|
-
* @param {string} repoPath - Path to bi-repo
|
|
117
|
-
* @returns {string[]} Array of project names
|
|
118
|
-
*/
|
|
119
|
-
function listProjectNames(repoPath) {
|
|
120
|
-
return getAllProjects(repoPath).map((p) => p.name);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Check if a project exists
|
|
125
|
-
* @param {string} repoPath - Path to bi-repo
|
|
126
|
-
* @param {string} projectName - Name of the project
|
|
127
|
-
* @returns {boolean} True if project exists
|
|
128
|
-
*/
|
|
129
|
-
function projectExists(repoPath, projectName) {
|
|
130
|
-
const projectPath = path.join(repoPath, 'projects', projectName);
|
|
131
|
-
const configPath = path.join(projectPath, 'project.json');
|
|
132
|
-
return fs.existsSync(configPath);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Get project path
|
|
137
|
-
* @param {string} repoPath - Path to bi-repo
|
|
138
|
-
* @param {string} projectName - Name of the project
|
|
139
|
-
* @returns {string} Path to project directory
|
|
140
|
-
*/
|
|
141
|
-
function getProjectPath(repoPath, projectName) {
|
|
142
|
-
return path.join(repoPath, 'projects', projectName);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Print available projects to console
|
|
147
|
-
* @param {string} repoPath - Path to bi-repo
|
|
148
|
-
* @param {string} prefix - Prefix for each line (default: ' - ')
|
|
149
|
-
*/
|
|
150
|
-
function printAvailableProjects(repoPath, prefix = ' - ') {
|
|
151
|
-
const projects = getAllProjects(repoPath);
|
|
152
|
-
if (projects.length === 0) {
|
|
153
|
-
console.log(`${prefix}(no projects found)`);
|
|
154
|
-
} else {
|
|
155
|
-
projects.forEach((p) => {
|
|
156
|
-
console.log(`${prefix}${p.name}`);
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
module.exports = {
|
|
162
|
-
getProject,
|
|
163
|
-
getAllProjects,
|
|
164
|
-
detectCurrentProject,
|
|
165
|
-
listProjectNames,
|
|
166
|
-
projectExists,
|
|
167
|
-
getProjectPath,
|
|
168
|
-
printAvailableProjects,
|
|
169
|
-
};
|
package/bin/utils/readline.js
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
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
|
-
};
|
|
@@ -1,47 +0,0 @@
|
|
|
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
|
-
});
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
# Configure Claude Code with OpenRouter (Free Models)
|
|
2
|
-
|
|
3
|
-
Use free AI models with Claude Code CLI and 1code.dev via OpenRouter.
|
|
4
|
-
|
|
5
|
-
## Prerequisites
|
|
6
|
-
|
|
7
|
-
- Node.js installed
|
|
8
|
-
- Claude Code CLI installed (`npm install -g @anthropic-ai/claude-code`)
|
|
9
|
-
- Free account at [openrouter.ai](https://openrouter.ai)
|
|
10
|
-
|
|
11
|
-
## Step 1: Create OpenRouter API Key
|
|
12
|
-
|
|
13
|
-
1. Go to [openrouter.ai](https://openrouter.ai) and create account (free)
|
|
14
|
-
2. Go to [openrouter.ai/keys](https://openrouter.ai/keys)
|
|
15
|
-
3. Click "Create Key"
|
|
16
|
-
4. Copy the key (starts with `sk-or-v1-...`)
|
|
17
|
-
|
|
18
|
-
## Step 2: Configure Environment Variables
|
|
19
|
-
|
|
20
|
-
Add to the end of `~/.zshrc` (macOS/Linux) or your shell profile:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
# OpenRouter + Claude Code
|
|
24
|
-
export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
|
|
25
|
-
export ANTHROPIC_AUTH_TOKEN="sk-or-v1-YOUR-KEY-HERE"
|
|
26
|
-
export ANTHROPIC_API_KEY=""
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
> **Important**: `ANTHROPIC_API_KEY` MUST be empty (`""`). If it doesn't exist, Claude Code will try to authenticate with Anthropic directly.
|
|
30
|
-
|
|
31
|
-
Then reload the shell:
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
source ~/.zshrc
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Step 3: Sign Out of Anthropic (if needed)
|
|
38
|
-
|
|
39
|
-
If you previously used Claude Code with an Anthropic account:
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
claude
|
|
43
|
-
# inside the session:
|
|
44
|
-
/logout
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Step 4: Verify Connection
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
claude
|
|
51
|
-
# inside the session:
|
|
52
|
-
/status
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
Should show that it's connected to OpenRouter.
|
|
56
|
-
|
|
57
|
-
## Recommended Free Models for Coding
|
|
58
|
-
|
|
59
|
-
| Model | OpenRouter ID | Context | Best For |
|
|
60
|
-
|-------|---------------|---------|----------|
|
|
61
|
-
| **Qwen3 Coder 480B** | `qwen/qwen3-coder-480b-a35b:free` | 262K | Best free model for agentic coding |
|
|
62
|
-
| **DeepSeek R1** | `deepseek/deepseek-r1:free` | 164K | Complex reasoning, debugging |
|
|
63
|
-
| **Devstral** | `mistralai/devstral-small:free` | 128K | Multi-file, agentic coding |
|
|
64
|
-
| **Llama 3.3 70B** | `meta-llama/llama-3.3-70b-instruct:free` | 128K | General purpose, fast |
|
|
65
|
-
|
|
66
|
-
To select a specific model, add to `~/.zshrc`:
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
export ANTHROPIC_MODEL="qwen/qwen3-coder-480b-a35b:free"
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Or use the free automatic router:
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
export ANTHROPIC_MODEL="openrouter/free"
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Limitations
|
|
79
|
-
|
|
80
|
-
- **Rate limits**: ~20 requests/min, ~200 requests/day on free models
|
|
81
|
-
- **Tool use**: Not all free models support tool calling (needed for agents)
|
|
82
|
-
- **Quality**: Inferior to Claude Opus/Sonnet for complex tasks
|
|
83
|
-
- **Availability**: Free models may disappear without notice
|
|
84
|
-
- **Not recommended for production**
|
|
85
|
-
|
|
86
|
-
## Verification
|
|
87
|
-
|
|
88
|
-
1. Open a new terminal (to load the variables)
|
|
89
|
-
2. `echo $ANTHROPIC_BASE_URL` → should show `https://openrouter.ai/api`
|
|
90
|
-
3. `claude` → should start without asking for Anthropic login
|
|
91
|
-
4. `/status` → confirm connection to OpenRouter
|
|
92
|
-
5. Ask a simple coding question to verify response
|
|
@@ -1,151 +0,0 @@
|
|
|
1
|
-
# Examples
|
|
2
|
-
|
|
3
|
-
Complete, end-to-end examples demonstrating BI Agent Superpowers patterns in real-world scenarios.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Available Examples
|
|
8
|
-
|
|
9
|
-
| Example | Description | Components |
|
|
10
|
-
|---------|-------------|------------|
|
|
11
|
-
| [retail-analytics](./retail-analytics/) | Complete retail sales analytics solution | Star schema, 50+ DAX measures, data model |
|
|
12
|
-
| [finance-reporting](./finance-reporting/) | P&L, Balance Sheet, variance analysis | Multi-statement model, 60+ financial measures |
|
|
13
|
-
| [hr-analytics](./hr-analytics/) | Headcount, turnover, diversity metrics | Employee snapshots, 40+ HR measures |
|
|
14
|
-
| [udf-library](./udf-library/) | DAX User Defined Functions library | 50+ reusable UDFs, typed parameters |
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## Learning Path (Recommended Order)
|
|
19
|
-
|
|
20
|
-
New to Power BI? Follow this progression to build your skills:
|
|
21
|
-
|
|
22
|
-
### Level 1: Foundations
|
|
23
|
-
1. **[retail-analytics](./retail-analytics/)** - Start here!
|
|
24
|
-
- Learn star schema basics (facts + dimensions)
|
|
25
|
-
- Understand fundamental DAX patterns (SUM, CALCULATE, time intelligence)
|
|
26
|
-
- Build your first KPI dashboard
|
|
27
|
-
|
|
28
|
-
### Level 2: Intermediate
|
|
29
|
-
2. **[hr-analytics](./hr-analytics/)** - Expand your skills
|
|
30
|
-
- Work with snapshot data (point-in-time analysis)
|
|
31
|
-
- Learn turnover and retention calculations
|
|
32
|
-
- Understand Row-Level Security (RLS) basics
|
|
33
|
-
|
|
34
|
-
### Level 3: Advanced
|
|
35
|
-
3. **[finance-reporting](./finance-reporting/)** - Master complex scenarios
|
|
36
|
-
- Handle multi-statement financial models
|
|
37
|
-
- Work with hierarchical account structures
|
|
38
|
-
- Build variance analysis (Actual vs Budget)
|
|
39
|
-
|
|
40
|
-
### Level 4: Expert
|
|
41
|
-
4. **[udf-library](./udf-library/)** - Cutting-edge DAX
|
|
42
|
-
- Create reusable User Defined Functions (preview feature)
|
|
43
|
-
- Build a personal library of typed functions
|
|
44
|
-
- Master advanced DAX patterns
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## What Each Example Includes
|
|
49
|
-
|
|
50
|
-
### Documentation
|
|
51
|
-
- **README.md** - Overview, business requirements, implementation guide
|
|
52
|
-
- **data-model.md** - Complete table definitions, relationships, sample data
|
|
53
|
-
|
|
54
|
-
### Code
|
|
55
|
-
- **measures.dax** - Complete DAX measure library, organized by category
|
|
56
|
-
|
|
57
|
-
### Styling
|
|
58
|
-
- Use themes from `library/themes/power-bi/` for consistent formatting
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
|
|
62
|
-
## Using Examples
|
|
63
|
-
|
|
64
|
-
### 1. Understand the Scenario
|
|
65
|
-
|
|
66
|
-
Read the README.md to understand:
|
|
67
|
-
- Business requirements and stakeholders
|
|
68
|
-
- Key questions the solution answers
|
|
69
|
-
- Recommended visualizations
|
|
70
|
-
|
|
71
|
-
### 2. Adapt the Data Model
|
|
72
|
-
|
|
73
|
-
Use data-model.md as a template:
|
|
74
|
-
- Match columns to your source data
|
|
75
|
-
- Adjust data types as needed
|
|
76
|
-
- Add/remove columns for your scenario
|
|
77
|
-
|
|
78
|
-
### 3. Copy Relevant Measures
|
|
79
|
-
|
|
80
|
-
From measures.dax:
|
|
81
|
-
- Start with base measures (Revenue, Cost, Profit)
|
|
82
|
-
- Add time intelligence as needed
|
|
83
|
-
- Customize rankings and percentages
|
|
84
|
-
|
|
85
|
-
### 4. Apply a Theme
|
|
86
|
-
|
|
87
|
-
1. Choose a theme from `library/themes/power-bi/`
|
|
88
|
-
2. View > Themes > Browse for themes
|
|
89
|
-
3. Select the JSON file
|
|
90
|
-
|
|
91
|
-
---
|
|
92
|
-
|
|
93
|
-
## Example Structure
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
library/examples/
|
|
97
|
-
├── README.md # This file
|
|
98
|
-
│
|
|
99
|
-
├── retail-analytics/ # Retail sales analytics
|
|
100
|
-
│ ├── README.md # Overview and guide
|
|
101
|
-
│ ├── data-model.md # Table definitions
|
|
102
|
-
│ └── measures.dax # 50+ DAX measures
|
|
103
|
-
│
|
|
104
|
-
├── finance-reporting/ # Financial statements
|
|
105
|
-
│ ├── README.md # P&L, Balance Sheet guide
|
|
106
|
-
│ ├── data-model.md # Account structure, scenarios
|
|
107
|
-
│ └── measures.dax # 60+ financial measures
|
|
108
|
-
│
|
|
109
|
-
├── hr-analytics/ # HR workforce analytics
|
|
110
|
-
│ ├── README.md # Headcount, turnover guide
|
|
111
|
-
│ ├── data-model.md # Employee snapshot model
|
|
112
|
-
│ └── measures.dax # 40+ HR measures
|
|
113
|
-
│
|
|
114
|
-
└── udf-library/ # DAX User Defined Functions
|
|
115
|
-
├── README.md # UDF usage guide and catalog
|
|
116
|
-
└── functions.dax # 50+ reusable typed functions
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
---
|
|
120
|
-
|
|
121
|
-
## Upcoming Examples
|
|
122
|
-
|
|
123
|
-
- **marketing-dashboard** - Campaign performance, funnel analysis
|
|
124
|
-
- **supply-chain** - Inventory, fulfillment, vendor performance
|
|
125
|
-
- **project-management** - Resource allocation, timeline tracking
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## Contributing Examples
|
|
130
|
-
|
|
131
|
-
Want to add an example? Include:
|
|
132
|
-
|
|
133
|
-
1. **README.md** with:
|
|
134
|
-
- Business scenario description
|
|
135
|
-
- Stakeholder requirements
|
|
136
|
-
- Data model diagram
|
|
137
|
-
- Visualization recommendations
|
|
138
|
-
- Implementation checklist
|
|
139
|
-
|
|
140
|
-
2. **data-model.md** with:
|
|
141
|
-
- All table definitions
|
|
142
|
-
- Column specifications
|
|
143
|
-
- Relationship diagram
|
|
144
|
-
- Sample data
|
|
145
|
-
|
|
146
|
-
3. **measures.dax** with:
|
|
147
|
-
- Organized by category
|
|
148
|
-
- Comments explaining each measure
|
|
149
|
-
- Naming conventions followed
|
|
150
|
-
|
|
151
|
-
See [CONTRIBUTING.md](../../CONTRIBUTING.md) for submission guidelines.
|