@dommaker/harness 1.4.0 → 1.6.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 (258) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +0 -2
  3. package/dist/cli/commands/check.d.ts.map +1 -1
  4. package/dist/cli/commands/check.js +28 -0
  5. package/dist/cli/commands/check.js.map +1 -1
  6. package/dist/cli/commands/definitions.d.ts.map +1 -1
  7. package/dist/cli/commands/definitions.js +1 -39
  8. package/dist/cli/commands/definitions.js.map +1 -1
  9. package/dist/cli/commands/knowledge.d.ts +0 -19
  10. package/dist/cli/commands/knowledge.d.ts.map +1 -1
  11. package/dist/cli/commands/knowledge.js +0 -105
  12. package/dist/cli/commands/knowledge.js.map +1 -1
  13. package/dist/cli/commands/passes-gate.d.ts +0 -2
  14. package/dist/cli/commands/passes-gate.d.ts.map +1 -1
  15. package/dist/cli/commands/passes-gate.js +0 -1
  16. package/dist/cli/commands/passes-gate.js.map +1 -1
  17. package/dist/cli/commands/performance.d.ts +0 -4
  18. package/dist/cli/commands/performance.d.ts.map +1 -1
  19. package/dist/cli/commands/performance.js +10 -20
  20. package/dist/cli/commands/performance.js.map +1 -1
  21. package/dist/cli/commands/report.d.ts +1 -1
  22. package/dist/cli/commands/report.d.ts.map +1 -1
  23. package/dist/cli/commands/report.js +2 -55
  24. package/dist/cli/commands/report.js.map +1 -1
  25. package/dist/cli/commands/status.d.ts.map +1 -1
  26. package/dist/cli/commands/status.js +4 -8
  27. package/dist/cli/commands/status.js.map +1 -1
  28. package/dist/context/index.d.ts +2 -5
  29. package/dist/context/index.d.ts.map +1 -1
  30. package/dist/context/index.js +2 -8
  31. package/dist/context/index.js.map +1 -1
  32. package/dist/context/token-budget.d.ts +0 -29
  33. package/dist/context/token-budget.d.ts.map +1 -1
  34. package/dist/context/token-budget.js +1 -65
  35. package/dist/context/token-budget.js.map +1 -1
  36. package/dist/context/types.d.ts +0 -1
  37. package/dist/context/types.d.ts.map +1 -1
  38. package/dist/context/types.js +0 -9
  39. package/dist/context/types.js.map +1 -1
  40. package/dist/core/constraints/checker.d.ts +14 -0
  41. package/dist/core/constraints/checker.d.ts.map +1 -1
  42. package/dist/core/constraints/checker.js +27 -5
  43. package/dist/core/constraints/checker.js.map +1 -1
  44. package/dist/core/constraints/checkers/capability-sync.d.ts +17 -6
  45. package/dist/core/constraints/checkers/capability-sync.d.ts.map +1 -1
  46. package/dist/core/constraints/checkers/capability-sync.js +48 -19
  47. package/dist/core/constraints/checkers/capability-sync.js.map +1 -1
  48. package/dist/core/constraints/checkers/docs-freshness.d.ts.map +1 -1
  49. package/dist/core/constraints/checkers/docs-freshness.js +15 -6
  50. package/dist/core/constraints/checkers/docs-freshness.js.map +1 -1
  51. package/dist/core/constraints/checkers/index.d.ts +2 -2
  52. package/dist/core/constraints/checkers/index.d.ts.map +1 -1
  53. package/dist/core/constraints/checkers/index.js +2 -1
  54. package/dist/core/constraints/checkers/index.js.map +1 -1
  55. package/dist/core/constraints/checkers/types.d.ts +41 -2
  56. package/dist/core/constraints/checkers/types.d.ts.map +1 -1
  57. package/dist/core/constraints/checkers/types.js +33 -0
  58. package/dist/core/constraints/checkers/types.js.map +1 -1
  59. package/dist/core/constraints/git-evidence.d.ts +6 -3
  60. package/dist/core/constraints/git-evidence.d.ts.map +1 -1
  61. package/dist/core/constraints/git-evidence.js +6 -3
  62. package/dist/core/constraints/git-evidence.js.map +1 -1
  63. package/dist/core/index.d.ts +1 -2
  64. package/dist/core/index.d.ts.map +1 -1
  65. package/dist/core/index.js +1 -9
  66. package/dist/core/index.js.map +1 -1
  67. package/dist/core/spec/validator.d.ts +2 -0
  68. package/dist/core/spec/validator.d.ts.map +1 -1
  69. package/dist/core/spec/validator.js +9 -11
  70. package/dist/core/spec/validator.js.map +1 -1
  71. package/dist/core/validators/index.d.ts +1 -1
  72. package/dist/core/validators/index.d.ts.map +1 -1
  73. package/dist/core/validators/passes-gate.d.ts +1 -15
  74. package/dist/core/validators/passes-gate.d.ts.map +1 -1
  75. package/dist/core/validators/passes-gate.js +0 -125
  76. package/dist/core/validators/passes-gate.js.map +1 -1
  77. package/dist/failure/index.d.ts +0 -1
  78. package/dist/failure/index.d.ts.map +1 -1
  79. package/dist/failure/index.js +1 -7
  80. package/dist/failure/index.js.map +1 -1
  81. package/dist/gates/checker-gate.d.ts +2 -1
  82. package/dist/gates/checker-gate.d.ts.map +1 -1
  83. package/dist/gates/checker-gate.js +10 -7
  84. package/dist/gates/checker-gate.js.map +1 -1
  85. package/dist/gates/definitions.d.ts.map +1 -1
  86. package/dist/gates/definitions.js +0 -4
  87. package/dist/gates/definitions.js.map +1 -1
  88. package/dist/gates/performance.d.ts +7 -22
  89. package/dist/gates/performance.d.ts.map +1 -1
  90. package/dist/gates/performance.js +7 -89
  91. package/dist/gates/performance.js.map +1 -1
  92. package/dist/gates/types.d.ts +2 -8
  93. package/dist/gates/types.d.ts.map +1 -1
  94. package/dist/index.d.ts +6 -8
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +4 -22
  97. package/dist/index.js.map +1 -1
  98. package/dist/knowledge/index.d.ts +0 -1
  99. package/dist/knowledge/index.d.ts.map +1 -1
  100. package/dist/knowledge/index.js +1 -3
  101. package/dist/knowledge/index.js.map +1 -1
  102. package/dist/monitoring/trace-analyzer.d.ts +25 -10
  103. package/dist/monitoring/trace-analyzer.d.ts.map +1 -1
  104. package/dist/monitoring/trace-analyzer.js +147 -116
  105. package/dist/monitoring/trace-analyzer.js.map +1 -1
  106. package/dist/types/constraint.d.ts +8 -0
  107. package/dist/types/constraint.d.ts.map +1 -1
  108. package/dist/types/constraint.js +6 -1
  109. package/dist/types/constraint.js.map +1 -1
  110. package/dist/types/passes-gate.d.ts +0 -19
  111. package/dist/types/passes-gate.d.ts.map +1 -1
  112. package/dist/types/trace.d.ts +9 -0
  113. package/dist/types/trace.d.ts.map +1 -1
  114. package/package.json +1 -1
  115. package/src/CONTEXT.md +1 -0
  116. package/src/__tests__/passes-gate-check.test.ts +20 -4
  117. package/src/__tests__/passes-gate.test.ts +18 -119
  118. package/src/__tests__/performance-gate.test.ts +3 -11
  119. package/src/__tests__/public-exports.test.ts +46 -16
  120. package/src/__tests__/trace-analyzer.test.ts +52 -2
  121. package/src/cli/commands/CONTEXT.md +5 -4
  122. package/src/cli/commands/__tests__/bin-exit-mapping.test.ts +6 -0
  123. package/src/cli/commands/__tests__/check.test.ts +74 -0
  124. package/src/cli/commands/__tests__/passes-gate-dead-options.test.ts +70 -0
  125. package/src/cli/commands/__tests__/passes-gate.test.ts +7 -3
  126. package/src/cli/commands/__tests__/performance.test.ts +5 -16
  127. package/src/cli/commands/__tests__/project-path-convention.test.ts +85 -23
  128. package/src/cli/commands/__tests__/registry.test.ts +52 -3
  129. package/src/cli/commands/__tests__/report-extra.test.ts +0 -19
  130. package/src/cli/commands/__tests__/report-false-green.test.ts +46 -0
  131. package/src/cli/commands/__tests__/report.test.ts +0 -20
  132. package/src/cli/commands/__tests__/status-analysis-wiring.test.ts +68 -0
  133. package/src/cli/commands/__tests__/status-extra.test.ts +63 -116
  134. package/src/cli/commands/__tests__/status.test.ts +66 -148
  135. package/src/cli/commands/check.ts +39 -1
  136. package/src/cli/commands/definitions.ts +1 -39
  137. package/src/cli/commands/knowledge.ts +0 -119
  138. package/src/cli/commands/passes-gate.ts +0 -3
  139. package/src/cli/commands/performance.ts +13 -27
  140. package/src/cli/commands/report.ts +3 -61
  141. package/src/cli/commands/status.ts +5 -10
  142. package/src/context/CONTEXT.md +2 -3
  143. package/src/context/__tests__/token-budget.test.ts +1 -81
  144. package/src/context/index.ts +2 -7
  145. package/src/context/token-budget.ts +0 -73
  146. package/src/context/types.ts +0 -9
  147. package/src/core/CONTEXT.md +6 -6
  148. package/src/core/constraints/__tests__/collect-constraints.test.ts +66 -0
  149. package/src/core/constraints/checker.ts +41 -6
  150. package/src/core/constraints/checkers/__tests__/capability-sync.test.ts +90 -31
  151. package/src/core/constraints/checkers/__tests__/check-outcome.test.ts +176 -0
  152. package/src/core/constraints/checkers/__tests__/docs-freshness.test.ts +18 -9
  153. package/src/core/constraints/checkers/__tests__/three-state-consistency.test.ts +12 -4
  154. package/src/core/constraints/checkers/capability-sync.ts +56 -18
  155. package/src/core/constraints/checkers/docs-freshness.ts +18 -5
  156. package/src/core/constraints/checkers/index.ts +9 -2
  157. package/src/core/constraints/checkers/types.ts +58 -2
  158. package/src/core/constraints/git-evidence.ts +6 -3
  159. package/src/core/index.ts +0 -11
  160. package/src/core/spec/__tests__/validator.test.ts +24 -0
  161. package/src/core/spec/validator.ts +9 -10
  162. package/src/core/validators/__tests__/passes-gate.test.ts +2 -9
  163. package/src/core/validators/index.ts +0 -1
  164. package/src/core/validators/passes-gate.ts +1 -149
  165. package/src/failure/CONTEXT.md +8 -6
  166. package/src/failure/index.ts +0 -10
  167. package/src/gates/CONTEXT.md +4 -3
  168. package/src/gates/__tests__/checker-gate.test.ts +24 -0
  169. package/src/gates/__tests__/performance.test.ts +6 -74
  170. package/src/gates/checker-gate.ts +11 -15
  171. package/src/gates/definitions.ts +0 -4
  172. package/src/gates/performance.ts +9 -111
  173. package/src/gates/types.ts +2 -8
  174. package/src/index.ts +1 -36
  175. package/src/knowledge/CONTEXT.md +1 -2
  176. package/src/knowledge/index.ts +0 -1
  177. package/src/monitoring/CONTEXT.md +2 -2
  178. package/src/monitoring/trace-analyzer.ts +160 -126
  179. package/src/types/constraint.ts +16 -2
  180. package/src/types/passes-gate.ts +0 -26
  181. package/src/types/trace.ts +10 -0
  182. package/src/utils/__tests__/jsonl-skip-disposition.test.ts +0 -1
  183. package/dist/cli/commands/analyze-sessions.d.ts +0 -20
  184. package/dist/cli/commands/analyze-sessions.d.ts.map +0 -1
  185. package/dist/cli/commands/analyze-sessions.js +0 -290
  186. package/dist/cli/commands/analyze-sessions.js.map +0 -1
  187. package/dist/cli/commands/update-user-model.d.ts +0 -25
  188. package/dist/cli/commands/update-user-model.d.ts.map +0 -1
  189. package/dist/cli/commands/update-user-model.js +0 -397
  190. package/dist/cli/commands/update-user-model.js.map +0 -1
  191. package/dist/cli/session-mining/corrections.d.ts +0 -17
  192. package/dist/cli/session-mining/corrections.d.ts.map +0 -1
  193. package/dist/cli/session-mining/corrections.js +0 -58
  194. package/dist/cli/session-mining/corrections.js.map +0 -1
  195. package/dist/cli/session-mining/index.d.ts +0 -13
  196. package/dist/cli/session-mining/index.d.ts.map +0 -1
  197. package/dist/cli/session-mining/index.js +0 -29
  198. package/dist/cli/session-mining/index.js.map +0 -1
  199. package/dist/cli/session-mining/text.d.ts +0 -31
  200. package/dist/cli/session-mining/text.d.ts.map +0 -1
  201. package/dist/cli/session-mining/text.js +0 -126
  202. package/dist/cli/session-mining/text.js.map +0 -1
  203. package/dist/cli/session-mining/transcript.d.ts +0 -34
  204. package/dist/cli/session-mining/transcript.d.ts.map +0 -1
  205. package/dist/cli/session-mining/transcript.js +0 -130
  206. package/dist/cli/session-mining/transcript.js.map +0 -1
  207. package/dist/context/compaction.d.ts +0 -57
  208. package/dist/context/compaction.d.ts.map +0 -1
  209. package/dist/context/compaction.js +0 -165
  210. package/dist/context/compaction.js.map +0 -1
  211. package/dist/core/session/clean-state.d.ts +0 -17
  212. package/dist/core/session/clean-state.d.ts.map +0 -1
  213. package/dist/core/session/clean-state.js +0 -192
  214. package/dist/core/session/clean-state.js.map +0 -1
  215. package/dist/core/session/index.d.ts +0 -6
  216. package/dist/core/session/index.d.ts.map +0 -1
  217. package/dist/core/session/index.js +0 -15
  218. package/dist/core/session/index.js.map +0 -1
  219. package/dist/core/session/startup.d.ts +0 -47
  220. package/dist/core/session/startup.d.ts.map +0 -1
  221. package/dist/core/session/startup.js +0 -263
  222. package/dist/core/session/startup.js.map +0 -1
  223. package/dist/failure/constraint-handler.d.ts +0 -83
  224. package/dist/failure/constraint-handler.d.ts.map +0 -1
  225. package/dist/failure/constraint-handler.js +0 -138
  226. package/dist/failure/constraint-handler.js.map +0 -1
  227. package/dist/knowledge/lifecycle-hooks.d.ts +0 -62
  228. package/dist/knowledge/lifecycle-hooks.d.ts.map +0 -1
  229. package/dist/knowledge/lifecycle-hooks.js +0 -143
  230. package/dist/knowledge/lifecycle-hooks.js.map +0 -1
  231. package/dist/types/session.d.ts +0 -113
  232. package/dist/types/session.d.ts.map +0 -1
  233. package/dist/types/session.js +0 -6
  234. package/dist/types/session.js.map +0 -1
  235. package/src/__tests__/clean-state-extra.test.ts +0 -301
  236. package/src/__tests__/clean-state.test.ts +0 -169
  237. package/src/__tests__/constraint-handler.test.ts +0 -132
  238. package/src/__tests__/passes-gate-extra.test.ts +0 -93
  239. package/src/__tests__/session-startup.test.ts +0 -334
  240. package/src/cli/commands/__tests__/analyze-sessions.test.ts +0 -184
  241. package/src/cli/commands/__tests__/update-user-model.test.ts +0 -234
  242. package/src/cli/commands/analyze-sessions.ts +0 -335
  243. package/src/cli/commands/update-user-model.ts +0 -461
  244. package/src/cli/session-mining/__tests__/transcript.test.ts +0 -118
  245. package/src/cli/session-mining/corrections.ts +0 -56
  246. package/src/cli/session-mining/index.ts +0 -13
  247. package/src/cli/session-mining/text.ts +0 -117
  248. package/src/cli/session-mining/transcript.ts +0 -125
  249. package/src/context/__tests__/compaction.test.ts +0 -169
  250. package/src/context/compaction.ts +0 -201
  251. package/src/core/session/__tests__/startup.test.ts +0 -281
  252. package/src/core/session/clean-state.ts +0 -178
  253. package/src/core/session/index.ts +0 -15
  254. package/src/core/session/startup.ts +0 -253
  255. package/src/failure/constraint-handler.ts +0 -171
  256. package/src/knowledge/__tests__/lifecycle-hooks.test.ts +0 -140
  257. package/src/knowledge/lifecycle-hooks.ts +0 -202
  258. package/src/types/session.ts +0 -132
