@dommaker/harness 1.1.1 → 1.2.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 (348) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +2 -4
  3. package/bin/harness.js +12 -37
  4. package/dist/cli/commands/check.d.ts +2 -2
  5. package/dist/cli/commands/check.d.ts.map +1 -1
  6. package/dist/cli/commands/check.js +7 -32
  7. package/dist/cli/commands/check.js.map +1 -1
  8. package/dist/cli/commands/definitions.d.ts +2 -0
  9. package/dist/cli/commands/definitions.d.ts.map +1 -1
  10. package/dist/cli/commands/definitions.js.map +1 -1
  11. package/dist/cli/commands/init.d.ts.map +1 -1
  12. package/dist/cli/commands/init.js +6 -37
  13. package/dist/cli/commands/init.js.map +1 -1
  14. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  15. package/dist/cli/commands/knowledge.js +1 -12
  16. package/dist/cli/commands/knowledge.js.map +1 -1
  17. package/dist/cli/commands/report.d.ts.map +1 -1
  18. package/dist/cli/commands/report.js +0 -2
  19. package/dist/cli/commands/report.js.map +1 -1
  20. package/dist/cli/commands/status.js +2 -2
  21. package/dist/cli/commands/status.js.map +1 -1
  22. package/dist/context/index.d.ts +9 -6
  23. package/dist/context/index.d.ts.map +1 -1
  24. package/dist/context/index.js +18 -20
  25. package/dist/context/index.js.map +1 -1
  26. package/dist/core/constraints/capabilities-parser.d.ts +3 -2
  27. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  28. package/dist/core/constraints/capabilities-parser.js +25 -47
  29. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  30. package/dist/core/constraints/checker.d.ts +29 -32
  31. package/dist/core/constraints/checker.d.ts.map +1 -1
  32. package/dist/core/constraints/checker.js +34 -126
  33. package/dist/core/constraints/checker.js.map +1 -1
  34. package/dist/core/constraints/checkers/index.d.ts +2 -1
  35. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  36. package/dist/core/constraints/checkers/index.js +3 -0
  37. package/dist/core/constraints/checkers/index.js.map +1 -1
  38. package/dist/core/constraints/checkers/types.d.ts +25 -0
  39. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  40. package/dist/core/constraints/checkers/types.js +24 -0
  41. package/dist/core/constraints/checkers/types.js.map +1 -1
  42. package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
  43. package/dist/core/constraints/definitions/guidelines.js +0 -2
  44. package/dist/core/constraints/definitions/guidelines.js.map +1 -1
  45. package/dist/core/constraints/definitions/prompts.d.ts.map +1 -1
  46. package/dist/core/constraints/definitions/prompts.js +0 -5
  47. package/dist/core/constraints/definitions/prompts.js.map +1 -1
  48. package/dist/core/constraints/index.d.ts +1 -2
  49. package/dist/core/constraints/index.d.ts.map +1 -1
  50. package/dist/core/constraints/index.js +1 -7
  51. package/dist/core/constraints/index.js.map +1 -1
  52. package/dist/core/constraints/usage-report.d.ts +1 -2
  53. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  54. package/dist/core/constraints/usage-report.js +2 -5
  55. package/dist/core/constraints/usage-report.js.map +1 -1
  56. package/dist/core/effective-constraints.d.ts +24 -4
  57. package/dist/core/effective-constraints.d.ts.map +1 -1
  58. package/dist/core/effective-constraints.js +28 -7
  59. package/dist/core/effective-constraints.js.map +1 -1
  60. package/dist/core/effective-set.d.ts +30 -0
  61. package/dist/core/effective-set.d.ts.map +1 -0
  62. package/dist/core/effective-set.js +35 -0
  63. package/dist/core/effective-set.js.map +1 -0
  64. package/dist/core/index.d.ts +13 -6
  65. package/dist/core/index.d.ts.map +1 -1
  66. package/dist/core/index.js +44 -21
  67. package/dist/core/index.js.map +1 -1
  68. package/dist/core/project-config-loader.d.ts +3 -6
  69. package/dist/core/project-config-loader.d.ts.map +1 -1
  70. package/dist/core/project-config-loader.js +47 -61
  71. package/dist/core/project-config-loader.js.map +1 -1
  72. package/dist/failure/constraint-handler.d.ts +1 -1
  73. package/dist/failure/constraint-handler.js +1 -1
  74. package/dist/gates/checker-gate.d.ts +1 -4
  75. package/dist/gates/checker-gate.d.ts.map +1 -1
  76. package/dist/gates/checker-gate.js +3 -11
  77. package/dist/gates/checker-gate.js.map +1 -1
  78. package/dist/gates/definitions.d.ts +9 -38
  79. package/dist/gates/definitions.d.ts.map +1 -1
  80. package/dist/gates/definitions.js +24 -13
  81. package/dist/gates/definitions.js.map +1 -1
  82. package/dist/gates/effective-gates.d.ts.map +1 -1
  83. package/dist/gates/effective-gates.js +14 -18
  84. package/dist/gates/effective-gates.js.map +1 -1
  85. package/dist/gates/index.d.ts +1 -1
  86. package/dist/gates/index.d.ts.map +1 -1
  87. package/dist/gates/index.js.map +1 -1
  88. package/dist/hooks/bootstrap.d.ts.map +1 -1
  89. package/dist/hooks/bootstrap.js +0 -3
  90. package/dist/hooks/bootstrap.js.map +1 -1
  91. package/dist/index.d.ts +43 -60
  92. package/dist/index.d.ts.map +1 -1
  93. package/dist/index.js +180 -143
  94. package/dist/index.js.map +1 -1
  95. package/dist/knowledge/query.d.ts +15 -0
  96. package/dist/knowledge/query.d.ts.map +1 -1
  97. package/dist/knowledge/query.js +23 -0
  98. package/dist/knowledge/query.js.map +1 -1
  99. package/dist/monitoring/analyzer-base.d.ts +0 -4
  100. package/dist/monitoring/analyzer-base.d.ts.map +1 -1
  101. package/dist/monitoring/analyzer-base.js +0 -21
  102. package/dist/monitoring/analyzer-base.js.map +1 -1
  103. package/dist/monitoring/index.d.ts +6 -12
  104. package/dist/monitoring/index.d.ts.map +1 -1
  105. package/dist/monitoring/index.js +13 -29
  106. package/dist/monitoring/index.js.map +1 -1
  107. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  108. package/dist/monitoring/trace-analyzer.js +2 -68
  109. package/dist/monitoring/trace-analyzer.js.map +1 -1
  110. package/dist/monitoring/traces.d.ts +0 -4
  111. package/dist/monitoring/traces.d.ts.map +1 -1
  112. package/dist/monitoring/traces.js +0 -14
  113. package/dist/monitoring/traces.js.map +1 -1
  114. package/dist/presets/index.d.ts +2 -2
  115. package/dist/presets/index.d.ts.map +1 -1
  116. package/dist/presets/index.js +3 -4
  117. package/dist/presets/index.js.map +1 -1
  118. package/dist/presets/standard.d.ts +10 -22
  119. package/dist/presets/standard.d.ts.map +1 -1
  120. package/dist/presets/standard.js +15 -75
  121. package/dist/presets/standard.js.map +1 -1
  122. package/dist/types/constraint.d.ts +1 -29
  123. package/dist/types/constraint.d.ts.map +1 -1
  124. package/dist/types/constraint.js +1 -1
  125. package/dist/types/constraint.js.map +1 -1
  126. package/dist/types/index.d.ts +0 -3
  127. package/dist/types/index.d.ts.map +1 -1
  128. package/dist/types/index.js +0 -4
  129. package/dist/types/index.js.map +1 -1
  130. package/dist/types/project-config.d.ts +4 -8
  131. package/dist/types/project-config.d.ts.map +1 -1
  132. package/dist/types/trace.d.ts +5 -18
  133. package/dist/types/trace.d.ts.map +1 -1
  134. package/package.json +2 -2
  135. package/src/CONTEXT.md +4 -5
  136. package/src/__tests__/checker-extra.test.ts +33 -139
  137. package/src/__tests__/checker.test.ts +0 -376
  138. package/src/__tests__/project-config-loader-extra.test.ts +42 -29
  139. package/src/__tests__/public-exports.test.ts +138 -0
  140. package/src/__tests__/trace-analyzer-extra.test.ts +6 -86
  141. package/src/__tests__/trace-analyzer.test.ts +4 -5
  142. package/src/__tests__/trace-collector.test.ts +0 -11
  143. package/src/__tests__/traces.test.ts +3 -22
  144. package/src/cli/commands/CONTEXT.md +2 -2
  145. package/src/cli/commands/__tests__/check-skip-output.test.ts +10 -7
  146. package/src/cli/commands/__tests__/check.test.ts +29 -69
  147. package/src/cli/commands/__tests__/constraints-report.test.ts +1 -1
  148. package/src/cli/commands/__tests__/knowledge.test.ts +90 -1
  149. package/src/cli/commands/__tests__/registry.test.ts +8 -6
  150. package/src/cli/commands/__tests__/status-extra.test.ts +6 -6
  151. package/src/cli/commands/__tests__/status.test.ts +6 -6
  152. package/src/cli/commands/check.ts +8 -34
  153. package/src/cli/commands/definitions.ts +2 -0
  154. package/src/cli/commands/init.ts +6 -37
  155. package/src/cli/commands/knowledge.ts +1 -16
  156. package/src/cli/commands/report.ts +0 -2
  157. package/src/cli/commands/status.ts +2 -2
  158. package/src/context/index.ts +29 -6
  159. package/src/core/CONTEXT.md +4 -3
  160. package/src/core/__tests__/effective-set.test.ts +80 -0
  161. package/src/core/constraints/capabilities-parser.ts +43 -49
  162. package/src/core/constraints/checker.ts +51 -145
  163. package/src/core/constraints/checkers/index.ts +2 -1
  164. package/src/core/constraints/checkers/types.ts +42 -0
  165. package/src/core/constraints/definitions/guidelines.ts +0 -2
  166. package/src/core/constraints/definitions/prompts.ts +0 -5
  167. package/src/core/constraints/index.ts +2 -17
  168. package/src/core/constraints/usage-report.ts +5 -8
  169. package/src/core/effective-constraints.ts +35 -7
  170. package/src/core/effective-set.ts +56 -0
  171. package/src/core/index.ts +80 -6
  172. package/src/core/project-config-loader.ts +53 -68
  173. package/src/failure/CONTEXT.md +1 -1
  174. package/src/failure/constraint-handler.ts +1 -1
  175. package/src/gates/CONTEXT.md +3 -3
  176. package/src/gates/checker-gate.ts +4 -12
  177. package/src/gates/definitions.ts +27 -50
  178. package/src/gates/effective-gates.ts +14 -21
  179. package/src/gates/index.ts +1 -1
  180. package/src/hooks/bootstrap.ts +0 -3
  181. package/src/index.ts +384 -148
  182. package/src/knowledge/CONTEXT.md +2 -2
  183. package/src/knowledge/__tests__/query.test.ts +64 -0
  184. package/src/knowledge/query.ts +28 -0
  185. package/src/monitoring/CONTEXT.md +7 -13
  186. package/src/monitoring/__tests__/traces.test.ts +0 -10
  187. package/src/monitoring/analyzer-base.ts +0 -22
  188. package/src/monitoring/index.ts +6 -12
  189. package/src/monitoring/trace-analyzer.ts +2 -73
  190. package/src/monitoring/traces.ts +0 -20
  191. package/src/presets/__tests__/standard.test.ts +48 -69
  192. package/src/presets/index.ts +3 -5
  193. package/src/presets/standard.ts +14 -79
  194. package/src/spec/CONTEXT.md +5 -13
  195. package/src/types/constraint.ts +1 -51
  196. package/src/types/index.ts +0 -12
  197. package/src/types/project-config.ts +4 -10
  198. package/src/types/trace.ts +5 -30
  199. package/dist/core/constraints/interceptor.d.ts +0 -39
  200. package/dist/core/constraints/interceptor.d.ts.map +0 -1
  201. package/dist/core/constraints/interceptor.js +0 -166
  202. package/dist/core/constraints/interceptor.js.map +0 -1
  203. package/dist/dashboard/data.d.ts +0 -31
  204. package/dist/dashboard/data.d.ts.map +0 -1
  205. package/dist/dashboard/data.js +0 -81
  206. package/dist/dashboard/data.js.map +0 -1
  207. package/dist/dashboard/index.d.ts +0 -4
  208. package/dist/dashboard/index.d.ts.map +0 -1
  209. package/dist/dashboard/index.js +0 -20
  210. package/dist/dashboard/index.js.map +0 -1
  211. package/dist/dashboard/stats.d.ts +0 -20
  212. package/dist/dashboard/stats.d.ts.map +0 -1
  213. package/dist/dashboard/stats.js +0 -115
  214. package/dist/dashboard/stats.js.map +0 -1
  215. package/dist/dashboard/types.d.ts +0 -110
  216. package/dist/dashboard/types.d.ts.map +0 -1
  217. package/dist/dashboard/types.js +0 -8
  218. package/dist/dashboard/types.js.map +0 -1
  219. package/dist/monitoring/constraint-doctor.d.ts +0 -76
  220. package/dist/monitoring/constraint-doctor.d.ts.map +0 -1
  221. package/dist/monitoring/constraint-doctor.js +0 -189
  222. package/dist/monitoring/constraint-doctor.js.map +0 -1
  223. package/dist/monitoring/diagnosis-rules.d.ts +0 -18
  224. package/dist/monitoring/diagnosis-rules.d.ts.map +0 -1
  225. package/dist/monitoring/diagnosis-rules.js +0 -119
  226. package/dist/monitoring/diagnosis-rules.js.map +0 -1
  227. package/dist/monitoring/knowledge-doctor.d.ts +0 -78
  228. package/dist/monitoring/knowledge-doctor.d.ts.map +0 -1
  229. package/dist/monitoring/knowledge-doctor.js +0 -266
  230. package/dist/monitoring/knowledge-doctor.js.map +0 -1
  231. package/dist/monitoring/knowledge-evolver.d.ts +0 -72
  232. package/dist/monitoring/knowledge-evolver.d.ts.map +0 -1
  233. package/dist/monitoring/knowledge-evolver.js +0 -205
  234. package/dist/monitoring/knowledge-evolver.js.map +0 -1
  235. package/dist/monitoring/performance-analyzer.d.ts +0 -92
  236. package/dist/monitoring/performance-analyzer.d.ts.map +0 -1
  237. package/dist/monitoring/performance-analyzer.js +0 -343
  238. package/dist/monitoring/performance-analyzer.js.map +0 -1
  239. package/dist/monitoring/performance-collector.d.ts +0 -103
  240. package/dist/monitoring/performance-collector.d.ts.map +0 -1
  241. package/dist/monitoring/performance-collector.js +0 -298
  242. package/dist/monitoring/performance-collector.js.map +0 -1
  243. package/dist/safety/index.d.ts +0 -6
  244. package/dist/safety/index.d.ts.map +0 -1
  245. package/dist/safety/index.js +0 -22
  246. package/dist/safety/index.js.map +0 -1
  247. package/dist/safety/input-guardrail.d.ts +0 -36
  248. package/dist/safety/input-guardrail.d.ts.map +0 -1
  249. package/dist/safety/input-guardrail.js +0 -118
  250. package/dist/safety/input-guardrail.js.map +0 -1
  251. package/dist/safety/output-guardrail.d.ts +0 -39
  252. package/dist/safety/output-guardrail.d.ts.map +0 -1
  253. package/dist/safety/output-guardrail.js +0 -147
  254. package/dist/safety/output-guardrail.js.map +0 -1
  255. package/dist/safety/sandbox.d.ts +0 -45
  256. package/dist/safety/sandbox.d.ts.map +0 -1
  257. package/dist/safety/sandbox.js +0 -134
  258. package/dist/safety/sandbox.js.map +0 -1
  259. package/dist/safety/tool-guardrail.d.ts +0 -51
  260. package/dist/safety/tool-guardrail.d.ts.map +0 -1
  261. package/dist/safety/tool-guardrail.js +0 -147
  262. package/dist/safety/tool-guardrail.js.map +0 -1
  263. package/dist/safety/types.d.ts +0 -104
  264. package/dist/safety/types.d.ts.map +0 -1
  265. package/dist/safety/types.js +0 -6
  266. package/dist/safety/types.js.map +0 -1
  267. package/dist/spec/annotation-checker.d.ts +0 -47
  268. package/dist/spec/annotation-checker.d.ts.map +0 -1
  269. package/dist/spec/annotation-checker.js +0 -279
  270. package/dist/spec/annotation-checker.js.map +0 -1
  271. package/dist/types/enforcement.d.ts +0 -42
  272. package/dist/types/enforcement.d.ts.map +0 -1
  273. package/dist/types/enforcement.js +0 -6
  274. package/dist/types/enforcement.js.map +0 -1
  275. package/dist/types/monitoring-types.d.ts +0 -53
  276. package/dist/types/monitoring-types.d.ts.map +0 -1
  277. package/dist/types/monitoring-types.js +0 -10
  278. package/dist/types/monitoring-types.js.map +0 -1
  279. package/dist/types/performance.d.ts +0 -204
  280. package/dist/types/performance.d.ts.map +0 -1
  281. package/dist/types/performance.js +0 -12
  282. package/dist/types/performance.js.map +0 -1
  283. package/dist/verification/index.d.ts +0 -4
  284. package/dist/verification/index.d.ts.map +0 -1
  285. package/dist/verification/index.js +0 -20
  286. package/dist/verification/index.js.map +0 -1
  287. package/dist/verification/loop.d.ts +0 -30
  288. package/dist/verification/loop.d.ts.map +0 -1
  289. package/dist/verification/loop.js +0 -114
  290. package/dist/verification/loop.js.map +0 -1
  291. package/dist/verification/rules-based.d.ts +0 -40
  292. package/dist/verification/rules-based.d.ts.map +0 -1
  293. package/dist/verification/rules-based.js +0 -130
  294. package/dist/verification/rules-based.js.map +0 -1
  295. package/dist/verification/types.d.ts +0 -69
  296. package/dist/verification/types.d.ts.map +0 -1
  297. package/dist/verification/types.js +0 -6
  298. package/dist/verification/types.js.map +0 -1
  299. package/src/__tests__/annotation-checker.test.ts +0 -183
  300. package/src/__tests__/constraint-doctor.test.ts +0 -271
  301. package/src/__tests__/doctor-extra.test.ts +0 -155
  302. package/src/__tests__/extend-exceptions.test.ts +0 -149
  303. package/src/__tests__/interceptor.test.ts +0 -89
  304. package/src/__tests__/performance-analyzer.test.ts +0 -499
  305. package/src/__tests__/performance-collector.test.ts +0 -276
  306. package/src/__tests__/presets.test.ts +0 -65
  307. package/src/core/constraints/__tests__/interceptor.test.ts +0 -267
  308. package/src/core/constraints/interceptor.ts +0 -217
  309. package/src/dashboard/CONTEXT.md +0 -21
  310. package/src/dashboard/__tests__/data.test.ts +0 -111
  311. package/src/dashboard/__tests__/stats.test.ts +0 -159
  312. package/src/dashboard/data.ts +0 -103
  313. package/src/dashboard/index.ts +0 -3
  314. package/src/dashboard/stats.ts +0 -127
  315. package/src/dashboard/types.ts +0 -130
  316. package/src/monitoring/__tests__/knowledge-doctor.test.ts +0 -278
  317. package/src/monitoring/__tests__/knowledge-evolver.test.ts +0 -368
  318. package/src/monitoring/__tests__/performance-analyzer.test.ts +0 -137
  319. package/src/monitoring/__tests__/performance-collector.test.ts +0 -331
  320. package/src/monitoring/constraint-doctor.ts +0 -228
  321. package/src/monitoring/diagnosis-rules.ts +0 -132
  322. package/src/monitoring/knowledge-doctor.ts +0 -322
  323. package/src/monitoring/knowledge-evolver.ts +0 -289
  324. package/src/monitoring/performance-analyzer.ts +0 -400
  325. package/src/monitoring/performance-collector.ts +0 -326
  326. package/src/safety/CONTEXT.md +0 -23
  327. package/src/safety/__tests__/input-guardrail.test.ts +0 -105
  328. package/src/safety/__tests__/output-guardrail.test.ts +0 -108
  329. package/src/safety/__tests__/sandbox.test.ts +0 -158
  330. package/src/safety/__tests__/tool-guardrail.test.ts +0 -127
  331. package/src/safety/index.ts +0 -5
  332. package/src/safety/input-guardrail.ts +0 -133
  333. package/src/safety/output-guardrail.ts +0 -170
  334. package/src/safety/sandbox.ts +0 -148
  335. package/src/safety/tool-guardrail.ts +0 -176
  336. package/src/safety/types.ts +0 -124
  337. package/src/spec/__tests__/annotation-checker.test.ts +0 -294
  338. package/src/spec/annotation-checker.ts +0 -320
  339. package/src/types/enforcement.ts +0 -48
  340. package/src/types/monitoring-types.ts +0 -68
  341. package/src/types/performance.ts +0 -295
  342. package/src/verification/CONTEXT.md +0 -23
  343. package/src/verification/__tests__/loop.test.ts +0 -303
  344. package/src/verification/__tests__/rules-based.test.ts +0 -240
  345. package/src/verification/index.ts +0 -3
  346. package/src/verification/loop.ts +0 -137
  347. package/src/verification/rules-based.ts +0 -152
  348. package/src/verification/types.ts +0 -81
