dev-playbooks-cn 1.2.3 → 1.2.5
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 +2 -0
- package/bin/devbooks.js +97 -15
- package/package.json +1 -1
- package/skills/devbooks-code-review/SKILL.md +9 -0
- package/skills/devbooks-coder/SKILL.md +1 -0
- package/skills/devbooks-delivery-workflow/scripts/change-check.sh +19 -0
- package/skills/devbooks-delivery-workflow/scripts/change-scaffold.sh +7 -1
- package/skills/devbooks-test-owner/SKILL.md +11 -0
- package/templates/dev-playbooks/README.md +2 -0
package/README.md
CHANGED
|
@@ -46,6 +46,7 @@ AI 编码助手很强大,但往往**不可预测**:
|
|
|
46
46
|
| **Claude Code** | 完整 Skills | `CLAUDE.md` |
|
|
47
47
|
| **Codex CLI** | 完整 Skills | `AGENTS.md` |
|
|
48
48
|
| **Qoder** | 完整 Skills | `AGENTS.md` |
|
|
49
|
+
| **OpenCode(oh-my-opencode)** | 完整 Skills | `AGENTS.md` |
|
|
49
50
|
| **Cursor** | Rules 系统 | `.cursor/rules/` |
|
|
50
51
|
| **Windsurf** | Rules 系统 | `.windsurf/rules/` |
|
|
51
52
|
| **Gemini CLI** | Rules 系统 | `GEMINI.md` |
|
|
@@ -83,6 +84,7 @@ npx dev-playbooks-cn@latest init
|
|
|
83
84
|
初始化后:
|
|
84
85
|
- Claude Code:`~/.claude/skills/devbooks-*`
|
|
85
86
|
- Codex CLI:`~/.codex/skills/devbooks-*`
|
|
87
|
+
- OpenCode:`~/.config/opencode/skill/devbooks-*`
|
|
86
88
|
|
|
87
89
|
### 快速集成
|
|
88
90
|
|
package/bin/devbooks.js
CHANGED
|
@@ -32,6 +32,7 @@ const __filename = fileURLToPath(import.meta.url);
|
|
|
32
32
|
const __dirname = path.dirname(__filename);
|
|
33
33
|
|
|
34
34
|
const CLI_COMMAND = 'dev-playbooks-cn';
|
|
35
|
+
const XDG_CONFIG_HOME = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config');
|
|
35
36
|
|
|
36
37
|
// ============================================================================
|
|
37
38
|
// Skills 支持级别定义
|
|
@@ -71,6 +72,18 @@ const AI_TOOLS = [
|
|
|
71
72
|
instructionFile: 'AGENTS.md',
|
|
72
73
|
available: true
|
|
73
74
|
},
|
|
75
|
+
{
|
|
76
|
+
id: 'opencode',
|
|
77
|
+
name: 'OpenCode',
|
|
78
|
+
description: 'OpenCode AI CLI (compatible with oh-my-opencode)',
|
|
79
|
+
skillsSupport: SKILLS_SUPPORT.FULL,
|
|
80
|
+
slashDir: '.opencode/command',
|
|
81
|
+
agentsDir: '.opencode/agent',
|
|
82
|
+
skillsDir: path.join(XDG_CONFIG_HOME, 'opencode', 'skill'),
|
|
83
|
+
globalDir: path.join(XDG_CONFIG_HOME, 'opencode'),
|
|
84
|
+
instructionFile: 'AGENTS.md',
|
|
85
|
+
available: true
|
|
86
|
+
},
|
|
74
87
|
|
|
75
88
|
// === Rules 类似系统 ===
|
|
76
89
|
{
|
|
@@ -115,17 +128,6 @@ const AI_TOOLS = [
|
|
|
115
128
|
instructionFile: 'GEMINI.md',
|
|
116
129
|
available: true
|
|
117
130
|
},
|
|
118
|
-
{
|
|
119
|
-
id: 'opencode',
|
|
120
|
-
name: 'OpenCode',
|
|
121
|
-
description: 'OpenCode AI CLI',
|
|
122
|
-
skillsSupport: SKILLS_SUPPORT.RULES,
|
|
123
|
-
slashDir: '.opencode/commands/devbooks',
|
|
124
|
-
agentsDir: '.opencode/agent',
|
|
125
|
-
globalDir: path.join(os.homedir(), '.config', 'opencode'),
|
|
126
|
-
instructionFile: 'AGENTS.md',
|
|
127
|
-
available: true
|
|
128
|
-
},
|
|
129
131
|
|
|
130
132
|
// === Agents/自定义指令 ===
|
|
131
133
|
{
|
|
@@ -473,11 +475,11 @@ function printSkillsSupportInfo() {
|
|
|
473
475
|
console.log(chalk.gray('─'.repeat(50)));
|
|
474
476
|
console.log();
|
|
475
477
|
|
|
476
|
-
console.log(chalk.green('★ 完整 Skills') + chalk.gray(' - Claude Code, Codex CLI, Qoder'));
|
|
478
|
+
console.log(chalk.green('★ 完整 Skills') + chalk.gray(' - Claude Code, Codex CLI, OpenCode, Qoder'));
|
|
477
479
|
console.log(chalk.gray(' └ 独立的 Skills/Agents 系统,可按需调用,有独立上下文'));
|
|
478
480
|
console.log();
|
|
479
481
|
|
|
480
|
-
console.log(chalk.blue('◆ Rules 系统') + chalk.gray(' - Cursor, Windsurf, Gemini, Antigravity,
|
|
482
|
+
console.log(chalk.blue('◆ Rules 系统') + chalk.gray(' - Cursor, Windsurf, Gemini, Antigravity, Continue'));
|
|
481
483
|
console.log(chalk.gray(' └ 规则自动应用于匹配的文件/场景,功能接近 Skills'));
|
|
482
484
|
console.log();
|
|
483
485
|
|
|
@@ -550,8 +552,8 @@ function installSkills(toolIds, update = false) {
|
|
|
550
552
|
const tool = AI_TOOLS.find(t => t.id === toolId);
|
|
551
553
|
if (!tool || tool.skillsSupport !== SKILLS_SUPPORT.FULL) continue;
|
|
552
554
|
|
|
553
|
-
// Claude Code
|
|
554
|
-
if ((toolId === 'claude' || toolId === 'codex') && tool.skillsDir) {
|
|
555
|
+
// Claude Code / Codex CLI / OpenCode(含 oh-my-opencode)支持相同格式的 Skills
|
|
556
|
+
if ((toolId === 'claude' || toolId === 'codex' || toolId === 'opencode') && tool.skillsDir) {
|
|
555
557
|
const skillsSrcDir = path.join(__dirname, '..', 'skills');
|
|
556
558
|
const skillsDestDir = tool.skillsDir;
|
|
557
559
|
|
|
@@ -612,6 +614,72 @@ function installSkills(toolIds, update = false) {
|
|
|
612
614
|
return results;
|
|
613
615
|
}
|
|
614
616
|
|
|
617
|
+
// ============================================================================
|
|
618
|
+
// OpenCode:安装项目级命令入口(.opencode/command/devbooks.md)
|
|
619
|
+
// ============================================================================
|
|
620
|
+
|
|
621
|
+
function generateOpenCodeDevbooksCommand() {
|
|
622
|
+
return `---
|
|
623
|
+
description: DevBooks 工作流入口(OpenCode / oh-my-opencode)
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
${DEVBOOKS_MARKERS.start}
|
|
627
|
+
# DevBooks(OpenCode / oh-my-opencode)
|
|
628
|
+
|
|
629
|
+
本项目使用 DevBooks 工作流进行规格驱动开发。
|
|
630
|
+
|
|
631
|
+
## 快速开始
|
|
632
|
+
|
|
633
|
+
1. **推荐入口(Router)**:在对话中输入:\`/devbooks-router\`
|
|
634
|
+
2. 或使用自然语言:\`请运行 devbooks-router skill,分析需求:<你的需求>\`
|
|
635
|
+
|
|
636
|
+
> 说明:在 oh-my-opencode 中,Skills 会作为可用的 Slash Commands 被加载,因此可以直接用 \`/<skill-name>\` 调用。
|
|
637
|
+
|
|
638
|
+
## 常用命令(直接用 /<skill-name>)
|
|
639
|
+
|
|
640
|
+
- \`/devbooks-router\`:入口路由(自动判断下一步)
|
|
641
|
+
- \`/devbooks-impact-analysis\`:影响分析(跨模块/对外契约)
|
|
642
|
+
- \`/devbooks-proposal-author\`:创建提案(禁止编码)
|
|
643
|
+
- \`/devbooks-design-doc\`:设计文档(What/Constraints + AC)
|
|
644
|
+
- \`/devbooks-implementation-plan\`:编码计划(tasks.md)
|
|
645
|
+
- \`/devbooks-test-owner\`:验收测试与追溯(独立对话)
|
|
646
|
+
- \`/devbooks-coder\`:按 tasks 实现(禁止改 tests/)
|
|
647
|
+
- \`/devbooks-spec-gardener\`:归档前规格修剪
|
|
648
|
+
|
|
649
|
+
## 核心约束(必须遵守)
|
|
650
|
+
|
|
651
|
+
- 在回答任何问题或写任何代码前:先做配置发现并阅读规则文档(\`.devbooks/config.yaml\` → \`dev-playbooks/project.md\` → \`project.md\`)
|
|
652
|
+
- 新功能/破坏性变更/架构改动:必须先创建 \`dev-playbooks/changes/<id>/\` 并产出 proposal/design/tasks/verification
|
|
653
|
+
- Test Owner 与 Coder 必须在独立对话/独立实例中执行;Coder 禁止修改 \`tests/**\`
|
|
654
|
+
|
|
655
|
+
${DEVBOOKS_MARKERS.end}
|
|
656
|
+
`;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
function installOpenCodeCommands(toolIds, projectDir, update = false) {
|
|
660
|
+
const results = [];
|
|
661
|
+
|
|
662
|
+
if (!toolIds.includes('opencode')) return results;
|
|
663
|
+
|
|
664
|
+
const destDir = path.join(projectDir, '.opencode', 'command');
|
|
665
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
666
|
+
|
|
667
|
+
const destPath = path.join(destDir, 'devbooks.md');
|
|
668
|
+
const content = generateOpenCodeDevbooksCommand();
|
|
669
|
+
|
|
670
|
+
if (!fs.existsSync(destPath)) {
|
|
671
|
+
fs.writeFileSync(destPath, content);
|
|
672
|
+
results.push({ tool: 'OpenCode', type: 'command', path: destPath, action: 'created' });
|
|
673
|
+
} else if (update) {
|
|
674
|
+
const updated = updateManagedContent(destPath, content);
|
|
675
|
+
if (updated) {
|
|
676
|
+
results.push({ tool: 'OpenCode', type: 'command', path: destPath, action: 'updated' });
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
return results;
|
|
681
|
+
}
|
|
682
|
+
|
|
615
683
|
// ============================================================================
|
|
616
684
|
// 安装 Claude Code 自定义子代理(解决内置子代理无法访问 Skills 的问题)
|
|
617
685
|
// ============================================================================
|
|
@@ -1088,6 +1156,12 @@ async function initCommand(projectDir, options) {
|
|
|
1088
1156
|
console.log(chalk.gray(` └ ${result.tool}: ${path.relative(projectDir, result.path)}`));
|
|
1089
1157
|
}
|
|
1090
1158
|
|
|
1159
|
+
// OpenCode:安装项目级命令入口(.opencode/command/devbooks.md)
|
|
1160
|
+
const openCodeCmdResults = installOpenCodeCommands(selectedTools, projectDir);
|
|
1161
|
+
for (const result of openCodeCmdResults) {
|
|
1162
|
+
console.log(chalk.gray(` └ ${result.tool}: ${path.relative(projectDir, result.path)}`));
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1091
1165
|
// 设置 ignore 文件
|
|
1092
1166
|
const ignoreSpinner = ora('配置 ignore 文件...').start();
|
|
1093
1167
|
const ignoreResults = setupIgnoreFiles(selectedTools, projectDir);
|
|
@@ -1197,6 +1271,14 @@ async function updateCommand(projectDir) {
|
|
|
1197
1271
|
}
|
|
1198
1272
|
}
|
|
1199
1273
|
|
|
1274
|
+
// OpenCode:更新项目级命令入口(.opencode/command/devbooks.md)
|
|
1275
|
+
const openCodeCmdResults = installOpenCodeCommands(configuredTools, projectDir, true);
|
|
1276
|
+
for (const result of openCodeCmdResults) {
|
|
1277
|
+
if (result.action === 'updated') {
|
|
1278
|
+
console.log(chalk.green('✓') + ` ${result.tool}: 更新了命令入口 ${path.relative(projectDir, result.path)}`);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1200
1282
|
console.log();
|
|
1201
1283
|
console.log(chalk.green('✓') + ' 更新完成!');
|
|
1202
1284
|
}
|
package/package.json
CHANGED
|
@@ -148,6 +148,15 @@ override dispose() {
|
|
|
148
148
|
| 无 spec deltas | 归档完成 | 无需其他 skill |
|
|
149
149
|
| 发现重大问题 | 交回 `devbooks-coder` | 归档前修复问题 |
|
|
150
150
|
|
|
151
|
+
### Reviewer 专属权限:设置 verification.md Status
|
|
152
|
+
|
|
153
|
+
**只有 Reviewer 可以将 `verification.md` 的 Status 设为 `Done`**。
|
|
154
|
+
|
|
155
|
+
Review 通过后,Reviewer 必须执行:
|
|
156
|
+
1. 打开 `<change-root>/<change-id>/verification.md`
|
|
157
|
+
2. 将 `- Status: Ready` 改为 `- Status: Done`
|
|
158
|
+
3. 这是归档的前置条件(`change-check.sh --mode archive` 会检查)
|
|
159
|
+
|
|
151
160
|
### 输出模板
|
|
152
161
|
|
|
153
162
|
完成 code-review 后,输出:
|
|
@@ -141,6 +141,7 @@ devbooks change-evidence <change-id> --label green-final -- npm test
|
|
|
141
141
|
### 角色边界约束
|
|
142
142
|
- **禁止修改 `tests/**`**(需要改测试必须交还 Test Owner)
|
|
143
143
|
- **禁止修改 `verification.md`**(由 Test Owner 维护)
|
|
144
|
+
- **禁止修改 `verification.md` 的 Status 字段**(只有 Reviewer 可以设为 Done)
|
|
144
145
|
- **禁止修改 `.devbooks/`、`build/`、工程配置文件**(除非 proposal.md 明确声明)
|
|
145
146
|
|
|
146
147
|
### 代码质量约束
|
|
@@ -410,6 +410,25 @@ check_verification() {
|
|
|
410
410
|
return 0
|
|
411
411
|
fi
|
|
412
412
|
|
|
413
|
+
# ==========================================================================
|
|
414
|
+
# AC-010: Verification Status Check
|
|
415
|
+
# Status field controls change package lifecycle: Draft → Ready → Done → Archived
|
|
416
|
+
# Only Reviewer can set Status to "Done" (Coder/Test Owner prohibited)
|
|
417
|
+
# ==========================================================================
|
|
418
|
+
if [[ "$mode" == "archive" || "$mode" == "strict" ]]; then
|
|
419
|
+
local status_line
|
|
420
|
+
status_line=$(rg -n "^- Status[::] *(Draft|Ready|Done|Archived)\b" "$verification_file" -m 1 || true)
|
|
421
|
+
if [[ -z "$status_line" ]]; then
|
|
422
|
+
err "verification missing Status line (e.g., '- Status: Done'): ${verification_file}"
|
|
423
|
+
else
|
|
424
|
+
local status_value
|
|
425
|
+
status_value="$(echo "$status_line" | sed -E 's/^[0-9]+:- Status[::] *//')"
|
|
426
|
+
if [[ "$status_value" != "Done" && "$status_value" != "Archived" ]]; then
|
|
427
|
+
err "verification Status must be 'Done' or 'Archived' for ${mode} (current: '${status_value}'). Only Reviewer can set Status to Done: ${verification_file}"
|
|
428
|
+
fi
|
|
429
|
+
fi
|
|
430
|
+
fi
|
|
431
|
+
|
|
413
432
|
for h in "A\) (Test Plan Directive Table|测试计划指令表)" "B\) (Traceability Matrix|追溯矩阵)" "C\) (Execution Anchors|执行锚点)" "D\) (MANUAL-\* Checklist|MANUAL-\* 清单)"; do
|
|
414
433
|
if ! rg -n "${h}" "$verification_file" >/dev/null; then
|
|
415
434
|
err "verification missing section '${h}': ${verification_file}"
|
|
@@ -263,7 +263,13 @@ cat <<'EOF' | render_template | write_file "${change_dir}/verification.md"
|
|
|
263
263
|
## Metadata
|
|
264
264
|
|
|
265
265
|
- Change ID: `__CHANGE_ID__`
|
|
266
|
-
- Status: Draft
|
|
266
|
+
- Status: Draft
|
|
267
|
+
> Status lifecycle: Draft → Ready → Done → Archived
|
|
268
|
+
> - Draft: Initial state
|
|
269
|
+
> - Ready: Test plan ready (set by Test Owner)
|
|
270
|
+
> - Done: All tests passed + Review approved (set by **Reviewer only**)
|
|
271
|
+
> - Archived: Archived (set by Spec Gardener)
|
|
272
|
+
> **Constraint: Coder is prohibited from modifying Status field**
|
|
267
273
|
- References:
|
|
268
274
|
- Proposal: `__CHANGE_ROOT__/__CHANGE_ID__/proposal.md`
|
|
269
275
|
- Design: `__CHANGE_ROOT__/__CHANGE_ID__/design.md`
|
|
@@ -40,6 +40,17 @@ allowed-tools:
|
|
|
40
40
|
|
|
41
41
|
Test Owner 必须产出结构化的 `verification.md`,同时作为测试计划和追溯文档。
|
|
42
42
|
|
|
43
|
+
### Status 字段权限
|
|
44
|
+
|
|
45
|
+
| 状态 | 含义 | 谁可以设置 |
|
|
46
|
+
|------|------|-----------|
|
|
47
|
+
| `Draft` | 初始状态 | 自动生成 |
|
|
48
|
+
| `Ready` | 测试计划就绪 | **Test Owner** |
|
|
49
|
+
| `Done` | Review 通过 | Reviewer(禁止 Test Owner/Coder) |
|
|
50
|
+
| `Archived` | 已归档 | Spec Gardener |
|
|
51
|
+
|
|
52
|
+
**约束**:Test Owner 完成测试计划后,应将 Status 设为 `Ready`。
|
|
53
|
+
|
|
43
54
|
```markdown
|
|
44
55
|
# 验证计划:<change-id>
|
|
45
56
|
|
|
@@ -61,6 +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
65
|
| **Cursor** | Rules 系统 | `.cursor/rules/` |
|
|
65
66
|
| **Windsurf** | Rules 系统 | `.windsurf/rules/` |
|
|
66
67
|
| **Gemini CLI** | Rules 系统 | `GEMINI.md` |
|
|
@@ -98,6 +99,7 @@ npx dev-playbooks-cn@latest init
|
|
|
98
99
|
初始化后:
|
|
99
100
|
- Claude Code:`~/.claude/skills/devbooks-*`
|
|
100
101
|
- Codex CLI:`~/.codex/skills/devbooks-*`
|
|
102
|
+
- OpenCode:`~/.config/opencode/skill/devbooks-*`
|
|
101
103
|
|
|
102
104
|
### 快速集成
|
|
103
105
|
|