@@ -128,7 +128,6 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
128
128
  { flags: '-t, --test-command <command>', description: '测试命令' },
129
129
  { flags: '-p, --project-path <path>', description: '项目路径' },
130
130
  { flags: '--allow-partial', description: '允许部分测试通过', defaultValue: false },
131
- { flags: '--max-retries <n>', description: '最大重试次数', defaultValue: '2' },
132
131
  { flags: '--coverage', description: '检查测试覆盖率' },
133
132
  { flags: '--coverage-threshold <n>', description: '覆盖率阈值', defaultValue: '80' },
134
133
  ],
@@ -157,7 +156,7 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
157
156
  description: '生成检查报告',
158
157
  options: [
159
158
  { flags: '-o, --output <path>', description: '输出文件路径' },
160
- { flags: '-f, --format <format>', description: '输出格式 (json/markdown/html)', defaultValue: 'markdown' },
159
+ { flags: '-f, --format <format>', description: '输出格式 (json/markdown)', defaultValue: 'markdown' },
161
160
  { flags: '-p, --project-path <path>', description: '项目路径' },
162
161
  ],
163
162
  action: { module: 'report', export: 'report' },
@@ -235,11 +234,6 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
235
234
  { flags: '--sources <sources>', description: '导入源(逗号分隔: code,git,docs)' },
