@boyingliu01/xp-gate 0.18.4 → 0.19.0

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 (248) hide show
  1. package/adapter-common.sh +27 -0
  2. package/adapters/powershell.sh +85 -33
  3. package/adapters/typescript.sh +8 -8
  4. package/build-integrity/__tests__/import-resolver.test.ts +22 -0
  5. package/build-integrity/__tests__/orchestrator.test.ts +1 -2
  6. package/build-integrity/gate-10.ts +7 -0
  7. package/gate-12-file-hygiene.sh +230 -0
  8. package/hooks/adapter-common.sh +27 -0
  9. package/hooks/gate-10.sh +105 -0
  10. package/hooks/lib/validate-code-walkthrough.cjs +125 -0
  11. package/hooks/pre-commit +130 -33
  12. package/hooks/pre-push +15 -91
  13. package/lib/__tests__/check-version.test.js +67 -46
  14. package/lib/__tests__/doctor.test.js +7 -6
  15. package/lib/__tests__/gate-runner.test.js +267 -0
  16. package/lib/__tests__/init.test.js +32 -0
  17. package/lib/__tests__/npm-package.test.js +13 -0
  18. package/lib/__tests__/phase-transition.test.js +604 -12
  19. package/lib/__tests__/sprint-discovery.test.ts +0 -1
  20. package/lib/__tests__/sprint-status-rework.test.js +100 -1
  21. package/lib/__tests__/update-hooks.test.js +143 -10
  22. package/lib/__tests__/upgrade-exec.test.js +73 -45
  23. package/lib/__tests__/upgrade-skill-sync.test.js +1 -1
  24. package/lib/__tests__/upgrade.test.js +12 -11
  25. package/lib/doctor.js +2 -1
  26. package/lib/gate-runner.js +68 -23
  27. package/lib/init.js +34 -5
  28. package/lib/install-skill.js +1 -0
  29. package/lib/mattpocock-license-verdict.json +1 -1
  30. package/lib/phase-transition.js +203 -23
  31. package/lib/shared-paths.js +2 -0
  32. package/lib/sprint-status.js +15 -4
  33. package/lib/test-alignment.ts +3 -13
  34. package/lib/update-hooks.js +129 -15
  35. package/mock-policy/AGENTS.md +5 -5
  36. package/mock-policy/__tests__/gate-m3.test.ts +0 -5
  37. package/mock-policy/__tests__/scope-scanner.test.ts +8 -2
  38. package/mutation/AGENTS.md +4 -4
  39. package/mutation/__tests__/mutmut-runner.test.ts +443 -2
  40. package/mutation/__tests__/update-baseline.test.ts +0 -2
  41. package/mutation/runners/mutmut-runner.ts +67 -17
  42. package/package.json +9 -3
  43. package/plugins/claude-code/.claude-plugin/plugin.json +1 -1
  44. package/plugins/claude-code/skills/clipboard-vision/SKILL.md +47 -0
  45. package/plugins/claude-code/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  46. package/plugins/claude-code/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  47. package/plugins/claude-code/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  48. package/plugins/claude-code/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  49. package/plugins/claude-code/skills/clipboard-vision/describe-clipboard.ps1 +115 -0
  50. package/plugins/claude-code/skills/clipboard-vision/describe-clipboard.sh +161 -0
  51. package/plugins/claude-code/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  52. package/plugins/claude-code/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  53. package/plugins/claude-code/skills/delphi-review/.delphi-config.json.example +24 -27
  54. package/plugins/claude-code/skills/delphi-review/AGENTS.md +13 -12
  55. package/plugins/claude-code/skills/delphi-review/INSTALL.md +15 -17
  56. package/plugins/claude-code/skills/delphi-review/SKILL.md +30 -29
  57. package/plugins/claude-code/skills/delphi-review/opencode.json.delphi.example +6 -10
  58. package/plugins/claude-code/skills/delphi-review/references/code-walkthrough.md +33 -49
  59. package/plugins/claude-code/skills/delphi-review/references/requirements.md +66 -54
  60. package/plugins/claude-code/skills/delphi-review/references/round-templates.md +7 -7
  61. package/plugins/claude-code/skills/sprint-flow/AGENTS.md +5 -5
  62. package/plugins/claude-code/skills/sprint-flow/SKILL.md +4 -4
  63. package/plugins/claude-code/skills/sprint-flow/references/components/skill-invocations.md +2 -2
  64. package/plugins/claude-code/skills/sprint-flow/references/force-levels.md +37 -35
  65. package/plugins/claude-code/skills/sprint-flow/references/orchestration-rules.md +1 -1
  66. package/plugins/claude-code/skills/sprint-flow/references/phase-1-prep.md +1 -1
  67. package/plugins/claude-code/skills/sprint-flow/references/phase-2-design.md +24 -14
  68. package/plugins/claude-code/skills/sprint-flow/references/phase-4-verify.md +6 -6
  69. package/plugins/claude-code/skills/sprint-flow/references/phase-overview.md +2 -2
  70. package/plugins/claude-code/skills/test-specification-alignment/AGENTS.md +4 -4
  71. package/plugins/dsh/README.md +25 -0
  72. package/plugins/dsh/cordis.patch.yml +7 -0
  73. package/plugins/dsh/package.json +70 -0
  74. package/plugins/dsh/scripts/prepack.cjs +82 -0
  75. package/plugins/dsh/skills/admin-template-guidelines/SKILL.md +113 -0
  76. package/plugins/dsh/skills/admin-template-guidelines/references/rule-1.md +91 -0
  77. package/plugins/dsh/skills/admin-template-guidelines/references/rule-2.md +155 -0
  78. package/plugins/dsh/skills/admin-template-guidelines/references/rule-3.md +70 -0
  79. package/plugins/dsh/skills/admin-template-guidelines/references/rule-4.md +154 -0
  80. package/plugins/dsh/skills/admin-template-guidelines/references/rule-5.md +126 -0
  81. package/plugins/dsh/skills/admin-template-guidelines/references/rule-6.md +180 -0
  82. package/plugins/dsh/skills/batch-grill-me/SKILL.md +15 -0
  83. package/plugins/dsh/skills/clipboard-vision/SKILL.md +47 -0
  84. package/plugins/dsh/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  85. package/plugins/dsh/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  86. package/plugins/dsh/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  87. package/plugins/dsh/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  88. package/plugins/dsh/skills/clipboard-vision/describe-clipboard.ps1 +115 -0
  89. package/plugins/dsh/skills/clipboard-vision/describe-clipboard.sh +161 -0
  90. package/plugins/dsh/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  91. package/plugins/dsh/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  92. package/plugins/dsh/skills/delphi-review/.delphi-config.json.example +70 -0
  93. package/plugins/dsh/skills/delphi-review/AGENTS.md +67 -0
  94. package/plugins/dsh/skills/delphi-review/INSTALL.md +150 -0
  95. package/plugins/dsh/skills/delphi-review/SKILL.md +559 -0
  96. package/plugins/dsh/skills/delphi-review/hooks.md +19 -0
  97. package/plugins/dsh/skills/delphi-review/opencode.json.delphi.example +52 -0
  98. package/plugins/dsh/skills/delphi-review/references/code-walkthrough.md +470 -0
  99. package/plugins/dsh/skills/delphi-review/references/orchestrator-dispatch.md +64 -0
  100. package/plugins/dsh/skills/delphi-review/references/requirements.md +402 -0
  101. package/plugins/dsh/skills/delphi-review/references/round-templates.md +134 -0
  102. package/plugins/dsh/skills/delphi-review/scripts/verify-consensus.sh +43 -0
  103. package/plugins/dsh/skills/delphi-review/tools.md +29 -0
  104. package/plugins/dsh/skills/domain-modeling/ADR-FORMAT.md +64 -0
  105. package/plugins/dsh/skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  106. package/plugins/dsh/skills/domain-modeling/SKILL.md +74 -0
  107. package/plugins/dsh/skills/grill-with-docs/SKILL.md +7 -0
  108. package/plugins/dsh/skills/grilling/SKILL.md +12 -0
  109. package/plugins/dsh/skills/improve-codebase-architecture/SKILL.md +156 -0
  110. package/plugins/dsh/skills/ralph-loop/SKILL.md +198 -0
  111. package/plugins/dsh/skills/ralph-loop/references/components.md +113 -0
  112. package/plugins/dsh/skills/ralph-loop/references/phase-2-build-ralph.md +89 -0
  113. package/plugins/dsh/skills/ralph-loop/references/workflow-details.md +99 -0
  114. package/plugins/dsh/skills/ralph-loop/templates/progress-log.md +36 -0
  115. package/plugins/dsh/skills/sprint-flow/AGENTS.md +103 -0
  116. package/plugins/dsh/skills/sprint-flow/SKILL.md +411 -0
  117. package/plugins/dsh/skills/sprint-flow/__tests__/sprint-flow.test.cjs +457 -0
  118. package/plugins/dsh/skills/sprint-flow/hooks.md +18 -0
  119. package/plugins/dsh/skills/sprint-flow/references/components/memory.md +87 -0
  120. package/plugins/dsh/skills/sprint-flow/references/components/middleware.md +75 -0
  121. package/plugins/dsh/skills/sprint-flow/references/components/skill-invocations.md +105 -0
  122. package/plugins/dsh/skills/sprint-flow/references/components/system-prompt.md +27 -0
  123. package/plugins/dsh/skills/sprint-flow/references/components/tool-descriptions.md +95 -0
  124. package/plugins/dsh/skills/sprint-flow/references/force-levels.md +204 -0
  125. package/plugins/dsh/skills/sprint-flow/references/orchestration-rules.md +236 -0
  126. package/plugins/dsh/skills/sprint-flow/references/phase-1-prep.md +294 -0
  127. package/plugins/dsh/skills/sprint-flow/references/phase-2-design.md +273 -0
  128. package/plugins/dsh/skills/sprint-flow/references/phase-3-build.md +348 -0
  129. package/plugins/dsh/skills/sprint-flow/references/phase-4-verify.md +225 -0
  130. package/plugins/dsh/skills/sprint-flow/references/phase-5-ship.md +222 -0
  131. package/plugins/dsh/skills/sprint-flow/references/phase-6-close.md +266 -0
  132. package/plugins/dsh/skills/sprint-flow/references/phase-overview.md +486 -0
  133. package/plugins/dsh/skills/sprint-flow/scripts/verify-sprint-state.sh +38 -0
  134. package/plugins/dsh/skills/sprint-flow/templates/auto-estimate-learning-log.md +136 -0
  135. package/plugins/dsh/skills/sprint-flow/templates/auto-estimate-output-template.md +110 -0
  136. package/plugins/dsh/skills/sprint-flow/templates/emergent-issues-template.md +120 -0
  137. package/plugins/dsh/skills/sprint-flow/templates/pain-document-template.md +115 -0
  138. package/plugins/dsh/skills/sprint-flow/templates/sprint-progress-template.md +140 -0
  139. package/plugins/dsh/skills/sprint-flow/templates/sprint-summary-template.md +121 -0
  140. package/plugins/dsh/skills/sprint-flow/tools.md +29 -0
  141. package/plugins/dsh/skills/test-driven-development/SKILL.md +371 -0
  142. package/plugins/dsh/skills/test-driven-development/testing-anti-patterns.md +299 -0
  143. package/plugins/dsh/skills/test-specification-alignment/AGENTS.md +56 -0
  144. package/plugins/dsh/skills/test-specification-alignment/SKILL.md +205 -0
  145. package/plugins/dsh/skills/test-specification-alignment/references/alignment-verification-algorithm.md +493 -0
  146. package/plugins/dsh/skills/test-specification-alignment/references/phase2-constraint-enforcement.md +431 -0
  147. package/plugins/dsh/skills/test-specification-alignment/references/specification-format.md +348 -0
  148. package/plugins/dsh/skills/to-issues/SKILL.md +277 -0
  149. package/plugins/dsh/src/command.test.ts +102 -0
  150. package/plugins/dsh/src/command.ts +75 -0
  151. package/plugins/dsh/src/contract.test.ts +62 -0
  152. package/plugins/dsh/src/gate-runner.test.ts +100 -0
  153. package/plugins/dsh/src/gate-runner.ts +58 -0
  154. package/plugins/dsh/src/index.test.ts +97 -0
  155. package/plugins/dsh/src/index.ts +94 -0
  156. package/plugins/dsh/src/skills.test.ts +58 -0
  157. package/plugins/dsh/tsconfig.build.json +13 -0
  158. package/plugins/dsh/tsconfig.json +19 -0
  159. package/plugins/dsh/vitest.config.ts +8 -0
  160. package/plugins/opencode/package.json +1 -1
  161. package/plugins/opencode/scripts/prepack.cjs +1 -0
  162. package/plugins/opencode/skills/clipboard-vision/SKILL.md +47 -0
  163. package/plugins/opencode/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  164. package/plugins/opencode/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  165. package/plugins/opencode/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  166. package/plugins/opencode/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  167. package/plugins/opencode/skills/clipboard-vision/describe-clipboard.ps1 +115 -0
  168. package/plugins/opencode/skills/clipboard-vision/describe-clipboard.sh +161 -0
  169. package/plugins/opencode/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  170. package/plugins/opencode/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  171. package/plugins/opencode/skills/delphi-review/.delphi-config.json.example +24 -27
  172. package/plugins/opencode/skills/delphi-review/AGENTS.md +13 -12
  173. package/plugins/opencode/skills/delphi-review/INSTALL.md +15 -17
  174. package/plugins/opencode/skills/delphi-review/SKILL.md +30 -29
  175. package/plugins/opencode/skills/delphi-review/opencode.json.delphi.example +6 -10
  176. package/plugins/opencode/skills/delphi-review/references/code-walkthrough.md +33 -49
  177. package/plugins/opencode/skills/delphi-review/references/requirements.md +66 -54
  178. package/plugins/opencode/skills/delphi-review/references/round-templates.md +7 -7
  179. package/plugins/opencode/skills/sprint-flow/AGENTS.md +5 -5
  180. package/plugins/opencode/skills/sprint-flow/SKILL.md +4 -4
  181. package/plugins/opencode/skills/sprint-flow/references/components/skill-invocations.md +2 -2
  182. package/plugins/opencode/skills/sprint-flow/references/force-levels.md +37 -35
  183. package/plugins/opencode/skills/sprint-flow/references/orchestration-rules.md +1 -1
  184. package/plugins/opencode/skills/sprint-flow/references/phase-1-prep.md +1 -1
  185. package/plugins/opencode/skills/sprint-flow/references/phase-2-design.md +24 -14
  186. package/plugins/opencode/skills/sprint-flow/references/phase-4-verify.md +6 -6
  187. package/plugins/opencode/skills/sprint-flow/references/phase-overview.md +2 -2
  188. package/plugins/opencode/skills/test-specification-alignment/AGENTS.md +4 -4
  189. package/plugins/qoder/plugin.json +1 -1
  190. package/plugins/qoder/skills/clipboard-vision/SKILL.md +47 -0
  191. package/plugins/qoder/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  192. package/plugins/qoder/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  193. package/plugins/qoder/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  194. package/plugins/qoder/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  195. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/SKILL.md +47 -0
  196. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  197. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  198. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  199. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  200. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  201. package/plugins/qoder/skills/clipboard-vision/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  202. package/plugins/qoder/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  203. package/plugins/qoder/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  204. package/plugins/qoder/skills/delphi-review/.delphi-config.json.example +3 -11
  205. package/plugins/qoder/skills/delphi-review/AGENTS.md +15 -17
  206. package/plugins/qoder/skills/delphi-review/INSTALL.md +12 -12
  207. package/plugins/qoder/skills/delphi-review/SKILL.md +58 -25
  208. package/plugins/qoder/skills/delphi-review/opencode.json.delphi.example +1 -1
  209. package/plugins/qoder/skills/delphi-review/references/code-walkthrough.md +33 -49
  210. package/plugins/qoder/skills/sprint-flow/AGENTS.md +5 -5
  211. package/plugins/qoder/skills/sprint-flow/SKILL.md +2 -2
  212. package/plugins/qoder/skills/sprint-flow/references/force-levels.md +38 -35
  213. package/plugins/qoder/skills/sprint-flow/references/phase-1-prep.md +1 -1
  214. package/plugins/qoder/skills/sprint-flow/references/phase-2-design.md +48 -6
  215. package/plugins/qoder/skills/sprint-flow/references/phase-4-verify.md +5 -6
  216. package/plugins/qoder/skills/test-specification-alignment/AGENTS.md +4 -4
  217. package/principles/AGENTS.md +4 -4
  218. package/scripts/__tests__/sync-package-content.test.js +30 -0
  219. package/scripts/delphi-external-review.cjs +194 -63
  220. package/scripts/sync-package-content.js +9 -2
  221. package/skills/clipboard-vision/SKILL.md +47 -0
  222. package/skills/clipboard-vision/__tests__/clipboard-vision-distribution.test.cjs +65 -0
  223. package/skills/clipboard-vision/__tests__/clipboard-vision-security.test.cjs +185 -0
  224. package/skills/clipboard-vision/__tests__/clipboard-vision.Tests.ps1 +138 -0
  225. package/skills/clipboard-vision/__tests__/clipboard-vision.test.cjs +273 -0
  226. package/skills/clipboard-vision/describe-clipboard.ps1 +115 -0
  227. package/skills/clipboard-vision/describe-clipboard.sh +161 -0
  228. package/skills/clipboard-vision/scripts/clipboard-vision.ps1 +86 -0
  229. package/skills/clipboard-vision/scripts/clipboard-vision.sh +137 -0
  230. package/skills/delphi-review/.delphi-config.json.example +24 -27
  231. package/skills/delphi-review/AGENTS.md +13 -12
  232. package/skills/delphi-review/INSTALL.md +15 -17
  233. package/skills/delphi-review/SKILL.md +30 -29
  234. package/skills/delphi-review/opencode.json.delphi.example +6 -10
  235. package/skills/delphi-review/references/code-walkthrough.md +33 -49
  236. package/skills/delphi-review/references/requirements.md +66 -54
  237. package/skills/delphi-review/references/round-templates.md +7 -7
  238. package/skills/sprint-flow/AGENTS.md +5 -5
  239. package/skills/sprint-flow/SKILL.md +4 -4
  240. package/skills/sprint-flow/references/components/skill-invocations.md +2 -2
  241. package/skills/sprint-flow/references/force-levels.md +37 -35
  242. package/skills/sprint-flow/references/orchestration-rules.md +1 -1
  243. package/skills/sprint-flow/references/phase-1-prep.md +1 -1
  244. package/skills/sprint-flow/references/phase-2-design.md +24 -14
  245. package/skills/sprint-flow/references/phase-4-verify.md +6 -6
  246. package/skills/sprint-flow/references/phase-overview.md +2 -2
  247. package/skills/test-specification-alignment/AGENTS.md +4 -4
  248. package/sprint-gate.sh +291 -0
