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,505 @@
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 "$req_id" 2>&1) || exit_code=$?
267
+
268
+ # Assert
269
+ assert_not_equals "$exit_code" "0" "Should fail when PRD.md missing"
270
+ assert_contains "$output" "PRD.md not found" "Should mention missing PRD"
271
+ }
272
+
273
+ test_valid_minimal_requirement() {
274
+ describe "Should succeed with minimal valid requirement"
275
+
276
+ # Arrange
277
+ local req_id="REQ-004"
278
+ setup_full_requirement "$req_id"
279
+
280
+ # Act
281
+ local exit_code=0
282
+ local output=$(run_check_prereq "$req_id" 2>&1) || exit_code=$?
283
+
284
+ # Assert
285
+ assert_equals "$exit_code" "0" "Should succeed with PRD.md present"
286
+ }
287
+
288
+ # ============================================================================
289
+ # 测试 --require-epic 选项
290
+ # ============================================================================
291
+
292
+ test_require_epic_missing() {
293
+ describe "Should fail with --require-epic when EPIC.md missing"
294
+
295
+ # Arrange
296
+ local req_id="REQ-005"
297
+ setup_full_requirement "$req_id"
298
+ # 不创建 EPIC.md
299
+
300
+ # Act
301
+ local exit_code=0
302
+ local output=$(run_check_prereq "$req_id" --require-epic 2>&1) || exit_code=$?
303
+
304
+ # Assert
305
+ assert_not_equals "$exit_code" "0" "Should fail when EPIC.md required but missing"
306
+ assert_contains "$output" "EPIC.md not found" "Should mention missing EPIC"
307
+ }
308
+
309
+ test_require_epic_present() {
310
+ describe "Should succeed with --require-epic when EPIC.md exists"
311
+
312
+ # Arrange
313
+ local req_id="REQ-006"
314
+ local req_dir=$(setup_full_requirement "$req_id")
315
+ echo "# EPIC" > "$req_dir/EPIC.md"
316
+
317
+ # Act
318
+ local exit_code=0
319
+ local output=$(run_check_prereq "$req_id" --require-epic 2>&1) || exit_code=$?
320
+
321
+ # Assert
322
+ assert_equals "$exit_code" "0" "Should succeed when EPIC.md present"
323
+ }
324
+
325
+ # ============================================================================
326
+ # 测试 --require-tasks 选项
327
+ # ============================================================================
328
+
329
+ test_require_tasks_empty_dir() {
330
+ describe "Should fail with --require-tasks when tasks/ is empty"
331
+
332
+ # Arrange
333
+ local req_id="REQ-007"
334
+ local req_dir=$(setup_full_requirement "$req_id")
335
+ echo "# EPIC" > "$req_dir/EPIC.md"
336
+ # tasks/ 目录存在但为空
337
+
338
+ # Act
339
+ local exit_code=0
340
+ local output=$(run_check_prereq "$req_id" --require-tasks 2>&1) || exit_code=$?
341
+
342
+ # Assert
343
+ assert_not_equals "$exit_code" "0" "Should fail when tasks/ empty"
344
+ assert_contains "$output" "tasks/ directory" "Should mention tasks directory issue"
345
+ }
346
+
347
+ test_require_tasks_with_files() {
348
+ describe "Should succeed with --require-tasks when tasks/ has files"
349
+
350
+ # Arrange
351
+ local req_id="REQ-008"
352
+ local req_dir=$(setup_full_requirement "$req_id")
353
+ echo "# EPIC" > "$req_dir/EPIC.md"
354
+ echo "task" > "$req_dir/tasks/TASK_001.md"
355
+
356
+ # Act
357
+ local exit_code=0
358
+ local output=$(run_check_prereq "$req_id" --require-epic --require-tasks 2>&1) || exit_code=$?
359
+
360
+ # Assert
361
+ assert_equals "$exit_code" "0" "Should succeed when tasks/ has files"
362
+ }
363
+
364
+ # ============================================================================
365
+ # 测试 JSON 输出
366
+ # ============================================================================
367
+
368
+ test_json_output_valid() {
369
+ describe "Should output valid JSON with --json"
370
+
371
+ # Arrange
372
+ local req_id="REQ-009"
373
+ setup_full_requirement "$req_id"
374
+
375
+ # Act
376
+ local output=$(run_check_prereq "$req_id" --json)
377
+
378
+ # Assert
379
+ assert_json_valid "$output" "Should be valid JSON"
380
+ }
381
+
382
+ test_json_output_has_req_id() {
383
+ describe "JSON should include REQ_ID field"
384
+
385
+ # Arrange
386
+ local req_id="REQ-010"
387
+ setup_full_requirement "$req_id"
388
+
389
+ # Act
390
+ local output=$(run_check_prereq "$req_id" --json)
391
+
392
+ # Assert
393
+ assert_contains "$output" "\"REQ_ID\"" "Should have REQ_ID field"
394
+ assert_contains "$output" "\"$req_id\"" "Should have correct REQ_ID value"
395
+ }
396
+
397
+ test_json_output_available_docs() {
398
+ describe "JSON should include AVAILABLE_DOCS array"
399
+
400
+ # Arrange
401
+ local req_id="REQ-011"
402
+ local req_dir=$(setup_full_requirement "$req_id")
403
+
404
+ # 添加一些文档
405
+ echo "test" > "$req_dir/research/test.md"
406
+ echo "# Test Plan" > "$req_dir/TEST_PLAN.md"
407
+
408
+ # Act
409
+ local output=$(run_check_prereq "$req_id" --json)
410
+
411
+ # Assert
412
+ assert_contains "$output" "\"AVAILABLE_DOCS\"" "Should have AVAILABLE_DOCS field"
413
+ assert_contains "$output" "research/" "Should list research/"
414
+ assert_contains "$output" "TEST_PLAN.md" "Should list TEST_PLAN.md"
415
+ }
416
+
417
+ # ============================================================================
418
+ # 测试 BUG 类型需求
419
+ # ============================================================================
420
+
421
+ test_bug_type_requirement() {
422
+ describe "Should handle BUG-XXX format"
423
+
424
+ # Arrange
425
+ local req_id="BUG-999"
426
+ local req_dir=$(setup_full_requirement "$req_id")
427
+
428
+ # Act
429
+ local exit_code=0
430
+ local output=$(run_check_prereq "$req_id" --json 2>&1) || exit_code=$?
431
+
432
+ # Assert
433
+ assert_equals "$exit_code" "0" "Should handle BUG format"
434
+ assert_contains "$output" "BUG-999" "Should preserve BUG ID"
435
+ }
436
+
437
+ # ============================================================================
438
+ # 测试 --include-tasks 选项
439
+ # ============================================================================
440
+
441
+ test_include_tasks_in_output() {
442
+ describe "Should include tasks/ in output with --include-tasks"
443
+
444
+ # Arrange
445
+ local req_id="REQ-012"
446
+ local req_dir=$(setup_full_requirement "$req_id")
447
+ echo "task" > "$req_dir/tasks/TASK_001.md"
448
+
449
+ # Act
450
+ local output=$(run_check_prereq "$req_id" --include-tasks --json)
451
+
452
+ # Assert
453
+ assert_contains "$output" "tasks/" "Should include tasks/ in AVAILABLE_DOCS"
454
+ }
455
+
456
+ # ============================================================================
457
+ # 测试错误处理
458
+ # ============================================================================
459
+
460
+ test_invalid_option() {
461
+ describe "Should reject invalid options"
462
+
463
+ # Arrange - 创建测试脚本副本
464
+ local test_scripts_dir="$TEST_TMP_DIR/scripts"
465
+ mkdir -p "$test_scripts_dir"
466
+ create_test_common
467
+ cp "$CHECK_PREREQ_SCRIPT" "$test_scripts_dir/"
468
+
469
+ # Act
470
+ local exit_code=0
471
+ local output=$(
472
+ cd "$TEST_TMP_DIR"
473
+ bash "$test_scripts_dir/check-prerequisites.sh" --invalid-option 2>&1
474
+ ) || exit_code=$?
475
+
476
+ # Assert
477
+ assert_not_equals "$exit_code" "0" "Should fail on invalid option"
478
+ if [[ $exit_code -ne 0 ]]; then
479
+ assert_contains "$output" "Unknown option" "Should mention unknown option"
480
+ fi
481
+ }
482
+
483
+ # ============================================================================
484
+ # 运行所有测试
485
+ # ============================================================================
486
+
487
+ run_tests \
488
+ test_help_flag \
489
+ test_help_short_flag \
490
+ test_no_req_id_error \
491
+ test_paths_only_mode \
492
+ test_paths_only_json_mode \
493
+ test_missing_req_dir \
494
+ test_missing_prd_file \
495
+ test_valid_minimal_requirement \
496
+ test_require_epic_missing \
497
+ test_require_epic_present \
498
+ test_require_tasks_empty_dir \
499
+ test_require_tasks_with_files \
500
+ test_json_output_valid \
501
+ test_json_output_has_req_id \
502
+ test_json_output_available_docs \
503
+ test_bug_type_requirement \
504
+ test_include_tasks_in_output \
505
+ test_invalid_option