cc-devflow 1.0.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.
Files changed (277) hide show
  1. package/.claude/CLAUDE.md +83 -0
  2. package/.claude/agents/architecture-designer.md +443 -0
  3. package/.claude/agents/bug-analyzer.md +382 -0
  4. package/.claude/agents/checklist-agent.md +175 -0
  5. package/.claude/agents/clarify-analyst.md +50 -0
  6. package/.claude/agents/code-reviewer.md +71 -0
  7. package/.claude/agents/codex-analyzer.md +39 -0
  8. package/.claude/agents/compatibility-checker.md +580 -0
  9. package/.claude/agents/consistency-checker.md +532 -0
  10. package/.claude/agents/impact-analyzer.md +441 -0
  11. package/.claude/agents/planner.md +230 -0
  12. package/.claude/agents/prd-writer.md +320 -0
  13. package/.claude/agents/project-guidelines-generator.md +1329 -0
  14. package/.claude/agents/qa-tester.md +313 -0
  15. package/.claude/agents/release-manager.md +295 -0
  16. package/.claude/agents/security-reviewer.md +314 -0
  17. package/.claude/agents/style-guide-generator.md +458 -0
  18. package/.claude/agents/tech-architect.md +516 -0
  19. package/.claude/agents/ui-designer.md +485 -0
  20. package/.claude/commands/code-review-high.md +58 -0
  21. package/.claude/commands/core-architecture.md +429 -0
  22. package/.claude/commands/core-guidelines.md +486 -0
  23. package/.claude/commands/core-roadmap.md +439 -0
  24. package/.claude/commands/core-style.md +293 -0
  25. package/.claude/commands/flow-archive.md +245 -0
  26. package/.claude/commands/flow-checklist.md +260 -0
  27. package/.claude/commands/flow-clarify.md +136 -0
  28. package/.claude/commands/flow-constitution.md +82 -0
  29. package/.claude/commands/flow-dev.md +134 -0
  30. package/.claude/commands/flow-epic.md +150 -0
  31. package/.claude/commands/flow-fix.md +104 -0
  32. package/.claude/commands/flow-ideate.md +214 -0
  33. package/.claude/commands/flow-init.md +313 -0
  34. package/.claude/commands/flow-new.md +394 -0
  35. package/.claude/commands/flow-prd.md +131 -0
  36. package/.claude/commands/flow-qa.md +93 -0
  37. package/.claude/commands/flow-release.md +92 -0
  38. package/.claude/commands/flow-restart.md +98 -0
  39. package/.claude/commands/flow-status.md +64 -0
  40. package/.claude/commands/flow-tech.md +142 -0
  41. package/.claude/commands/flow-ui.md +189 -0
  42. package/.claude/commands/flow-update.md +111 -0
  43. package/.claude/commands/flow-upgrade.md +115 -0
  44. package/.claude/commands/flow-verify.md +96 -0
  45. package/.claude/commands/problem-analyzer.md +60 -0
  46. package/.claude/config/quality-rules.yml +161 -0
  47. package/.claude/docs/SPEC_KIT_CONSTITUTION_ANALYSIS.md +426 -0
  48. package/.claude/docs/design/consistency-conflict-detection-algorithms.md +658 -0
  49. package/.claude/docs/design/intent-driven-input-design.md +380 -0
  50. package/.claude/docs/design/prd-version-management-design.md +437 -0
  51. package/.claude/docs/guides/INIT_TROUBLESHOOTING.md +117 -0
  52. package/.claude/docs/guides/NEW_TROUBLESHOOTING.md +151 -0
  53. package/.claude/docs/guides/ROADMAP_TROUBLESHOOTING.md +188 -0
  54. package/.claude/docs/guides/TASK_COMPLETION_MARKING.md +338 -0
  55. package/.claude/docs/templates/ARCHITECTURE_TEMPLATE.md +633 -0
  56. package/.claude/docs/templates/BACKLOG_TEMPLATE.md +261 -0
  57. package/.claude/docs/templates/CHECKLIST_TEMPLATE.md +52 -0
  58. package/.claude/docs/templates/CLARIFICATION_REPORT_TEMPLATE.md +206 -0
  59. package/.claude/docs/templates/CODE_REVIEW_TEMPLATE.md +71 -0
  60. package/.claude/docs/templates/EPIC_TEMPLATE.md +805 -0
  61. package/.claude/docs/templates/INIT_FLOW_TEMPLATE.md +213 -0
  62. package/.claude/docs/templates/INTENT_CLARIFICATION_TEMPLATE.md +57 -0
  63. package/.claude/docs/templates/NEW_ORCHESTRATION_TEMPLATE.md +148 -0
  64. package/.claude/docs/templates/PRD_TEMPLATE.md +562 -0
  65. package/.claude/docs/templates/RESEARCH_TEMPLATE.md +276 -0
  66. package/.claude/docs/templates/REVIEW-HIGH.md +57 -0
  67. package/.claude/docs/templates/ROADMAP_DIALOGUE_TEMPLATE.md +198 -0
  68. package/.claude/docs/templates/ROADMAP_TEMPLATE.md +310 -0
  69. package/.claude/docs/templates/STYLE_TEMPLATE.md +1266 -0
  70. package/.claude/docs/templates/TASKS_TEMPLATE.md +523 -0
  71. package/.claude/docs/templates/TECH_DESIGN_TEMPLATE.md +1019 -0
  72. package/.claude/docs/templates/UI_PROTOTYPE_TEMPLATE.md +1436 -0
  73. package/.claude/guides/agent-guides/agent-coordination-guide.md +459 -0
  74. package/.claude/guides/project-guidelines-system.md +463 -0
  75. package/.claude/guides/technical-guides/datetime-handling-guide.md +563 -0
  76. package/.claude/guides/technical-guides/git-github-guide.md +642 -0
  77. package/.claude/guides/technical-guides/test-execution-guide.md +618 -0
  78. package/.claude/guides/workflow-guides/bug-fix-orchestrator.md +217 -0
  79. package/.claude/guides/workflow-guides/flow-orchestrator.md +282 -0
  80. package/.claude/hooks/checklist-gate.js +397 -0
  81. package/.claude/hooks/error-handling-reminder.sh +12 -0
  82. package/.claude/hooks/error-handling-reminder.ts +459 -0
  83. package/.claude/hooks/post-tool-use-tracker.sh +280 -0
  84. package/.claude/hooks/pre-tool-use-guardrail.sh +36 -0
  85. package/.claude/hooks/pre-tool-use-guardrail.ts +342 -0
  86. package/.claude/hooks/skill-activation-prompt.sh +36 -0
  87. package/.claude/hooks/skill-activation-prompt.ts +214 -0
  88. package/.claude/hooks/state/skills-used-test-guard.json +3 -0
  89. package/.claude/rules/devflow-conventions.md +305 -0
  90. package/.claude/rules/project-constitution.md +748 -0
  91. package/.claude/schemas/constitution.schema.json +43 -0
  92. package/.claude/scripts/analyze-upgrade-impact.sh +200 -0
  93. package/.claude/scripts/archive-requirement.sh +351 -0
  94. package/.claude/scripts/calculate-checklist-completion.sh +243 -0
  95. package/.claude/scripts/calculate-quarter.sh +206 -0
  96. package/.claude/scripts/check-dependencies.sh +409 -0
  97. package/.claude/scripts/check-prerequisites.sh +232 -0
  98. package/.claude/scripts/check-task-status.sh +264 -0
  99. package/.claude/scripts/checklist-errors.sh +131 -0
  100. package/.claude/scripts/common.sh +570 -0
  101. package/.claude/scripts/consolidate-research.sh +182 -0
  102. package/.claude/scripts/create-requirement.sh +426 -0
  103. package/.claude/scripts/export-contracts.sh +117 -0
  104. package/.claude/scripts/extract-data-model.sh +78 -0
  105. package/.claude/scripts/generate-clarification-questions.sh +377 -0
  106. package/.claude/scripts/generate-clarification-report.sh +463 -0
  107. package/.claude/scripts/generate-quickstart.sh +146 -0
  108. package/.claude/scripts/generate-research-tasks.sh +157 -0
  109. package/.claude/scripts/generate-status-report.sh +523 -0
  110. package/.claude/scripts/generate-tech-analysis.sh +46 -0
  111. package/.claude/scripts/locate-requirement-in-roadmap.sh +233 -0
  112. package/.claude/scripts/manage-constitution.sh +602 -0
  113. package/.claude/scripts/mark-task-complete.sh +198 -0
  114. package/.claude/scripts/populate-research-tasks.sh +259 -0
  115. package/.claude/scripts/recover-workflow.sh +460 -0
  116. package/.claude/scripts/run-clarify-scan.sh +601 -0
  117. package/.claude/scripts/run-high-review.sh +62 -0
  118. package/.claude/scripts/run-problem-analysis.sh +68 -0
  119. package/.claude/scripts/setup-epic.sh +173 -0
  120. package/.claude/scripts/sync-roadmap-progress.sh +300 -0
  121. package/.claude/scripts/sync-task-marks.sh +199 -0
  122. package/.claude/scripts/test-clarify-scan.sh +515 -0
  123. package/.claude/scripts/update-agent-context.sh +806 -0
  124. package/.claude/scripts/validate-constitution.sh +567 -0
  125. package/.claude/scripts/validate-hooks.sh +487 -0
  126. package/.claude/scripts/validate-research.sh +332 -0
  127. package/.claude/scripts/validate-scope-boundary.sh +493 -0
  128. package/.claude/scripts/verify-setup.sh +37 -0
  129. package/.claude/settings.json +76 -0
  130. package/.claude/skills/_reference-implementations/README.md +96 -0
  131. package/.claude/skills/_reference-implementations/backend-express-prisma/SKILL.md +302 -0
  132. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/architecture-overview.md +451 -0
  133. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/async-and-errors.md +307 -0
  134. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/complete-examples.md +638 -0
  135. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/configuration.md +275 -0
  136. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/database-patterns.md +224 -0
  137. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/middleware-guide.md +213 -0
  138. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/routing-and-controllers.md +756 -0
  139. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/sentry-and-monitoring.md +336 -0
  140. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/services-and-repositories.md +789 -0
  141. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/testing-guide.md +235 -0
  142. package/.claude/skills/_reference-implementations/backend-express-prisma/resources/validation-patterns.md +754 -0
  143. package/.claude/skills/_reference-implementations/frontend-react-mui/SKILL.md +399 -0
  144. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/common-patterns.md +331 -0
  145. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/complete-examples.md +872 -0
  146. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/component-patterns.md +502 -0
  147. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/data-fetching.md +767 -0
  148. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/file-organization.md +502 -0
  149. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/loading-and-error-states.md +501 -0
  150. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/performance.md +406 -0
  151. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/routing-guide.md +364 -0
  152. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/styling-guide.md +428 -0
  153. package/.claude/skills/_reference-implementations/frontend-react-mui/resources/typescript-standards.md +418 -0
  154. package/.claude/skills/cc-devflow-orchestrator/SKILL.md +229 -0
  155. package/.claude/skills/constitution-guardian/SKILL.md +306 -0
  156. package/.claude/skills/devflow-constitution-quick-ref/SKILL.md +374 -0
  157. package/.claude/skills/devflow-file-standards/SKILL.md +353 -0
  158. package/.claude/skills/devflow-tdd-enforcer/SKILL.md +192 -0
  159. package/.claude/skills/skill-developer/ADVANCED.md +197 -0
  160. package/.claude/skills/skill-developer/HOOK_MECHANISMS.md +306 -0
  161. package/.claude/skills/skill-developer/PATTERNS_LIBRARY.md +152 -0
  162. package/.claude/skills/skill-developer/SKILL.md +426 -0
  163. package/.claude/skills/skill-developer/SKILL_RULES_REFERENCE.md +315 -0
  164. package/.claude/skills/skill-developer/TRIGGER_TYPES.md +305 -0
  165. package/.claude/skills/skill-developer/TROUBLESHOOTING.md +514 -0
  166. package/.claude/skills/skill-rules.json +213 -0
  167. package/.claude/tests/README.md +300 -0
  168. package/.claude/tests/TODO.md +69 -0
  169. package/.claude/tests/__pycache__/test_analyze_upgrade_impact.cpython-311-pytest-7.2.2.pyc +0 -0
  170. package/.claude/tests/__pycache__/test_consolidate_research.cpython-311-pytest-7.2.2.pyc +0 -0
  171. package/.claude/tests/__pycache__/test_export_contracts.cpython-311-pytest-7.2.2.pyc +0 -0
  172. package/.claude/tests/__pycache__/test_extract_data_model.cpython-311-pytest-7.2.2.pyc +0 -0
  173. package/.claude/tests/__pycache__/test_generate_quickstart.cpython-311-pytest-7.2.2.pyc +0 -0
  174. package/.claude/tests/__pycache__/test_generate_research_tasks.cpython-311-pytest-7.2.2.pyc +0 -0
  175. package/.claude/tests/constitution/run_all_constitution_tests.sh +111 -0
  176. package/.claude/tests/constitution/test_agent_assignment.sh +207 -0
  177. package/.claude/tests/constitution/test_article_coverage.sh +201 -0
  178. package/.claude/tests/constitution/test_template_completeness.sh +150 -0
  179. package/.claude/tests/constitution/test_version_consistency.sh +120 -0
  180. package/.claude/tests/fixtures/spec_delta_full.md +16 -0
  181. package/.claude/tests/fixtures/tasks_progress_sample.md +5 -0
  182. package/.claude/tests/run-all-tests.sh +229 -0
  183. package/.claude/tests/scripts/run.sh +30 -0
  184. package/.claude/tests/scripts/test-framework.sh +128 -0
  185. package/.claude/tests/scripts/test_check_prerequisites.sh +511 -0
  186. package/.claude/tests/scripts/test_check_prerequisites.sh.bak +504 -0
  187. package/.claude/tests/scripts/test_check_prerequisites.sh.bak2 +505 -0
  188. package/.claude/tests/scripts/test_check_prerequisites.sh.bak3 +506 -0
  189. package/.claude/tests/scripts/test_check_prerequisites.sh.bak4 +507 -0
  190. package/.claude/tests/scripts/test_check_prerequisites.sh.bak5 +508 -0
  191. package/.claude/tests/scripts/test_check_task_status.sh +499 -0
  192. package/.claude/tests/scripts/test_common.sh +244 -0
  193. package/.claude/tests/scripts/test_generate_status_report.sh +71 -0
  194. package/.claude/tests/scripts/test_mark_task_complete.sh +441 -0
  195. package/.claude/tests/scripts/test_mark_task_complete.sh.backup +410 -0
  196. package/.claude/tests/scripts/test_recover_workflow.sh +304 -0
  197. package/.claude/tests/scripts/test_setup_epic.sh +437 -0
  198. package/.claude/tests/scripts/test_sync_task_marks.sh +196 -0
  199. package/.claude/tests/scripts/test_validate_constitution.sh +74 -0
  200. package/.claude/tests/scripts/test_validate_research.sh +462 -0
  201. package/.claude/tests/slugify.bats +82 -0
  202. package/.claude/tests/test-framework.sh +732 -0
  203. package/.claude/tests/test_analyze_upgrade_impact.py +34 -0
  204. package/.claude/tests/test_consolidate_research.py +48 -0
  205. package/.claude/tests/test_export_contracts.py +43 -0
  206. package/.claude/tests/test_extract_data_model.py +33 -0
  207. package/.claude/tests/test_generate_quickstart.py +50 -0
  208. package/.claude/tests/test_generate_research_tasks.py +52 -0
  209. package/.claude/tsc-cache/6e64f818-6398-49ca-8623-581a9af85c44/edited-files.log +1 -0
  210. package/.claude/tsc-cache/795ba6e3-b98a-423b-bab2-51aa62812569/affected-repos.txt +1 -0
  211. package/.claude/tsc-cache/795ba6e3-b98a-423b-bab2-51aa62812569/edited-files.log +1 -0
  212. package/.claude/tsc-cache/ae335694-be5a-4ba4-a1a0-b676c09a7906/affected-repos.txt +1 -0
  213. package/.claude/tsc-cache/ae335694-be5a-4ba4-a1a0-b676c09a7906/edited-files.log +1 -0
  214. package/CHANGELOG.md +507 -0
  215. package/LICENSE +21 -0
  216. package/README.md +534 -0
  217. package/README.zh-CN.md +530 -0
  218. package/bin/adapt.js +240 -0
  219. package/bin/cc-devflow-cli.js +185 -0
  220. package/bin/cc-devflow.js +78 -0
  221. package/config/adapters.yml +5 -0
  222. package/config/schema/adapters.schema.json +44 -0
  223. package/docs/CLAUDE.md +26 -0
  224. package/docs/commands/README.md +61 -0
  225. package/docs/commands/README.zh-CN.md +55 -0
  226. package/docs/commands/core-roadmap.md +106 -0
  227. package/docs/commands/core-roadmap.zh-CN.md +102 -0
  228. package/docs/commands/core-style.md +405 -0
  229. package/docs/commands/core-style.zh-CN.md +405 -0
  230. package/docs/commands/flow-init.md +134 -0
  231. package/docs/commands/flow-init.zh-CN.md +163 -0
  232. package/docs/commands/flow-new.md +274 -0
  233. package/docs/commands/flow-new.zh-CN.md +270 -0
  234. package/docs/guides/getting-started.md +204 -0
  235. package/docs/guides/getting-started.zh-CN.md +152 -0
  236. package/lib/adapters/adapter-interface.js +57 -0
  237. package/lib/adapters/claude-adapter.js +74 -0
  238. package/lib/adapters/codex-adapter.js +40 -0
  239. package/lib/adapters/config-validator.js +68 -0
  240. package/lib/adapters/logger.js +42 -0
  241. package/lib/adapters/registry.js +153 -0
  242. package/lib/compiler/CLAUDE.md +92 -0
  243. package/lib/compiler/__tests__/drift.test.js +215 -0
  244. package/lib/compiler/__tests__/errors.test.js +184 -0
  245. package/lib/compiler/__tests__/incremental.test.js +174 -0
  246. package/lib/compiler/__tests__/integration.test.js +174 -0
  247. package/lib/compiler/__tests__/manifest.test.js +233 -0
  248. package/lib/compiler/__tests__/parser.test.js +456 -0
  249. package/lib/compiler/__tests__/schemas.test.js +301 -0
  250. package/lib/compiler/__tests__/skills-registry.test.js +125 -0
  251. package/lib/compiler/__tests__/transformer.test.js +286 -0
  252. package/lib/compiler/emitters/antigravity-emitter.js +171 -0
  253. package/lib/compiler/emitters/base-emitter.js +73 -0
  254. package/lib/compiler/emitters/codex-emitter.js +52 -0
  255. package/lib/compiler/emitters/cursor-emitter.js +31 -0
  256. package/lib/compiler/emitters/index.js +50 -0
  257. package/lib/compiler/emitters/qwen-emitter.js +39 -0
  258. package/lib/compiler/errors.js +119 -0
  259. package/lib/compiler/index.js +256 -0
  260. package/lib/compiler/manifest.js +242 -0
  261. package/lib/compiler/parser.js +258 -0
  262. package/lib/compiler/platforms.js +113 -0
  263. package/lib/compiler/resource-copier.js +320 -0
  264. package/lib/compiler/rules-emitters/__tests__/antigravity-rules-emitter.test.js +191 -0
  265. package/lib/compiler/rules-emitters/__tests__/codex-rules-emitter.test.js +109 -0
  266. package/lib/compiler/rules-emitters/__tests__/cursor-rules-emitter.test.js +123 -0
  267. package/lib/compiler/rules-emitters/__tests__/qwen-rules-emitter.test.js +123 -0
  268. package/lib/compiler/rules-emitters/antigravity-rules-emitter.js +253 -0
  269. package/lib/compiler/rules-emitters/base-rules-emitter.js +83 -0
  270. package/lib/compiler/rules-emitters/codex-rules-emitter.js +116 -0
  271. package/lib/compiler/rules-emitters/cursor-rules-emitter.js +98 -0
  272. package/lib/compiler/rules-emitters/index.js +71 -0
  273. package/lib/compiler/rules-emitters/qwen-rules-emitter.js +70 -0
  274. package/lib/compiler/schemas.js +144 -0
  275. package/lib/compiler/skills-registry.js +225 -0
  276. package/lib/compiler/transformer.js +236 -0
  277. package/package.json +50 -0
