dev-playbooks-cn 2.0.0 → 2.1.1

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 CHANGED
@@ -79,7 +79,7 @@ AI 编码助手很强大,但往往**不可预测**:
79
79
  | **Claude Code** | 完整 Skills | `CLAUDE.md` |
80
80
  | **Codex CLI** | 完整 Skills | `AGENTS.md` |
81
81
  | **Qoder** | 完整 Skills | `AGENTS.md` |
82
- | **OpenCode(oh-my-opencode)** | 完整 Skills | `AGENTS.md` |
82
+ | **OpenCode** | 完整 Skills | `AGENTS.md` |
83
83
  | **Cursor** | Rules 系统 | `.cursor/rules/` |
84
84
  | **Windsurf** | Rules 系统 | `.windsurf/rules/` |
85
85
  | **Gemini CLI** | Rules 系统 | `GEMINI.md` |
package/bin/devbooks.js CHANGED
@@ -84,7 +84,7 @@ const AI_TOOLS = [
84
84
  {
85
85
  id: 'opencode',
86
86
  name: 'OpenCode',
87
- description: 'OpenCode AI CLI (compatible with oh-my-opencode)',
87
+ description: 'OpenCode AI CLI',
88
88
  skillsSupport: SKILLS_SUPPORT.FULL,
89
89
  slashDir: '.opencode/command',
90
90
  agentsDir: '.opencode/agent',
@@ -380,6 +380,195 @@ async function performNpmUpdate() {
380
380
  });
381
381
  }
382
382
 
