prizmkit 1.0.127 → 1.0.129
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/bin/create-prizmkit.js +1 -1
- package/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/assets/playwright-cli-reference.md +113 -0
- package/bundled/dev-pipeline/lib/common.sh +21 -0
- package/bundled/dev-pipeline/run-bugfix.sh +4 -1
- package/bundled/dev-pipeline/run.sh +6 -3
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +51 -8
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +57 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +57 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +57 -0
- package/bundled/dev-pipeline/templates/feature-list-schema.json +27 -0
- package/bundled/skills/_metadata.json +8 -5
- package/bundled/skills/app-planner/SKILL.md +49 -0
- package/bundled/skills/bug-planner/SKILL.md +3 -0
- package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +72 -51
- package/bundled/skills/dev-pipeline-launcher/SKILL.md +143 -101
- package/bundled/skills/prizmkit-clarify/SKILL.md +35 -9
- package/bundled/skills/prizmkit-specify/SKILL.md +3 -3
- package/package.json +1 -1
- package/src/external-skills.js +57 -28
- package/src/gitignore-template.js +6 -0
- package/src/index.js +9 -0
- package/src/scaffold.js +53 -3
package/src/external-skills.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* External Skills Installer
|
|
3
3
|
*
|
|
4
|
-
* Delegates to `npx skills add <repo> --skill <name> --yes` to fetch
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Delegates to `npx skills add <repo> [--skill <name>] --yes` to fetch skills.
|
|
5
|
+
* Supports two modes:
|
|
6
|
+
* - Single skill: `--skill <name>` selects one skill from a repo
|
|
7
|
+
* - Install all: installs all skills from a repo (e.g. pbakaus/impeccable)
|
|
8
|
+
*
|
|
9
|
+
* When run non-interactively (stdio: 'pipe'), npx skills writes canonical
|
|
10
|
+
* .agents/skills/<name>/SKILL.md files. We copy those to the selected
|
|
11
|
+
* platform dir(s), then clean up .agents/ and skills-lock.json.
|
|
9
12
|
*/
|
|
10
13
|
|
|
11
14
|
import { execSync } from 'node:child_process';
|
|
@@ -14,8 +17,9 @@ import fs from 'fs-extra';
|
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* @param {Object} skill - Skill definition from external_skills.known
|
|
17
|
-
* skill.repo
|
|
18
|
-
* skill.name
|
|
20
|
+
* skill.repo {string} - GitHub short ref (e.g. "pbakaus/impeccable") or full URL
|
|
21
|
+
* skill.name {string} - Skill name (used for display / single-skill mode)
|
|
22
|
+
* skill.installAll {boolean} - If true, install all skills from the repo
|
|
19
23
|
* @param {string} platform - 'claude' | 'codebuddy' | 'both'
|
|
20
24
|
* @param {string} projectRoot - Target project root
|
|
21
25
|
* @param {boolean} dryRun
|
|
@@ -25,35 +29,60 @@ export async function installExternalSkill(skill, platform, projectRoot, dryRun)
|
|
|
25
29
|
throw new Error(`Skill "${skill.name}" has no repo URL defined`);
|
|
26
30
|
}
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
// installAll: install entire repo (all skills), otherwise install single skill by name
|
|
33
|
+
const cmd = skill.installAll
|
|
34
|
+
? `npx skills add ${skill.repo} --yes`
|
|
35
|
+
: `npx skills add ${skill.repo} --skill ${skill.name} --yes`;
|
|
29
36
|
|
|
30
37
|
if (dryRun) {
|
|
31
|
-
const targets = getTargetDirs(platform, projectRoot)
|
|
32
|
-
.map(d => path.relative(projectRoot, path.join(d, skill.name, 'SKILL.md')));
|
|
33
38
|
console.log(` [dry-run] ${cmd}`);
|
|
34
|
-
|
|
39
|
+
if (skill.installAll) {
|
|
40
|
+
console.log(` [dry-run] → all skills from ${skill.repo}`);
|
|
41
|
+
} else {
|
|
42
|
+
const targets = getTargetDirs(platform, projectRoot)
|
|
43
|
+
.map(d => path.relative(projectRoot, path.join(d, skill.name, 'SKILL.md')));
|
|
44
|
+
for (const t of targets) console.log(` [dry-run] → ${t}`);
|
|
45
|
+
}
|
|
35
46
|
return;
|
|
36
47
|
}
|
|
37
48
|
|
|
38
|
-
// stdio: 'pipe' → npx skills runs non-interactively
|
|
39
|
-
execSync(cmd, { cwd: projectRoot, stdio: 'pipe', timeout:
|
|
49
|
+
// stdio: 'pipe' → npx skills runs non-interactively
|
|
50
|
+
execSync(cmd, { cwd: projectRoot, stdio: 'pipe', timeout: 120000 });
|
|
40
51
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
52
|
+
const agentsSkillsDir = path.join(projectRoot, '.agents', 'skills');
|
|
53
|
+
|
|
54
|
+
if (skill.installAll) {
|
|
55
|
+
// Repo-level install: copy ALL skill dirs from .agents/skills/ to platform dirs
|
|
56
|
+
if (!await fs.pathExists(agentsSkillsDir)) {
|
|
57
|
+
throw new Error(`npx skills did not produce .agents/skills/ for repo ${skill.repo}`);
|
|
58
|
+
}
|
|
59
|
+
const skillDirs = (await fs.readdir(agentsSkillsDir, { withFileTypes: true }))
|
|
60
|
+
.filter(d => d.isDirectory())
|
|
61
|
+
.map(d => d.name);
|
|
62
|
+
|
|
63
|
+
for (const targetDir of getTargetDirs(platform, projectRoot)) {
|
|
64
|
+
for (const skillName of skillDirs) {
|
|
65
|
+
const srcDir = path.join(agentsSkillsDir, skillName);
|
|
66
|
+
const destDir = path.join(targetDir, skillName);
|
|
67
|
+
await fs.remove(destDir).catch(() => {});
|
|
68
|
+
await fs.copy(srcDir, destDir);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
// Single-skill install
|
|
73
|
+
const canonicalSkillMd = path.join(agentsSkillsDir, skill.name, 'SKILL.md');
|
|
74
|
+
if (!await fs.pathExists(canonicalSkillMd)) {
|
|
75
|
+
throw new Error(`npx skills did not produce .agents/skills/${skill.name}/SKILL.md`);
|
|
76
|
+
}
|
|
45
77
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
await fs.remove(skillDir).catch(() => {});
|
|
55
|
-
await fs.ensureDir(skillDir);
|
|
56
|
-
await fs.writeFile(path.join(skillDir, 'SKILL.md'), content);
|
|
78
|
+
const content = await fs.readFile(canonicalSkillMd, 'utf8');
|
|
79
|
+
|
|
80
|
+
for (const targetDir of getTargetDirs(platform, projectRoot)) {
|
|
81
|
+
const skillDir = path.join(targetDir, skill.name);
|
|
82
|
+
await fs.remove(skillDir).catch(() => {});
|
|
83
|
+
await fs.ensureDir(skillDir);
|
|
84
|
+
await fs.writeFile(path.join(skillDir, 'SKILL.md'), content);
|
|
85
|
+
}
|
|
57
86
|
}
|
|
58
87
|
|
|
59
88
|
// Clean up npx skills artifacts after copying
|
package/src/index.js
CHANGED
|
@@ -67,6 +67,7 @@ export async function runScaffold(directory, options) {
|
|
|
67
67
|
skills: options.skills || 'full',
|
|
68
68
|
team: options.team !== false,
|
|
69
69
|
pipeline: options.pipeline !== false,
|
|
70
|
+
playwrightCli: options.playwrightCli !== false,
|
|
70
71
|
rules: options.rules || 'recommended',
|
|
71
72
|
aiCli: options.aiCli || '',
|
|
72
73
|
externalSkills: options.externalSkills ? options.externalSkills.split(',').map(s => s.trim()).filter(Boolean) : [],
|
|
@@ -202,6 +203,12 @@ export async function runScaffold(directory, options) {
|
|
|
202
203
|
default: true,
|
|
203
204
|
});
|
|
204
205
|
|
|
206
|
+
// 4.5. Playwright CLI (browser interaction support)
|
|
207
|
+
const playwrightCli = await confirm({
|
|
208
|
+
message: '安装浏览器交互工具 (playwright-cli)? 支持 UI 自动验证',
|
|
209
|
+
default: true,
|
|
210
|
+
});
|
|
211
|
+
|
|
205
212
|
// 5. Rules 预设
|
|
206
213
|
const rulesPreset = await select({
|
|
207
214
|
message: '安装 AI 行为规则 (rules):',
|
|
@@ -227,6 +234,7 @@ export async function runScaffold(directory, options) {
|
|
|
227
234
|
console.log(` 技能: ${chalk.cyan(suiteLabel)}`);
|
|
228
235
|
console.log(` 团队模式: ${team ? chalk.green('启用') : chalk.gray('禁用')}`);
|
|
229
236
|
console.log(` 流水线: ${pipeline ? chalk.green('启用') : chalk.gray('禁用')}`);
|
|
237
|
+
console.log(` 浏览器工具: ${playwrightCli ? chalk.green('启用') : chalk.gray('禁用')}`);
|
|
230
238
|
console.log(` 规则: ${chalk.cyan(rulesPreset)}`);
|
|
231
239
|
if (aiCli) console.log(` AI CLI: ${chalk.cyan(aiCli)}`);
|
|
232
240
|
if (selectedExternalSkills.length > 0) console.log(` 外部技能: ${chalk.cyan(selectedExternalSkills.join(', '))}`);
|
|
@@ -249,6 +257,7 @@ export async function runScaffold(directory, options) {
|
|
|
249
257
|
skills: skillSuite,
|
|
250
258
|
team,
|
|
251
259
|
pipeline,
|
|
260
|
+
playwrightCli,
|
|
252
261
|
rules: rulesPreset,
|
|
253
262
|
aiCli: aiCli || '',
|
|
254
263
|
externalSkills: selectedExternalSkills,
|
package/src/scaffold.js
CHANGED
|
@@ -10,9 +10,10 @@
|
|
|
10
10
|
import chalk from 'chalk';
|
|
11
11
|
import fs from 'fs-extra';
|
|
12
12
|
import path from 'path';
|
|
13
|
-
import { readFileSync } from 'fs';
|
|
13
|
+
import { readFileSync, existsSync } from 'fs';
|
|
14
14
|
import { fileURLToPath } from 'url';
|
|
15
15
|
import { dirname, join } from 'path';
|
|
16
|
+
import { execSync } from 'child_process';
|
|
16
17
|
import {
|
|
17
18
|
loadMetadata,
|
|
18
19
|
getSkillsDir,
|
|
@@ -691,6 +692,46 @@ export async function installGitignore(projectRoot, options, dryRun) {
|
|
|
691
692
|
}
|
|
692
693
|
}
|
|
693
694
|
|
|
695
|
+
// ============================================================
|
|
696
|
+
// Playwright CLI 安装
|
|
697
|
+
// ============================================================
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* 安装 playwright-cli(全局 npm 包 + workspace 初始化)
|
|
701
|
+
* 用于浏览器交互验证(browser_interaction 功能)
|
|
702
|
+
*/
|
|
703
|
+
export async function installPlaywrightCli(projectRoot, dryRun) {
|
|
704
|
+
if (dryRun) {
|
|
705
|
+
console.log(chalk.gray(' [dry-run] @playwright/cli (global install + workspace init)'));
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Check if already installed
|
|
710
|
+
try {
|
|
711
|
+
execSync('playwright-cli --version', { stdio: 'pipe' });
|
|
712
|
+
console.log(chalk.green(' ✓ playwright-cli (already installed)'));
|
|
713
|
+
} catch {
|
|
714
|
+
// Not installed, install it
|
|
715
|
+
try {
|
|
716
|
+
console.log(chalk.blue(' ⏳ Installing @playwright/cli globally...'));
|
|
717
|
+
execSync('npm install -g @playwright/cli@latest', { stdio: 'pipe', timeout: 120000 });
|
|
718
|
+
console.log(chalk.green(' ✓ @playwright/cli installed globally'));
|
|
719
|
+
} catch (e) {
|
|
720
|
+
console.log(chalk.yellow(` ⚠ @playwright/cli install failed: ${e.message}`));
|
|
721
|
+
console.log(chalk.yellow(' ⚠ Run manually: npm install -g @playwright/cli@latest'));
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// Initialize workspace
|
|
727
|
+
try {
|
|
728
|
+
execSync('playwright-cli install', { cwd: projectRoot, stdio: 'pipe', timeout: 60000 });
|
|
729
|
+
console.log(chalk.green(' ✓ playwright-cli workspace initialized'));
|
|
730
|
+
} catch (e) {
|
|
731
|
+
console.log(chalk.yellow(` ⚠ playwright-cli workspace init skipped: ${e.message}`));
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
694
735
|
// ============================================================
|
|
695
736
|
// 主安装函数
|
|
696
737
|
// ============================================================
|
|
@@ -705,11 +746,12 @@ export async function installGitignore(projectRoot, options, dryRun) {
|
|
|
705
746
|
* @param {string} [config.rules] - Rules preset: 'recommended' | 'minimal' | 'none'
|
|
706
747
|
* @param {string} [config.aiCli] - AI CLI 可执行命令(写入 .prizmkit/config.json)
|
|
707
748
|
* @param {string[]} [config.externalSkills] - 要安装的外部 skill 名称列表
|
|
749
|
+
* @param {boolean} [config.playwrightCli] - 是否安装 playwright-cli
|
|
708
750
|
* @param {string} config.projectRoot - 目标项目根目录
|
|
709
751
|
* @param {boolean} config.dryRun - 是否为预览模式
|
|
710
752
|
*/
|
|
711
753
|
export async function scaffold(config) {
|
|
712
|
-
const { platform, skills, team, pipeline, rules, aiCli, externalSkills, projectRoot, dryRun } = config;
|
|
754
|
+
const { platform, skills, team, pipeline, rules, aiCli, externalSkills, playwrightCli, projectRoot, dryRun } = config;
|
|
713
755
|
const platforms = platform === 'both' ? ['codebuddy', 'claude'] : [platform];
|
|
714
756
|
|
|
715
757
|
if (dryRun) {
|
|
@@ -803,7 +845,14 @@ export async function scaffold(config) {
|
|
|
803
845
|
}
|
|
804
846
|
}
|
|
805
847
|
|
|
806
|
-
// 10.
|
|
848
|
+
// 10. Playwright CLI (optional)
|
|
849
|
+
if (playwrightCli) {
|
|
850
|
+
console.log(chalk.blue(' 浏览器交互工具:'));
|
|
851
|
+
await installPlaywrightCli(projectRoot, dryRun);
|
|
852
|
+
console.log('');
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// 11. Clean up stray .codebuddy/ directory left by third-party tools (e.g. npx skills)
|
|
807
856
|
// when installing for Claude Code only. CodeBuddy files should never appear in a
|
|
808
857
|
// claude-only install.
|
|
809
858
|
if (!dryRun && !platforms.includes('codebuddy')) {
|
|
@@ -890,6 +939,7 @@ export async function scaffold(config) {
|
|
|
890
939
|
console.log(chalk.gray(` 平台: ${platforms.map(p => p === 'codebuddy' ? 'CodeBuddy' : 'Claude Code').join(' + ')}`));
|
|
891
940
|
console.log(chalk.gray(` 团队: ${team ? '已启用' : '未启用'}`));
|
|
892
941
|
console.log(chalk.gray(` 流水线: ${pipeline ? '已安装' : '未安装'}`));
|
|
942
|
+
console.log(chalk.gray(` 浏览器工具: ${playwrightCli ? '已安装 (playwright-cli)' : '未安装'}`));
|
|
893
943
|
console.log(chalk.gray(` 规则: ${rules || 'recommended'}`));
|
|
894
944
|
if (aiCli) console.log(chalk.gray(` AI CLI: ${aiCli}`));
|
|
895
945
|
console.log('');
|