@@ -0,0 +1,508 @@
1
+ #!/usr/bin/env bash
2
+ # test_check_prerequisites.sh - 测试 check-prerequisites.sh
3
+ # 注意: check-prerequisites.sh 通过环境变量 DEVFLOW_REQ_ID 或 Git 分支获取 REQ_ID
4
+
5
+ # 加载测试框架
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ source "$SCRIPT_DIR/../test-framework.sh"
8
+
9
+ # 脚本路径
10
+ REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
11
+ CHECK_PREREQ_SCRIPT="$REPO_ROOT/scripts/check-prerequisites.sh"
12
+
13
+ # ============================================================================
14
+ # 辅助函数
15
+ # ============================================================================
16
+
17
+ # 创建完整的模拟需求目录结构
18
+ setup_full_requirement() {
19
+ local req_id="$1"
20
+ local req_dir="$TEST_TMP_DIR/.claude/docs/requirements/$req_id"
21
+
22
+ mkdir -p "$req_dir"/{research,tasks}
23
+
24
+ # 创建状态文件
25
+ cat > "$req_dir/orchestration_status.json" << EOF
26
+ {
27
+ "reqId": "$req_id",
28
+ "title": "Test Requirement",
29
+ "status": "prd_complete",
30
+ "phase": "epic_planning",
31
+ "createdAt": "2025-10-01T00:00:00Z",
32
+ "updatedAt": "2025-10-01T00:00:00Z"
33
+ }
34
+ EOF
35
+
36
+ # 创建必需文档
37
+ echo "# PRD" > "$req_dir/PRD.md"
38
+ echo "# Execution Log" > "$req_dir/EXECUTION_LOG.md"
39
+
40
+ echo "$req_dir"
41
+ }
42
+
43
+ # 创建测试专用的 common.sh(覆盖 get_repo_root 函数)
44
+ create_test_common() {
45
+ local test_common="$TEST_TMP_DIR/scripts/common.sh"
46
+ mkdir -p "$(dirname "$test_common")"
47
+
48
+ # 复制原始 common.sh 到临时文件
49
+ cp "$REPO_ROOT/scripts/common.sh" "$test_common"
50
+
51
+ # 使用 awk 替换 get_repo_root 函数
52
+ awk -v tmpdir="$TEST_TMP_DIR" '
53
+ /^get_repo_root\(\)/ {
54
+ print "get_repo_root() {"
55
+ print " echo \"" tmpdir "\""
56
+ print "}"
57
+ in_function = 1
58
+ next
59
+ }
60
+ in_function && /^}/ {
61
+ in_function = 0
62
+ next
63
+ }
64
+ !in_function {
65
+ print
66
+ }
67
+ ' "$REPO_ROOT/scripts/common.sh" > "$test_common.tmp"
68
+
69
+ mv "$test_common.tmp" "$test_common"
70
+ }
71
+
72
+ # 在测试环境中运行脚本并捕获退出码
73
+ run_check_prereq_with_exit() {
74
+ local req_id="$1"
75
+ shift
76
+ local args=("$@")
77
+
78
+ # 设置环境
79
+ export DEVFLOW_REQ_ID="$req_id"
80
+
81
+ # 创建测试专用的脚本副本
82
+ local test_scripts_dir="$TEST_TMP_DIR/scripts"
83
+ mkdir -p "$test_scripts_dir"
84
+
85
+ # 创建测试专用的 common.sh
86
+ create_test_common
87
+
88
+ # 复制 check-prerequisites.sh 到测试目录
89
+ cp "$CHECK_PREREQ_SCRIPT" "$test_scripts_dir/"
90
+
91
+ # 运行脚本并保存输出和退出码
92
+ local output_file="$TEST_TMP_DIR/output.txt"
93
+ local exit_code_file="$TEST_TMP_DIR/exitcode.txt"
94
+
95
+ (
96
+ cd "$TEST_TMP_DIR"
97
+ bash "$test_scripts_dir/check-prerequisites.sh" "${args[@]}" > "$output_file" 2>&1
98
+ echo $? > "$exit_code_file"
99
+ )
100
+
101
+ # 返回输出(退出码需要从文件读取)
102
+ cat "$output_file"
103
+ }
104
+
105
+ # 获取最后一次运行的退出码
106
+ get_last_exit_code() {
107
+ cat "$TEST_TMP_DIR/exitcode.txt" 2>/dev/null || echo "0"
108
+ }
109
+
110
+ # 在测试环境中运行脚本(旧版本,向后兼容)
111
+ run_check_prereq() {
112
+ local req_id="$1"
113
+ shift
114
+ local args=("$@")
115
+
116
+ # 设置环境
117
+ export DEVFLOW_REQ_ID="$req_id"
118
+
119
+ # 创建测试专用的脚本副本
120
+ local test_scripts_dir="$TEST_TMP_DIR/scripts"
121
+ mkdir -p "$test_scripts_dir"
122
+
123
+ # 创建测试专用的 common.sh
124
+ create_test_common
125
+
126
+ # 复制 check-prerequisites.sh 到测试目录
127
+ cp "$CHECK_PREREQ_SCRIPT" "$test_scripts_dir/"
128
+
129
+ # 在测试目录中运行脚本
130
+ (
131
+ cd "$TEST_TMP_DIR"
132
+ bash "$test_scripts_dir/check-prerequisites.sh" "${args[@]}" 2>&1
133
+ )
134
+ }
135
+
136
+ # ============================================================================
137
+ # 测试帮助信息
138
+ # ============================================================================
139
+
140
+ test_help_flag() {
141
+ describe "Should show help with --help"
142
+
143
+ # Act
144
+ local output=$(bash "$CHECK_PREREQ_SCRIPT" --help 2>&1)
145
+
146
+ # Assert
147
+ assert_contains "$output" "Usage:" "Should show usage"
148
+ assert_contains "$output" "check-prerequisites.sh" "Should mention script name"
149
+ assert_contains "$output" "--json" "Should document --json flag"
150
+ assert_contains "$output" "--paths-only" "Should document --paths-only flag"
151
+ }
152
+
153
+ test_help_short_flag() {
154
+ describe "Should show help with -h"
155
+
156
+ # Act
157
+ local output=$(bash "$CHECK_PREREQ_SCRIPT" -h 2>&1)
158
+
159
+ # Assert
160
+ assert_contains "$output" "Usage:" "Should show usage with -h"
161
+ }
162
+
163
+ # ============================================================================
164
+ # 测试无 REQ_ID 的情况
165
+ # ============================================================================
166
+
167
+ test_no_req_id_error() {
168
+ describe "Should fail when no REQ_ID is available"
169
+
170
+ # Arrange - 创建测试脚本副本但不设置 REQ_ID
171
+ local test_scripts_dir="$TEST_TMP_DIR/scripts"
172
+ mkdir -p "$test_scripts_dir"
173
+ create_test_common
174
+ cp "$CHECK_PREREQ_SCRIPT" "$test_scripts_dir/"
175
+
176
+ # Act - 不设置 DEVFLOW_REQ_ID 环境变量
177
+ local output_file="$TEST_TMP_DIR/output.txt"
178
+ local exit_code_file="$TEST_TMP_DIR/exitcode.txt"
179
+
180
+ (
181
+ cd "$TEST_TMP_DIR"
182
+ unset DEVFLOW_REQ_ID
183
+ bash "$test_scripts_dir/check-prerequisites.sh" > "$output_file" 2>&1
184
+ echo $? > "$exit_code_file"
185
+ )
186
+
187
+ local output=$(cat "$output_file")
188
+ local exit_code=$(cat "$exit_code_file")
189
+
190
+ # Assert
191
+ assert_not_equals "$exit_code" "0" "Should fail without REQ_ID"
192
+ assert_contains "$output" "ERROR" "Should show error message"
193
+ }
194
+
195
+ # ============================================================================
196
+ # 测试 --paths-only 模式
197
+ # ============================================================================
198
+
199
+ test_paths_only_mode() {
200
+ describe "Should output paths in --paths-only mode"
201
+
202
+ # Arrange
203
+ local req_id="REQ-001"
204
+ setup_full_requirement "$req_id"
205
+
206
+ # Act
207
+ local output=$(run_check_prereq "$req_id" --paths-only)
208
+
209
+ # Assert
210
+ assert_contains "$output" "REPO_ROOT:" "Should output REPO_ROOT"
211
+ assert_contains "$output" "REQ_ID:" "Should output REQ_ID"
212
+ assert_contains "$output" "REQ_DIR:" "Should output REQ_DIR"
213
+ assert_contains "$output" "PRD_FILE:" "Should output PRD_FILE"
214
+ }
215
+
216
+ test_paths_only_json_mode() {
217
+ describe "Should output JSON in --paths-only --json mode"
218
+
219
+ # Arrange
220
+ local req_id="REQ-002"
221
+ setup_full_requirement "$req_id"
222
+
223
+ # Act
224
+ local output=$(run_check_prereq "$req_id" --paths-only --json)
225
+
226
+ # Assert
227
+ assert_json_valid "$output" "Should output valid JSON"
228
+ assert_contains "$output" "\"REPO_ROOT\"" "Should have REPO_ROOT in JSON"
229
+ assert_contains "$output" "\"REQ_ID\"" "Should have REQ_ID in JSON"
230
+ assert_contains "$output" "\"REQ_DIR\"" "Should have REQ_DIR in JSON"
231
+ }
232
+
233
+ # ============================================================================
234
+ # 测试必需文件验证
235
+ # ============================================================================
236
+
237
+ test_missing_req_dir() {
238
+ describe "Should fail when requirement directory doesn't exist"
239
+
240
+ # Arrange
241
+ local req_id="REQ-NOTEXIST"
242
+ # 不创建目录
243
+
244
+ # Act
245
+ local exit_code=0
246
+ local output=$(run_check_prereq_with_exit "$req_id")
247
+ local exit_code=$(get_last_exit_code)
248
+
249
+ # Assert
250
+ assert_not_equals "$exit_code" "0" "Should fail when REQ_DIR missing"
251
+ assert_contains "$output" "ERROR" "Should show error"
252
+ assert_contains "$output" "directory not found" "Should mention missing directory"
253
+ }
254
+
255
+ test_missing_prd_file() {
256
+ describe "Should fail when PRD.md doesn't exist"
257
+
258
+ # Arrange
259
+ local req_id="REQ-003"
260
+ local req_dir="$TEST_TMP_DIR/.claude/docs/requirements/$req_id"
261
+ mkdir -p "$req_dir"
262
+ # 不创建 PRD.md
263
+
264
+ # Act
265
+ local exit_code=0
266
+ local output=$(run_check_prereq_with_exit "$req_id")
267
+ local exit_code=$(get_last_exit_code)
268
+
269
+ # Assert
270
+ assert_not_equals "$exit_code" "0" "Should fail when PRD.md missing"
271
+ assert_contains "$output" "PRD.md not found" "Should mention missing PRD"
272
+ }
273
+
274
+ test_valid_minimal_requirement() {
275
+ describe "Should succeed with minimal valid requirement"
276
+
277
+ # Arrange
278
+ local req_id="REQ-004"
279
+ setup_full_requirement "$req_id"
280
+
281
+ # Act
282
+ local exit_code=0
283
+ local output=$(run_check_prereq "$req_id" 2>&1) || exit_code=$?
284
+
285
+ # Assert
286
+ assert_equals "$exit_code" "0" "Should succeed with PRD.md present"
287
+ }
288
+
289
+ # ============================================================================
290
+ # 测试 --require-epic 选项
291
+ # ============================================================================
292
+
293
+ test_require_epic_missing() {
294
+ describe "Should fail with --require-epic when EPIC.md missing"
295
+
296
+ # Arrange
297
+ local req_id="REQ-005"
298
+ setup_full_requirement "$req_id"
299
+ # 不创建 EPIC.md
300
+
301
+ # Act
302
+ local exit_code=0
303
+ local output=$(run_check_prereq_with_exit "$req_id" --require-epic)
304
+ local exit_code=$(get_last_exit_code)
305
+
306
+ # Assert
307
+ assert_not_equals "$exit_code" "0" "Should fail when EPIC.md required but missing"
308
+ assert_contains "$output" "EPIC.md not found" "Should mention missing EPIC"
309
+ }
310
+
311
+ test_require_epic_present() {
312
+ describe "Should succeed with --require-epic when EPIC.md exists"
313
+
314
+ # Arrange
315
+ local req_id="REQ-006"
316
+ local req_dir=$(setup_full_requirement "$req_id")
317
+ echo "# EPIC" > "$req_dir/EPIC.md"
318
+
319
+ # Act
320
+ local exit_code=0
321
+ local output=$(run_check_prereq "$req_id" --require-epic 2>&1) || exit_code=$?
322
+
323
+ # Assert
324
+ assert_equals "$exit_code" "0" "Should succeed when EPIC.md present"
325
+ }
326
+
327
+ # ============================================================================
328
+ # 测试 --require-tasks 选项
329
+ # ============================================================================
330
+
331
+ test_require_tasks_empty_dir() {
332
+ describe "Should fail with --require-tasks when tasks/ is empty"
333
+
334
+ # Arrange
335
+ local req_id="REQ-007"
336
+ local req_dir=$(setup_full_requirement "$req_id")
337
+ echo "# EPIC" > "$req_dir/EPIC.md"
338
+ # tasks/ 目录存在但为空
339
+
340
+ # Act
341
+ local exit_code=0
342
+ local output=$(run_check_prereq_with_exit "$req_id" --require-tasks)
343
+ local exit_code=$(get_last_exit_code)
344
+
345
+ # Assert
346
+ assert_not_equals "$exit_code" "0" "Should fail when tasks/ empty"
347
+ assert_contains "$output" "tasks/ directory" "Should mention tasks directory issue"
348
+ }
349
+
350
+ test_require_tasks_with_files() {
351
+ describe "Should succeed with --require-tasks when tasks/ has files"
352
+
353
+ # Arrange
354
+ local req_id="REQ-008"
355
+ local req_dir=$(setup_full_requirement "$req_id")
356
+ echo "# EPIC" > "$req_dir/EPIC.md"
357
+ echo "task" > "$req_dir/tasks/TASK_001.md"
358
+
359
+ # Act
360
+ local exit_code=0
361
+ local output=$(run_check_prereq "$req_id" --require-epic --require-tasks 2>&1) || exit_code=$?
362
+
363
+ # Assert
364
+ assert_equals "$exit_code" "0" "Should succeed when tasks/ has files"
365
+ }
366
+
367
+ # ============================================================================
368
+ # 测试 JSON 输出
369
+ # ============================================================================
370
+
371
+ test_json_output_valid() {
372
+ describe "Should output valid JSON with --json"
373
+
374
+ # Arrange
375
+ local req_id="REQ-009"
376
+ setup_full_requirement "$req_id"
377
+
378
+ # Act
379
+ local output=$(run_check_prereq "$req_id" --json)
380
+
381
+ # Assert
382
+ assert_json_valid "$output" "Should be valid JSON"
383
+ }
384
+
385
+ test_json_output_has_req_id() {
386
+ describe "JSON should include REQ_ID field"
387
+
388
+ # Arrange
389
+ local req_id="REQ-010"
390
+ setup_full_requirement "$req_id"
391
+
392
+ # Act
393
+ local output=$(run_check_prereq "$req_id" --json)
394
+
395
+ # Assert
396
+ assert_contains "$output" "\"REQ_ID\"" "Should have REQ_ID field"
397
+ assert_contains "$output" "\"$req_id\"" "Should have correct REQ_ID value"
398
+ }
399
+
400
+ test_json_output_available_docs() {
401
+ describe "JSON should include AVAILABLE_DOCS array"
402
+
403
+ # Arrange
404
+ local req_id="REQ-011"
405
+ local req_dir=$(setup_full_requirement "$req_id")
406
+
407
+ # 添加一些文档
408
+ echo "test" > "$req_dir/research/test.md"
409
+ echo "# Test Plan" > "$req_dir/TEST_PLAN.md"
410
+
411
+ # Act
412
+ local output=$(run_check_prereq "$req_id" --json)
413
+
414
+ # Assert
415
+ assert_contains "$output" "\"AVAILABLE_DOCS\"" "Should have AVAILABLE_DOCS field"
416
+ assert_contains "$output" "research/" "Should list research/"
417
+ assert_contains "$output" "TEST_PLAN.md" "Should list TEST_PLAN.md"
418
+ }
419
+
420
+ # ============================================================================
421
+ # 测试 BUG 类型需求
422
+ # ============================================================================
423
+
424
+ test_bug_type_requirement() {
425
+ describe "Should handle BUG-XXX format"
426
+
427
+ # Arrange
428
+ local req_id="BUG-999"
429
+ local req_dir=$(setup_full_requirement "$req_id")
430
+
431
+ # Act
432
+ local exit_code=0
433
+ local output=$(run_check_prereq "$req_id" --json 2>&1) || exit_code=$?
434
+
435
+ # Assert
436
+ assert_equals "$exit_code" "0" "Should handle BUG format"
437
+ assert_contains "$output" "BUG-999" "Should preserve BUG ID"
438
+ }
439
+
440
+ # ============================================================================
441
+ # 测试 --include-tasks 选项
442
+ # ============================================================================
443
+
444
+ test_include_tasks_in_output() {
445
+ describe "Should include tasks/ in output with --include-tasks"
446
+
447
+ # Arrange
448
+ local req_id="REQ-012"
449
+ local req_dir=$(setup_full_requirement "$req_id")
450
+ echo "task" > "$req_dir/tasks/TASK_001.md"
451
+
452
+ # Act
453
+ local output=$(run_check_prereq "$req_id" --include-tasks --json)
454
+
455
+ # Assert
456
+ assert_contains "$output" "tasks/" "Should include tasks/ in AVAILABLE_DOCS"
457
+ }
458
+
459
+ # ============================================================================
460
+ # 测试错误处理
461
+ # ============================================================================
462
+
463
+ test_invalid_option() {
464
+ describe "Should reject invalid options"
465
+
466
+ # Arrange - 创建测试脚本副本
467
+ local test_scripts_dir="$TEST_TMP_DIR/scripts"
468
+ mkdir -p "$test_scripts_dir"
469
+ create_test_common
470
+ cp "$CHECK_PREREQ_SCRIPT" "$test_scripts_dir/"
471
+
472
+ # Act
473
+ local exit_code=0
474
+ local output=$(
475
+ cd "$TEST_TMP_DIR"
476
+ bash "$test_scripts_dir/check-prerequisites.sh" --invalid-option 2>&1
477
+ ) || exit_code=$?
478
+
479
+ # Assert
480
+ assert_not_equals "$exit_code" "0" "Should fail on invalid option"
481
+ if [[ $exit_code -ne 0 ]]; then
482
+ assert_contains "$output" "Unknown option" "Should mention unknown option"
483
+ fi
484
+ }
485
+
486
+ # ============================================================================
487
+ # 运行所有测试
488
+ # ============================================================================
489
+
490
+ run_tests \
491
+ test_help_flag \
492
+ test_help_short_flag \
493
+ test_no_req_id_error \
494
+ test_paths_only_mode \
495
+ test_paths_only_json_mode \
496
+ test_missing_req_dir \
497
+ test_missing_prd_file \
498
+ test_valid_minimal_requirement \
499
+ test_require_epic_missing \
500
+ test_require_epic_present \
501
+ test_require_tasks_empty_dir \
502
+ test_require_tasks_with_files \
503
+ test_json_output_valid \
504
+ test_json_output_has_req_id \
505
+ test_json_output_available_docs \
506
+ test_bug_type_requirement \
507
+ test_include_tasks_in_output \
508
+ test_invalid_option