236
235
  { flags: '--limit <n>', description: '结果数量限制', defaultValue: '20' },
237
236
  { flags: '--reset', description: '重置导入状态', defaultValue: false },
238
- { flags: '--scope <scope>', description: '知识范围(用于 upsert 去重)' },
239
- { flags: '--title <title>', description: '知识标题(用于 upsert)' },
240
- { flags: '--content <content>', description: '知识内容 Markdown(用于 upsert)' },
241
- { flags: '--file <path>', description: '从文件读取内容(用于 upsert)' },
242
- { flags: '--source <source>', description: '知识来源 (cli/design)', defaultValue: 'cli' },
243
237
  { flags: '--fix', description: '自动修复(用于 audit)', defaultValue: false },
244
238
  { flags: '--dry-run', description: '只输出报告不修改(用于 audit)', defaultValue: false },
245
239
  { flags: '--threshold <n>', description: '短内容阈值(字符数,用于 audit)', defaultValue: '50' },
@@ -258,8 +252,6 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
258
252
  decay: { impl: { module: 'knowledge', export: 'knowledgeDecay' }, aliases: ['d'] },
259
253
  stats: { impl: { module: 'knowledge', export: 'knowledgeStats' }, aliases: ['st'] },
260
254
  'sync-rag': { impl: { module: 'knowledge', export: 'knowledgeSyncRag' } },
