@dommaker/harness 1.1.0 → 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 (349) hide show
  1. package/CHANGELOG.md +19 -2
  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.d.ts.map +1 -1
  21. package/dist/cli/commands/status.js +2 -11
  22. package/dist/cli/commands/status.js.map +1 -1
  23. package/dist/context/index.d.ts +9 -6
  24. package/dist/context/index.d.ts.map +1 -1
  25. package/dist/context/index.js +18 -20
  26. package/dist/context/index.js.map +1 -1
  27. package/dist/core/constraints/capabilities-parser.d.ts +3 -2
  28. package/dist/core/constraints/capabilities-parser.d.ts.map +1 -1
  29. package/dist/core/constraints/capabilities-parser.js +25 -47
  30. package/dist/core/constraints/capabilities-parser.js.map +1 -1
  31. package/dist/core/constraints/checker.d.ts +32 -33
  32. package/dist/core/constraints/checker.d.ts.map +1 -1
  33. package/dist/core/constraints/checker.js +38 -128
  34. package/dist/core/constraints/checker.js.map +1 -1
  35. package/dist/core/constraints/checkers/index.d.ts +2 -1
  36. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  37. package/dist/core/constraints/checkers/index.js +3 -0
  38. package/dist/core/constraints/checkers/index.js.map +1 -1
  39. package/dist/core/constraints/checkers/types.d.ts +25 -0
  40. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  41. package/dist/core/constraints/checkers/types.js +24 -0
  42. package/dist/core/constraints/checkers/types.js.map +1 -1
  43. package/dist/core/constraints/definitions/guidelines.d.ts.map +1 -1
  44. package/dist/core/constraints/definitions/guidelines.js +0 -2
  45. package/dist/core/constraints/definitions/guidelines.js.map +1 -1
  46. package/dist/core/constraints/definitions/prompts.d.ts.map +1 -1
  47. package/dist/core/constraints/definitions/prompts.js +0 -5
  48. package/dist/core/constraints/definitions/prompts.js.map +1 -1
  49. package/dist/core/constraints/index.d.ts +1 -2
  50. package/dist/core/constraints/index.d.ts.map +1 -1
  51. package/dist/core/constraints/index.js +1 -7
  52. package/dist/core/constraints/index.js.map +1 -1
  53. package/dist/core/constraints/usage-report.d.ts +1 -2
  54. package/dist/core/constraints/usage-report.d.ts.map +1 -1
  55. package/dist/core/constraints/usage-report.js +2 -5
  56. package/dist/core/constraints/usage-report.js.map +1 -1
  57. package/dist/core/effective-constraints.d.ts +24 -4
  58. package/dist/core/effective-constraints.d.ts.map +1 -1
  59. package/dist/core/effective-constraints.js +28 -7
  60. package/dist/core/effective-constraints.js.map +1 -1
  61. package/dist/core/effective-set.d.ts +30 -0
  62. package/dist/core/effective-set.d.ts.map +1 -0
  63. package/dist/core/effective-set.js +35 -0
  64. package/dist/core/effective-set.js.map +1 -0
  65. package/dist/core/index.d.ts +13 -6
  66. package/dist/core/index.d.ts.map +1 -1
  67. package/dist/core/index.js +44 -21
  68. package/dist/core/index.js.map +1 -1
  69. package/dist/core/project-config-loader.d.ts +3 -6
  70. package/dist/core/project-config-loader.d.ts.map +1 -1
  71. package/dist/core/project-config-loader.js +47 -61
  72. package/dist/core/project-config-loader.js.map +1 -1
  73. package/dist/failure/constraint-handler.d.ts +1 -1
  74. package/dist/failure/constraint-handler.js +1 -1
  75. package/dist/gates/checker-gate.d.ts +1 -4
  76. package/dist/gates/checker-gate.d.ts.map +1 -1
  77. package/dist/gates/checker-gate.js +3 -11
  78. package/dist/gates/checker-gate.js.map +1 -1
  79. package/dist/gates/definitions.d.ts +9 -38
  80. package/dist/gates/definitions.d.ts.map +1 -1
  81. package/dist/gates/definitions.js +24 -13
  82. package/dist/gates/definitions.js.map +1 -1
  83. package/dist/gates/effective-gates.d.ts.map +1 -1
  84. package/dist/gates/effective-gates.js +14 -18
  85. package/dist/gates/effective-gates.js.map +1 -1
  86. package/dist/gates/index.d.ts +1 -1
  87. package/dist/gates/index.d.ts.map +1 -1
  88. package/dist/gates/index.js.map +1 -1
  89. package/dist/hooks/bootstrap.d.ts.map +1 -1
  90. package/dist/hooks/bootstrap.js +0 -3
  91. package/dist/hooks/bootstrap.js.map +1 -1
  92. package/dist/index.d.ts +43 -53
  93. package/dist/index.d.ts.map +1 -1
  94. package/dist/index.js +180 -138
  95. package/dist/index.js.map +1 -1
  96. package/dist/knowledge/query.d.ts +15 -0
  97. package/dist/knowledge/query.d.ts.map +1 -1
  98. package/dist/knowledge/query.js +23 -0
  99. package/dist/knowledge/query.js.map +1 -1
  100. package/dist/monitoring/analyzer-base.d.ts +0 -4
  101. package/dist/monitoring/analyzer-base.d.ts.map +1 -1
  102. package/dist/monitoring/analyzer-base.js +0 -21
  103. package/dist/monitoring/analyzer-base.js.map +1 -1
  104. package/dist/monitoring/index.d.ts +6 -12
  105. package/dist/monitoring/index.d.ts.map +1 -1
  106. package/dist/monitoring/index.js +13 -29
  107. package/dist/monitoring/index.js.map +1 -1
  108. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  109. package/dist/monitoring/trace-analyzer.js +2 -68
  110. package/dist/monitoring/trace-analyzer.js.map +1 -1
  111. package/dist/monitoring/traces.d.ts +2 -6
  112. package/dist/monitoring/traces.d.ts.map +1 -1
  113. package/dist/monitoring/traces.js +0 -14
  114. package/dist/monitoring/traces.js.map +1 -1
  115. package/dist/presets/index.d.ts +2 -2
  116. package/dist/presets/index.d.ts.map +1 -1
  117. package/dist/presets/index.js +3 -4
  118. package/dist/presets/index.js.map +1 -1
  119. package/dist/presets/standard.d.ts +10 -22
  120. package/dist/presets/standard.d.ts.map +1 -1
  121. package/dist/presets/standard.js +15 -75
  122. package/dist/presets/standard.js.map +1 -1
  123. package/dist/types/constraint.d.ts +1 -29
  124. package/dist/types/constraint.d.ts.map +1 -1
  125. package/dist/types/constraint.js +1 -1
  126. package/dist/types/constraint.js.map +1 -1
  127. package/dist/types/index.d.ts +0 -3
  128. package/dist/types/index.d.ts.map +1 -1
  129. package/dist/types/index.js +0 -4
  130. package/dist/types/index.js.map +1 -1
  131. package/dist/types/project-config.d.ts +4 -8
  132. package/dist/types/project-config.d.ts.map +1 -1
  133. package/dist/types/trace.d.ts +9 -22
  134. package/dist/types/trace.d.ts.map +1 -1
  135. package/package.json +2 -2
  136. package/src/CONTEXT.md +5 -7
  137. package/src/__tests__/checker-extra.test.ts +80 -139
  138. package/src/__tests__/checker.test.ts +0 -376
  139. package/src/__tests__/project-config-loader-extra.test.ts +42 -29
  140. package/src/__tests__/public-exports.test.ts +138 -0
  141. package/src/__tests__/trace-analyzer-extra.test.ts +6 -86
  142. package/src/__tests__/trace-analyzer.test.ts +4 -5
  143. package/src/__tests__/trace-collector.test.ts +0 -11
  144. package/src/__tests__/traces.test.ts +3 -22
  145. package/src/cli/commands/CONTEXT.md +2 -2
  146. package/src/cli/commands/__tests__/check-skip-output.test.ts +10 -7
  147. package/src/cli/commands/__tests__/check.test.ts +29 -69
  148. package/src/cli/commands/__tests__/constraints-report.test.ts +1 -1
  149. package/src/cli/commands/__tests__/knowledge.test.ts +90 -1
  150. package/src/cli/commands/__tests__/registry.test.ts +8 -6
  151. package/src/cli/commands/__tests__/status-extra.test.ts +6 -28
  152. package/src/cli/commands/__tests__/status.test.ts +6 -21
  153. package/src/cli/commands/check.ts +8 -34
  154. package/src/cli/commands/definitions.ts +2 -0
  155. package/src/cli/commands/init.ts +6 -37
  156. package/src/cli/commands/knowledge.ts +1 -16
  157. package/src/cli/commands/report.ts +0 -2
  158. package/src/cli/commands/status.ts +2 -12
  159. package/src/context/index.ts +29 -6
  160. package/src/core/CONTEXT.md +4 -3
  161. package/src/core/__tests__/effective-set.test.ts +80 -0
  162. package/src/core/constraints/capabilities-parser.ts +43 -49
  163. package/src/core/constraints/checker.ts +56 -147
  164. package/src/core/constraints/checkers/index.ts +2 -1
  165. package/src/core/constraints/checkers/types.ts +42 -0
  166. package/src/core/constraints/definitions/guidelines.ts +0 -2
  167. package/src/core/constraints/definitions/prompts.ts +0 -5
  168. package/src/core/constraints/index.ts +2 -17
  169. package/src/core/constraints/usage-report.ts +5 -8
  170. package/src/core/effective-constraints.ts +35 -7
  171. package/src/core/effective-set.ts +56 -0
  172. package/src/core/index.ts +80 -6
  173. package/src/core/project-config-loader.ts +53 -68
  174. package/src/failure/CONTEXT.md +1 -1
  175. package/src/failure/constraint-handler.ts +1 -1
  176. package/src/gates/CONTEXT.md +3 -3
  177. package/src/gates/checker-gate.ts +4 -12
  178. package/src/gates/definitions.ts +27 -50
  179. package/src/gates/effective-gates.ts +14 -21
  180. package/src/gates/index.ts +1 -1
  181. package/src/hooks/bootstrap.ts +0 -3
  182. package/src/index.ts +384 -137
  183. package/src/knowledge/CONTEXT.md +2 -2
  184. package/src/knowledge/__tests__/query.test.ts +64 -0
  185. package/src/knowledge/query.ts +28 -0
  186. package/src/monitoring/CONTEXT.md +7 -13
  187. package/src/monitoring/__tests__/traces.test.ts +0 -10
  188. package/src/monitoring/analyzer-base.ts +0 -22
  189. package/src/monitoring/index.ts +6 -12
  190. package/src/monitoring/trace-analyzer.ts +2 -73
  191. package/src/monitoring/traces.ts +2 -22
  192. package/src/presets/__tests__/standard.test.ts +48 -69
  193. package/src/presets/index.ts +3 -5
  194. package/src/presets/standard.ts +14 -79
  195. package/src/spec/CONTEXT.md +5 -13
  196. package/src/types/constraint.ts +1 -51
  197. package/src/types/index.ts +0 -12
  198. package/src/types/project-config.ts +4 -10
  199. package/src/types/trace.ts +9 -34
  200. package/dist/core/constraints/interceptor.d.ts +0 -38
  201. package/dist/core/constraints/interceptor.d.ts.map +0 -1
  202. package/dist/core/constraints/interceptor.js +0 -166
  203. package/dist/core/constraints/interceptor.js.map +0 -1
  204. package/dist/dashboard/data.d.ts +0 -31
  205. package/dist/dashboard/data.d.ts.map +0 -1
  206. package/dist/dashboard/data.js +0 -81
  207. package/dist/dashboard/data.js.map +0 -1
  208. package/dist/dashboard/index.d.ts +0 -4
  209. package/dist/dashboard/index.d.ts.map +0 -1
  210. package/dist/dashboard/index.js +0 -20
  211. package/dist/dashboard/index.js.map +0 -1
  212. package/dist/dashboard/stats.d.ts +0 -20
  213. package/dist/dashboard/stats.d.ts.map +0 -1
  214. package/dist/dashboard/stats.js +0 -115
  215. package/dist/dashboard/stats.js.map +0 -1
  216. package/dist/dashboard/types.d.ts +0 -110
  217. package/dist/dashboard/types.d.ts.map +0 -1
  218. package/dist/dashboard/types.js +0 -8
  219. package/dist/dashboard/types.js.map +0 -1
  220. package/dist/monitoring/constraint-doctor.d.ts +0 -82
  221. package/dist/monitoring/constraint-doctor.d.ts.map +0 -1
  222. package/dist/monitoring/constraint-doctor.js +0 -191
  223. package/dist/monitoring/constraint-doctor.js.map +0 -1
  224. package/dist/monitoring/diagnosis-rules.d.ts +0 -18
  225. package/dist/monitoring/diagnosis-rules.d.ts.map +0 -1
  226. package/dist/monitoring/diagnosis-rules.js +0 -119
  227. package/dist/monitoring/diagnosis-rules.js.map +0 -1
  228. package/dist/monitoring/knowledge-doctor.d.ts +0 -78
  229. package/dist/monitoring/knowledge-doctor.d.ts.map +0 -1
  230. package/dist/monitoring/knowledge-doctor.js +0 -266
  231. package/dist/monitoring/knowledge-doctor.js.map +0 -1
  232. package/dist/monitoring/knowledge-evolver.d.ts +0 -72
  233. package/dist/monitoring/knowledge-evolver.d.ts.map +0 -1
  234. package/dist/monitoring/knowledge-evolver.js +0 -205
  235. package/dist/monitoring/knowledge-evolver.js.map +0 -1
  236. package/dist/monitoring/performance-analyzer.d.ts +0 -92
  237. package/dist/monitoring/performance-analyzer.d.ts.map +0 -1
  238. package/dist/monitoring/performance-analyzer.js +0 -343
  239. package/dist/monitoring/performance-analyzer.js.map +0 -1
  240. package/dist/monitoring/performance-collector.d.ts +0 -103
  241. package/dist/monitoring/performance-collector.d.ts.map +0 -1
  242. package/dist/monitoring/performance-collector.js +0 -298
  243. package/dist/monitoring/performance-collector.js.map +0 -1
  244. package/dist/safety/index.d.ts +0 -6
  245. package/dist/safety/index.d.ts.map +0 -1
  246. package/dist/safety/index.js +0 -22
  247. package/dist/safety/index.js.map +0 -1
  248. package/dist/safety/input-guardrail.d.ts +0 -36
  249. package/dist/safety/input-guardrail.d.ts.map +0 -1
  250. package/dist/safety/input-guardrail.js +0 -118
  251. package/dist/safety/input-guardrail.js.map +0 -1
  252. package/dist/safety/output-guardrail.d.ts +0 -39
  253. package/dist/safety/output-guardrail.d.ts.map +0 -1
  254. package/dist/safety/output-guardrail.js +0 -147
  255. package/dist/safety/output-guardrail.js.map +0 -1
  256. package/dist/safety/sandbox.d.ts +0 -45
  257. package/dist/safety/sandbox.d.ts.map +0 -1
  258. package/dist/safety/sandbox.js +0 -134
  259. package/dist/safety/sandbox.js.map +0 -1
  260. package/dist/safety/tool-guardrail.d.ts +0 -51
  261. package/dist/safety/tool-guardrail.d.ts.map +0 -1
  262. package/dist/safety/tool-guardrail.js +0 -147
  263. package/dist/safety/tool-guardrail.js.map +0 -1
  264. package/dist/safety/types.d.ts +0 -104
  265. package/dist/safety/types.d.ts.map +0 -1
  266. package/dist/safety/types.js +0 -6
  267. package/dist/safety/types.js.map +0 -1
  268. package/dist/spec/annotation-checker.d.ts +0 -47
  269. package/dist/spec/annotation-checker.d.ts.map +0 -1
  270. package/dist/spec/annotation-checker.js +0 -279
  271. package/dist/spec/annotation-checker.js.map +0 -1
  272. package/dist/types/enforcement.d.ts +0 -42
  273. package/dist/types/enforcement.d.ts.map +0 -1
  274. package/dist/types/enforcement.js +0 -6
  275. package/dist/types/enforcement.js.map +0 -1
  276. package/dist/types/monitoring-types.d.ts +0 -53
  277. package/dist/types/monitoring-types.d.ts.map +0 -1
  278. package/dist/types/monitoring-types.js +0 -10
  279. package/dist/types/monitoring-types.js.map +0 -1
  280. package/dist/types/performance.d.ts +0 -204
  281. package/dist/types/performance.d.ts.map +0 -1
  282. package/dist/types/performance.js +0 -12
  283. package/dist/types/performance.js.map +0 -1
  284. package/dist/verification/index.d.ts +0 -4
  285. package/dist/verification/index.d.ts.map +0 -1
  286. package/dist/verification/index.js +0 -20
  287. package/dist/verification/index.js.map +0 -1
  288. package/dist/verification/loop.d.ts +0 -30
  289. package/dist/verification/loop.d.ts.map +0 -1
  290. package/dist/verification/loop.js +0 -114
  291. package/dist/verification/loop.js.map +0 -1
  292. package/dist/verification/rules-based.d.ts +0 -40
  293. package/dist/verification/rules-based.d.ts.map +0 -1
  294. package/dist/verification/rules-based.js +0 -130
  295. package/dist/verification/rules-based.js.map +0 -1
  296. package/dist/verification/types.d.ts +0 -69
  297. package/dist/verification/types.d.ts.map +0 -1
  298. package/dist/verification/types.js +0 -6
  299. package/dist/verification/types.js.map +0 -1
  300. package/src/__tests__/annotation-checker.test.ts +0 -183
  301. package/src/__tests__/constraint-doctor.test.ts +0 -271
  302. package/src/__tests__/doctor-extra.test.ts +0 -155
  303. package/src/__tests__/extend-exceptions.test.ts +0 -149
  304. package/src/__tests__/interceptor.test.ts +0 -89
  305. package/src/__tests__/performance-analyzer.test.ts +0 -499
  306. package/src/__tests__/performance-collector.test.ts +0 -276
  307. package/src/__tests__/presets.test.ts +0 -65
  308. package/src/core/constraints/__tests__/interceptor.test.ts +0 -253
  309. package/src/core/constraints/interceptor.ts +0 -214
  310. package/src/dashboard/CONTEXT.md +0 -21
  311. package/src/dashboard/__tests__/data.test.ts +0 -111
  312. package/src/dashboard/__tests__/stats.test.ts +0 -159
  313. package/src/dashboard/data.ts +0 -103
  314. package/src/dashboard/index.ts +0 -3
  315. package/src/dashboard/stats.ts +0 -127
  316. package/src/dashboard/types.ts +0 -130
  317. package/src/monitoring/__tests__/knowledge-doctor.test.ts +0 -278
  318. package/src/monitoring/__tests__/knowledge-evolver.test.ts +0 -368
  319. package/src/monitoring/__tests__/performance-analyzer.test.ts +0 -137
  320. package/src/monitoring/__tests__/performance-collector.test.ts +0 -331
  321. package/src/monitoring/constraint-doctor.ts +0 -239
  322. package/src/monitoring/diagnosis-rules.ts +0 -132
  323. package/src/monitoring/knowledge-doctor.ts +0 -322
  324. package/src/monitoring/knowledge-evolver.ts +0 -289
  325. package/src/monitoring/performance-analyzer.ts +0 -400
  326. package/src/monitoring/performance-collector.ts +0 -326
  327. package/src/safety/CONTEXT.md +0 -23
  328. package/src/safety/__tests__/input-guardrail.test.ts +0 -105
  329. package/src/safety/__tests__/output-guardrail.test.ts +0 -108
  330. package/src/safety/__tests__/sandbox.test.ts +0 -158
  331. package/src/safety/__tests__/tool-guardrail.test.ts +0 -127
  332. package/src/safety/index.ts +0 -5
  333. package/src/safety/input-guardrail.ts +0 -133
  334. package/src/safety/output-guardrail.ts +0 -170
  335. package/src/safety/sandbox.ts +0 -148
  336. package/src/safety/tool-guardrail.ts +0 -176
  337. package/src/safety/types.ts +0 -124
  338. package/src/spec/__tests__/annotation-checker.test.ts +0 -294
  339. package/src/spec/annotation-checker.ts +0 -320
  340. package/src/types/enforcement.ts +0 -48
  341. package/src/types/monitoring-types.ts +0 -68
  342. package/src/types/performance.ts +0 -295
  343. package/src/verification/CONTEXT.md +0 -23
  344. package/src/verification/__tests__/loop.test.ts +0 -303
  345. package/src/verification/__tests__/rules-based.test.ts +0 -240
  346. package/src/verification/index.ts +0 -3
  347. package/src/verification/loop.ts +0 -137
  348. package/src/verification/rules-based.ts +0 -152
  349. 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
- }