@@ -0,0 +1,493 @@
1
+ # 对齐验证算法
2
+
3
+ ## 核心原则
4
+
5
+ **使用确定性算法验证对齐,不依赖 LLM 语义理解。**
6
+
7
+ ---
8
+
9
+ ## 算法实现
10
+
11
+ ### Step 1: 解析 Specification
12
+
13
+ ```typescript
14
+ interface SpecificationMap {
15
+ requirements: Requirement[];
16
+ designDecisions: DesignDecision[];
17
+ apiContracts: ApiContract[];
18
+ }
19
+
20
+ interface Requirement {
21
+ id: string; // REQ-AUTH-001
22
+ description: string;
23
+ acceptanceCriteria: string[]; // ["AC-AUTH-001-01", "AC-AUTH-001-02"]
24
+ edgeCases: string[];
25
+ securityConsiderations: string[];
26
+ }
27
+
28
+ function parseSpecification(specPath: string): SpecificationMap {
29
+ // 使用 YAML parser,不依赖 LLM
30
+ const content = fs.readFileSync(specPath, 'utf-8');
31
+ const spec = yaml.parse(content);
32
+
33
+ return {
34
+ requirements: spec.requirements.map(r => ({
35
+ id: r.id,
36
+ description: r.description,
37
+ acceptanceCriteria: r.acceptance_criteria?.map(ac => ac.id) || [],
38
+ edgeCases: r.edge_cases || [],
39
+ securityConsiderations: r.security_considerations || []
40
+ })),
41
+ designDecisions: spec.design_decisions?.map(d => d.id) || [],
42
+ apiContracts: spec.api_contracts?.map(a => a.endpoint) || []
43
+ };
44
+ }
45
+ ```
46
+
47
+ ---
48
+
49
+ ### Step 2: 解析测试文件
50
+
51
+ ```typescript
52
+ interface TestMap {
53
+ tests: TestCase[];
54
+ totalTests: number;
55
+ totalAssertions: number;
56
+ }
57
+
58
+ interface TestCase {
59
+ name: string;
60
+ file: string;
61
+ requirementId: string | null; // 从 @test 标签提取
62
+ intent: string | null; // 从 @intent 标签提取
63
+ covers: string[]; // 从 @covers 标签提取
64
+ edgeCases: string[]; // 从 @edge_cases 标签提取
65
+ assertions: number; // 断言数量
66
+ }
67
+
68
+ function parseTestFiles(testPaths: string[]): TestMap {
69
+ const tests: TestCase[] = [];
70
+ let totalAssertions = 0;
71
+
72
+ for (const path of testPaths) {
73
+ const content = fs.readFileSync(path, 'utf-8');
74
+
75
+ // 根据文件类型选择解析器
76
+ if (path.endsWith('.ts') || path.endsWith('.js')) {
77
+ const result = parseTypeScriptTests(content, path);
78
+ tests.push(...result.tests);
79
+ totalAssertions += result.assertions;
80
+ } else if (path.endsWith('.py')) {
81
+ const result = parsePythonTests(content, path);
82
+ tests.push(...result.tests);
83
+ totalAssertions += result.assertions;
84
+ } else if (path.endsWith('.go')) {
85
+ const result = parseGoTests(content, path);
86
+ tests.push(...result.tests);
87
+ totalAssertions += result.assertions;
88
+ }
89
+ }
90
+
91
+ return { tests, totalTests: tests.length, totalAssertions };
92
+ }
93
+
94
+ // TypeScript/JavaScript 解析
95
+ function parseTypeScriptTests(content: string, filePath: string): { tests: TestCase[], assertions: number } {
96
+ const tests: TestCase[] = [];
97
+ let totalAssertions = 0;
98
+
99
+ // 使用正则提取 JSDoc 注释和测试函数
100
+ const testPattern = /\/\*\*([\s\S]*?)\*\/\s*(test|it|describe)\s*\(\s*['"`]([^'"`]+)['"`]/g;
101
+
102
+ let match;
103
+ while ((match = testPattern.exec(content)) !== null) {
104
+ const jsdoc = match[1];
105
+ const testName = match[3];
106
+
107
+ // 提取标签
108
+ const requirementId = extractTag(jsdoc, '@test');
109
+ const intent = extractTag(jsdoc, '@intent');
110
+ const covers = extractAllTags(jsdoc, '@covers');
111
+ const edgeCases = extractAllTags(jsdoc, '@edge_cases');
112
+
113
+ // 计算断言数量 (expect, assert, should)
114
+ const testBody = extractTestBody(content, match.index);
115
+ const assertions = countAssertions(testBody);
116
+ totalAssertions += assertions;
117
+
118
+ tests.push({
119
+ name: testName,
120
+ file: filePath,
121
+ requirementId,
122
+ intent,
123
+ covers,
124
+ edgeCases,
125
+ assertions
126
+ });
127
+ }
128
+
129
+ return { tests, assertions: totalAssertions };
130
+ }
131
+
132
+ // Python 解析
133
+ function parsePythonTests(content: string, filePath: string): { tests: TestCase[], assertions: number } {
134
+ const tests: TestCase[] = [];
135
+ let totalAssertions = 0;
136
+
137
+ // 提取注释和测试函数
138
+ const testPattern = /(# @test\s+(\S+)[\s\S]*?)def\s+(test_\w+)/g;
139
+
140
+ let match;
141
+ while ((match = testPattern.exec(content)) !== null) {
142
+ const comments = match[1];
143
+ const testName = match[3];
144
+
145
+ const requirementId = extractTagFromComment(comments, '@test');
146
+ const intent = extractTagFromComment(comments, '@intent');
147
+ const covers = extractAllTagsFromComment(comments, '@covers');
148
+ const edgeCases = extractAllTagsFromComment(comments, '@edge_cases');
149
+
150
+ // 计算 assert 语句数量
151
+ const testBody = extractPythonFunctionBody(content, match.index);
152
+ const assertions = (testBody.match(/\bassert\b/g) || []).length;
153
+ totalAssertions += assertions;
154
+
155
+ tests.push({
156
+ name: testName,
157
+ file: filePath,
158
+ requirementId,
159
+ intent,
160
+ covers,
161
+ edgeCases,
162
+ assertions
163
+ });
164
+ }
165
+
166
+ return { tests, assertions: totalAssertions };
167
+ }
168
+
169
+ // Go 解析
170
+ function parseGoTests(content: string, filePath: string): { tests: TestCase[], assertions: number } {
171
+ const tests: TestCase[] = [];
172
+ let totalAssertions = 0;
173
+
174
+ // 提取注释和测试函数
175
+ const testPattern = /(\/\/ @test\s+(\S+)[\s\S]*?)func\s+(Test_\w+)/g;
176
+
177
+ let match;
178
+ while ((match = testPattern.exec(content)) !== null) {
179
+ const comments = match[1];
180
+ const testName = match[3];
181
+
182
+ const requirementId = extractTagFromGoComment(comments, '@test');
183
+ const intent = extractTagFromGoComment(comments, '@intent');
184
+ const covers = extractAllTagsFromGoComment(comments, '@covers');
185
+ const edgeCases = extractAllTagsFromGoComment(comments, '@edge_cases');
186
+
187
+ // 计算 assert/t.Require 数量
188
+ const testBody = extractGoFunctionBody(content, match.index);
189
+ const assertions = (testBody.match(/\bassert\.|t\.Require|t\.Error/g) || []).length;
190
+ totalAssertions += assertions;
191
+
192
+ tests.push({
193
+ name: testName,
194
+ file: filePath,
195
+ requirementId,
196
+ intent,
197
+ covers,
198
+ edgeCases,
199
+ assertions
200
+ });
201
+ }
202
+
203
+ return { tests, assertions: totalAssertions };
204
+ }
205
+ ```
206
+
207
+ ---
208
+
209
+ ### Step 3: 对齐验证
210
+
211
+ ```typescript
212
+ interface AlignmentReport {
213
+ score: number;
214
+ issues: AlignmentIssue[];
215
+ coverage: CoverageReport;
216
+ passed: boolean;
217
+ }
218
+
219
+ interface AlignmentIssue {
220
+ type: 'MISSING_TEST' | 'MISSING_AC_COVERAGE' | 'MISSING_EDGE_CASE'
221
+ | 'MISSING_INTENT' | 'INCORRECT_INTENT' | 'LOW_ASSERTIONS';
222
+ severity: 'Critical' | 'Major' | 'Minor';
223
+ requirementId?: string;
224
+ acId?: string;
225
+ testId?: string;
226
+ message: string;
227
+ }
228
+
229
+ interface CoverageReport {
230
+ requirementsCovered: number;
231
+ requirementsTotal: number;
232
+ acCovered: number;
233
+ acTotal: number;
234
+ edgeCasesCovered: number;
235
+ edgeCasesTotal: number;
236
+ testsWithIntent: number;
237
+ testsTotal: number;
238
+ }
239
+
240
+ function verifyAlignment(
241
+ specMap: SpecificationMap,
242
+ testMap: TestMap
243
+ ): AlignmentReport {
244
+ const issues: AlignmentIssue[] = [];
245
+ const coverage: CoverageReport = {
246
+ requirementsCovered: 0,
247
+ requirementsTotal: specMap.requirements.length,
248
+ acCovered: 0,
249
+ acTotal: 0,
250
+ edgeCasesCovered: 0,
251
+ edgeCasesTotal: 0,
252
+ testsWithIntent: 0,
253
+ testsTotal: testMap.totalTests
254
+ };
255
+
256
+ // 规则 1: 每个 requirement 必须有测试
257
+ for (const req of specMap.requirements) {
258
+ const hasTest = testMap.tests.some(t => t.requirementId === req.id);
259
+ if (!hasTest) {
260
+ issues.push({
261
+ type: 'MISSING_TEST',
262
+ severity: 'Critical',
263
+ requirementId: req.id,
264
+ message: `Requirement ${req.id} 没有对应的测试`
265
+ });
266
+ } else {
267
+ coverage.requirementsCovered++;
268
+ }
269
+
270
+ // 规则 2: 每个 AC 必须有断言覆盖
271
+ for (const acId of req.acceptanceCriteria) {
272
+ coverage.acTotal++;
273
+ const hasCoverage = testMap.tests.some(t => t.covers.includes(acId));
274
+ if (!hasCoverage) {
275
+ issues.push({
276
+ type: 'MISSING_AC_COVERAGE',
277
+ severity: 'Major',
278
+ requirementId: req.id,
279
+ acId,
280
+ message: `Acceptance Criteria ${acId} 没有被测试覆盖`
281
+ });
282
+ } else {
283
+ coverage.acCovered++;
284
+ }
285
+ }
286
+
287
+ // 规则 3: 每个 edge case 应该有测试
288
+ for (const edgeCase of req.edgeCases) {
289
+ coverage.edgeCasesTotal++;
290
+ const hasTest = testMap.tests.some(t => t.edgeCases.includes(edgeCase));
291
+ if (!hasTest) {
292
+ issues.push({
293
+ type: 'MISSING_EDGE_CASE',
294
+ severity: 'Minor',
295
+ requirementId: req.id,
296
+ message: `Edge case "${edgeCase}" 没有对应的测试`
297
+ });
298
+ } else {
299
+ coverage.edgeCasesCovered++;
300
+ }
301
+ }
302
+ }
303
+
304
+ // 规则 4: 每个测试必须有意图声明
305
+ for (const test of testMap.tests) {
306
+ if (!test.intent) {
307
+ issues.push({
308
+ type: 'MISSING_INTENT',
309
+ severity: 'Major',
310
+ testId: test.name,
311
+ message: `Test ${test.name} 缺少 @intent 声明`
312
+ });
313
+ } else {
314
+ coverage.testsWithIntent++;
315
+ }
316
+
317
+ // 规则 5: 每个测试应该有足够的断言
318
+ if (test.assertions < 2) {
319
+ issues.push({
320
+ type: 'LOW_ASSERTIONS',
321
+ severity: 'Minor',
322
+ testId: test.name,
323
+ message: `Test ${test.name} 只有 ${test.assertions} 个断言,可能不够充分`
324
+ });
325
+ }
326
+ }
327
+
328
+ // 计算分数
329
+ const score = calculateScore(issues, coverage);
330
+
331
+ return {
332
+ score,
333
+ issues,
334
+ coverage,
335
+ passed: score >= 80
336
+ };
337
+ }
338
+ ```
339
+
340
+ ---
341
+
342
+ ### Step 4: 分数计算
343
+
344
+ ```typescript
345
+ function calculateScore(issues: AlignmentIssue[], coverage: CoverageReport): number {
346
+ // 维度权重
347
+ const weights = {
348
+ requirementCoverage: 30,
349
+ acCoverage: 25,
350
+ testIntent: 20,
351
+ edgeCaseCoverage: 15,
352
+ testDataValidity: 10
353
+ };
354
+
355
+ // 计算各维度得分
356
+ const reqScore = (coverage.requirementsCovered / coverage.requirementsTotal) * weights.requirementCoverage;
357
+
358
+ const acScore = coverage.acTotal > 0
359
+ ? (coverage.acCovered / coverage.acTotal) * weights.acCoverage
360
+ : weights.acCoverage; // 如果没有 AC,给满分
361
+
362
+ const intentScore = (coverage.testsWithIntent / coverage.testsTotal) * weights.testIntent;
363
+
364
+ const edgeScore = coverage.edgeCasesTotal > 0
365
+ ? (coverage.edgeCasesCovered / coverage.edgeCasesTotal) * weights.edgeCaseCoverage
366
+ : weights.edgeCaseCoverage;
367
+
368
+ // 测试数据有效性基于断言数量
369
+ const avgAssertions = coverage.testsTotal > 0
370
+ ? /* 需要从 testMap 传入 */ 3
371
+ : 0;
372
+ const dataScore = avgAssertions >= 3 ? weights.testDataValidity
373
+ : (avgAssertions / 3) * weights.testDataValidity;
374
+
375
+ // 扣除 Critical/Major 问题分数
376
+ const criticalCount = issues.filter(i => i.severity === 'Critical').length;
377
+ const majorCount = issues.filter(i => i.severity === 'Major').length;
378
+
379
+ const penalty = criticalCount * 5 + majorCount * 2;
380
+
381
+ const totalScore = Math.max(0, reqScore + acScore + intentScore + edgeScore + dataScore - penalty);
382
+
383
+ return Math.round(totalScore * 10) / 10;
384
+ }
385
+ ```
386
+
387
+ ---
388
+
389
+ ## 辅助函数
390
+
391
+ ```typescript
392
+ // 从 JSDoc 提取单个标签
393
+ function extractTag(jsdoc: string, tag: string): string | null {
394
+ const pattern = new RegExp(`@${tag}\\s+(.+?)(?:\\n|\\*/)`);
395
+ const match = jsdoc.match(pattern);
396
+ return match ? match[1].trim() : null;
397
+ }
398
+
399
+ // 从 JSDoc 提取所有标签
400
+ function extractAllTags(jsdoc: string, tag: string): string[] {
401
+ const pattern = new RegExp(`@${tag}\\s+([\\w\\-,\\s]+?)(?:\\n|\\*)`, 'g');
402
+ const matches = [];
403
+ let match;
404
+ while ((match = pattern.exec(jsdoc)) !== null) {
405
+ // 处理逗号分隔的多个值
406
+ const values = match[1].split(',').map(v => v.trim());
407
+ matches.push(...values);
408
+ }
409
+ return matches;
410
+ }
411
+
412
+ // 计算断言数量
413
+ function countAssertions(code: string): number {
414
+ // 匹配 expect(), assert, should
415
+ const patterns = [
416
+ /expect\s*\(/g,
417
+ /assert\.\w+\(/g,
418
+ /\.should\./g
419
+ ];
420
+
421
+ let count = 0;
422
+ for (const pattern of patterns) {
423
+ const matches = code.match(pattern);
424
+ if (matches) count += matches.length;
425
+ }
426
+ return count;
427
+ }
428
+ ```
429
+
430
+ ---
431
+
432
+ ## Legacy 模式算法
433
+
434
+ ```typescript
435
+ function verifyLegacyMode(testMap: TestMap): AlignmentReport {
436
+ // Legacy 模式只验证测试覆盖率,不验证对齐
437
+
438
+ const issues: AlignmentIssue[] = [];
439
+
440
+ // 检查是否有跳过的测试
441
+ const skippedTests = testMap.tests.filter(t => t.name.includes('.skip') || t.name.includes('xit'));
442
+ if (skippedTests.length > 0) {
443
+ issues.push({
444
+ type: 'SKIPPED_TESTS',
445
+ severity: 'Major',
446
+ message: `发现 ${skippedTests.length} 个跳过的测试`
447
+ });
448
+ }
449
+
450
+ // 计算基本分数
451
+ const score = testMap.totalTests > 0 && testMap.totalAssertions > 0 ? 80 : 0;
452
+
453
+ return {
454
+ score,
455
+ issues,
456
+ coverage: {
457
+ requirementsCovered: 0,
458
+ requirementsTotal: 0,
459
+ acCovered: 0,
460
+ acTotal: 0,
461
+ edgeCasesCovered: 0,
462
+ edgeCasesTotal: 0,
463
+ testsWithIntent: testMap.tests.filter(t => t.intent).length,
464
+ testsTotal: testMap.totalTests
465
+ },
466
+ passed: score >= 80 && issues.filter(i => i.severity === 'Critical').length === 0
467
+ };
468
+ }
469
+ ```
470
+
471
+ ---
472
+
473
+ ## 性能优化
474
+
475
+ ```typescript
476
+ // 缓存已解析的文件
477
+ const parseCache = new Map<string, { mtime: number, result: any }>();
478
+
479
+ function parseWithCache<T>(path: string, parser: (content: string) => T): T {
480
+ const stat = fs.statSync(path);
481
+ const cached = parseCache.get(path);
482
+
483
+ if (cached && cached.mtime === stat.mtimeMs) {
484
+ return cached.result;
485
+ }
486
+
487
+ const content = fs.readFileSync(path, 'utf-8');
488
+ const result = parser(content);
489
+
490
+ parseCache.set(path, { mtime: stat.mtimeMs, result });
491
+ return result;
492
+ }
493
+ ```