261
- 'sync-status': { impl: { module: 'knowledge', export: 'knowledgeSyncStatus' }, aliases: ['sync'] },
262
- upsert: { impl: { module: 'knowledge', export: 'knowledgeUpsert' }, aliases: ['up'] },
263
255
  audit: { impl: { module: 'knowledge', export: 'knowledgeAudit' }, aliases: ['a'] },
264
256
  snapshot: { impl: { module: 'knowledge', export: 'knowledgeSnapshot' } },
265
257
  migrate: { impl: { module: 'knowledge', export: 'knowledgeMigrate' } },
@@ -305,22 +297,6 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
305
297
  action: { module: 'posteval-plan', export: 'postevalPlan' },
306
298
  mapActionArgs: (positionals) => [{ planPath: positionals[0] }],
307
299
  },
308
- {
309
- command: 'update-user-model',
310
- alias: 'uum',
311
- description: '从新对话中提取信号,更新用户思维模型(增量演化)',
312
- options: [
313
- { flags: '--json', description: 'JSON 格式输出', defaultValue: false },
314
- { flags: '--dry-run', description: '只显示变化,不更新状态', defaultValue: false },
315
- { flags: '--days <n>', description: '只处理最近 N 天的会话(自然日,含今天)' },
316
- ],
317
- action: { module: 'update-user-model', export: 'updateUserModel' },
318
- mapActionArgs: (_pos, options) => [{
319
- days: options.days !== undefined ? parseInt(String(options.days), 10) : undefined,
320
- json: options.json,
321
- dryRun: options.dryRun,
322
- }],
323
- },
324
300
  {
325
301
  command: 'release',
326
302
  description: 'npm 发布流水线:tsc → dist 验证 → npm version → git push → npm publish → gh release。不依赖 Studio API。',
@@ -331,20 +307,6 @@ export const COMMAND_DEFINITIONS: CommandDefinition[] = [
331
307
  action: { module: 'release', export: 'release' },
332
308
  mapActionArgs: (_pos, options) => [{ bumpType: options.bump, dryRun: options.dryRun }],
333
309
  },
334
- {
335
- command: 'analyze-sessions',
336
- alias: 'analyze',
337
- description: '分析 Claude Code 对话,挖掘纠正模式和高频概念,生成规则候选',
338
- options: [
339
- { flags: '-d, --days <n>', description: '分析最近 N 天的会话', defaultValue: '7' },
340
- { flags: '--json', description: 'JSON 格式输出', defaultValue: false },
341
- ],
342
- action: { module: 'analyze-sessions', export: 'analyzeSessions' },
343
- mapActionArgs: (_pos, options) => [{
344
- days: parseInt(String(options.days), 10),
345
- json: options.json,
346
- }],
347
- },
348
310
  {
349
311
  command: 'constraints',
350
312
  description: '输出约束集合元数据(版本、hash、计数、文本大小)',
@@ -281,76 +281,6 @@ export async function knowledgeStats(options: KnowledgeOptions, io: CommandIO =
281
281
  return { kind: 'ok' };
282
282
  }
283
283
 
284
- export interface KnowledgeUpsertOptions {
285
- scope?: string;
286
- title?: string;
287
- content?: string;
288
- file?: string;
289
- type?: string;
290
- source?: string;
291
- }
292
-
293
- /**
294
- * 设计时知识沉淀:写入 KnowledgeStore + 同步 Prisma Document(Studio UI 可见)
295
- *
296
- * 调用 Studio API POST /api/knowledge/upsert(内部端点,无 auth)
297
- */
298
- export async function knowledgeUpsert(options: KnowledgeUpsertOptions, io: CommandIO = processIO): Promise<CommandResult> {
299
- const apiPort = process.env.API_PORT || '3001';
300
- const url = `http://localhost:${apiPort}/api/knowledge/upsert`;
301
-
302
- // Read content from file if --file specified
303
- let content = options.content || '';
304
- if (options.file && !content) {
305
- try {
306
- content = fs.readFileSync(options.file, 'utf-8');
307
- } catch (e: any) {
308
- logError(io, chalk.red(`Failed to read file: ${options.file}`));
309
- logError(io, chalk.red(String(e)));
310
- return { kind: 'fail', reason: `无法读取 --file ${options.file}: ${String(e)}` };
311
- }
312
- }
313
-
314
- if (!options.scope || !options.title || !content) {
315
- logError(io, chalk.red('--scope, --title, and --content (or --file) are required'));
316
- return { kind: 'usage-error', reason: '--scope/--title/--content(--file) 缺一不可' };
317
- }
318
-
319
- try {
320
- const res = await fetch(url, {
321
- method: 'POST',
322
- headers: { 'Content-Type': 'application/json' },
323
- body: JSON.stringify({
324
- scope: options.scope,
325
- title: options.title,
326
- content,
327
- type: options.type || 'architecture',
328
- source: options.source || 'cli',
329
- }),
330
- });
331
-
332
- if (!res.ok) {
333
- const err: any = await res.json().catch(() => ({ error: res.statusText }));
334
- logError(io, chalk.red(`API error ${res.status}: ${err.error || res.statusText}`));
335
- return { kind: 'fail', reason: `upsert API error ${res.status}: ${err.error || res.statusText}` };
336
- }
337
-
338
- const result: any = await res.json();
339
- log(io, chalk.green(`✅ Knowledge upserted`));
340
- log(io, ` KnowledgeStore: ${result.knowledgeStore?.action} → ${result.knowledgeStore?.entryId}`);
341
- log(io, ` Studio UI: ${result.prismaDocument?.action} → ${result.prismaDocument?.docId || 'skipped'}`);
342
- return { kind: 'ok' };
343
- } catch (e: any) {
344
- if (e?.code === 'ECONNREFUSED') {
345
- logError(io, chalk.red(`Cannot reach Studio API at ${url}. Is the API running?`));
346
- } else {
347
- logError(io, chalk.red(`Upsert failed: ${e.message}`));
348
- }
349
- return { kind: 'fail', reason: `knowledge upsert 失败: ${e?.code === 'ECONNREFUSED' ? `Studio API 不可达 ${url}` : e.message}` };
350
- }
351
- }
352
-
353
- /**
354
284
  /**
355
285
  * RAG 同步:扫描 .harness/knowledge-docs/ 输出需要 ingest 的文件列表
356
286
  */
@@ -383,55 +313,6 @@ export async function knowledgeSyncRag(options: KnowledgeOptions, io: CommandIO
383
313
  return { kind: 'ok' };
384
314
  }
385
315
 
386
- /**
387
- * 知识同步状态:检测所有 tracked scope 的新鲜度
388
- */
389
- export async function knowledgeSyncStatus(options: KnowledgeOptions, io: CommandIO = processIO): Promise<CommandResult> {
390
- const apiPort = process.env.API_PORT || '3001';
391
- const url = `http://localhost:${apiPort}/api/knowledge/sync-status`;
392
-
393
- try {
394
- const res = await fetch(url);
395
- if (!res.ok) {
396
- const err: any = await res.json().catch(() => ({ error: res.statusText }));
397
- logError(io, chalk.red(`API error ${res.status}: ${err.error || res.statusText}`));
398
- return { kind: 'fail', reason: `sync-status API error ${res.status}: ${err.error || res.statusText}` };
399
- }
400
-
401
- const data: any = await res.json();
402
-
403
- if (options.json) {
404
- log(io, JSON.stringify(data, null, 2));
405
- return { kind: 'ok' };
406
- }
407
-
408
- log(io, chalk.blue(`🔄 KnowledgeSync Status\n`));
409
- log(io, chalk.bold(`Tracked scopes: ${data.trackedScopes?.join(', ') || 'none'}`));
410
- log(io, chalk.bold(`Stale entries: ${data.stale?.length || 0}`));
411
-
412
- if (data.stale?.length > 0) {
413
- log(io, chalk.yellow(`\n⚠️ Stale knowledge:\n`));
414
- for (const s of data.stale) {
415
- log(io, chalk.yellow(` ${s.scope} (${s.title}): ${s.stalenessHours}h old, files changed: ${s.changedFiles.join(', ')}`));
416
- }
417
- } else {
418
- log(io, chalk.green('\n✅ All knowledge fresh'));
419
- }
420
-
421
- if (data.healed?.length > 0) {
422
- log(io, chalk.cyan(`\n🩹 Auto-healed: ${data.healed.join(', ')}`));
423
- }
424
- } catch (e: any) {
425
- if (e?.code === 'ECONNREFUSED') {
426
- logError(io, chalk.red(`Cannot reach Studio API at ${url}`));
427
- } else {
428
- logError(io, chalk.red(`Sync check failed: ${e.message}`));
429
- }
430
- return { kind: 'fail', reason: `knowledge sync status 检查失败: ${e?.code === 'ECONNREFUSED' ? `Studio API 不可达 ${url}` : e.message}` };
431
- }
432
- return { kind: 'ok' };
433
- }
434
-
435
316
  /**
436
317
  * 飞轮健康检查 — 零 token 检测知识飞轮数据流状态
437
318
  */
@@ -19,8 +19,6 @@ export interface PassesGateOptions {
19
19
  projectPath?: string;
20
20
  /** 是否允许部分通过 */
21
21
  allowPartial?: boolean;
22
- /** 最大重试次数 */
23
- maxRetries?: number;
24
22
  }
25
23
 
26
24
  /**
@@ -54,7 +52,6 @@ export async function runPassesGate(
54
52
  testCommand,
55
53
  requireEvidence: false,
56
54
  allowPartialPass: options.allowPartial || false,
57
- maxRetries: options.maxRetries || 2,
58
55
  };
59
56
 
60
57
  // 执行测试
@@ -5,7 +5,8 @@
5
5
  */
6
6
 
7
7
  import chalk from 'chalk';
8
- import { PerformanceGate } from '../../gates/performance';
8
+ import { PerformanceGate, type ExtendedPerformanceGateConfig } from '../../gates/performance';
9
+ import type { GateContext, PerformanceThresholds } from '../../gates/types';
9
10
  import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
10
11
 
11
12
  export interface PerformanceOptions {
@@ -19,10 +20,6 @@ export interface PerformanceOptions {
19
20
  bundle?: boolean;
20
21
  /** 打包大小阈值(KB) */
21
22
  bundleThreshold?: number;
22
- /** 是否检查基准测试 */
23
- benchmark?: boolean;
24
- /** 基准测试超时(秒) */
25
- benchmarkTimeout?: number;
26
23
  }
27
24
 
28
25
  /**
@@ -36,34 +33,28 @@ export async function performance(
36
33
 
37
34
  const projectPath = options.projectPath || process.cwd();
38
35
 
39
- // 构建配置
40
- const config: any = {};
36
+ // 构建配置(架构评审候选2:键名对齐 PerformanceThresholds 真字段——
37
+ // thresholds.coverage / bundleSize 字节换算是错位键,旗帜恒不生效)
38
+ const config: Partial<ExtendedPerformanceGateConfig> = {};
39
+ const thresholds: PerformanceThresholds = {};
41
40
 
42
41
  if (options.coverage && options.coverageThreshold) {
43
- config.thresholds = {
44
- coverage: options.coverageThreshold,
45
- };
42
+ thresholds.minCoverage = options.coverageThreshold;
46
43
  }
47
44
 
48
45
  if (options.bundleThreshold) {
49
- config.thresholds = config.thresholds || {};
50
- config.thresholds.bundleSize = options.bundleThreshold * 1024; // KB to bytes
46
+ thresholds.maxBundleSize = options.bundleThreshold; // KB 直传,gate 按 KB 比较
51
47
  }
52
48
 
53
- if (options.benchmarkTimeout) {
54
- config.benchmarkTimeout = options.benchmarkTimeout * 1000; // seconds to ms
49
+ if (Object.keys(thresholds).length > 0) {
50
+ config.thresholds = thresholds;
55
51
  }
56
52
 
57
53
  // 创建性能门控实例
58
54
  const gate = new PerformanceGate(config);
59
55
 
60
56
  try {
61
- const result = await gate.check({
62
- projectPath,
63
- checkCoverage: options.coverage,
64
- checkBundle: options.bundle,
65
- checkBenchmark: options.benchmark,
66
- } as any);
57
+ const result = await gate.check({ projectPath } as GateContext);
67
58
 
68
59
  if (result.passed) {
69
60
  log(io);
@@ -83,13 +74,8 @@ export async function performance(
83
74
 
84
75
  if (metrics.bundleSize !== undefined) {
85
76
  const thresholdKB = options.bundleThreshold || 500;
86
- const actualKB = metrics.bundleSize / 1024;
87
- const status = actualKB <= thresholdKB ? '✅' : '❌';
88
- log(io, chalk.gray(` 打包大小: ${actualKB.toFixed(2)} KB ${status}`));
89
- }
90
-
91
- if (metrics.benchmarkTime !== undefined) {
92
- log(io, chalk.gray(` 基准测试: ${metrics.benchmarkTime}ms`));
77
+ const status = metrics.bundleSize <= thresholdKB ? '✅' : '❌';
78
+ log(io, chalk.gray(` 打包大小: ${metrics.bundleSize} KB ${status}`));
93
79
  }
94
80
  }
95
81
  } else {
@@ -8,7 +8,6 @@ import chalk from 'chalk';
8
8
  import * as fs from 'fs/promises';
9
9
  import { ConstraintChecker } from '../../core/constraints/checker';
10
10
  import { IRON_LAWS, GUIDELINES, PROMPTS } from '../../core/constraints/definitions';
11
- import { executeWithCollect } from '../../failure/constraint-handler';
12
11
  import { getTraceCollector } from '../../monitoring/traces';
13
12
  import type { ConstraintContext } from '../../types/constraint';
14
13
  import { log, processIO, type CommandIO, type CommandResult } from '../command-contract';
@@ -17,7 +16,7 @@ export interface ReportOptions {
17
16
  /** 输出文件路径 */
18
17
  output?: string;
19
18
  /** 输出格式 */
20
- format: 'json' | 'markdown' | 'html';
19
+ format: 'json' | 'markdown';
21
20
  /** 项目路径 */
22
21
  projectPath?: string;
23
22
  }
@@ -59,12 +58,8 @@ export async function report(options: ReportOptions, io: CommandIO = processIO):
59
58
  projectPath,
60
59
  };
61
60
 
62
- // S4: 使用 COLLECT 策略 — Iron Law 违规不抛异常,收集到结果中
63
- const { checkResult } = await executeWithCollect(() =>
64
- checker.checkConstraints(context)
65
- );
66
- // COLLECT 策略始终返回 checkResult
67
- const result = checkResult!;
61
+ // 收集模式(架构评审候选1):不抛、全量收集,铁律违规如实进报告
62
+ const result = await checker.collectConstraints(context);
68
63
 
69
64
  const failedIronLaws = result.ironLaws.filter(r => !r.satisfied);
70
65
  const failedGuidelines = result.guidelines.filter(r => !r.satisfied);
@@ -99,9 +94,6 @@ export async function report(options: ReportOptions, io: CommandIO = processIO):
99
94
  case 'markdown':
100
95
  content = generateMarkdownReport(reportData);
101
96
  break;
102
- case 'html':
103
- content = generateHtmlReport(reportData);
104
- break;
105
97
  default:
106
98
  content = JSON.stringify(reportData, null, 2);
107
99
  }
