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,117 @@
1
+ #!/usr/bin/env bash
2
+ # shellcheck disable=SC2312
3
+
4
+ set -euo pipefail
5
+
6
+ usage() {
7
+ cat <<'USAGE'
8
+ Usage: scripts/bash/export-contracts.sh <requirement-dir>
9
+
10
+ Extracts API contract definitions from TECH_DESIGN.md and writes them into
11
+ contracts/openapi.yaml (or schema.graphql if GraphQL). Creates placeholders when
12
+ structured data is unavailable.
13
+ USAGE
14
+ }
15
+
16
+ if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
17
+ usage
18
+ exit 0
19
+ fi
20
+
21
+ if [[ $# -lt 1 ]]; then
22
+ echo "Error: requirement directory is required." >&2
23
+ usage
24
+ exit 1
25
+ fi
26
+
27
+ REQ_DIR="$1"
28
+ if [[ ! -d "$REQ_DIR" ]]; then
29
+ echo "Error: requirement directory '$REQ_DIR' does not exist." >&2
30
+ exit 1
31
+ fi
32
+
33
+ python3 - "$REQ_DIR" <<'PY'
34
+ from __future__ import annotations
35
+
36
+ import re
37
+ import sys
38
+ from datetime import datetime, timezone
39
+ from pathlib import Path
40
+
41
+ req_dir = Path(sys.argv[1]).resolve()
42
+ tech_design = req_dir / "TECH_DESIGN.md"
43
+ contracts_dir = req_dir / "contracts"
44
+ contracts_dir.mkdir(exist_ok=True, parents=True)
45
+ openapi_path = contracts_dir / "openapi.yaml"
46
+ graphql_path = contracts_dir / "schema.graphql"
47
+
48
+ if not tech_design.exists():
49
+ print(f"Error: {tech_design} not found.", file=sys.stderr)
50
+ sys.exit(1)
51
+
52
+ content = tech_design.read_text(encoding="utf-8")
53
+
54
+ api_patterns = [
55
+ r"(^##\s+4\.\s*API.*?)(?=^##\s+\d+\.)",
56
+ r"(^##\s+API Design.*?)(?=^##\s+)",
57
+ ]
58
+
59
+ api_section = None
60
+ for pattern in api_patterns:
61
+ match = re.search(pattern, content, re.MULTILINE | re.DOTALL)
62
+ if match:
63
+ api_section = match.group(1).strip()
64
+ break
65
+
66
+ generated_at = datetime.now(timezone.utc).isoformat()
67
+
68
+ def extract_code_block(section: str, languages: tuple[str, ...]) -> str | None:
69
+ fence_regex = re.compile(
70
+ r"```(?P<lang>[^\n]*)\n(?P<body>.*?)```",
71
+ re.DOTALL | re.IGNORECASE,
72
+ )
73
+ for match in fence_regex.finditer(section):
74
+ lang = match.group("lang").strip().lower()
75
+ body = match.group("body")
76
+ if not languages or lang in languages:
77
+ return body.strip()
78
+ return None
79
+
80
+ if api_section:
81
+ openapi_block = extract_code_block(api_section, ("yaml", "yml", "openapi", "json"))
82
+ graphql_block = extract_code_block(api_section, ("graphql",))
83
+ else:
84
+ openapi_block = graphql_block = None
85
+
86
+ if graphql_block:
87
+ graphql_path.write_text(graphql_block + "\n", encoding="utf-8")
88
+ print(f"Wrote GraphQL schema → {graphql_path}")
89
+ # If both exist, prefer OpenAPI as well; otherwise create stub below.
90
+
91
+ if openapi_block:
92
+ if not openapi_block.lstrip().startswith("openapi:"):
93
+ openapi_block = f"# Generated {generated_at}\n{openapi_block}"
94
+ openapi_path.write_text(openapi_block + "\n", encoding="utf-8")
95
+ print(f"Wrote OpenAPI contract → {openapi_path}")
96
+ else:
97
+ placeholder = f"""# openapi.yaml generated {generated_at}
98
+ openapi: 3.0.3
99
+ info:
100
+ title: {req_dir.name} API
101
+ version: 0.1.0
102
+ paths:
103
+ /example:
104
+ get:
105
+ summary: TODO - replace with real endpoint
106
+ responses:
107
+ '200':
108
+ description: OK
109
+ components:
110
+ schemas:
111
+ TODO:
112
+ type: object
113
+ description: Replace with actual schema
114
+ """
115
+ openapi_path.write_text(placeholder, encoding="utf-8")
116
+ print(f"Warning: No structured OpenAPI block found; wrote placeholder → {openapi_path}", file=sys.stderr)
117
+ PY
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env bash
2
+ # shellcheck disable=SC2312
3
+
4
+ set -euo pipefail
5
+
6
+ usage() {
7
+ cat <<'USAGE'
8
+ Usage: scripts/bash/extract-data-model.sh <requirement-dir>
9
+
10
+ Extracts the "Data Model" section from TECH_DESIGN.md into data-model.md.
11
+ USAGE
12
+ }
13
+
14
+ if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
15
+ usage
16
+ exit 0
17
+ fi
18
+
19
+ if [[ $# -lt 1 ]]; then
20
+ echo "Error: requirement directory is required." >&2
21
+ usage
22
+ exit 1
23
+ fi
24
+
25
+ REQ_DIR="$1"
26
+ if [[ ! -d "$REQ_DIR" ]]; then
27
+ echo "Error: requirement directory '$REQ_DIR' does not exist." >&2
28
+ exit 1
29
+ fi
30
+
31
+ python3 - "$REQ_DIR" <<'PY'
32
+ from __future__ import annotations
33
+
34
+ import re
35
+ import sys
36
+ from datetime import datetime, timezone
37
+ from pathlib import Path
38
+
39
+ req_dir = Path(sys.argv[1]).resolve()
40
+ tech_design = req_dir / "TECH_DESIGN.md"
41
+ output_path = req_dir / "data-model.md"
42
+
43
+ if not tech_design.exists():
44
+ print(f"Error: {tech_design} not found.", file=sys.stderr)
45
+ sys.exit(1)
46
+
47
+ content = tech_design.read_text(encoding="utf-8")
48
+
49
+ section_regexes = [
50
+ r"(^##\s+3\.\s*Data Model.*?)(?=^##\s+\d+\.)",
51
+ r"(^##\s+Data Model.*?)(?=^##\s+)",
52
+ ]
53
+
54
+ section = None
55
+ for pattern in section_regexes:
56
+ match = re.search(pattern, content, re.MULTILINE | re.DOTALL)
57
+ if match:
58
+ section = match.group(1).strip()
59
+ break
60
+
61
+ if section is None:
62
+ print("Warning: Data Model section not found; creating placeholder.", file=sys.stderr)
63
+ section = "## Data Model\n\n_TODO: populate data model details in TECH_DESIGN.md_"
64
+
65
+ generated_at = datetime.now(timezone.utc).isoformat()
66
+
67
+ lines = [
68
+ f"# Data Model — {req_dir.name}",
69
+ "",
70
+ f"_Generated from TECH_DESIGN.md on {generated_at}_",
71
+ "",
72
+ section,
73
+ "",
74
+ ]
75
+
76
+ output_path.write_text("\n".join(lines), encoding="utf-8")
77
+ print(f"Wrote data model extract → {output_path}")
78
+ PY
@@ -0,0 +1,377 @@
1
+ #!/usr/bin/env bash
2
+ # =============================================================================
3
+ # generate-clarification-questions.sh - 智能问题生成与优先级排序
4
+ # =============================================================================
5
+ # Purpose: 基于扫描结果生成优先级排序问题 (≤5)
6
+ # Usage: generate-clarification-questions.sh --input scan_result.json --max 5
7
+ # Output: JSON (stdout) - ClarificationQuestion[]
8
+ # Exit codes: 0=success, 1=no issues, 2=fatal
9
+ # =============================================================================
10
+
11
+ set -euo pipefail
12
+
13
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
14
+ source "${SCRIPT_DIR}/common.sh"
15
+
16
+ # Import functions from run-clarify-scan.sh
17
+ source "${SCRIPT_DIR}/run-clarify-scan.sh" 2>/dev/null || true
18
+
19
+ # =============================================================================
20
+ # API Key 检测 (与 run-clarify-scan.sh 对齐)
21
+ # =============================================================================
22
+ if ! declare -F has_valid_api_key >/dev/null 2>&1; then
23
+ has_valid_api_key() {
24
+ [[ -n "${CLAUDE_API_KEY:-}" ]] && [[ "${CLAUDE_API_KEY}" =~ ^sk-ant- ]]
25
+ }
26
+ fi
27
+
28
+ # Configuration
29
+ MAX_QUESTIONS=5
30
+ INPUT_FILE=""
31
+
32
+ # =============================================================================
33
+ # T026: 优先级计算
34
+ # =============================================================================
35
+ calculate_priority() {
36
+ local issue_json="$1"
37
+ local impact uncertainty
38
+ impact=$(echo "$issue_json" | jq -r '.impact // 5')
39
+ uncertainty=$(echo "$issue_json" | jq -r '.uncertainty // 5')
40
+ echo $((impact * uncertainty))
41
+ }
42
+
43
+ # =============================================================================
44
+ # T027: 问题合并 (同维度多个歧义合并为 1 个问题)
45
+ # =============================================================================
46
+ merge_similar_issues() {
47
+ local issues_json="$1"
48
+
49
+ # 按维度分组,每个维度取最高优先级的问题
50
+ echo "$issues_json" | jq '
51
+ group_by(.dimensionId) |
52
+ map(
53
+ sort_by(-.priority) |
54
+ .[0] + {
55
+ relatedIssues: (. | length),
56
+ mergedDescriptions: (map(.description) | join("; "))
57
+ }
58
+ )
59
+ '
60
+ }
61
+
62
+ # =============================================================================
63
+ # T028: 问题模板生成
64
+ # =============================================================================
65
+ generate_heuristic_question() {
66
+ local dim_id="$1"
67
+ local description="$2"
68
+
69
+ case "$dim_id" in
70
+ 1)
71
+ jq -n \
72
+ --arg desc "$description" \
73
+ '{
74
+ text: "REQ-004 的 MVP 适配范围应如何定义?",
75
+ options: [
76
+ {optionId: "A", text: "双平台可运行", description: "交付 claude-code + codex-cli 两个可运行 adapter,其它平台先留 stub"},
77
+ {optionId: "B", text: "单平台先抽象", description: "只交付 claude-code adapter + 接口/注册表,其它平台后续需求再做"},
78
+ {optionId: "C", text: "多平台一次到位", description: "至少 3 个可运行 adapter(Claude/Codex/Cursor 等)"},
79
+ {optionId: "D", text: "仅出设计不落地", description: "只输出 PRD/Tech Design,本需求不交付代码"}
80
+ ],
81
+ recommendedOption: "A",
82
+ recommendedRationale: "至少落地 2 个可运行 adapter 才能验证架构正确性,同时把范围控制在可交付的最小集合"
83
+ }'
84
+ ;;
85
+ 4)
86
+ jq -n \
87
+ --arg desc "$description" \
88
+ '{
89
+ text: "对 adapter 的探测/执行链路,有哪些硬性非功能要求需要现在锁定?",
90
+ options: [
91
+ {optionId: "A", text: "轻量指标 + 结构化日志", description: "detect 总耗时 <50ms(缓存后 <5ms),记录 adapter/timing/result 的结构化日志"},
92
+ {optionId: "B", text: "严格指标 + 可观测套件", description: "detect <5ms,强制 metrics/tracing,所有执行都有 traceId"},
93
+ {optionId: "C", text: "不设指标", description: "先按 best-effort 做通功能,后续再补性能与观测"}
94
+ ],
95
+ recommendedOption: "A",
96
+ recommendedRationale: "先把可观测性与基本性能边界写清,避免后续返工;同时不引入过度工程"
97
+ }'
98
+ ;;
99
+ 6)
100
+ jq -n \
101
+ --arg desc "$description" \
102
+ '{
103
+ text: "当多个 adapter 同时命中或没有命中时,选择/降级策略应是什么?",
104
+ options: [
105
+ {optionId: "A", text: "可覆盖 + 确定性优先级", description: "用户显式指定(ENV/CLI) > 配置 > detect 打分最高 > fallback 默认 adapter;冲突时输出告警"},
106
+ {optionId: "B", text: "冲突即失败", description: "多个命中或无命中直接报错,要求用户显式指定"},
107
+ {optionId: "C", text: "先到先得", description: "按注册顺序 first-match,不做打分与冲突处理"}
108
+ ],
109
+ recommendedOption: "A",
110
+ recommendedRationale: "保证可预测性与可控性:默认自动化,但允许用户明确覆盖,并且对冲突有确定性规则"
111
+ }'
112
+ ;;
113
+ 9)
114
+ jq -n \
115
+ --arg desc "$description" \
116
+ '{
117
+ text: "REQ-004 的 Definition of Done 应以哪些可验证交付物为准?",
118
+ options: [
119
+ {optionId: "A", text: "可运行 + 可验证", description: "接口规范 + registry + 默认 adapter + 配置机制 + 测试 + 文档 + 至少 1 个非默认平台 adapter"},
120
+ {optionId: "B", text: "先抽象后验证", description: "接口规范 + registry + 默认 adapter + 基础测试;非默认 adapter 仅 stub"},
121
+ {optionId: "C", text: "文档优先", description: "只产出 PRD/Tech Design/TASKS,代码实现拆到后续需求"}
122
+ ],
123
+ recommendedOption: "A",
124
+ recommendedRationale: "定义完成必须可验证;至少一个非默认 adapter 能证明架构不是纸上谈兵"
125
+ }'
126
+ ;;
127
+ 11)
128
+ jq -n \
129
+ --arg desc "$description" \
130
+ '{
131
+ text: "Adapter 的能力边界与默认安全策略应如何设计(shell/filesystem/network)?",
132
+ options: [
133
+ {optionId: "A", text: "Capability allow-list", description: "adapter 声明 capabilities;命令声明 required capabilities;默认 deny 危险能力(shell/network),启用需显式配置并写审计日志"},
134
+ {optionId: "B", text: "完全信任", description: "adapter 拥有全部能力,不做额外限制"},
135
+ {optionId: "C", text: "全局 Safe Mode", description: "默认关闭 shell/network,提供全局开关;不做细粒度 capability 控制"}
136
+ ],
137
+ recommendedOption: "A",
138
+ recommendedRationale: "用能力模型把危险操作从设计上隔离出去,默认最小权限,审计可追踪"
139
+ }'
140
+ ;;
141
+ *)
142
+ jq -n \
143
+ --arg desc "$description" \
144
+ '{
145
+ text: ("需要澄清:" + $desc),
146
+ options: [
147
+ {optionId: "A", text: "采用推荐方案", description: "采用行业最佳实践"},
148
+ {optionId: "B", text: "自定义方案", description: "需要进一步说明"},
149
+ {optionId: "C", text: "暂时跳过", description: "稍后决定"}
150
+ ],
151
+ recommendedOption: "A",
152
+ recommendedRationale: "优先选可验证、低风险路径"
153
+ }'
154
+ ;;
155
+ esac
156
+ }
157
+
158
+ generate_question_template() {
159
+ local issue_json="$1"
160
+ local question_id="$2"
161
+
162
+ local dim_id dim_name description
163
+ dim_id=$(echo "$issue_json" | jq -r '.dimensionId')
164
+ description=$(echo "$issue_json" | jq -r '.description // .mergedDescriptions // "需要澄清"')
165
+
166
+ # 维度名称映射
167
+ local dim_names=(
168
+ "" "Functional Scope" "Data Model" "UX Flow" "Non-Functional Quality"
169
+ "Integration & Dependencies" "Edge Cases" "Constraints & Tradeoffs"
170
+ "Terminology" "Completion Signals" "Misc & Placeholders" "Security & Privacy"
171
+ )
172
+ dim_name="${dim_names[$dim_id]:-Unknown}"
173
+
174
+ # 生成问题文本
175
+ local question_text="关于 ${dim_name}: ${description}"
176
+
177
+ local template_json options recommended recommended_rationale
178
+ template_json="{}"
179
+ options='[]'
180
+ recommended="A"
181
+ recommended_rationale="推荐使用行业最佳实践以降低风险"
182
+
183
+ if has_valid_api_key; then
184
+ template_json=$(generate_ai_question "$issue_json" "$dim_name") || true
185
+ else
186
+ template_json=$(generate_heuristic_question "$dim_id" "$description") || true
187
+ fi
188
+
189
+ if [[ -n "$template_json" ]] && echo "$template_json" | jq -e '.text and (.options | length > 0)' >/dev/null 2>&1; then
190
+ question_text=$(echo "$template_json" | jq -r '.text')
191
+ options=$(echo "$template_json" | jq '.options')
192
+ recommended=$(echo "$template_json" | jq -r '.recommendedOption // "A"')
193
+ recommended_rationale=$(echo "$template_json" | jq -r '.recommendedRationale // "推荐使用行业最佳实践以降低风险"')
194
+ else
195
+ # 兜底:使用最通用模板
196
+ options='[
197
+ {"optionId": "A", "text": "使用推荐方案", "description": "采用行业最佳实践"},
198
+ {"optionId": "B", "text": "自定义方案", "description": "需要进一步说明"},
199
+ {"optionId": "C", "text": "暂时跳过", "description": "稍后决定"}
200
+ ]'
201
+ recommended="A"
202
+ recommended_rationale="推荐使用行业最佳实践以降低风险"
203
+ fi
204
+
205
+ # 构建问题 JSON
206
+ jq -n \
207
+ --arg qid "$question_id" \
208
+ --argjson dimId "$dim_id" \
209
+ --arg text "$question_text" \
210
+ --argjson options "$options" \
211
+ --arg recommended "$recommended" \
212
+ --arg rationale "$recommended_rationale" \
213
+ '{
214
+ questionId: $qid,
215
+ dimensionId: $dimId,
216
+ text: $text,
217
+ type: "multiple_choice",
218
+ options: $options,
219
+ recommendedOption: $recommended,
220
+ recommendedRationale: $rationale,
221
+ answer: null,
222
+ answeredAt: null,
223
+ rationale: null
224
+ }'
225
+ }
226
+
227
+ # =============================================================================
228
+ # AI 问题生成 (使用 Claude Sonnet)
229
+ # =============================================================================
230
+ generate_ai_question() {
231
+ local issue_json="$1"
232
+ local dim_name="$2"
233
+
234
+ local description
235
+ description=$(echo "$issue_json" | jq -r '.description // .mergedDescriptions')
236
+
237
+ local system_prompt="You are a requirements clarification specialist.
238
+ Generate a clarification question for this ambiguity:
239
+ Dimension: ${dim_name}
240
+ Issue: ${description}
241
+
242
+ Output ONLY valid JSON:
243
+ {
244
+ \"text\": \"问题文本(中文,简洁明确)\",
245
+ \"options\": [
246
+ {\"optionId\": \"A\", \"text\": \"选项A\", \"description\": \"说明\"},
247
+ {\"optionId\": \"B\", \"text\": \"选项B\", \"description\": \"说明\"},
248
+ {\"optionId\": \"C\", \"text\": \"选项C\", \"description\": \"说明\"}
249
+ ],
250
+ \"recommendedOption\": \"A\",
251
+ \"recommendedRationale\": \"推荐理由\"
252
+ }"
253
+
254
+ call_claude_api "claude-sonnet-4-5-20241022" "$system_prompt" "$description" 1000 30 2>/dev/null || echo '{}'
255
+ }
256
+
257
+ # =============================================================================
258
+ # T029: 主入口
259
+ # =============================================================================
260
+ parse_args() {
261
+ local input_file=""
262
+ local max_questions="$MAX_QUESTIONS"
263
+
264
+ while [[ $# -gt 0 ]]; do
265
+ case "$1" in
266
+ --input)
267
+ input_file="$2"
268
+ shift 2
269
+ ;;
270
+ --max)
271
+ max_questions="$2"
272
+ shift 2
273
+ ;;
274
+ --help|-h)
275
+ echo "Usage: generate-clarification-questions.sh --input scan_result.json [--max 5]"
276
+ exit 0
277
+ ;;
278
+ *)
279
+ shift
280
+ ;;
281
+ esac
282
+ done
283
+
284
+ echo "$input_file|$max_questions"
285
+ }
286
+
287
+ extract_all_issues() {
288
+ local scan_result="$1"
289
+
290
+ # 从扫描结果中提取所有 issues
291
+ echo "$scan_result" | jq '
292
+ .dimensions // [] |
293
+ map(select(.status == "ambiguous")) |
294
+ map(.issues[] + {dimensionId: .dimensionId, dimensionName: .name}) |
295
+ sort_by(-.priority)
296
+ '
297
+ }
298
+
299
+ main() {
300
+ # 解析参数
301
+ local parsed
302
+ parsed=$(parse_args "$@")
303
+ local input_file max_questions
304
+ IFS='|' read -r input_file max_questions <<< "$parsed"
305
+
306
+ # 验证输入
307
+ if [[ -z "$input_file" ]]; then
308
+ echo '{"error": {"code": "MISSING_INPUT", "message": "--input is required"}}' >&2
309
+ exit 2
310
+ fi
311
+
312
+ local scan_result
313
+ if [[ "$input_file" == "-" ]]; then
314
+ scan_result=$(cat)
315
+ elif [[ -f "$input_file" ]]; then
316
+ scan_result=$(cat "$input_file")
317
+ else
318
+ echo '{"error": {"code": "FILE_NOT_FOUND", "message": "Input file not found"}}' >&2
319
+ exit 2
320
+ fi
321
+
322
+ # 验证 JSON
323
+ if ! echo "$scan_result" | jq -e '.' >/dev/null 2>&1; then
324
+ echo '{"error": {"code": "INVALID_JSON", "message": "Input is not valid JSON"}}' >&2
325
+ exit 2
326
+ fi
327
+
328
+ # 提取所有 issues
329
+ local all_issues
330
+ all_issues=$(extract_all_issues "$scan_result")
331
+
332
+ local issue_count
333
+ issue_count=$(echo "$all_issues" | jq 'length')
334
+
335
+ # T024: 如果没有 issues,返回空
336
+ if [[ "$issue_count" -eq 0 ]]; then
337
+ echo '{"questions": [], "message": "No ambiguities found - research.md is clear"}'
338
+ exit 1
339
+ fi
340
+
341
+ # 合并相似问题
342
+ local merged_issues
343
+ merged_issues=$(merge_similar_issues "$all_issues")
344
+
345
+ # 按优先级排序并限制数量
346
+ local top_issues
347
+ top_issues=$(echo "$merged_issues" | jq --argjson max "$max_questions" '
348
+ sort_by(-.priority) | .[:$max]
349
+ ')
350
+
351
+ # 生成问题
352
+ local questions="[]"
353
+ local idx=0
354
+ while IFS= read -r issue; do
355
+ idx=$((idx + 1))
356
+ local question_id="Q${idx}"
357
+ local question
358
+ question=$(generate_question_template "$issue" "$question_id")
359
+ questions=$(echo "$questions" | jq --argjson q "$question" '. + [$q]')
360
+ done < <(echo "$top_issues" | jq -c '.[]')
361
+
362
+ # 输出结果
363
+ jq -n \
364
+ --argjson questions "$questions" \
365
+ --argjson totalIssues "$issue_count" \
366
+ --argjson generatedCount "$(echo "$questions" | jq 'length')" \
367
+ '{
368
+ questions: $questions,
369
+ totalIssuesFound: $totalIssues,
370
+ questionsGenerated: $generatedCount
371
+ }'
372
+ }
373
+
374
+ # 只在直接执行时运行 main
375
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
376
+ main "$@"
377
+ fi