@@ -1,294 +0,0 @@
1
- /**
2
- * AnnotationChecker 测试
3
- */
4
-
5
- import { checkFile, checkDirectory, generateReport } from '../annotation-checker';
6
- import * as fs from 'fs';
7
-
8
- // Mock fs
9
- jest.mock('fs', () => ({
10
- readFileSync: jest.fn(),
11
- readdirSync: jest.fn(),
12
- statSync: jest.fn(),
13
- existsSync: jest.fn(),
14
- }));
15
-
16
- const mockFs = fs as jest.Mocked<typeof fs>;
17
-
18
- describe('AnnotationChecker', () => {
19
- const tempDir = '/test/project';
20
-
21
- beforeEach(() => {
22
- jest.clearAllMocks();
23
- });
24
-
25
- describe('checkFile', () => {
26
- it('应该检查有效的 JSDoc 注释', () => {
27
- mockFs.readFileSync.mockReturnValue(`
28
- /**
29
- * @spec AR-001
30
- * @implements feature-auth
31
- * @acceptance AC-001
32
- * @author test
33
- * @since 2026-04-28
34
- */
35
- export function auth() {}
36
- `);
37
-
38
- const result = checkFile('/test/file.ts');
39
-
40
- expect(result.annotations.length).toBe(1);
41
- expect(result.annotations[0]?.specId).toBe('AR-001');
42
- expect(result.annotations[0]?.implements).toContain('feature-auth');
43
- expect(result.annotations[0]?.acceptance).toContain('AC-001');
44
- expect(result.annotations[0]?.author).toBe('test');
45
- expect(result.annotations[0]?.since).toBe('2026-04-28');
46
- });
47
-
48
- it('应该检查行内注释', () => {
49
- mockFs.readFileSync.mockReturnValue(`
50
- // @spec AR-002
51
- const x = 1;
52
- `);
53
-
54
- const result = checkFile('/test/file.ts');
55
-
56
- expect(result.annotations.length).toBe(1);
57
- expect(result.annotations[0]?.specId).toBe('AR-002');
58
- expect(result.annotations[0]?.type).toBe('inline');
59
- });
60
-
61
- it('应该检测无效 Spec ID 格式', () => {
62
- mockFs.readFileSync.mockReturnValue(`
63
- /**
64
- * @spec INVALID-ID
65
- */
66
- export function test() {}
67
- `);
68
-
69
- const result = checkFile('/test/file.ts');
70
-
71
- expect(result.errors.length).toBeGreaterThan(0);
72
- expect(result.errors[0]?.code).toBe('INVALID_SPEC_FORMAT');
73
- });
74
-
75
- it('应该警告缺少 @implements', () => {
76
- mockFs.readFileSync.mockReturnValue(`
77
- /**
78
- * @spec AR-003
79
- */
80
- class MyClass {}
81
- `);
82
-
83
- const result = checkFile('/test/file.ts');
84
-
85
- expect(result.warnings.length).toBeGreaterThan(0);
86
- expect(result.warnings.some(w => w.code === 'MISSING_IMPLEMENTS')).toBe(true);
87
- });
88
-
89
- it('应该警告缺少 @acceptance', () => {
90
- mockFs.readFileSync.mockReturnValue(`
91
- /**
92
- * @spec AR-004
93
- * @implements feat
94
- */
95
- function myFunc() {}
96
- `);
97
-
98
- const result = checkFile('/test/file.ts');
99
-
100
- expect(result.warnings.some(w => w.code === 'MISSING_ACCEPTANCE')).toBe(true);
101
- });
102
-
103
- it('应该推断注释类型', () => {
104
- mockFs.readFileSync.mockReturnValue(`
105
- /**
106
- * @spec AR-005
107
- */
108
- class MyClass {}
109
- `);
110
-
111
- const result = checkFile('/test/file.ts');
112
-
113
- expect(result.annotations[0]?.type).toBeDefined();
114
- });
115
-
116
- it('应该推断 function 类型', () => {
117
- mockFs.readFileSync.mockReturnValue(`
118
- /**
119
- * @spec AR-006
120
- */
121
- async function myAsync() {}
122
- `);
123
-
124
- const result = checkFile('/test/file.ts');
125
-
126
- expect(result.annotations[0]?.type).toBeDefined();
127
- });
128
-
129
- it('应该推断 method 类型', () => {
130
- mockFs.readFileSync.mockReturnValue(`
131
- /**
132
- * @spec AR-007
133
- */
134
- myMethod() {}
135
- `);
136
-
137
- const result = checkFile('/test/file.ts');
138
-
139
- expect(result.annotations[0]?.type).toBeDefined();
140
- });
141
-
142
- it('应该检查公共导出缺少 @spec', () => {
143
- mockFs.readFileSync.mockReturnValue(`
144
- export class NoSpecClass {}
145
- export function noSpecFunc() {}
146
- `);
147
-
148
- const result = checkFile('/test/file.ts');
149
-
150
- // 公共导出可能触发 MISSING_SPEC 警告(通过 checkPublicExports)
151
- expect(result.warnings.length + result.errors.length).toBeGreaterThanOrEqual(0);
152
- });
153
- });
154
-
155
- describe('checkDirectory', () => {
156
- it('应该递归检查目录', () => {
157
- // 需要更完整的 mock,简化测试
158
- mockFs.readdirSync.mockReturnValue([] as any);
159
-
160
- const results = checkDirectory(tempDir);
161
-
162
- expect(Array.isArray(results)).toBe(true);
163
- });
164
-
165
- it('应该跳过 node_modules 和 dist', () => {
166
- mockFs.readFileSync.mockReturnValue('');
167
- mockFs.readdirSync.mockReturnValue([
168
- { name: 'node_modules', isDirectory: () => true, isFile: () => false },
169
- { name: 'dist', isDirectory: () => true, isFile: () => false },
170
- { name: 'file.ts', isDirectory: () => false, isFile: () => true },
171
- ] as any);
172
-
173
- const results = checkDirectory(tempDir);
174
-
175
- // 只收集 file.ts,跳过 node_modules 与 dist 目录
176
- expect(results).toHaveLength(1);
177
- expect(results[0].file).toBe('/test/project/file.ts');
178
- });
179
-
180
- it('应该处理空目录', () => {
181
- mockFs.readdirSync.mockReturnValue([]);
182
-
183
- const results = checkDirectory(tempDir);
184
-
185
- expect(results.length).toBe(0);
186
- });
187
- });
188
-
189
- describe('generateReport', () => {
190
- it('应该生成报告', () => {
191
- const results = [
192
- {
193
- valid: true,
194
- file: '/test/file.ts',
195
- annotations: [],
196
- errors: [],
197
- warnings: [],
198
- },
199
- {
200
- valid: false,
201
- file: '/test/bad.ts',
202
- annotations: [],
203
- errors: [{ line: 1, message: 'Error', code: 'INVALID_SPEC_FORMAT' as const }],
204
- warnings: [{ line: 2, message: 'Warning', code: 'MISSING_ACCEPTANCE' as const }],
205
- },
206
- ];
207
-
208
- const report = generateReport(results);
209
-
210
- expect(report).toContain('注释规范检查报告');
211
- expect(report).toContain('检查文件: 2');
212
- expect(report).toContain('通过: 1');
213
- expect(report).toContain('错误: 1');
214
- expect(report).toContain('警告: 1');
215
- });
216
-
217
- it('应该处理空结果', () => {
218
- const report = generateReport([]);
219
-
220
- expect(report).toContain('检查文件: 0');
221
- expect(report).toContain('通过: 0');
222
- });
223
-
224
- it('应该截断警告显示(最多5条)', () => {
225
- const results = [{
226
- valid: true,
227
- file: '/test/file.ts',
228
- annotations: [],
229
- errors: [],
230
- warnings: Array(10).fill({ line: 1, message: 'Warning', code: 'MISSING_ACCEPTANCE' as const }),
231
- }];
232
-
233
- const report = generateReport(results);
234
-
235
- expect(report).toContain('警告');
236
- });
237
- });
238
-
239
- describe('边缘情况', () => {
240
- it('应该处理空文件', () => {
241
- mockFs.readFileSync.mockReturnValue('');
242
-
243
- const result = checkFile('/test/empty.ts');
244
-
245
- expect(result.annotations.length).toBe(0);
246
- expect(result.errors.length).toBe(0);
247
- });
248
-
249
- it('应该处理多行 JSDoc', () => {
250
- mockFs.readFileSync.mockReturnValue(`
251
- /**
252
- * First line
253
- * Second line
254
- * @spec AR-009
255
- * Third line
256
- */
257
- export function multi() {}
258
- `);
259
-
260
- const result = checkFile('/test/file.ts');
261
-
262
- expect(result.annotations.length).toBe(1);
263
- expect(result.annotations[0]?.specId).toBe('AR-009');
264
- });
265
-
266
- it('应该处理多个 @implements', () => {
267
- mockFs.readFileSync.mockReturnValue(`
268
- /**
269
- * @spec AR-010
270
- * @implements feat1, feat2, feat3
271
- */
272
- export function multiImpl() {}
273
- `);
274
-
275
- const result = checkFile('/test/file.ts');
276
-
277
- expect(result.annotations[0]?.implements?.length).toBeGreaterThanOrEqual(3);
278
- });
279
-
280
- it('应该处理 @dependencies', () => {
281
- mockFs.readFileSync.mockReturnValue(`
282
- /**
283
- * @spec AR-011
284
- * @dependencies lib1, lib2
285
- */
286
- export function withDeps() {}
287
- `);
288
-
289
- const result = checkFile('/test/file.ts');
290
-
291
- expect(result.annotations[0]?.dependencies?.length).toBeGreaterThan(0);
292
- });
293
- });
294
- });
@@ -1,320 +0,0 @@
1
- /**
2
- * 代码注释规范检查器
3
- *
4
- * 检查代码中的 @spec 注释是否规范
5
- */
6
-
7
- import { readFileSync } from 'fs';
8
- import * as path from 'path';
9
- import { walkFiles } from '../utils/file-walk';
10
-
11
- export interface AnnotationCheckResult {
12
- valid: boolean;
13
- file: string;
14
- annotations: SpecAnnotation[];
15
- errors: AnnotationError[];
16
- warnings: AnnotationWarning[];
17
- }
18
-
19
- export interface SpecAnnotation {
20
- specId: string;
21
- implements?: string[];
22
- acceptance?: string[];
23
- dependencies?: string[];
24
- author?: string;
25
- since?: string;
26
- line: number;
27
- type: 'class' | 'method' | 'function' | 'inline';
28
- }
29
-
30
- export interface AnnotationError {
31
- line: number;
32
- message: string;
33
- code: 'MISSING_SPEC' | 'INVALID_SPEC_FORMAT' | 'SPEC_NOT_APPROVED' | 'IMPLEMENTS_NOT_FOUND';
34
- }
35
-
36
- export interface AnnotationWarning {
37
- line: number;
38
- message: string;
39
- code: 'MISSING_IMPLEMENTS' | 'MISSING_ACCEPTANCE' | 'MISSING_AUTHOR';
40
- }
41
-
42
- // Spec ID 格式: AR-XXX, WS-XXX, etc.
43
- const SPEC_ID_REGEX = /^[A-Z]{2,3}-\d{3}$/;
44
-
45
- /**
46
- * 检查单个文件
47
- */
48
- export function checkFile(filePath: string): AnnotationCheckResult {
49
- const content = readFileSync(filePath, 'utf-8');
50
- const lines = content.split('\n');
51
-
52
- const result: AnnotationCheckResult = {
53
- valid: true,
54
- file: filePath,
55
- annotations: [],
56
- errors: [],
57
- warnings: [],
58
- };
59
-
60
- let inJSDoc = false;
61
- let currentJSDoc: string[] = [];
62
- let currentJSDocStartLine = 0;
63
-
64
- for (let i = 0; i < lines.length; i++) {
65
- const line = lines[i].trim();
66
-
67
- // JSDoc 开始
68
- if (line.startsWith('/**')) {
69
- inJSDoc = true;
70
- currentJSDoc = [line];
71
- currentJSDocStartLine = i + 1;
72
- continue;
73
- }
74
-
75
- // JSDoc 结束
76
- if (inJSDoc && line.endsWith('*/')) {
77
- inJSDoc = false;
78
- currentJSDoc.push(line);
79
-
80
- const annotation = parseJSDoc(currentJSDoc, currentJSDocStartLine);
81
- if (annotation) {
82
- result.annotations.push(annotation);
83
- validateAnnotation(annotation, result);
84
- }
85
-
86
- currentJSDoc = [];
87
- continue;
88
- }
89
-
90
- // JSDoc 中间
91
- if (inJSDoc) {
92
- currentJSDoc.push(line);
93
- }
94
-
95
- // 行内注释 // @spec AR-001
96
- const inlineMatch = line.match(/\/\/\s*@spec\s+(\S+)/);
97
- if (inlineMatch) {
98
- const specId = inlineMatch[1];
99
- const annotation: SpecAnnotation = {
100
- specId,
101
- line: i + 1,
102
- type: 'inline',
103
- };
104
- result.annotations.push(annotation);
105
- validateAnnotation(annotation, result);
106
- }
107
- }
108
-
109
- // 检查公共导出是否有注释
110
- checkPublicExports(content, result);
111
-
112
- result.valid = result.errors.length === 0;
113
- return result;
114
- }
115
-
116
- /**
117
- * 解析 JSDoc 注释
118
- */
119
- function parseJSDoc(lines: string[], startLine: number): SpecAnnotation | null {
120
- const content = lines.join('\n');
121
-
122
- // 检查是否有 @spec
123
- const specMatch = content.match(/@spec\s+(\S+)/);
124
- if (!specMatch) {
125
- return null;
126
- }
127
-
128
- const specId = specMatch[1];
129
-
130
- // 解析其他标签
131
- const annotation: SpecAnnotation = {
132
- specId,
133
- line: startLine,
134
- type: inferType(content),
135
- };
136
-
137
- // @implements
138
- const implementsMatch = content.match(/@implements\s+([\w\-_,\s]+)/);
139
- if (implementsMatch) {
140
- annotation.implements = implementsMatch[1]
141
- .split(/[,\s]+/)
142
- .map(s => s.trim())
143
- .filter(Boolean);
144
- }
145
-
146
- // @acceptance
147
- const acceptanceMatch = content.match(/@acceptance\s+([\w\-_,\s]+)/);
148
- if (acceptanceMatch) {
149
- annotation.acceptance = acceptanceMatch[1]
150
- .split(/[,\s]+/)
151
- .map(s => s.trim())
152
- .filter(Boolean);
153
- }
154
-
155
- // @dependencies
156
- const depsMatch = content.match(/@dependencies\s+([\w\-_,\s/]+)/);
157
- if (depsMatch) {
158
- annotation.dependencies = depsMatch[1]
159
- .split(/[,\s]+/)
160
- .map(s => s.trim())
161
- .filter(Boolean);
162
- }
163
-
164
- // @author
165
- const authorMatch = content.match(/@author\s+(\S+)/);
166
- if (authorMatch) {
167
- annotation.author = authorMatch[1];
168
- }
169
-
170
- // @since
171
- const sinceMatch = content.match(/@since\s+(\d{4}-\d{2}-\d{2})/);
172
- if (sinceMatch) {
173
- annotation.since = sinceMatch[1];
174
- }
175
-
176
- return annotation;
177
- }
178
-
179
- /**
180
- * 推断注释类型
181
- */
182
- function inferType(content: string): SpecAnnotation['type'] {
183
- if (content.includes('class ')) return 'class';
184
- if (content.includes('async ') || content.includes('function ')) return 'function';
185
- return 'method';
186
- }
187
-
188
- /**
189
- * 验证注释
190
- */
191
- function validateAnnotation(
192
- annotation: SpecAnnotation,
193
- result: AnnotationCheckResult
194
- ): void {
195
- // 检查 Spec ID 格式
196
- if (!SPEC_ID_REGEX.test(annotation.specId)) {
197
- result.errors.push({
198
- line: annotation.line,
199
- message: `Invalid spec ID format: ${annotation.specId}`,
200
- code: 'INVALID_SPEC_FORMAT',
201
- });
202
- }
203
-
204
- // 警告:建议标记 @implements
205
- if (!annotation.implements && annotation.type !== 'inline') {
206
- result.warnings.push({
207
- line: annotation.line,
208
- message: 'Missing @implements tag',
209
- code: 'MISSING_IMPLEMENTS',
210
- });
211
- }
212
-
213
- // 警告:建议标记 @acceptance
214
- if (!annotation.acceptance) {
215
- result.warnings.push({
216
- line: annotation.line,
217
- message: 'Missing @acceptance tag',
218
- code: 'MISSING_ACCEPTANCE',
219
- });
220
- }
221
- }
222
-
223
- /**
224
- * 检查公共导出是否有注释
225
- */
226
- function checkPublicExports(content: string, result: AnnotationCheckResult): void {
227
- // 查找 export class/function 但没有 @spec 的
228
- const exportRegex = /^(export\s+(?:abstract\s+)?(?:class|interface|function|const|let|var))\s+(\w+)/gm;
229
- let match;
230
-
231
- while ((match = exportRegex.exec(content)) !== null) {
232
- const line = content.substring(0, match.index).split('\n').length;
233
- const name = match[2];
234
-
235
- // 检查前10行是否有 @spec
236
- const beforeContent = content.substring(
237
- Math.max(0, match.index - 500),
238
- match.index
239
- );
240
-
241
- if (!beforeContent.includes('@spec')) {
242
- result.warnings.push({
243
- line,
244
- message: `Public export "${name}" missing @spec annotation`,
245
- code: 'MISSING_SPEC' as any,
246
- });
247
- }
248
- }
249
- }
250
-
251
- /**
252
- * 递归获取目录下所有文件(收敛到 utils/file-walk 的 walkFiles,工单 O3)
253
- */
254
- function getFilesRecursively(dir: string, extensions: string[]): string[] {
255
- return walkFiles(dir, {
256
- skipDirs: ['node_modules', 'dist'],
257
- filter: (name) => extensions.includes(path.extname(name)) && !name.endsWith('.d.ts'),
258
- });
259
- }
260
-
261
- /**
262
- * 批量检查目录
263
- */
264
- export function checkDirectory(
265
- dir: string,
266
- options: { extensions?: string[] } = {}
267
- ): AnnotationCheckResult[] {
268
- const extensions = options.extensions || ['.ts', '.tsx', '.js', '.jsx'];
269
- const files = getFilesRecursively(dir, extensions);
270
-
271
- return files.map(file => checkFile(file));
272
- }
273
-
274
- /**
275
- * 生成报告
276
- */
277
- export function generateReport(results: AnnotationCheckResult[]): string {
278
- const totalFiles = results.length;
279
- const validFiles = results.filter(r => r.valid).length;
280
- const totalErrors = results.reduce((sum, r) => sum + r.errors.length, 0);
281
- const totalWarnings = results.reduce((sum, r) => sum + r.warnings.length, 0);
282
-
283
- let report = `## 注释规范检查报告\n\n`;
284
- report += `- 检查文件: ${totalFiles}\n`;
285
- report += `- 通过: ${validFiles}/${totalFiles}\n`;
286
- report += `- 错误: ${totalErrors}\n`;
287
- report += `- 警告: ${totalWarnings}\n\n`;
288
-
289
- if (totalErrors > 0) {
290
- report += `### ❌ 错误\n\n`;
291
- for (const result of results) {
292
- for (const error of result.errors) {
293
- report += `- ${result.file}:${error.line} - ${error.message}\n`;
294
- }
295
- }
296
- report += '\n';
297
- }
298
-
299
- if (totalWarnings > 0) {
300
- report += `### ⚠️ 警告\n\n`;
301
- for (const result of results) {
302
- for (const warning of result.warnings.slice(0, 5)) {
303
- report += `- ${result.file}:${warning.line} - ${warning.message}\n`;
304
- }
305
- }
306
- }
307
-
308
- return report;
309
- }
310
-
311
- // CLI 入口
312
- if (require.main === module) {
313
- const args = process.argv.slice(2);
314
- const dir = args[0] || process.cwd();
315
-
316
- const results = checkDirectory(dir);
317
- console.log(generateReport(results));
318
- const hasErrors = results.some(r => r.errors.length > 0);
319
- process.exit(hasErrors ? 1 : 0);
320
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * Enforcement 执行器类型定义
3
- */
4
-
5
- import type { Constraint, ConstraintContext } from './constraint';
6
-
7
- export type EnforcementId = string;
8
-
9
- export interface EnforcementContext extends ConstraintContext {
10
- enforcementId: EnforcementId;
11
- constraint: Constraint;
12
- params?: Record<string, any>;
13
- }
14
-
15
- export interface EnforcementResult {
16
- passed: boolean;
17
- evidence?: string;
18
- message?: string;
19
- error?: string;
20
- duration?: number;
21
- validatedAt?: Date;
22
- }
23
-
24
- export interface EnforcementExecutor {
25
- execute(context: EnforcementContext): Promise<EnforcementResult>;
26
- description?: string;
27
- supportedParams?: string[];
28
- }
29
-
30
- export interface EnforcementRegistration {
31
- id: EnforcementId;
32
- executor: EnforcementExecutor;
33
- registeredAt: Date;
34
- source?: string;
35
- }
36
-
37
- export interface InterceptionResult {
38
- passed: boolean;
39
- constraints: {
40
- constraint: Constraint;
41
- enforcementResult?: EnforcementResult;
42
- skipped?: boolean;
43
- skipReason?: string;
44
- }[];
45
- violations: Constraint[];
46
- message?: string;
47
- interceptedAt: Date;
48
- }