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.
@@ -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. Choose an available port — check what the project defaults to, or pick one that is free:
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
- lsof -ti:<port> 2>/dev/null && echo "PORT_IN_USE" || echo "PORT_FREE"
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. Start the dev server in background, capture PID:
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
- 4. Wait for server to be ready: poll the target URL with `curl -s -o /dev/null -w "%{http_code}"` until it returns 200 or 302 (max 30 seconds, 2s interval)
377
- 5. If the page requires authentication, use playwright-cli to register a test user and log in first
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:<port> | xargs kill -9 2>/dev/null || true`
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: <actual URL used>
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. Choose an available port — check what the project defaults to, or pick one that is free:
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
- lsof -ti:<port> 2>/dev/null && echo "PORT_IN_USE" || echo "PORT_FREE"
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. Start the dev server in background, capture PID:
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
- 4. Wait for server to be ready: poll the target URL with `curl -s -o /dev/null -w "%{http_code}"` until it returns 200 or 302 (max 30 seconds, 2s interval)
20
- 5. If the page requires authentication, use playwright-cli to register a test user and log in first
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:<port> | xargs kill -9 2>/dev/null || true`
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: <actual URL used>
56
+ URL: http://localhost:$DEV_PORT
42
57
  Dev Server Command: <actual command used>
43
58
  Steps executed: [list]
44
59
  Screenshot: [path]
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.19",
2
+ "version": "1.1.21",
3
3
  "skills": {
4
4
  "prizm-kit": {
5
5
  "description": "Full-lifecycle dev toolkit. Covers spec-driven development, Prizm context docs, code quality, debugging, deployment, and knowledge management.",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.1.19",
3
+ "version": "1.1.21",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {
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. Remove files for platforms being dropped
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
- // 5b. Handle skill/rule diff for existing platforms (suite or rules changed)
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
- // 5c. Install/update files for new + existing platforms
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
- // 5d. Pipeline changes
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
- // 5e. Update .gitignore
508
+ // 5f. Update .gitignore
445
509
  console.log(chalk.blue('\n Gitignore:'));
446
510
  await installGitignore(projectRoot, { pipeline: newConfig.pipeline }, false);
447
511
 
448
- // 5f. Update .prizmkit/config.json (ai_cli)
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
- // 5g. Write new manifest
529
+ // 5h. Write new manifest
466
530
  const newManifest = buildManifest({
467
531
  version: pkg.version,
468
532
  platform: newConfig.platform,