prizmkit 1.1.19 → 1.1.21
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/bundled/VERSION.json +3 -3
- package/bundled/dev-pipeline/lib/branch.sh +187 -23
- package/bundled/dev-pipeline/run-bugfix.sh +113 -26
- package/bundled/dev-pipeline/run-feature.sh +113 -27
- package/bundled/dev-pipeline/run-refactor.sh +113 -26
- package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +32 -0
- package/bundled/dev-pipeline/templates/bootstrap-tier1.md +22 -7
- package/bundled/dev-pipeline/templates/bootstrap-tier2.md +22 -7
- package/bundled/dev-pipeline/templates/bootstrap-tier3.md +22 -7
- package/bundled/dev-pipeline/templates/sections/phase-browser-verification.md +22 -7
- package/bundled/skills/_metadata.json +1 -1
- package/package.json +1 -1
- package/src/config.js +71 -7
|
@@ -364,17 +364,32 @@ You MUST execute this phase. Do NOT skip it. Do NOT mark it as completed without
|
|
|
364
364
|
You know this project's tech stack. Detect and start the dev server yourself:
|
|
365
365
|
|
|
366
366
|
1. Identify the dev server start command from project config (`package.json` scripts, `Makefile`, `docker-compose.yml`, etc.)
|
|
367
|
-
2.
|
|
367
|
+
2. **Detect the dev server port** — use the pre-detected port from pipeline if available, otherwise extract from project config. Do NOT hardcode or guess the port:
|
|
368
368
|
```bash
|
|
369
|
-
|
|
369
|
+
# Use pipeline-injected port if available, otherwise extract from package.json
|
|
370
|
+
DEV_PORT={{DEV_PORT}}
|
|
371
|
+
# If DEV_PORT is still a placeholder, detect at runtime:
|
|
372
|
+
if [ "$DEV_PORT" = "{{DEV_PORT}}" ]; then
|
|
373
|
+
DEV_PORT=$(node -e "const s=require('./package.json').scripts.dev; const m=s.match(/-p\s+(\d+)/); console.log(m?m[1]:'')")
|
|
374
|
+
if [ -z "$DEV_PORT" ]; then
|
|
375
|
+
DEV_PORT=$(echo "$NEXT_PUBLIC_SITE_URL" | sed -nE 's|.*:([0-9]+).*|\1|p')
|
|
376
|
+
fi
|
|
377
|
+
DEV_PORT=${DEV_PORT:-3000}
|
|
378
|
+
fi
|
|
379
|
+
echo "Detected DEV_PORT=$DEV_PORT"
|
|
370
380
|
```
|
|
371
|
-
3.
|
|
381
|
+
3. Verify the port is available:
|
|
382
|
+
```bash
|
|
383
|
+
lsof -ti:$DEV_PORT 2>/dev/null && echo "PORT_IN_USE" || echo "PORT_FREE"
|
|
384
|
+
```
|
|
385
|
+
4. Start the dev server in background, capture PID:
|
|
372
386
|
```bash
|
|
373
387
|
<start-command> &
|
|
374
388
|
DEV_SERVER_PID=$!
|
|
375
389
|
```
|
|
376
|
-
|
|
377
|
-
|
|
390
|
+
5. Wait for server to be ready: poll `http://localhost:$DEV_PORT` with `curl -s -o /dev/null -w "%{http_code}"` until it returns 200 or 302 (max 30 seconds, 2s interval)
|
|
391
|
+
6. Open the app in playwright-cli: `playwright-cli open http://localhost:$DEV_PORT`
|
|
392
|
+
7. If the page requires authentication, use playwright-cli to register a test user and log in first
|
|
378
393
|
|
|
379
394
|
**Step 2 — Verification**:
|
|
380
395
|
|
|
@@ -387,14 +402,14 @@ Take a final screenshot for evidence.
|
|
|
387
402
|
**Step 3 — Cleanup (REQUIRED — you started it, you stop it)**:
|
|
388
403
|
|
|
389
404
|
1. Kill the dev server process: `kill $DEV_SERVER_PID 2>/dev/null || true`
|
|
390
|
-
2. Verify port is released: `lsof -ti
|
|
405
|
+
2. Verify port is released: `lsof -ti:$DEV_PORT | xargs kill -9 2>/dev/null || true`
|
|
391
406
|
|
|
392
407
|
**Step 4 — Reporting**:
|
|
393
408
|
|
|
394
409
|
Append results to `context-snapshot.md`:
|
|
395
410
|
```
|
|
396
411
|
## Browser Verification
|
|
397
|
-
URL:
|
|
412
|
+
URL: http://localhost:$DEV_PORT
|
|
398
413
|
Dev Server Command: <actual command used>
|
|
399
414
|
Steps executed: [list]
|
|
400
415
|
Screenshot: [path]
|
|
@@ -7,17 +7,32 @@ You MUST execute this phase. Do NOT skip it. Do NOT mark it as completed without
|
|
|
7
7
|
You know this project's tech stack. Detect and start the dev server yourself:
|
|
8
8
|
|
|
9
9
|
1. Identify the dev server start command from project config (`package.json` scripts, `Makefile`, `docker-compose.yml`, etc.)
|
|
10
|
-
2.
|
|
10
|
+
2. **Detect the dev server port** — use the pre-detected port from pipeline if available, otherwise extract from project config. Do NOT hardcode or guess the port:
|
|
11
11
|
```bash
|
|
12
|
-
|
|
12
|
+
# Use pipeline-injected port if available, otherwise extract from package.json
|
|
13
|
+
DEV_PORT={{DEV_PORT}}
|
|
14
|
+
# If DEV_PORT is still a placeholder, detect at runtime:
|
|
15
|
+
if [ "$DEV_PORT" = "{{DEV_PORT}}" ]; then
|
|
16
|
+
DEV_PORT=$(node -e "const s=require('./package.json').scripts.dev; const m=s.match(/-p\s+(\d+)/); console.log(m?m[1]:'')")
|
|
17
|
+
if [ -z "$DEV_PORT" ]; then
|
|
18
|
+
DEV_PORT=$(echo "$NEXT_PUBLIC_SITE_URL" | sed -nE 's|.*:([0-9]+).*|\1|p')
|
|
19
|
+
fi
|
|
20
|
+
DEV_PORT=${DEV_PORT:-3000}
|
|
21
|
+
fi
|
|
22
|
+
echo "Detected DEV_PORT=$DEV_PORT"
|
|
13
23
|
```
|
|
14
|
-
3.
|
|
24
|
+
3. Verify the port is available:
|
|
25
|
+
```bash
|
|
26
|
+
lsof -ti:$DEV_PORT 2>/dev/null && echo "PORT_IN_USE" || echo "PORT_FREE"
|
|
27
|
+
```
|
|
28
|
+
4. Start the dev server in background, capture PID:
|
|
15
29
|
```bash
|
|
16
30
|
<start-command> &
|
|
17
31
|
DEV_SERVER_PID=$!
|
|
18
32
|
```
|
|
19
|
-
|
|
20
|
-
|
|
33
|
+
5. Wait for server to be ready: poll `http://localhost:$DEV_PORT` with `curl -s -o /dev/null -w "%{http_code}"` until it returns 200 or 302 (max 30 seconds, 2s interval)
|
|
34
|
+
6. Open the app in playwright-cli: `playwright-cli open http://localhost:$DEV_PORT`
|
|
35
|
+
7. If the page requires authentication, use playwright-cli to register a test user and log in first
|
|
21
36
|
|
|
22
37
|
**Step 2 — Verification**:
|
|
23
38
|
|
|
@@ -31,14 +46,14 @@ Take a final screenshot for evidence.
|
|
|
31
46
|
**Step 3 — Cleanup (REQUIRED — you started it, you stop it)**:
|
|
32
47
|
|
|
33
48
|
1. Kill the dev server process: `kill $DEV_SERVER_PID 2>/dev/null || true`
|
|
34
|
-
2. Verify port is released: `lsof -ti
|
|
49
|
+
2. Verify port is released: `lsof -ti:$DEV_PORT | xargs kill -9 2>/dev/null || true`
|
|
35
50
|
|
|
36
51
|
**Step 4 — Reporting**:
|
|
37
52
|
|
|
38
53
|
Append results to `context-snapshot.md`:
|
|
39
54
|
```
|
|
40
55
|
## Browser Verification
|
|
41
|
-
URL:
|
|
56
|
+
URL: http://localhost:$DEV_PORT
|
|
42
57
|
Dev Server Command: <actual command used>
|
|
43
58
|
Steps executed: [list]
|
|
44
59
|
Screenshot: [path]
|
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -79,6 +79,65 @@ function expandPlatforms(platform) {
|
|
|
79
79
|
return platform === 'both' ? ['codebuddy', 'claude'] : [platform];
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
function getProjectMemoryFile(platform) {
|
|
83
|
+
if (platform === 'claude') return 'CLAUDE.md';
|
|
84
|
+
if (platform === 'codebuddy') return 'CODEBUDDY.md';
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function getCounterpartPlatform(platform) {
|
|
89
|
+
return platform === 'claude' ? 'codebuddy' : platform === 'codebuddy' ? 'claude' : null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async function migrateProjectMemoryOnPlatformDrop(droppedPlatform, newPlatforms, projectRoot, dryRun) {
|
|
93
|
+
const sourceFile = getProjectMemoryFile(droppedPlatform);
|
|
94
|
+
if (!sourceFile) return;
|
|
95
|
+
|
|
96
|
+
const sourcePath = path.join(projectRoot, sourceFile);
|
|
97
|
+
if (!await fs.pathExists(sourcePath)) return;
|
|
98
|
+
|
|
99
|
+
const counterpart = getCounterpartPlatform(droppedPlatform);
|
|
100
|
+
const targetPlatform = (counterpart && newPlatforms.includes(counterpart))
|
|
101
|
+
? counterpart
|
|
102
|
+
: newPlatforms.find(p => p !== droppedPlatform);
|
|
103
|
+
|
|
104
|
+
if (!targetPlatform || targetPlatform === droppedPlatform) return;
|
|
105
|
+
|
|
106
|
+
const targetFile = getProjectMemoryFile(targetPlatform);
|
|
107
|
+
if (!targetFile || targetFile === sourceFile) return;
|
|
108
|
+
|
|
109
|
+
const targetPath = path.join(projectRoot, targetFile);
|
|
110
|
+
|
|
111
|
+
if (dryRun) {
|
|
112
|
+
console.log(chalk.gray(` [dry-run] migrate ${sourceFile} -> ${targetFile}`));
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const sourceContent = await fs.readFile(sourcePath, 'utf-8');
|
|
117
|
+
if (!sourceContent.trim()) return;
|
|
118
|
+
|
|
119
|
+
if (!await fs.pathExists(targetPath)) {
|
|
120
|
+
const normalized = sourceContent.endsWith('\n') ? sourceContent : `${sourceContent}\n`;
|
|
121
|
+
await fs.writeFile(targetPath, normalized, 'utf-8');
|
|
122
|
+
console.log(chalk.green(` ✓ migrated ${sourceFile} -> ${targetFile}`));
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const targetContent = await fs.readFile(targetPath, 'utf-8');
|
|
127
|
+
const normalizedSource = sourceContent.replace(/\r\n/g, '\n').trim();
|
|
128
|
+
const normalizedTarget = targetContent.replace(/\r\n/g, '\n').trim();
|
|
129
|
+
|
|
130
|
+
if (!normalizedSource || normalizedTarget.includes(normalizedSource)) {
|
|
131
|
+
console.log(chalk.gray(` • ${targetFile} already contains ${sourceFile} content, skip merge`));
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const separator = targetContent.endsWith('\n') ? '\n' : '\n\n';
|
|
136
|
+
const merged = `${targetContent}${separator}<!-- MIGRATED FROM ${sourceFile} via prizmkit config -->\n\n${sourceContent.trimEnd()}\n`;
|
|
137
|
+
await fs.writeFile(targetPath, merged, 'utf-8');
|
|
138
|
+
console.log(chalk.green(` ✓ merged ${sourceFile} content into ${targetFile}`));
|
|
139
|
+
}
|
|
140
|
+
|
|
82
141
|
const platformLabel = (p) => p === 'both' ? 'CodeBuddy + Claude Code'
|
|
83
142
|
: p === 'codebuddy' ? 'CodeBuddy' : 'Claude Code';
|
|
84
143
|
|
|
@@ -364,13 +423,18 @@ export async function runConfig(directory, options = {}) {
|
|
|
364
423
|
const newRuleFiles = (rulesPresetDef?.rules || []).map(name => `${name}.md`);
|
|
365
424
|
const newPipelineFiles = newConfig.pipeline ? resolvePipelineFileList() : [];
|
|
366
425
|
|
|
367
|
-
// 5a.
|
|
426
|
+
// 5a. Migrate project memory before removing dropped platforms
|
|
427
|
+
for (const p of platformsToRemove) {
|
|
428
|
+
await migrateProjectMemoryOnPlatformDrop(p, newPlatforms, projectRoot, false);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// 5b. Remove files for platforms being dropped
|
|
368
432
|
for (const p of platformsToRemove) {
|
|
369
433
|
console.log(chalk.bold(` 移除 ${platformLabel(p)} 平台文件...`));
|
|
370
434
|
await removePlatformFiles(p, projectRoot, oldManifest, false);
|
|
371
435
|
}
|
|
372
436
|
|
|
373
|
-
//
|
|
437
|
+
// 5c. Handle skill/rule diff for existing platforms (suite or rules changed)
|
|
374
438
|
if (newConfig.suite !== currentConfig.suite || newConfig.rules !== currentConfig.rules) {
|
|
375
439
|
const newTempManifest = buildManifest({
|
|
376
440
|
version: pkg.version, platform: newConfig.platform, suite: newConfig.suite,
|
|
@@ -393,7 +457,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
393
457
|
}
|
|
394
458
|
}
|
|
395
459
|
|
|
396
|
-
//
|
|
460
|
+
// 5d. Install/update files for new + existing platforms
|
|
397
461
|
const allTargetPlatforms = [...platformsToAdd, ...platformsToUpdate];
|
|
398
462
|
const needsReinstall = newConfig.platform !== currentConfig.platform
|
|
399
463
|
|| newConfig.suite !== currentConfig.suite
|
|
@@ -427,7 +491,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
427
491
|
}
|
|
428
492
|
}
|
|
429
493
|
|
|
430
|
-
//
|
|
494
|
+
// 5e. Pipeline changes
|
|
431
495
|
if (newConfig.pipeline !== currentConfig.pipeline) {
|
|
432
496
|
if (newConfig.pipeline) {
|
|
433
497
|
console.log(chalk.blue('\n 安装 Pipeline:'));
|
|
@@ -441,11 +505,11 @@ export async function runConfig(directory, options = {}) {
|
|
|
441
505
|
}
|
|
442
506
|
}
|
|
443
507
|
|
|
444
|
-
//
|
|
508
|
+
// 5f. Update .gitignore
|
|
445
509
|
console.log(chalk.blue('\n Gitignore:'));
|
|
446
510
|
await installGitignore(projectRoot, { pipeline: newConfig.pipeline }, false);
|
|
447
511
|
|
|
448
|
-
//
|
|
512
|
+
// 5g. Update .prizmkit/config.json (ai_cli)
|
|
449
513
|
if (newConfig.aiCli !== currentConfig.aiCli) {
|
|
450
514
|
const prizmkitDir = path.join(projectRoot, '.prizmkit');
|
|
451
515
|
await fs.ensureDir(prizmkitDir);
|
|
@@ -462,7 +526,7 @@ export async function runConfig(directory, options = {}) {
|
|
|
462
526
|
console.log(chalk.green(`\n ✓ .prizmkit/config.json (ai_cli: ${newConfig.aiCli || '(cleared)'})`));
|
|
463
527
|
}
|
|
464
528
|
|
|
465
|
-
//
|
|
529
|
+
// 5h. Write new manifest
|
|
466
530
|
const newManifest = buildManifest({
|
|
467
531
|
version: pkg.version,
|
|
468
532
|
platform: newConfig.platform,
|