@@ -150,53 +142,3 @@ function generateMarkdownReport(data: ReportData): string {
150
142
  return lines.join('\n');
151
143
  }
152
144
 
153
- function generateHtmlReport(data: ReportData): string {
154
- const violationsHtml = data.constraints.violations.length > 0
155
- ? `<h3>违规项</h3><ul>${data.constraints.violations.map(v =>
156
- `<li><strong>${v.id}</strong> (${v.level}): ${v.message}</li>`
157
- ).join('')}</ul>`
158
- : '';
159
-
160
- return `<!DOCTYPE html>
161
- <html lang="zh-CN">
162
- <head>
163
- <meta charset="UTF-8">
164
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
165
- <title>Harness 检查报告</title>
166
- <style>
167
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
168
- h1 { color: #333; border-bottom: 2px solid #4CAF50; padding-bottom: 10px; }
169
- h2 { color: #555; margin-top: 30px; }
170
- table { width: 100%; border-collapse: collapse; margin: 15px 0; }
171
- th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
172
- th { background-color: #4CAF50; color: white; }
173
- tr:nth-child(even) { background-color: #f2f2f2; }
174
- .passed { color: #4CAF50; }
175
- .failed { color: #f44336; }
176
- .meta { color: #666; font-size: 0.9em; margin-bottom: 20px; }
177
- </style>
178
- </head>
179
- <body>
180
- <h1>Harness 检查报告</h1>
181
- <p class="meta">生成时间: ${data.timestamp}<br>项目路径: ${data.projectPath}</p>
182
-
183
- <h2>约束检查</h2>
184
- <table>
185
- <tr><th>指标</th><th>数值</th></tr>
186
- <tr><td>总约束</td><td>${data.constraints.total}</td></tr>
187
- <tr><td>Iron Laws</td><td>${data.constraints.ironLaws}</td></tr>
188
- <tr><td>Guidelines</td><td>${data.constraints.guidelines}</td></tr>
189
- <tr><td>Prompts</td><td>${data.constraints.prompts}</td></tr>
190
- <tr><td>通过</td><td class="passed">${data.constraints.passed}</td></tr>
191
- <tr><td>失败</td><td class="failed">${data.constraints.failed}</td></tr>
192
- <tr><td>警告</td><td>${data.constraints.warnings}</td></tr>
193
- </table>
194
-
195
- ${violationsHtml}
196
-
197
- <footer style="margin-top: 40px; color: #999; text-align: center;">
198
- 报告由 @dommaker/harness 生成
199
- </footer>
200
- </body>
201
- </html>`;
202
- }
@@ -7,8 +7,7 @@
7
7
  import chalk from 'chalk';