383
+ /**
384
+ * 显示版本变更摘要
385
+ * @param {string} fromVersion - 当前版本
386
+ * @param {string} toVersion - 目标版本
387
+ */
388
+ async function displayVersionChangelog(fromVersion, toVersion) {
389
+ try {
390
+ // 尝试从 npm 获取 CHANGELOG
391
+ const { execSync } = await import('child_process');
392
+ const changelogUrl = `https://raw.githubusercontent.com/Darkbluelr/dev-playbooks-cn/master/CHANGELOG.md`;
393
+
394
+ // 使用 curl 获取 CHANGELOG(如果可用)
395
+ let changelog = '';
396
+ try {
397
+ changelog = execSync(`curl -s -m 5 "${changelogUrl}"`, {
398
+ encoding: 'utf-8',
399
+ stdio: ['pipe', 'pipe', 'pipe']
400
+ });
401
+ } catch {
402
+ // 如果获取失败,显示简化信息
403
+ console.log(chalk.cyan('📋 版本变更摘要'));
404
+ console.log(chalk.gray('─'.repeat(60)));
405
+ console.log(chalk.yellow('⚠ 无法获取详细变更日志,请访问:'));
406
+ console.log(chalk.blue(` https://github.com/Darkbluelr/dev-playbooks-cn/releases/tag/v${toVersion}`));
407
+ return;
408
+ }
409
+
410
+ // 解析 CHANGELOG,提取相关版本的变更
411
+ const changes = parseChangelog(changelog, fromVersion, toVersion);
412
+
413
+ if (changes.length === 0) {
414
+ console.log(chalk.cyan('📋 版本变更摘要'));
415
+ console.log(chalk.gray('─'.repeat(60)));
416
+ console.log(chalk.yellow('⚠ 未找到详细变更信息,请访问:'));
417
+ console.log(chalk.blue(` https://github.com/Darkbluelr/dev-playbooks-cn/releases/tag/v${toVersion}`));
418
+ return;
419
+ }
420
+
421
+ // 显示变更摘要
422
+ console.log(chalk.cyan('📋 版本变更摘要'));
423
+ console.log(chalk.gray('─'.repeat(60)));
424
+
425
+ for (const change of changes) {
426
+ console.log();
427
+ console.log(chalk.bold.green(`## ${change.version}`));
428
+ if (change.date) {
429
+ console.log(chalk.gray(` 发布日期: ${change.date}`));
430
+ }
431
+ console.log();
432
+
433
+ // 显示主要变更(限制显示前10条)
434
+ const highlights = change.content.split('\n')
435
+ .filter(line => line.trim().length > 0)
436
+ .slice(0, 10);
437
+
438
+ for (const line of highlights) {
439
+ if (line.startsWith('###')) {
440
+ console.log(chalk.bold.yellow(line));
441
+ } else if (line.startsWith('####')) {
442
+ console.log(chalk.bold(line));
443
+ } else if (line.startsWith('- ✅') || line.startsWith('- ✓')) {
444
+ console.log(chalk.green(line));
445
+ } else if (line.startsWith('- ⚠️') || line.startsWith('- ❌')) {
446
+ console.log(chalk.yellow(line));
447
+ } else if (line.startsWith('- ')) {
448
+ console.log(chalk.white(line));
449
+ } else {
450
+ console.log(chalk.gray(line));
451
+ }
452
+ }
453
+
454
+ if (change.content.split('\n').length > 10) {
455
+ console.log(chalk.gray(' ... (更多变更请查看完整日志)'));
456
+ }
457
+ }
458
+
459
+ console.log();
460
+ console.log(chalk.gray('─'.repeat(60)));
461
+ console.log(chalk.blue('📖 完整变更日志: ') + chalk.underline(`https://github.com/Darkbluelr/dev-playbooks-cn/blob/master/CHANGELOG.md`));
462
+
463
+ } catch (error) {
464
+ // 静默失败,不影响更新流程
465
+ console.log(chalk.gray('提示: 无法显示变更摘要'));
466
+ }
467
+ }
468
+
469
+ /**
470
+ * 解析 CHANGELOG 内容,提取指定版本范围的变更
471
+ * @param {string} changelog - CHANGELOG 内容
472
+ * @param {string} fromVersion - 起始版本
473
+ * @param {string} toVersion - 目标版本
474
+ * @returns {Array} - 变更列表
475
+ */
476
+ function parseChangelog(changelog, fromVersion, toVersion) {
477
+ const changes = [];
478
+ const lines = changelog.split('\n');
479
+
480
+ let currentVersion = null;
481
+ let currentDate = null;
482
+ let currentContent = [];
483
+ let inVersionBlock = false;
484
+ let shouldCapture = false;
485
+
486
+ // 解析版本号(移除 'v' 前缀)
487
+ const from = fromVersion.replace(/^v/, '');
488
+ const to = toVersion.replace(/^v/, '');
489
+
490
+ for (let i = 0; i < lines.length; i++) {
491
+ const line = lines[i];
492
+
493
+ // 匹配版本标题:## [2.0.0] - 2026-01-19
494
+ const versionMatch = line.match(/^##\s+\[?(\d+\.\d+\.\d+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/);
495
+
496
+ if (versionMatch) {
497
+ // 保存上一个版本的内容
498
+ if (inVersionBlock && shouldCapture && currentVersion) {
499
+ changes.push({
500
+ version: currentVersion,
501
+ date: currentDate,
502
+ content: currentContent.join('\n').trim()
503
+ });
504
+ }
505
+
506
+ // 开始新版本
507
+ currentVersion = versionMatch[1];
508
+ currentDate = versionMatch[2] || null;
509
+ currentContent = [];
510
+ inVersionBlock = true;
511
+
512
+ // 判断是否应该捕获这个版本
513
+ // 捕获从 fromVersion 到 toVersion 之间的所有版本
514
+ const versionNum = currentVersion.split('.').map(Number);
515
+ const fromNum = from.split('.').map(Number);
516
+ const toNum = to.split('.').map(Number);
517
+
518
+ const isAfterFrom = compareVersions(versionNum, fromNum) > 0;
519
+ const isBeforeOrEqualTo = compareVersions(versionNum, toNum) <= 0;
520
+
521
+ shouldCapture = isAfterFrom && isBeforeOrEqualTo;
522
+
523
+ continue;
524
+ }
525
+
526
+ // 如果遇到下一个版本标题或分隔线,结束当前版本
527
+ if (line.startsWith('---') && inVersionBlock) {
528
+ if (shouldCapture && currentVersion) {
529
+ changes.push({
530
+ version: currentVersion,
531
+ date: currentDate,
532
+ content: currentContent.join('\n').trim()
533
+ });
534
+ }
535
+ inVersionBlock = false;
536
+ shouldCapture = false;
537
+ continue;
538
+ }
539
+
540
+ // 收集内容
541
+ if (inVersionBlock && shouldCapture) {
542
+ currentContent.push(line);
543
+ }
544
+ }
545
+
546
+ // 保存最后一个版本
547
+ if (inVersionBlock && shouldCapture && currentVersion) {
548
+ changes.push({
549
+ version: currentVersion,
550
+ date: currentDate,
551
+ content: currentContent.join('\n').trim()
552
+ });
553
+ }
554
+
555
+ return changes;
556
+ }
557
+
558
+ /**
559
+ * 比较两个版本号
560
+ * @param {number[]} v1 - 版本1 [major, minor, patch]
561
+ * @param {number[]} v2 - 版本2 [major, minor, patch]
562
+ * @returns {number} - 1 if v1 > v2, -1 if v1 < v2, 0 if equal
563
+ */
564
+ function compareVersions(v1, v2) {
565
+ for (let i = 0; i < 3; i++) {
566
+ if (v1[i] > v2[i]) return 1;
567
+ if (v1[i] < v2[i]) return -1;
568
+ }
569
+ return 0;
570
+ }
571
+
383
572
  // ============================================================================
384
573
  // 自动更新 .gitignore 和 .npmignore
385
574
  // ============================================================================
@@ -681,7 +870,7 @@ function installSkills(toolIds, projectDir, scope = INSTALL_SCOPE.GLOBAL, update
681
870
  const tool = AI_TOOLS.find(t => t.id === toolId);
682
871
  if (!tool || tool.skillsSupport !== SKILLS_SUPPORT.FULL) continue;
683
872
 
684
- // Claude Code / Codex CLI / OpenCode(含 oh-my-opencode)支持相同格式的 Skills
873
+ // Claude Code / Codex CLI / OpenCode 支持相同格式的 Skills
685
874
  if ((toolId === 'claude' || toolId === 'codex' || toolId === 'opencode') && tool.skillsDir) {
686
875
  const skillsSrcDir = path.join(__dirname, '..', 'skills');
687
876
  const skillsDestDir = getSkillsDestDir(tool, scope, projectDir);
@@ -751,11 +940,11 @@ function installSkills(toolIds, projectDir, scope = INSTALL_SCOPE.GLOBAL, update
751
940
 
752
941
  function generateOpenCodeDevbooksCommand() {
753
942
  return `---
754
- description: DevBooks 工作流入口(OpenCode / oh-my-opencode)
943
+ description: DevBooks 工作流入口(OpenCode)
755
944
  ---
756
945
 
757
946
  ${DEVBOOKS_MARKERS.start}
758
- # DevBooksOpenCode / oh-my-opencode)
947
+ # DevBooks(OpenCode)
759
948
 
760
949
  本项目使用 DevBooks 工作流进行规格驱动开发。
761
950
 
@@ -764,7 +953,7 @@ ${DEVBOOKS_MARKERS.start}
764
953
  1. **推荐入口(Router)**:在对话中输入:\`/devbooks-router\`
765
954
  2. 或使用自然语言:\`请运行 devbooks-router skill,分析需求:<你的需求>\`
766
955
 
767
- > 说明:在 oh-my-opencode 中,Skills 会作为可用的 Slash Commands 被加载,因此可以直接用 \`/<skill-name>\` 调用。
956
+ > 说明:在 OpenCode 中,Skills 会作为可用的 Slash Commands 被加载,因此可以直接用 \`/<skill-name>\` 调用。
768
957
 
769
958
  ## 常用命令(直接用 /<skill-name>)
770
959
 
@@ -1373,6 +1562,12 @@ async function updateCommand(projectDir) {
1373
1562
 
1374
1563
  if (hasUpdate) {
1375
1564
  spinner.info(`发现新版本: ${currentVersion} → ${latestVersion}`);
1565
+
1566
+ // 显示版本变更摘要
1567
+ console.log();
1568
+ await displayVersionChangelog(currentVersion, latestVersion);
1569
+ console.log();
1570
+
1376
1571
  const shouldUpdate = await confirm({
1377
1572
  message: `是否更新 ${CLI_COMMAND} 到 ${latestVersion}?`,
1378
1573
  default: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dev-playbooks-cn",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "AI-driven spec-based development workflow",
5
5
  "keywords": [
6
6
  "devbooks",
@@ -61,7 +61,7 @@ AI 编码助手很强大,但往往**不可预测**:
61
61
  | **Claude Code** | 完整 Skills | `CLAUDE.md` |
62
62
  | **Codex CLI** | 完整 Skills | `AGENTS.md` |
63
63
  | **Qoder** | 完整 Skills | `AGENTS.md` |
64
- | **OpenCode(oh-my-opencode)** | 完整 Skills | `AGENTS.md` |
64
+ | **OpenCode** | 完整 Skills | `AGENTS.md` |
65
65
  | **Cursor** | Rules 系统 | `.cursor/rules/` |
66
66
  | **Windsurf** | Rules 系统 | `.windsurf/rules/` |
67
67
  | **Gemini CLI** | Rules 系统 | `GEMINI.md` |