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,511 @@
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/devflow/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-999"
242
+ # 不创建目录 - 使用合法ID格式但目录不存在
243
+
244
+ # Act
245
+ local output=$(run_check_prereq_with_exit "$req_id")
246
+ local exit_code=$(get_last_exit_code)
247
+
248
+ # Assert
249
+ assert_not_equals "$exit_code" "0" "Should fail when REQ_DIR missing"
250
+ assert_contains "$output" "ERROR" "Should show error"
251
+ assert_contains "$output" "directory not found" "Should mention missing directory"
252
+ }
253
+
254
+ test_missing_prd_file() {
255
+ describe "Should fail when PRD.md doesn't exist"
256
+
257
+ # Arrange
258
+ local req_id="REQ-003"
259
+ local req_dir="$TEST_TMP_DIR/devflow/requirements/$req_id"
260
+ mkdir -p "$req_dir"
261
+ # 不创建 PRD.md
262
+
263
+ # Act
264
+ local exit_code=0
265
+ local output=$(run_check_prereq_with_exit "$req_id")
266
+ local exit_code=$(get_last_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_with_exit "$req_id" --require-epic)
303
+ local exit_code=$(get_last_exit_code)
304
+
305
+ # Assert
306
+ assert_not_equals "$exit_code" "0" "Should fail when EPIC.md required but missing"
307
+ assert_contains "$output" "EPIC.md not found" "Should mention missing EPIC"
308
+ }
309
+
310
+ test_require_epic_present() {
311
+ describe "Should succeed with --require-epic when EPIC.md exists"
312
+
313
+ # Arrange
314
+ local req_id="REQ-006"
315
+ local req_dir=$(setup_full_requirement "$req_id")
316
+ echo "# EPIC" > "$req_dir/EPIC.md"
317
+
318
+ # Act
319
+ local exit_code=0
320
+ local output=$(run_check_prereq "$req_id" --require-epic 2>&1) || exit_code=$?
321
+
322
+ # Assert
323
+ assert_equals "$exit_code" "0" "Should succeed when EPIC.md present"
324
+ }
325
+
326
+ # ============================================================================
327
+ # 测试 --require-tasks 选项
328
+ # ============================================================================
329
+
330
+ test_require_tasks_empty_dir() {
331
+ describe "Should fail with --require-tasks when tasks/ is empty"
332
+
333
+ # Arrange
334
+ local req_id="REQ-007"
335
+ local req_dir=$(setup_full_requirement "$req_id")
336
+ echo "# EPIC" > "$req_dir/EPIC.md"
337
+ # tasks/ 目录存在但为空
338
+
339
+ # Act
340
+ local exit_code=0
341
+ local output=$(run_check_prereq_with_exit "$req_id" --require-tasks)
342
+ local exit_code=$(get_last_exit_code)
343
+
344
+ # Assert
345
+ assert_not_equals "$exit_code" "0" "Should fail when tasks/ empty"
346
+ assert_contains "$output" "tasks/ directory" "Should mention tasks directory issue"
347
+ }
348
+
349
+ test_require_tasks_with_files() {
350
+ describe "Should succeed with --require-tasks when tasks/ has files"
351
+
352
+ # Arrange
353
+ local req_id="REQ-008"
354
+ local req_dir=$(setup_full_requirement "$req_id")
355
+ echo "# EPIC" > "$req_dir/EPIC.md"
356
+ echo "task" > "$req_dir/tasks/TASK_001.md"
357
+
358
+ # Act
359
+ local exit_code=0
360
+ local output=$(run_check_prereq "$req_id" --require-epic --require-tasks 2>&1) || exit_code=$?
361
+
362
+ # Assert
363
+ assert_equals "$exit_code" "0" "Should succeed when tasks/ has files"
364
+ }
365
+
366
+ # ============================================================================
367
+ # 测试 JSON 输出
368
+ # ============================================================================
369
+
370
+ test_json_output_valid() {
371
+ describe "Should output valid JSON with --json"
372
+
373
+ # Arrange
374
+ local req_id="REQ-009"
375
+ setup_full_requirement "$req_id"
376
+
377
+ # Act
378
+ local output=$(run_check_prereq "$req_id" --json)
379
+
380
+ # Assert
381
+ assert_json_valid "$output" "Should be valid JSON"
382
+ }
383
+
384
+ test_json_output_has_req_id() {
385
+ describe "JSON should include REQ_ID field"
386
+
387
+ # Arrange
388
+ local req_id="REQ-010"
389
+ setup_full_requirement "$req_id"
390
+
391
+ # Act
392
+ local output=$(run_check_prereq "$req_id" --json)
393
+
394
+ # Assert
395
+ assert_contains "$output" "\"REQ_ID\"" "Should have REQ_ID field"
396
+ assert_contains "$output" "\"$req_id\"" "Should have correct REQ_ID value"
397
+ }
398
+
399
+ test_json_output_available_docs() {
400
+ describe "JSON should include AVAILABLE_DOCS array"
401
+
402
+ # Arrange
403
+ local req_id="REQ-011"
404
+ local req_dir=$(setup_full_requirement "$req_id")
405
+
406
+ # 添加一些文档
407
+ echo "test" > "$req_dir/research/test.md"
408
+ echo "# Test Plan" > "$req_dir/TEST_PLAN.md"
409
+
410
+ # Act
411
+ local output=$(run_check_prereq "$req_id" --json)
412
+
413
+ # Assert
414
+ assert_contains "$output" "\"AVAILABLE_DOCS\"" "Should have AVAILABLE_DOCS field"
415
+ assert_contains "$output" "research/" "Should list research/"
416
+ assert_contains "$output" "TEST_PLAN.md" "Should list TEST_PLAN.md"
417
+ }
418
+
419
+ # ============================================================================
420
+ # 测试 BUG 类型需求
421
+ # ============================================================================
422
+
423
+ test_bug_type_requirement() {
424
+ describe "Should handle BUG-XXX format"
425
+
426
+ # Arrange
427
+ local req_id="BUG-999"
428
+ local req_dir=$(setup_full_requirement "$req_id")
429
+
430
+ # Act
431
+ local exit_code=0
432
+ local output=$(run_check_prereq "$req_id" --json 2>&1) || exit_code=$?
433
+
434
+ # Assert
435
+ assert_equals "$exit_code" "0" "Should handle BUG format"
436
+ assert_contains "$output" "BUG-999" "Should preserve BUG ID"
437
+ }
438
+
439
+ # ============================================================================
440
+ # 测试 --include-tasks 选项
441
+ # ============================================================================
442
+
443
+ test_include_tasks_in_output() {
444
+ describe "Should include tasks/ in output with --include-tasks"
445
+
446
+ # Arrange
447
+ local req_id="REQ-012"
448
+ local req_dir=$(setup_full_requirement "$req_id")
449
+ echo "task" > "$req_dir/tasks/TASK_001.md"
450
+
451
+ # Act
452
+ local output=$(run_check_prereq "$req_id" --include-tasks --json)
453
+
454
+ # Assert
455
+ assert_contains "$output" "tasks/" "Should include tasks/ in AVAILABLE_DOCS"
456
+ }
457
+
458
+ # ============================================================================
459
+ # 测试错误处理
460
+ # ============================================================================
461
+
462
+ test_invalid_option() {
463
+ describe "Should reject invalid options"
464
+
465
+ # Arrange - 创建测试脚本副本
466
+ local test_scripts_dir="$TEST_TMP_DIR/scripts"
467
+ mkdir -p "$test_scripts_dir"
468
+ create_test_common
469
+ cp "$CHECK_PREREQ_SCRIPT" "$test_scripts_dir/"
470
+
471
+ # Act - 使用 temp file 模式捕获 exit code
472
+ local output_file="$TEST_TMP_DIR/output.txt"
473
+ local exit_code_file="$TEST_TMP_DIR/exitcode.txt"
474
+
475
+ (
476
+ cd "$TEST_TMP_DIR"
477
+ bash "$test_scripts_dir/check-prerequisites.sh" --invalid-option > "$output_file" 2>&1
478
+ echo $? > "$exit_code_file"
479
+ )
480
+
481
+ local output=$(cat "$output_file")
482
+ local exit_code=$(cat "$exit_code_file")
483
+
484
+ # Assert
485
+ assert_not_equals "$exit_code" "0" "Should fail on invalid option"
486
+ assert_contains "$output" "Unknown option" "Should mention unknown option"
487
+ }
488
+
489
+ # ============================================================================
490
+ # 运行所有测试
491
+ # ============================================================================
492
+
493
+ run_tests \
494
+ test_help_flag \
495
+ test_help_short_flag \
496
+ test_no_req_id_error \
497
+ test_paths_only_mode \
498
+ test_paths_only_json_mode \
499
+ test_missing_req_dir \
500
+ test_missing_prd_file \
501
+ test_valid_minimal_requirement \
502
+ test_require_epic_missing \
503
+ test_require_epic_present \
504
+ test_require_tasks_empty_dir \
505
+ test_require_tasks_with_files \
506
+ test_json_output_valid \
507
+ test_json_output_has_req_id \
508
+ test_json_output_available_docs \
509
+ test_bug_type_requirement \
510
+ test_include_tasks_in_output \
511
+ test_invalid_option