8
8
  import * as fs from 'fs';
9
9
  import * as path from 'path';
10
- import { TraceCollector } from '../../monitoring/traces';
11
- import { TraceAnalyzer } from '../../monitoring/trace-analyzer';
10
+ import { summarizeTraces, detectTraceAnomalies } from '../../monitoring/trace-analyzer';
12
11
  import { readJsonl } from '../../utils/jsonl';
13
12
  import { DEFAULT_TRACE_FILE } from '../../types/trace';
14
13
  import type { ExecutionTrace } from '../../types/trace';
@@ -57,18 +56,14 @@ export async function status(options: StatusOptions, io: CommandIO = processIO):
57
56
  // filter(Boolean) 沿用原语义:parse 成功但值为 falsy 的行(如 "null")不进分析
58
57
  // 计数去向:harness#100——skippedLines 另起一行走 stderr 告知(口径不改,只补告知)。
59
58
  // 不经 TraceCollector.readReport():本命令按 -p 的 projectPath 直读读链正本,且要的是
60
- // records + skippedLines 的原始行数口径;下面另建的 collector/analyzer 只用于 summarize/detectAnomalies
59
+ // records + skippedLines 的原始行数口径;下游只做纯判定(ADR-0020 直调模块级函数)
61
60
  const { records, skippedLines } = readJsonl<ExecutionTrace>(tracesPath, 'skip');
