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 +1 -0
- package/bin/devbooks.js +215 -3
- package/package.json +1 -1
- package/scripts/install-skills.sh +13 -4
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
|
|
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
|
@@ -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
|