dev-playbooks 2.0.0 → 2.2.0

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
@@ -80,6 +80,7 @@ In the proposal phase, guide users through questions:
80
80
  | **Codex CLI** | Full Skills | `AGENTS.md` |
81
81
  | **Qoder** | Full Skills | `AGENTS.md` |
82
82
  | **OpenCode (oh-my-opencode)** | Full Skills | `AGENTS.md` |
83
+ | **Every Code** | Full Skills | `AGENTS.md` |
83
84
  | **Cursor** | Rules | `.cursor/rules/` |
84
85
  | **Windsurf** | Rules | `.windsurf/rules/` |
85
86
  | **Gemini CLI** | Rules | `GEMINI.md` |
package/bin/devbooks.js CHANGED
@@ -172,6 +172,19 @@ const AI_TOOLS = [
172
172
  globalSlashDir: path.join(os.homedir(), '.codex', 'prompts'),
173
173
  instructionFile: 'AGENTS.md',
174
174
  available: true
175
+ },
176
+
177
+ // === Every Code / just-every/code (Full Skills Support) ===
178
+ {
179
+ id: 'code',
180
+ name: 'Every Code',
181
+ description: 'Every Code CLI (@just-every/code)',
182
+ skillsSupport: SKILLS_SUPPORT.FULL,
183
+ slashDir: null,
184
+ skillsDir: path.join(os.homedir(), '.code', 'skills'),
185
+ globalSlashDir: null,
186
+ instructionFile: 'AGENTS.md',
187
+ available: true
175
188
  }
176
189
  ];
177
190
 
@@ -380,6 +393,195 @@ async function performNpmUpdate() {
380
393
  });
381
394
  }
382
395
 
