@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,400 +0,0 @@
1
- /**
2
- * Performance Analyzer
3
- *
4
- * 纯计算,零 Token 成本
5
- *
6
- * 功能:
7
- * - 统计汇总(每小时自动执行)
8
- * - 异常检测(每日检查)
9
- * - 趋势分析(对比上一周期)
10
- *
11
- * 与 TraceAnalyzer 的区别:
12
- * - TraceAnalyzer: 分析约束检查结果
13
- * - PerformanceAnalyzer: 分析操作耗时
14
- */
15
-
16
- import type {
17
- PerformanceTrace,
18
- PerformanceSummary,
19
- PerformanceAnomaly,
20
- PerformanceAnalyzerConfig,
21
- } from '../types/performance';
22
- import { PerformanceCollector } from './performance-collector';
23
- import {
24
- groupByKey,
25
- timeRangeOf,
26
- calcAverage,
27
- calcPercentile,
28
- splitByTime,
29
- writeSummaryJson,
30
- readSummaryJson,
31
- MIN_TREND_SAMPLES,
32
- } from './analyzer-base';
33
-
34
- /**
35
- * 默认配置
36
- */
37
- const DEFAULT_CONFIG: PerformanceAnalyzerConfig = {
38
- summaryFile: '.harness/logs/performance-summary.json',
39
- periodMs: 3600 * 1000, // 1 小时
40
- thresholds: {
41
- avgDuration: 5000, // 平均耗时 > 5s 视为异常
42
- exceededRate: 0.3, // 超阈值率 > 30% 视为异常
43
- errorRate: 0.1, // 错误率 > 10% 视为异常
44
- },
45
- };
46
-
47
- /**
48
- * Performance Analyzer
49
- *
50
- * 使用方式:
51
- * ```typescript
52
- * const analyzer = new PerformanceAnalyzer(collector);
53
- * const summaries = analyzer.summarize(traces);
54
- * const anomalies = analyzer.detectAnomalies(summaries);
55
- * ```
56
- */
57
- export class PerformanceAnalyzer {
58
- private config: PerformanceAnalyzerConfig;
59
- private collector: PerformanceCollector;
60
-
61
- constructor(collector: PerformanceCollector, config?: Partial<PerformanceAnalyzerConfig>) {
62
- this.collector = collector;
63
- this.config = { ...DEFAULT_CONFIG, ...config };
64
- }
65
-
66
- /**
67
- * 生成统计汇总
68
- *
69
- * 纯计算,零 Token 成本
70
- */
71
- summarize(traces: PerformanceTrace[]): PerformanceSummary[] {
72
- // 按操作类型分组
73
- const grouped = groupByKey(traces, t => t.operation);
74
-
75
- const summaries: PerformanceSummary[] = [];
76
-
77
- for (const [operation, group] of grouped) {
78
- // 计算时间范围
79
- const timeRange = timeRangeOf(group.map(t => t.timestamp));
80
-
81
- // 单次遍历计算核心统计
82
- const totalCalls = group.length;
83
- let okCount = 0, exceededCount = 0, errorCount = 0;
84
- for (const t of group) {
85
- if (t.result === 'ok') okCount++;
86
- else if (t.result === 'exceeded') exceededCount++;
87
- else if (t.result === 'error') errorCount++;
88
- }
89
-
90
- // 计算比率
91
- const okRate = totalCalls > 0 ? okCount / totalCalls : 0;
92
- const exceededRate = totalCalls > 0 ? exceededCount / totalCalls : 0;
93
- const errorRate = totalCalls > 0 ? errorCount / totalCalls : 0;
94
-
95
- // 计算耗时统计
96
- const durations = group.map(t => t.duration);
97
- const avgDuration = calcAverage(durations);
98
- const maxDuration = Math.max(...durations);
99
- const minDuration = Math.min(...durations);
100
- const p95Duration = calcPercentile(durations, 95);
101
- const p99Duration = calcPercentile(durations, 99);
102
-
103
- // 计算趋势
104
- const recentTrend = this.calculateTrend(group);
105
-
106
- summaries.push({
107
- operation,
108
- timeRange,
109
- totalCalls,
110
- okCount,
111
- exceededCount,
112
- errorCount,
113
- avgDuration,
114
- maxDuration,
115
- minDuration,
116
- p95Duration,
117
- p99Duration,
118
- okRate,
119
- exceededRate,
120
- errorRate,
121
- recentTrend,
122
- });
123
- }
124
-
125
- return summaries;
126
- }
127
-
128
- /**
129
- * 分析最近 N 小时的 traces
130
- */
131
- analyzeRecent(hours: number): PerformanceSummary[] {
132
- const traces = this.collector.readRecent(hours);
133
- return this.summarize(traces);
134
- }
135
-
136
- /**
137
- * 分析特定操作
138
- */
139
- analyzeOperation(operation: string): PerformanceSummary[] {
140
- const traces = this.collector.readByOperation(operation);
141
- return this.summarize(traces);
142
- }
143
-
144
- /**
145
- * 检测异常
146
- *
147
- * 基于阈值检测异常模式
148
- */
149
- detectAnomalies(summaries: PerformanceSummary[]): PerformanceAnomaly[] {
150
- const anomalies: PerformanceAnomaly[] = [];
151
- const thresholds = this.config.thresholds!;
152
-
153
- for (const summary of summaries) {
154
- // 检测高平均耗时
155
- if (summary.avgDuration > thresholds.avgDuration!) {
156
- anomalies.push({
157
- type: 'high_avg_duration',
158
- operation: summary.operation,
159
- message: `操作 ${summary.operation} 平均耗时 ${Math.round(summary.avgDuration)}ms,超过阈值 ${thresholds.avgDuration}ms`,
160
- data: {
161
- currentValue: summary.avgDuration,
162
- threshold: thresholds.avgDuration!,
163
- },
164
- detectedAt: Date.now(),
165
- suggestedAction: 'optimize',
166
- });
167
- }
168
-
169
- // 检测耗时趋势上升
170
- if (summary.recentTrend === 'rising') {
171
- anomalies.push({
172
- type: 'rising_duration',
173
- operation: summary.operation,
174
- message: `操作 ${summary.operation} 耗时趋势上升`,
175
- data: {
176
- currentValue: summary.avgDuration,
177
- threshold: 0,
178
- trend: 'rising',
179
- },
180
- detectedAt: Date.now(),
181
- suggestedAction: 'optimize',
182
- });
183
- }
184
-
185
- // 检测高超阈值率
186
- if (summary.exceededRate > thresholds.exceededRate!) {
187
- anomalies.push({
188
- type: 'high_exceeded_rate',
189
- operation: summary.operation,
190
- message: `操作 ${summary.operation} 超阈值率 ${Math.round(summary.exceededRate * 100)}%,超过阈值 ${thresholds.exceededRate! * 100}%`,
191
- data: {
192
- currentValue: summary.exceededRate,
193
- threshold: thresholds.exceededRate!,
194
- },
195
- detectedAt: Date.now(),
196
- suggestedAction: 'adjust_threshold',
197
- });
198
- }
199
-
200
- // 检测超阈值率上升
201
- if (summary.exceededRate > 0.1 && summary.recentTrend === 'rising') {
202
- anomalies.push({
203
- type: 'rising_exceeded_rate',
204
- operation: summary.operation,
205
- message: `操作 ${summary.operation} 超阈值率 ${Math.round(summary.exceededRate * 100)}% 且趋势上升`,
206
- data: {
207
- currentValue: summary.exceededRate,
208
- threshold: 0.1,
209
- trend: 'rising',
210
- },
211
- detectedAt: Date.now(),
212
- suggestedAction: 'optimize',
213
- });
214
- }
215
-
216
- // 检测高错误率
217
- if (summary.errorRate > thresholds.errorRate!) {
218
- anomalies.push({
219
- type: 'high_error_rate',
220
- operation: summary.operation,
221
- message: `操作 ${summary.operation} 错误率 ${Math.round(summary.errorRate * 100)}%,超过阈值 ${thresholds.errorRate! * 100}%`,
222
- data: {
223
- currentValue: summary.errorRate,
224
- threshold: thresholds.errorRate!,
225
- },
226
- detectedAt: Date.now(),
227
- suggestedAction: 'notify_user',
228
- });
229
- }
230
- }
231
-
232
- return anomalies;
233
- }
234
-
235
- /**
236
- * 对比上一周期
237
- *
238
- * 计算各指标的环比变化
239
- */
240
- compareWithPrevious(
241
- current: PerformanceSummary[],
242
- previous: PerformanceSummary[]
243
- ): PerformanceSummary[] {
244
- const previousMap = new Map(
245
- previous.map(s => [s.operation, s])
246
- );
247
-
248
- return current.map(summary => {
249
- const prev = previousMap.get(summary.operation);
250
-
251
- if (prev) {
252
- summary.changeFromLastPeriod = {
253
- avgDurationDelta: summary.avgDuration - prev.avgDuration,
254
- exceededRateDelta: summary.exceededRate - prev.exceededRate,
255
- };
256
- }
257
-
258
- return summary;
259
- });
260
- }
261
-
262
- /**
263
- * 计算趋势
264
- *
265
- * 对比前半段和后半段的平均耗时
266
- */
267
- private calculateTrend(traces: PerformanceTrace[]): 'stable' | 'rising' | 'falling' {
268
- if (traces.length < MIN_TREND_SAMPLES) {
269
- return 'stable';
270
- }
271
-
272
- // 分成前后两半(按时间排序)
273
- const [firstHalf, secondHalf] = splitByTime(traces);
274
-
275
- // 计算前半段和后半段的平均耗时
276
- const firstAvg = calcAverage(firstHalf.map(t => t.duration));
277
- const secondAvg = calcAverage(secondHalf.map(t => t.duration));
278
-
279
- // 计算变化率
280
- const delta = secondAvg - firstAvg;
281
- const changeRate = firstAvg > 0 ? delta / firstAvg : 0;
282
-
283
- // 判断趋势(变化 > 10% 才算显著)
284
- if (changeRate > 0.1) {
285
- return 'rising';
286
- } else if (changeRate < -0.1) {
287
- return 'falling';
288
- } else {
289
- return 'stable';
290
- }
291
- }
292
-
293
- /**
294
- * 保存汇总结果
295
- */
296
- saveSummary(summaries: PerformanceSummary[]): void {
297
- writeSummaryJson(this.config.summaryFile!, summaries);
298
- }
299
-
300
- /**
301
- * 加载上次汇总结果
302
- */
303
- loadSummary(): PerformanceSummary[] | null {
304
- return readSummaryJson<PerformanceSummary[]>(this.config.summaryFile!);
305
- }
306
-
307
- /**
308
- * 运行每小时汇总
309
- *
310
- * 自动执行,零 Token 成本
311
- */
312
- runHourlySummary(): PerformanceSummary[] {
313
- // 分析最近 1 小时
314
- const current = this.analyzeRecent(1);
315
-
316
- // 加载上次汇总,对比趋势
317
- const previous = this.loadSummary();
318
- if (previous) {
319
- this.compareWithPrevious(current, previous);
320
- }
321
-
322
- // 保存当前汇总
323
- this.saveSummary(current);
324
-
325
- return current;
326
- }
327
-
328
- /**
329
- * 运行每日异常检测
330
- *
331
- * 返回异常列表,用于触发优化
332
- */
333
- runDailyAnomalyCheck(): PerformanceAnomaly[] {
334
- // 分析最近 24 小时
335
- const summaries = this.analyzeRecent(24);
336
-
337
- // 检测异常
338
- const anomalies = this.detectAnomalies(summaries);
339
-
340
- return anomalies;
341
- }
342
-
343
- /**
344
- * 生成报告(文本格式)
345
- */
346
- generateReport(summaries: PerformanceSummary[], anomalies: PerformanceAnomaly[]): string {
347
- const lines: string[] = [];
348
-
349
- lines.push('# Performance Report');
350
- lines.push(`Generated: ${new Date().toISOString()}`);
351
- lines.push('');
352
-
353
- // 汇总部分
354
- lines.push('## Operation Summaries');
355
- lines.push('');
356
-
357
- for (const summary of summaries) {
358
- const trendEmoji = {
359
- rising: '📈',
360
- falling: '📉',
361
- stable: '➡️',
362
- }[summary.recentTrend];
363
-
364
- lines.push(`**${summary.operation}** ${trendEmoji}`);
365
- lines.push(` - Calls: ${summary.totalCalls}`);
366
- lines.push(` - Avg: ${Math.round(summary.avgDuration)}ms`);
367
- lines.push(` - P95: ${Math.round(summary.p95Duration)}ms`);
368
- lines.push(` - P99: ${Math.round(summary.p99Duration)}ms`);
369
- lines.push(` - OK: ${Math.round(summary.okRate * 100)}%`);
370
- lines.push(` - Exceeded: ${Math.round(summary.exceededRate * 100)}%`);
371
- lines.push(` - Errors: ${Math.round(summary.errorRate * 100)}%`);
372
- lines.push('');
373
- }
374
-
375
- // 异常部分
376
- if (anomalies.length > 0) {
377
- lines.push('## Anomalies Detected');
378
- lines.push('');
379
-
380
- for (const anomaly of anomalies) {
381
- lines.push(`⚠️ **${anomaly.type}**: ${anomaly.operation}`);
382
- lines.push(` - ${anomaly.message}`);
383
- lines.push(` - Suggested: ${anomaly.suggestedAction}`);
384
- lines.push('');
385
- }
386
- } else {
387
- lines.push('## No Anomalies Detected ✅');
388
- }
389
-
390
- return lines.join('\n');
391
- }
392
- }
393
-
394
- /**
395
- * 创建分析器(使用全局收集器)
396
- */
397
- export function createPerformanceAnalyzer(config?: Partial<PerformanceAnalyzerConfig>): PerformanceAnalyzer {
398
- const collector = new PerformanceCollector();
399
- return new PerformanceAnalyzer(collector, config);
400
- }
@@ -1,326 +0,0 @@
1
- /**
2
- * Performance Collector
3
- *
4
- * 轻量设计,零 Token 成本
5
- *
6
- * 功能:
7
- * - 记录操作耗时(追加写入)
8
- * - 批量读取 traces(按时间范围过滤)
9
- * - 文件滚动(防止文件过大)
10
- *
11
- * 与 TraceCollector 的区别:
12
- * - TraceCollector: 记录约束检查结果
13
- * - PerformanceCollector: 记录操作耗时
14
- */
15
-
16
- import * as fs from 'fs';
17
- import * as path from 'path';
18
- import type {
19
- PerformanceTrace,
20
- PerformanceTraceFilter,
21
- PerformanceCollectorConfig,
22
- } from '../types/performance';
23
-
24
- /**
25
- * 默认配置
26
- */
27
- const DEFAULT_CONFIG: PerformanceCollectorConfig = {
28
- logFile: '.harness/logs/performance.log',
29
- maxFileSize: 10 * 1024 * 1024, // 10MB
30
- enabled: true,
31
- };
32
-
33
- /**
34
- * Performance Collector
35
- *
36
- * 使用方式:
37
- * ```typescript
38
- * const collector = new PerformanceCollector();
39
- * collector.recordOk('extract', 150);
40
- * collector.recordExceeded('invokeSkillAgent', 35000, 30000);
41
- * ```
42
- */
43
- export class PerformanceCollector {
44
- private config: PerformanceCollectorConfig;
45
- private logFile: string;
46
-
47
- constructor(config?: Partial<PerformanceCollectorConfig>) {
48
- this.config = { ...DEFAULT_CONFIG, ...config };
49
- this.logFile = this.config.logFile!;
50
- this.ensureDirectory();
51
- }
52
-
53
- /**
54
- * 确保日志目录存在
55
- */
56
- private ensureDirectory(): void {
57
- const dir = path.dirname(this.logFile);
58
- if (!fs.existsSync(dir)) {
59
- fs.mkdirSync(dir, { recursive: true });
60
- }
61
- }
62
-
63
- /**
64
- * 记录一条性能数据
65
- *
66
- * 轻量操作:
67
- * - 追加写入(不读取现有内容)
68
- * - 单行 JSON(便于批量处理)
69
- * - 零 Token 成本
70
- */
71
- record(trace: PerformanceTrace): void {
72
- if (!this.config.enabled) return;
73
-
74
- // 检查文件大小,必要时滚动
75
- this.checkFileSize();
76
-
77
- // 追加写入
78
- const line = JSON.stringify(trace);
79
- fs.appendFileSync(this.logFile, line + '\n', 'utf-8');
80
- }
81
-
82
- /**
83
- * 快捷方法:记录正常执行
84
- */
85
- recordOk(
86
- operation: string,
87
- duration: number,
88
- metadata?: Record<string, unknown>
89
- ): void {
90
- this.record({
91
- operation,
92
- timestamp: Date.now(),
93
- duration,
94
- result: 'ok',
95
- metadata,
96
- });
97
- }
98
-
99
- /**
100
- * 快捷方法:记录超阈值
101
- */
102
- recordExceeded(
103
- operation: string,
104
- duration: number,
105
- threshold: number,
106
- metadata?: Record<string, unknown>
107
- ): void {
108
- this.record({
109
- operation,
110
- timestamp: Date.now(),
111
- duration,
112
- result: 'exceeded',
113
- threshold,
114
- metadata,
115
- });
116
- }
117
-
118
- /**
119
- * 快捷方法:记录错误
120
- */
121
- recordError(
122
- operation: string,
123
- duration: number,
124
- error: Error | string,
125
- metadata?: Record<string, unknown>
126
- ): void {
127
- this.record({
128
- operation,
129
- timestamp: Date.now(),
130
- duration,
131
- result: 'error',
132
- metadata: {
133
- ...metadata,
134
- error: error instanceof Error ? error.message : error,
135
- },
136
- });
137
- }
138
-
139
- /**
140
- * 批量读取 traces
141
- *
142
- * 支持过滤条件:
143
- * - 时间范围
144
- * - 操作类型
145
- * - 结果类型
146
- */
147
- read(filter?: PerformanceTraceFilter): PerformanceTrace[] {
148
- if (!fs.existsSync(this.logFile)) {
149
- return [];
150
- }
151
-
152
- const content = fs.readFileSync(this.logFile, 'utf-8');
153
- const lines = content.split('\n').filter(l => l.trim());
154
-
155
- let traces = lines.map(line => JSON.parse(line) as PerformanceTrace);
156
-
157
- // 应用过滤条件
158
- if (filter) {
159
- traces = this.applyFilter(traces, filter);
160
- }
161
-
162
- return traces;
163
- }
164
-
165
- /**
166
- * 读取最近 N 小时的 traces
167
- */
168
- readRecent(hours: number): PerformanceTrace[] {
169
- const start = Date.now() - hours * 3600 * 1000;
170
- return this.read({ timeRange: { start, end: Date.now() } });
171
- }
172
-
173
- /**
174
- * 读取特定操作的 traces
175
- */
176
- readByOperation(operation: string): PerformanceTrace[] {
177
- return this.read({ operation });
178
- }
179
-
180
- /**
181
- * 应用过滤条件
182
- */
183
- private applyFilter(traces: PerformanceTrace[], filter: PerformanceTraceFilter): PerformanceTrace[] {
184
- return traces.filter(trace => {
185
- // 操作类型
186
- if (filter.operation && trace.operation !== filter.operation) {
187
- return false;
188
- }
189
-
190
- // 结果
191
- if (filter.result && trace.result !== filter.result) {
192
- return false;
193
- }
194
-
195
- // 时间范围
196
- if (filter.timeRange) {
197
- if (trace.timestamp < filter.timeRange.start) {
198
- return false;
199
- }
200
- if (filter.timeRange.end && trace.timestamp > filter.timeRange.end) {
201
- return false;
202
- }
203
- }
204
-
205
- // 项目路径
206
- if (filter.projectPath && trace.projectPath !== filter.projectPath) {
207
- return false;
208
- }
209
-
210
- // 会话 ID
211
- if (filter.sessionId && trace.sessionId !== filter.sessionId) {
212
- return false;
213
- }
214
-
215
- // 任务 ID
216
- if (filter.taskId && trace.taskId !== filter.taskId) {
217
- return false;
218
- }
219
-
220
- // 角色 ID
221
- if (filter.roleId && trace.roleId !== filter.roleId) {
222
- return false;
223
- }
224
-
225
- return true;
226
- });
227
- }
228
-
229
- /**
230
- * 检查文件大小,必要时滚动
231
- */
232
- private checkFileSize(): void {
233
- if (!fs.existsSync(this.logFile)) {
234
- return;
235
- }
236
-
237
- const stats = fs.statSync(this.logFile);
238
- if (stats.size >= this.config.maxFileSize!) {
239
- this.rotateFile();
240
- }
241
- }
242
-
243
- /**
244
- * 滚动文件
245
- *
246
- * 将当前文件重命名为带时间戳的备份
247
- */
248
- private rotateFile(): void {
249
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
250
- const backupFile = this.logFile.replace('.log', `-${timestamp}.log`);
251
-
252
- // 重命名当前文件
253
- fs.renameSync(this.logFile, backupFile);
254
-
255
- // 创建新文件
256
- fs.writeFileSync(this.logFile, '', 'utf-8');
257
- }
258
-
259
- /**
260
- * 清理旧备份文件
261
- *
262
- * 删除超过 maxAge 天的备份文件
263
- */
264
- cleanupOldFiles(maxAgeDays: number = 30): number {
265
- const dir = path.dirname(this.logFile);
266
- if (!fs.existsSync(dir)) {
267
- return 0;
268
- }
269
-
270
- const files = fs.readdirSync(dir);
271
- const baseName = path.basename(this.logFile);
272
- const backupFiles = files.filter(f => f.endsWith('.log') && f !== baseName);
273
-
274
- const cutoffTime = Date.now() - maxAgeDays * 24 * 3600 * 1000;
275
- let deletedCount = 0;
276
-
277
- for (const file of backupFiles) {
278
- const filePath = path.join(dir, file);
279
- const stats = fs.statSync(filePath);
280
-
281
- if (stats.mtimeMs < cutoffTime) {
282
- fs.unlinkSync(filePath);
283
- deletedCount++;
284
- }
285
- }
286
-
287
- return deletedCount;
288
- }
289
-
290
- /**
291
- * 获取日志文件统计信息
292
- */
293
- getStats(): {
294
- fileExists: boolean;
295
- fileSize: number;
296
- totalRecords: number;
297
- oldestRecord?: number;
298
- newestRecord?: number;
299
- } {
300
- if (!fs.existsSync(this.logFile)) {
301
- return { fileExists: false, fileSize: 0, totalRecords: 0 };
302
- }
303
-
304
- const stats = fs.statSync(this.logFile);
305
- const content = fs.readFileSync(this.logFile, 'utf-8');
306
- const lines = content.split('\n').filter(l => l.trim());
307
-
308
- let oldest: number | undefined;
309
- let newest: number | undefined;
310
-
311
- if (lines.length > 0) {
312
- const firstTrace = JSON.parse(lines[0]) as PerformanceTrace;
313
- const lastTrace = JSON.parse(lines[lines.length - 1]) as PerformanceTrace;
314
- oldest = firstTrace.timestamp;
315
- newest = lastTrace.timestamp;
316
- }
317
-
318
- return {
319
- fileExists: true,
320
- fileSize: stats.size,
321
- totalRecords: lines.length,
322
- oldestRecord: oldest,
323
- newestRecord: newest,
324
- };
325
- }
326
- }