62
61
  const traces = records.filter(Boolean);
63
62
  const traceCount = records.length + skippedLines;
64
63
 
65
- // 创建收集器和分析器
66
- const collector = new TraceCollector({ traceFile: tracesPath });
67
- const analyzer = new TraceAnalyzer(collector);
68
-
69
- // 生成统计
70
- const summaries = analyzer.summarize(traces);
71
- const anomalies = analyzer.detectAnomalies(summaries);
64
+ // 生成统计(数据进数据出,无需 collector/分析器实例)
65
+ const summaries = summarizeTraces(traces);
66
+ const anomalies = detectTraceAnomalies(summaries);
72
67
 
73
68
  // 基本统计
74
69
  log(io, chalk.gray(`记录数: ${traceCount} 条`));
@@ -1,11 +1,10 @@
1
1
  # context/
2
2
 
3
3
  ## 职责
4
- 上下文管理:Token 预算(多级分配)、会话压缩、会话管理、知识注入。
4
+ 上下文管理:Token 预算(多级分配)、会话管理、知识注入。
5
5
 
6
6
  ## 核心导出
7
7
  - `TokenBudget` — 多级 token 预算(system/user/tool/reserve)
8
- - `Compaction` — 会话压缩(摘要/截断/滑动窗口)
9
8
  - `SessionManager` — 会话管理
10
9
  - `KnowledgeInjector` — 知识注入引擎
11
10
 
@@ -16,7 +15,7 @@
16
15
 
17
16
  ## 约定
18
17
  - Token 预算策略由配置文件控制
19
- - 会话压缩策略可组合
18
+ - 压缩只剩词汇不留引擎:`types.ts` 保留 `CompactionLevel`(被 `ContextUsageSnapshot.compactionLevel` 引用)与 `CompactionConfig`,但 `SessionCompaction` 引擎、`CompactionResult`、`DEFAULT_COMPACTION_CONFIG` 与 `AdaptiveTokenBudget` 已随 ADR-0022(零生产消费者)删除,本目录不再提供压缩策略组合点
20
19
 
21
20
  ## 注意事项
22
21
  - 零 Token 成本:纯计算,不调用 LLM
@@ -2,7 +2,7 @@
2
2
  * TokenBudget 和 TokenEstimator 测试
3
3
  */
4
4
 
5
- import { TokenBudget, TokenEstimator, AdaptiveTokenBudget } from '../token-budget';
5
+ import { TokenBudget, TokenEstimator } from '../token-budget';
6
6
 
7
7
  describe('TokenEstimator', () => {
8
8
  describe('estimateText()', () => {
@@ -256,83 +256,3 @@ describe('TokenBudget', () => {
256
256
  });
257
257
  });
258
258
  });