396
+ /**
397
+ * Display version changelog summary
398
+ * @param {string} fromVersion - Current version
399
+ * @param {string} toVersion - Target version
400
+ */
401
+ async function displayVersionChangelog(fromVersion, toVersion) {
402
+ try {
403
+ // Try to fetch CHANGELOG from GitHub
404
+ const { execSync } = await import('child_process');
405
+ const changelogUrl = `https://raw.githubusercontent.com/Darkbluelr/dev-playbooks/master/CHANGELOG.md`;
406
+
407
+ // Use curl to fetch CHANGELOG (if available)
408
+ let changelog = '';
409
+ try {
410
+ changelog = execSync(`curl -s -m 5 "${changelogUrl}"`, {
411
+ encoding: 'utf-8',
412
+ stdio: ['pipe', 'pipe', 'pipe']
413
+ });
414
+ } catch {
415
+ // If fetch fails, show simplified info
416
+ console.log(chalk.cyan('📋 Version Changelog'));
417
+ console.log(chalk.gray('─'.repeat(60)));
418
+ console.log(chalk.yellow('⚠ Unable to fetch detailed changelog, please visit:'));
419
+ console.log(chalk.blue(` https://github.com/Darkbluelr/dev-playbooks/releases/tag/v${toVersion}`));
420
+ return;
421
+ }
422
+
423
+ // Parse CHANGELOG, extract changes for relevant versions
424
+ const changes = parseChangelog(changelog, fromVersion, toVersion);
425
+
426
+ if (changes.length === 0) {
427
+ console.log(chalk.cyan('📋 Version Changelog'));
428
+ console.log(chalk.gray('─'.repeat(60)));
429
+ console.log(chalk.yellow('⚠ No detailed changelog found, please visit:'));
430
+ console.log(chalk.blue(` https://github.com/Darkbluelr/dev-playbooks/releases/tag/v${toVersion}`));
431
+ return;
432
+ }
433
+
434
+ // Display changelog summary
435
+ console.log(chalk.cyan('📋 Version Changelog'));
436
+ console.log(chalk.gray('─'.repeat(60)));
437
+
438
+ for (const change of changes) {
439
+ console.log();
440
+ console.log(chalk.bold.green(`## ${change.version}`));
441
+ if (change.date) {
442
+ console.log(chalk.gray(` Release date: ${change.date}`));
443
+ }
444
+ console.log();
445
+
446
+ // Display main changes (limit to first 10 lines)
447
+ const highlights = change.content.split('\n')
448
+ .filter(line => line.trim().length > 0)
449
+ .slice(0, 10);
450
+
451
+ for (const line of highlights) {
452
+ if (line.startsWith('###')) {
453
+ console.log(chalk.bold.yellow(line));
454
+ } else if (line.startsWith('####')) {
455
+ console.log(chalk.bold(line));
456
+ } else if (line.startsWith('- ✅') || line.startsWith('- ✓')) {
457
+ console.log(chalk.green(line));
458
+ } else if (line.startsWith('- ⚠️') || line.startsWith('- ❌')) {
459
+ console.log(chalk.yellow(line));
460
+ } else if (line.startsWith('- ')) {
461
+ console.log(chalk.white(line));
462
+ } else {
463
+ console.log(chalk.gray(line));
464
+ }
465
+ }
466
+
467
+ if (change.content.split('\n').length > 10) {
468
+ console.log(chalk.gray(' ... (see full changelog for more)'));
469
+ }
470
+ }
471
+
472
+ console.log();
473
+ console.log(chalk.gray('─'.repeat(60)));
474
+ console.log(chalk.blue('📖 Full changelog: ') + chalk.underline(`https://github.com/Darkbluelr/dev-playbooks/blob/master/CHANGELOG.md`));
475
+
476
+ } catch (error) {
477
+ // Silent failure, don't affect update process
478
+ console.log(chalk.gray('Note: Unable to display changelog summary'));
479
+ }
480
+ }
481
+
482
+ /**
483
+ * Parse CHANGELOG content, extract changes for specified version range
484
+ * @param {string} changelog - CHANGELOG content
485
+ * @param {string} fromVersion - Starting version
486
+ * @param {string} toVersion - Target version
487
+ * @returns {Array} - List of changes
488
+ */
489
+ function parseChangelog(changelog, fromVersion, toVersion) {
490
+ const changes = [];
491
+ const lines = changelog.split('\n');
492
+
493
+ let currentVersion = null;
494
+ let currentDate = null;
495
+ let currentContent = [];
496
+ let inVersionBlock = false;
497
+ let shouldCapture = false;
498
+
499
+ // Parse version numbers (remove 'v' prefix)
500
+ const from = fromVersion.replace(/^v/, '');
501
+ const to = toVersion.replace(/^v/, '');
502
+
503
+ for (let i = 0; i < lines.length; i++) {
504
+ const line = lines[i];
505
+
506
+ // Match version header: ## [2.0.0] - 2026-01-19
507
+ const versionMatch = line.match(/^##\s+\[?(\d+\.\d+\.\d+)\]?\s*(?:-\s*(\d{4}-\d{2}-\d{2}))?/);
508
+
509
+ if (versionMatch) {
510
+ // Save previous version's content
511
+ if (inVersionBlock && shouldCapture && currentVersion) {
512
+ changes.push({
513
+ version: currentVersion,
514
+ date: currentDate,
515
+ content: currentContent.join('\n').trim()
516
+ });
517
+ }
518
+
519
+ // Start new version
520
+ currentVersion = versionMatch[1];
521
+ currentDate = versionMatch[2] || null;
522
+ currentContent = [];
523
+ inVersionBlock = true;
524
+
525
+ // Determine if this version should be captured
526
+ // Capture all versions between fromVersion and toVersion
527
+ const versionNum = currentVersion.split('.').map(Number);
528
+ const fromNum = from.split('.').map(Number);
529
+ const toNum = to.split('.').map(Number);
530
+
531
+ const isAfterFrom = compareVersions(versionNum, fromNum) > 0;
532
+ const isBeforeOrEqualTo = compareVersions(versionNum, toNum) <= 0;
533
+
534
+ shouldCapture = isAfterFrom && isBeforeOrEqualTo;
535
+
536
+ continue;
537
+ }
538
+
539
+ // If we encounter next version header or separator, end current version
540
+ if (line.startsWith('---') && inVersionBlock) {
541
+ if (shouldCapture && currentVersion) {
542
+ changes.push({
543
+ version: currentVersion,
544
+ date: currentDate,
545
+ content: currentContent.join('\n').trim()
546
+ });
547
+ }
548
+ inVersionBlock = false;
549
+ shouldCapture = false;
550
+ continue;
551
+ }
552
+
553
+ // Collect content
554
+ if (inVersionBlock && shouldCapture) {
555
+ currentContent.push(line);
556
+ }
557
+ }
558
+
559
+ // Save last version
560
+ if (inVersionBlock && shouldCapture && currentVersion) {
561
+ changes.push({
562
+ version: currentVersion,
563
+ date: currentDate,
564
+ content: currentContent.join('\n').trim()
565
+ });
566
+ }
567
+
568
+ return changes;
569
+ }
570
+
571
+ /**
572
+ * Compare two version numbers
573
+ * @param {number[]} v1 - Version 1 [major, minor, patch]
574
+ * @param {number[]} v2 - Version 2 [major, minor, patch]
575
+ * @returns {number} - 1 if v1 > v2, -1 if v1 < v2, 0 if equal
576
+ */
577
+ function compareVersions(v1, v2) {
578
+ for (let i = 0; i < 3; i++) {
579
+ if (v1[i] > v2[i]) return 1;
580
+ if (v1[i] < v2[i]) return -1;
581
+ }
582
+ return 0;
583
+ }
584
+
383
585
  // ============================================================================
384
586
  // Auto-update .gitignore and .npmignore
385
587
  // ============================================================================
@@ -454,6 +656,8 @@ function getNpmIgnoreEntries() {
454
656
  '.opencode/',
455
657
  '.continue/',
456
658
  '.qoder/',
659
+ '.code/',
660
+ '.codex/',
457
661
  '.github/instructions/',
458
662
  '.github/copilot-instructions.md',
459
663
  '',
@@ -548,7 +752,7 @@ function printSkillsSupportInfo() {
548
752
  console.log(chalk.gray('─'.repeat(50)));
549
753
  console.log();
550
754
 
551
- console.log(chalk.green('★ 完整 Skills') + chalk.gray(' - Claude Code, Codex CLI, OpenCode, Qoder'));
755
+ console.log(chalk.green('★ 完整 Skills') + chalk.gray(' - Claude Code, Codex CLI, OpenCode, Qoder, Every Code'));
552
756
  console.log(chalk.gray(' └ 独立的 Skills/Agents 系统,可按需调用,有独立上下文'));
553
757
  console.log();
554
758
 
@@ -668,6 +872,8 @@ function getSkillsDestDir(tool, scope, projectDir) {
668
872
  return path.join(projectDir, '.codex', 'skills');
669
873
  } else if (tool.id === 'opencode') {
670
874
  return path.join(projectDir, '.opencode', 'skill');
875
+ } else if (tool.id === 'code') {
876
+ return path.join(projectDir, '.code', 'skills');
671
877
  }
672
878
  }
673
879
  // Global installation: use tool's defined global directory
@@ -681,8 +887,8 @@ function installSkills(toolIds, projectDir, scope = INSTALL_SCOPE.GLOBAL, update
681
887
  const tool = AI_TOOLS.find(t => t.id === toolId);
682
888
  if (!tool || tool.skillsSupport !== SKILLS_SUPPORT.FULL) continue;
683
889
 
684
- // Claude Code / Codex CLI / OpenCode (incl. oh-my-opencode) share the same Skills format
685
- if ((toolId === 'claude' || toolId === 'codex' || toolId === 'opencode') && tool.skillsDir) {
890
+ // Claude Code / Codex CLI / OpenCode / Every Code share the same Skills format
891
+ if ((toolId === 'claude' || toolId === 'codex' || toolId === 'opencode' || toolId === 'code') && tool.skillsDir) {
686
892
  const skillsSrcDir = path.join(__dirname, '..', 'skills');
687
893
  const skillsDestDir = getSkillsDestDir(tool, scope, projectDir);
688
894
 
@@ -1369,6 +1575,12 @@ async function updateCommand(projectDir) {
1369
1575
 
1370
1576
  if (hasUpdate) {
1371
1577
  spinner.info(`New version available: ${currentVersion} → ${latestVersion}`);
1578
+
1579
+ // Display version changelog summary
1580
+ console.log();
1581
+ await displayVersionChangelog(currentVersion, latestVersion);
1582
+ console.log();
1583
+
1372
1584
  const shouldUpdate = await confirm({
1373
1585
  message: `Update ${CLI_COMMAND} to ${latestVersion}?`,
1374
1586
  default: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dev-playbooks",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "AI-powered spec-driven development workflow",
5
5
  "keywords": [
6
6
  "devbooks",
@@ -4,12 +4,13 @@ set -euo pipefail
4
4
  usage() {
5
5
  cat <<'EOF'
6
6
  Usage:
7
- ./scripts/install-skills.sh [--claude-only|--codex-only|--opencode-only] [--with-opencode] [--with-codex-prompts] [--dry-run] [--no-prune]
7
+ ./scripts/install-skills.sh [--claude-only|--codex-only|--opencode-only|--code-only] [--with-opencode] [--with-code] [--with-codex-prompts] [--dry-run] [--no-prune]
8
8
 
9
9
  Installs DevBooks skills (skills/devbooks-*) to:
10
10
  - Claude Code: ~/.claude/skills/
11
11
  - Codex CLI: $CODEX_HOME/skills (default: ~/.codex/skills/)
12
12
  - OpenCode: $XDG_CONFIG_HOME/opencode/skill (default: ~/.config/opencode/skill/)
13
+ - Every Code: $CODE_HOME/skills (default: ~/.code/skills/)
13
14
 
14
15
  Optionally installs Codex prompt entrypoints (templates/claude-commands/devbooks/*.md) to:
15
16
  - Codex CLI: $CODEX_HOME/prompts (default: ~/.codex/prompts/)
@@ -22,6 +23,7 @@ EOF
22
23
  install_claude=true
23
24
  install_codex=true
24
25
  install_opencode=false
26
+ install_code=false
25
27
  install_codex_prompts=false
26
28
  dry_run=false
27
29
  prune_removed=true
@@ -29,10 +31,12 @@ prune_removed=true
29
31
  while [[ $# -gt 0 ]]; do
30
32
  case "$1" in
31
33
  -h|--help) usage; exit 0 ;;
32
- --claude-only) install_codex=false ;;
33
- --codex-only) install_claude=false ;;
34
- --opencode-only) install_claude=false; install_codex=false; install_opencode=true ;;
34
+ --claude-only) install_codex=false; install_code=false ;;
35
+ --codex-only) install_claude=false; install_code=false ;;
36
+ --opencode-only) install_claude=false; install_codex=false; install_opencode=true; install_code=false ;;
37
+ --code-only) install_claude=false; install_codex=false; install_code=true ;;
35
38
  --with-opencode) install_opencode=true ;;
39
+ --with-code) install_code=true ;;
36
40
  --with-codex-prompts) install_codex_prompts=true ;;
37
41
  --dry-run) dry_run=true ;;
38
42
  --no-prune) prune_removed=false ;;
@@ -229,6 +233,11 @@ if [[ "$install_opencode" == true ]]; then
229
233
  install_into "${xdg_config_home}/opencode/skill"
230
234
  fi
231
235
 
236
+ if [[ "$install_code" == true ]]; then
237
+ code_home="${CODE_HOME:-${HOME}/.code}"
238
+ install_into "${code_home}/skills"
239
+ fi
240
+
232
241
  if [[ "$dry_run" == true ]]; then
233
242
  echo "[dry-run] done"
234
243
  else