@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,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
- }