259
-
260
- describe('AdaptiveTokenBudget', () => {
261
- describe('recordActualUsage()', () => {
262
- it('should record usage history', () => {
263
- const budget = new AdaptiveTokenBudget(1000);
264
- budget.recordActualUsage(500);
265
- budget.recordActualUsage(600);
266
- expect(budget.getAverageUsage()).toBe(550);
267
- });
268
-
269
- it('should trim history when exceeding max size', () => {
270
- const budget = new AdaptiveTokenBudget(1000);
271
- for (let i = 0; i < 15; i++) {
272
- budget.recordActualUsage(100 + i);
273
- }
274
- expect(budget.getAverageUsage()).toBeGreaterThan(0);
275
- });
276
- });
277
-
278
- describe('getAverageUsage()', () => {
279
- it('should return 0 when no history', () => {
280
- const budget = new AdaptiveTokenBudget(1000);
281
- expect(budget.getAverageUsage()).toBe(0);
282
- });
283
- });
284
-
285
- describe('predictNeed()', () => {
286
- it('should return total when no history', () => {
287
- const budget = new AdaptiveTokenBudget(1000);
288
- expect(budget.predictNeed()).toBe(1000);
289
- });
290
-
291
- it('should predict based on history', () => {
292
- const budget = new AdaptiveTokenBudget(1000);
293
- budget.recordActualUsage(400);
294
- budget.recordActualUsage(500);
295
- budget.recordActualUsage(600);
296
- const predicted = budget.predictNeed(0.9);
297
- expect(predicted).toBeGreaterThan(0);
298
- });
299
- });
300
-
301
- describe('suggestBudgetAdjustment()', () => {
302
- it('should suggest increase when ratio > 0.9', () => {
303
- const budget = new AdaptiveTokenBudget(1000);
304
- for (let i = 0; i < 5; i++) {
305
- budget.recordActualUsage(950);
306
- }
307
- const suggestion = budget.suggestBudgetAdjustment();
308
- expect(suggestion.action).toBe('increase');
309
- expect(suggestion.suggestedBudget).toBeGreaterThan(1000);
310
- });
311
-
312
- it('should suggest decrease when ratio < 0.5 and history >= 5', () => {
313
- const budget = new AdaptiveTokenBudget(1000);
314
- for (let i = 0; i < 5; i++) {
315
- budget.recordActualUsage(100);
316
- }
317
- const suggestion = budget.suggestBudgetAdjustment();
318
- expect(suggestion.action).toBe('decrease');
319
- });
320
-
321
- it('should maintain when ratio is moderate', () => {
322
- const budget = new AdaptiveTokenBudget(1000);
323
- for (let i = 0; i < 5; i++) {
324
- budget.recordActualUsage(600);
325
- }
326
- const suggestion = budget.suggestBudgetAdjustment();
327
- expect(suggestion.action).toBe('maintain');
328
- });
329
-
330
- it('should maintain when history < 5 even if low usage', () => {
331
- const budget = new AdaptiveTokenBudget(1000);
332
- budget.recordActualUsage(100);
333
- budget.recordActualUsage(100);
334
- const suggestion = budget.suggestBudgetAdjustment();
335
- expect(suggestion.action).toBe('maintain');
336
- });
337
- });
338
- });
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * 上下文管理模块(ADR-0003:显式清单,禁 export *)
3
3
  *
4
- * Token 预算 + 会话压缩 + 知识注入
4
+ * Token 预算 + 会话管理 + 知识注入
5
5
  */
6
6
 
7
7
  // 类型
@@ -17,14 +17,9 @@ export type {
17
17
  SessionHandle,
18
18
  SessionMessage,
19
19
  } from './types';
20
- export { DEFAULT_COMPACTION_CONFIG } from './types';
21
20
 
22
21
  // Token 预算
23
- export { AdaptiveTokenBudget, TokenBudget, TokenEstimator } from './token-budget';
24
-
25
- // 会话压缩
26
- export { SessionCompaction } from './compaction';
27
- export type { CompactionResult } from './compaction';
22
+ export { TokenBudget, TokenEstimator } from './token-budget';
28
23
 
29
24
  // 会话管理
30
25
  export { SessionManager } from './session-manager';
@@ -220,76 +220,3 @@ export class TokenBudget {
220
220
  };
221
221
  }
222
222
  }
223
-
224
- /**
225
- * 自适应预算管理器
226
- *
227
- * 根据历史使用情况动态调整预算
228
- */
229
- export class AdaptiveTokenBudget extends TokenBudget {
230
- private history: number[] = [];
231
- private maxHistorySize: number = 10;
232
-
233
- /**
234
- * 记录实际使用情况
235
- */
236
- recordActualUsage(actualTokens: number): void {
237
- this.history.push(actualTokens);
238
- if (this.history.length > this.maxHistorySize) {
239
- this.history.shift();
240
- }
241
- }
242
-
243
- /**
244
- * 获取平均使用量
245
- */
246
- getAverageUsage(): number {
247
- if (this.history.length === 0) return 0;
248
- return this.history.reduce((a, b) => a + b, 0) / this.history.length;
249
- }
250
-
251
- /**
252
- * 预测未来需求
253
- */
254
- predictNeed(confidence: number = 0.9): number {
255
- if (this.history.length === 0) return this.total;
256
-
257
- const avg = this.getAverageUsage();
258
- const max = Math.max(...this.history);
259
-
260
- // 简单预测:平均值 + 一定比例的最大值
261
- return Math.ceil(avg + (max - avg) * confidence);
262
- }
263
-
264
- /**
265
- * 建议预算调整
266
- */
267
- suggestBudgetAdjustment(): {
268
- action: 'increase' | 'decrease' | 'maintain';
269
- suggestedBudget: number;
270
- reason: string;
271
- } {
272
- const avg = this.getAverageUsage();
273
- const ratio = avg / this.total;
274
-
275
- if (ratio > 0.9) {
276
- return {
277
- action: 'increase',
278
- suggestedBudget: Math.ceil(avg * 1.2),
279
- reason: '平均使用量接近预算上限,建议增加 20%'
280
- };
281
- } else if (ratio < 0.5 && this.history.length >= 5) {
282
- return {
283
- action: 'decrease',
284
- suggestedBudget: Math.ceil(avg * 1.2),
285
- reason: '平均使用量远低于预算,可减少预算'
286
- };
287
- }
288
-
289
- return {
290
- action: 'maintain',
291
- suggestedBudget: this.total,
292
- reason: '预算使用合理'
293
- };
294
- }
295
- }
@@ -19,15 +19,6 @@ export interface CompactionConfig {
19
19
  fallbackStrategy: 'truncate-middle' | 'head-drop' | 'retry-with-clamp';
20
20
  }
21
21
 
22
- export const DEFAULT_COMPACTION_CONFIG: CompactionConfig = {
23
- triggerRatio: 0.8,
24
- level: 'eviction',
25
- preserveToolCallPairs: true,
26
- structuredSummary: true,
27
- maxSummaryTokens: 2000,
28
- fallbackStrategy: 'truncate-middle',
29
- };
30
-
31
22
  export interface SessionMessage {
32
23
  role: 'user' | 'assistant' | 'tool';
33
24
  content: string;