@powerbuilder/skill 1.0.3 → 1.0.6
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/README.md +3 -8
- package/lib/banner.js +7 -10
- package/lib/detect-targets.js +20 -17
- package/lib/wizard-codeapp.js +33 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
# @powerbuilder/skill
|
|
2
1
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Install production-ready AI agent skills into your **.cursor**, **.claude**, or **.gemini** workspace folders with a single command.
|
|
2
|
+
**PowerBuilder** — a toolkit for the Microsoft Power Platform.
|
|
6
3
|
|
|
7
4
|
---
|
|
8
5
|
|
|
@@ -15,7 +12,6 @@ npx @powerbuilder/skill codeapp
|
|
|
15
12
|
|
|
16
13
|
The wizard will:
|
|
17
14
|
1. Auto-detect `.cursor`, `.claude`, and `.gemini` folders in your project
|
|
18
|
-
2. Copy the skill files into each detected agent folder
|
|
19
15
|
3. Install `@playwright/cli` globally for automated testing
|
|
20
16
|
4. Open `make.powerapps.com` in a persistent browser session for first-time login
|
|
21
17
|
|
|
@@ -46,12 +42,11 @@ The installer searches upward from your current directory to your home folder an
|
|
|
46
42
|
## Requirements
|
|
47
43
|
|
|
48
44
|
- Node.js ≥ 18
|
|
49
|
-
- At least one of: Cursor, Claude Code, or Gemini CLI installed in the workspace
|
|
50
45
|
|
|
51
46
|
---
|
|
52
47
|
|
|
53
48
|
## About PowerBuilder
|
|
54
49
|
|
|
55
|
-
**PowerBuilder** is a
|
|
50
|
+
**PowerBuilder** is a toolkit by [TuongDoan](https://github.com/tuongdoan) — a growing collection of AI agent skills, scripts, and utilities for the Microsoft Power Platform.
|
|
56
51
|
|
|
57
|
-
©
|
|
52
|
+
© 2026 TuongDoan
|
package/lib/banner.js
CHANGED
|
@@ -4,18 +4,15 @@ export function printBanner() {
|
|
|
4
4
|
const cyan = chalk.cyanBright.bold;
|
|
5
5
|
const yellow = chalk.yellowBright.bold;
|
|
6
6
|
const dim = chalk.dim;
|
|
7
|
-
const green = chalk.greenBright;
|
|
8
7
|
|
|
9
8
|
console.log();
|
|
10
|
-
console.log(cyan(' ██████╗ ██████╗ ██╗ ██╗███████╗██████╗
|
|
11
|
-
console.log(cyan(' ██╔══██╗██╔═══██╗██║
|
|
12
|
-
console.log(cyan(' ██████╔╝██║ ██║██║ █╗ ██║█████╗
|
|
13
|
-
console.log(cyan(' ██╔═══╝ ██║ ██║██║███╗██║██╔══╝
|
|
14
|
-
console.log(cyan(' ██║ ╚██████╔╝╚███╔███╔╝███████╗██║
|
|
15
|
-
console.log(cyan(' ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝
|
|
9
|
+
console.log(cyan(' ██████╗ ██████╗ ██╗ ██╗███████╗██████╗ ██████╗ ██╗ ██╗██╗██╗ ██████╗ ███████╗██████╗ '));
|
|
10
|
+
console.log(cyan(' ██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗ ██╔══██╗██║ ██║██║██║ ██╔══██╗██╔════╝██╔══██╗'));
|
|
11
|
+
console.log(cyan(' ██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝ ██████╔╝██║ ██║██║██║ ██║ ██║█████╗ ██████╔╝'));
|
|
12
|
+
console.log(cyan(' ██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗ ██╔══██╗██║ ██║██║██║ ██║ ██║██╔══╝ ██╔══██╗'));
|
|
13
|
+
console.log(cyan(' ██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║ ██████╔╝╚██████╔╝██║███████╗██████╔╝███████╗██║ ██║'));
|
|
14
|
+
console.log(cyan(' ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝'));
|
|
16
15
|
console.log();
|
|
17
|
-
console.log(' ' + yellow('⚡ Power Apps Code App Skill') + dim('
|
|
18
|
-
console.log(' ' + green(' Skill Set by TuongDoan') + dim(' · github.com/tuongdoan · © 2025'));
|
|
19
|
-
console.log(' ' + dim('─'.repeat(85)));
|
|
16
|
+
console.log(' ' + yellow('⚡ Power Apps Code App Skill') + dim(' · by TuongDoan · © 2026'));
|
|
20
17
|
console.log();
|
|
21
18
|
}
|
package/lib/detect-targets.js
CHANGED
|
@@ -3,13 +3,10 @@ import { existsSync } from 'fs';
|
|
|
3
3
|
import os from 'os';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* - .cursor → skills go into <target>/.cursor/rules/ (or just .cursor/skills/)
|
|
11
|
-
* - .claude → skills go into <target>/.claude/skills/
|
|
12
|
-
* - .gemini → skills go into <target>/.gemini/antigravity/skills/
|
|
6
|
+
* Detect where to install skills:
|
|
7
|
+
* - .cursor → optional: skip if folder doesn't exist
|
|
8
|
+
* - .gemini → optional: skip if folder doesn't exist
|
|
9
|
+
* - .claude → always: create ~/.claude if it doesn't exist
|
|
13
10
|
*/
|
|
14
11
|
export function detectTargets(startDir = process.cwd()) {
|
|
15
12
|
const home = os.homedir();
|
|
@@ -22,34 +19,30 @@ export function detectTargets(startDir = process.cwd()) {
|
|
|
22
19
|
dirs.push(current);
|
|
23
20
|
if (current === home) break;
|
|
24
21
|
const parent = path.dirname(current);
|
|
25
|
-
if (parent === current) break;
|
|
22
|
+
if (parent === current) break;
|
|
26
23
|
current = parent;
|
|
27
24
|
}
|
|
28
25
|
|
|
29
26
|
for (const dir of dirs) {
|
|
30
27
|
const cursorDir = path.join(dir, '.cursor');
|
|
31
|
-
const claudeDir = path.join(dir, '.claude');
|
|
32
28
|
const geminiDir = path.join(dir, '.gemini');
|
|
33
29
|
|
|
30
|
+
// .cursor — optional: only add if the folder already exists
|
|
34
31
|
if (existsSync(cursorDir)) {
|
|
35
32
|
targets.push({
|
|
36
33
|
target: '.cursor',
|
|
34
|
+
label: 'Cursor',
|
|
37
35
|
agentFolder: cursorDir,
|
|
38
36
|
skillsDir: path.join(cursorDir, 'rules', 'skills'),
|
|
39
37
|
dir,
|
|
40
38
|
});
|
|
41
39
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
target: '.claude',
|
|
45
|
-
agentFolder: claudeDir,
|
|
46
|
-
skillsDir: path.join(claudeDir, 'skills'),
|
|
47
|
-
dir,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
40
|
+
|
|
41
|
+
// .gemini — optional: only add if the folder already exists
|
|
50
42
|
if (existsSync(geminiDir)) {
|
|
51
43
|
targets.push({
|
|
52
44
|
target: '.gemini',
|
|
45
|
+
label: 'Google Antigravity',
|
|
53
46
|
agentFolder: geminiDir,
|
|
54
47
|
skillsDir: path.join(geminiDir, 'antigravity', 'skills'),
|
|
55
48
|
dir,
|
|
@@ -57,6 +50,16 @@ export function detectTargets(startDir = process.cwd()) {
|
|
|
57
50
|
}
|
|
58
51
|
}
|
|
59
52
|
|
|
53
|
+
// .claude — always install to home dir; folder will be created if missing
|
|
54
|
+
const claudeDir = path.join(home, '.claude');
|
|
55
|
+
targets.push({
|
|
56
|
+
target: '.claude',
|
|
57
|
+
label: 'Claude',
|
|
58
|
+
agentFolder: claudeDir,
|
|
59
|
+
skillsDir: path.join(claudeDir, 'skills'),
|
|
60
|
+
dir: home,
|
|
61
|
+
});
|
|
62
|
+
|
|
60
63
|
// Deduplicate by agentFolder
|
|
61
64
|
const seen = new Set();
|
|
62
65
|
return targets.filter(t => {
|
package/lib/wizard-codeapp.js
CHANGED
|
@@ -55,10 +55,6 @@ const SKILL_SRC = path.resolve(__dirname, '..', 'skills', 'codeapp');
|
|
|
55
55
|
// ─── STEP 1 — Detect & confirm targets ───────────────────────────────────────
|
|
56
56
|
|
|
57
57
|
async function stepDetectTargets() {
|
|
58
|
-
hr();
|
|
59
|
-
log(chalk.bold('Step 1/4 · Detecting AI agent folders…'));
|
|
60
|
-
hr();
|
|
61
|
-
|
|
62
58
|
const detected = detectTargets();
|
|
63
59
|
|
|
64
60
|
if (detected.length === 0) {
|
|
@@ -67,21 +63,45 @@ async function stepDetectTargets() {
|
|
|
67
63
|
process.exit(1);
|
|
68
64
|
}
|
|
69
65
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
66
|
+
return detected;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ─── SUMMARY — Show plan & confirm before doing anything ──────────────────────
|
|
70
|
+
|
|
71
|
+
async function stepShowSummary(targets) {
|
|
72
|
+
console.log();
|
|
73
|
+
log(chalk.bold.yellowBright(' 📋 Installation Plan'));
|
|
74
|
+
console.log();
|
|
75
|
+
|
|
76
|
+
// Item 1 — skill files, list human-friendly target names
|
|
77
|
+
log(` ${chalk.cyanBright('1.')} Power Apps Code App Skill for:`);
|
|
78
|
+
for (const t of targets) {
|
|
79
|
+
log(` ${chalk.greenBright('•')} ${chalk.white(t.label)}`);
|
|
73
80
|
}
|
|
74
81
|
console.log();
|
|
75
82
|
|
|
76
|
-
|
|
83
|
+
// Item 2 — playwright (description inline)
|
|
84
|
+
log(` ${chalk.cyanBright('2.')} Playwright CLI ${chalk.dim('(used for automated E2E testing of your Power Apps)')}`);
|
|
85
|
+
console.log();
|
|
86
|
+
|
|
87
|
+
// Login heads-up
|
|
88
|
+
log(chalk.bold.yellowBright(' ⚠️ One-time login required after install:'));
|
|
89
|
+
log(` After Playwright CLI is installed, a browser window will open`);
|
|
90
|
+
log(` and you will need to log in to ${chalk.white('Power Apps')} ${chalk.dim('(make.powerapps.com)')}`);
|
|
91
|
+
log(` This saves a persistent session so future test runs won't ask`);
|
|
92
|
+
log(` you to log in again.`);
|
|
93
|
+
console.log();
|
|
94
|
+
|
|
95
|
+
const proceed = await askConfirm('Proceed with installation?', true);
|
|
77
96
|
if (!proceed) {
|
|
78
|
-
warn('Installation cancelled.');
|
|
97
|
+
warn('Installation cancelled. Nothing was changed.');
|
|
79
98
|
process.exit(0);
|
|
80
99
|
}
|
|
81
|
-
|
|
82
|
-
return detected;
|
|
100
|
+
console.log();
|
|
83
101
|
}
|
|
84
102
|
|
|
103
|
+
|
|
104
|
+
|
|
85
105
|
// ─── STEP 2 — Copy skill files ────────────────────────────────────────────────
|
|
86
106
|
|
|
87
107
|
async function stepCopySkill(targets) {
|
|
@@ -185,11 +205,9 @@ async function stepOpenPowerApps() {
|
|
|
185
205
|
// ─── MAIN ─────────────────────────────────────────────────────────────────────
|
|
186
206
|
|
|
187
207
|
export async function runCodeAppWizard() {
|
|
188
|
-
|
|
189
|
-
console.log(chalk.dim(' This wizard will install the skill into your AI agent folders'));
|
|
190
|
-
console.log(chalk.dim(' and set up Playwright for automated testing.\n'));
|
|
191
|
-
|
|
208
|
+
// Detect first, show summary, confirm — then execute
|
|
192
209
|
const targets = await stepDetectTargets();
|
|
210
|
+
await stepShowSummary(targets);
|
|
193
211
|
await stepCopySkill(targets);
|
|
194
212
|
await stepInstallPlaywright();
|
|
195
213
|
await stepOpenPowerApps();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerbuilder/skill",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "PowerBuilder skill installer — drop production-ready AI agent skills into .cursor, .claude, or .gemini folders with one command.",
|
|
5
5
|
"author": "TuongDoan",
|
|
6
6
|
"license": "MIT",
|