@hongmaple0820/scale-engine 0.7.2 → 0.9.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 (224) hide show
  1. package/README.en.md +220 -0
  2. package/README.md +91 -50
  3. package/dist/adapters/ClaudeCodeAdapter.d.ts +2 -0
  4. package/dist/adapters/ClaudeCodeAdapter.js +10 -3
  5. package/dist/adapters/ClaudeCodeAdapter.js.map +1 -1
  6. package/dist/adapters/CodexAdapter.d.ts +1 -0
  7. package/dist/adapters/CodexAdapter.js +10 -3
  8. package/dist/adapters/CodexAdapter.js.map +1 -1
  9. package/dist/adapters/CursorAdapter.js +5 -3
  10. package/dist/adapters/CursorAdapter.js.map +1 -1
  11. package/dist/adapters/GeminiAdapter.d.ts +1 -0
  12. package/dist/adapters/GeminiAdapter.js +9 -3
  13. package/dist/adapters/GeminiAdapter.js.map +1 -1
  14. package/dist/adapters/HermesAdapter.d.ts +1 -0
  15. package/dist/adapters/HermesAdapter.js +9 -3
  16. package/dist/adapters/HermesAdapter.js.map +1 -1
  17. package/dist/adapters/OpenClawAdapter.d.ts +1 -0
  18. package/dist/adapters/OpenClawAdapter.js +9 -3
  19. package/dist/adapters/OpenClawAdapter.js.map +1 -1
  20. package/dist/adapters/OpenCodeAdapter.js +5 -3
  21. package/dist/adapters/OpenCodeAdapter.js.map +1 -1
  22. package/dist/adapters/QCoderAdapter.d.ts +1 -0
  23. package/dist/adapters/QCoderAdapter.js +9 -3
  24. package/dist/adapters/QCoderAdapter.js.map +1 -1
  25. package/dist/adapters/TraeAdapter.d.ts +1 -0
  26. package/dist/adapters/TraeAdapter.js +9 -3
  27. package/dist/adapters/TraeAdapter.js.map +1 -1
  28. package/dist/adapters/VSCAdapter.d.ts +1 -0
  29. package/dist/adapters/VSCAdapter.js +9 -3
  30. package/dist/adapters/VSCAdapter.js.map +1 -1
  31. package/dist/adapters/WorkBuddyAdapter.d.ts +1 -0
  32. package/dist/adapters/WorkBuddyAdapter.js +9 -3
  33. package/dist/adapters/WorkBuddyAdapter.js.map +1 -1
  34. package/dist/agents/AgentChannel.d.ts +43 -0
  35. package/dist/agents/AgentChannel.js +136 -0
  36. package/dist/agents/AgentChannel.js.map +1 -0
  37. package/dist/agents/AgentCoordinator.d.ts +29 -0
  38. package/dist/agents/AgentCoordinator.js +136 -0
  39. package/dist/agents/AgentCoordinator.js.map +1 -0
  40. package/dist/agents/AgentDispatcher.d.ts +24 -0
  41. package/dist/agents/AgentDispatcher.js +112 -0
  42. package/dist/agents/AgentDispatcher.js.map +1 -0
  43. package/dist/agents/AgentManager.d.ts +14 -0
  44. package/dist/agents/AgentManager.js +85 -0
  45. package/dist/agents/AgentManager.js.map +1 -0
  46. package/dist/agents/AgentPool.d.ts +59 -0
  47. package/dist/agents/AgentPool.js +192 -0
  48. package/dist/agents/AgentPool.js.map +1 -0
  49. package/dist/agents/AgentRegistry.d.ts +20 -0
  50. package/dist/agents/AgentRegistry.js +36 -0
  51. package/dist/agents/AgentRegistry.js.map +1 -0
  52. package/dist/agents/AgentSourceLoader.d.ts +73 -0
  53. package/dist/agents/AgentSourceLoader.js +101 -0
  54. package/dist/agents/AgentSourceLoader.js.map +1 -0
  55. package/dist/agents/IAgent.d.ts +53 -0
  56. package/dist/agents/IAgent.js +4 -0
  57. package/dist/agents/IAgent.js.map +1 -0
  58. package/dist/agents/definitions/debugger.d.ts +2 -0
  59. package/dist/agents/definitions/debugger.js +6 -0
  60. package/dist/agents/definitions/debugger.js.map +1 -0
  61. package/dist/agents/definitions/doc-writer.d.ts +2 -0
  62. package/dist/agents/definitions/doc-writer.js +6 -0
  63. package/dist/agents/definitions/doc-writer.js.map +1 -0
  64. package/dist/agents/definitions/implementer.d.ts +2 -0
  65. package/dist/agents/definitions/implementer.js +6 -0
  66. package/dist/agents/definitions/implementer.js.map +1 -0
  67. package/dist/agents/definitions/planner.d.ts +2 -0
  68. package/dist/agents/definitions/planner.js +6 -0
  69. package/dist/agents/definitions/planner.js.map +1 -0
  70. package/dist/agents/definitions/researcher.d.ts +2 -0
  71. package/dist/agents/definitions/researcher.js +6 -0
  72. package/dist/agents/definitions/researcher.js.map +1 -0
  73. package/dist/agents/definitions/reviewer.d.ts +2 -0
  74. package/dist/agents/definitions/reviewer.js +6 -0
  75. package/dist/agents/definitions/reviewer.js.map +1 -0
  76. package/dist/agents/definitions/security.d.ts +2 -0
  77. package/dist/agents/definitions/security.js +6 -0
  78. package/dist/agents/definitions/security.js.map +1 -0
  79. package/dist/agents/definitions/tester.d.ts +2 -0
  80. package/dist/agents/definitions/tester.js +6 -0
  81. package/dist/agents/definitions/tester.js.map +1 -0
  82. package/dist/agents/index.d.ts +23 -0
  83. package/dist/agents/index.js +44 -0
  84. package/dist/agents/index.js.map +1 -0
  85. package/dist/agents/profiles.d.ts +26 -0
  86. package/dist/agents/profiles.js +197 -0
  87. package/dist/agents/profiles.js.map +1 -0
  88. package/dist/agents/types.d.ts +262 -0
  89. package/dist/agents/types.js +4 -0
  90. package/dist/agents/types.js.map +1 -0
  91. package/dist/api/cli.js +136 -3
  92. package/dist/api/cli.js.map +1 -1
  93. package/dist/api/doctor.js +0 -2
  94. package/dist/api/doctor.js.map +1 -1
  95. package/dist/api/mcp.js +0 -5
  96. package/dist/api/mcp.js.map +1 -1
  97. package/dist/artifact/fsm.js +3 -5
  98. package/dist/artifact/fsm.js.map +1 -1
  99. package/dist/artifact/sqliteStore.js +1 -14
  100. package/dist/artifact/sqliteStore.js.map +1 -1
  101. package/dist/artifact/store.js +2 -4
  102. package/dist/artifact/store.js.map +1 -1
  103. package/dist/artifact/types.d.ts +98 -1
  104. package/dist/artifact/types.js +0 -3
  105. package/dist/artifact/types.js.map +1 -1
  106. package/dist/cli/liteCommands.d.ts +81 -0
  107. package/dist/cli/liteCommands.js +148 -0
  108. package/dist/cli/liteCommands.js.map +1 -0
  109. package/dist/cli/phaseCommands.d.ts +129 -0
  110. package/dist/cli/phaseCommands.js +572 -0
  111. package/dist/cli/phaseCommands.js.map +1 -0
  112. package/dist/context/AntiPatternRegistry.d.ts +38 -0
  113. package/dist/context/AntiPatternRegistry.js +203 -0
  114. package/dist/context/AntiPatternRegistry.js.map +1 -0
  115. package/dist/context/CavemanCompressor.d.ts +20 -0
  116. package/dist/context/CavemanCompressor.js +14 -0
  117. package/dist/context/CavemanCompressor.js.map +1 -0
  118. package/dist/context/ContextBuilder.js +132 -4
  119. package/dist/context/ContextBuilder.js.map +1 -1
  120. package/dist/context/SessionStartSequence.d.ts +54 -0
  121. package/dist/context/SessionStartSequence.js +153 -0
  122. package/dist/context/SessionStartSequence.js.map +1 -0
  123. package/dist/core/container.js +4 -2
  124. package/dist/core/container.js.map +1 -1
  125. package/dist/core/eventBus.js +5 -6
  126. package/dist/core/eventBus.js.map +1 -1
  127. package/dist/dashboard/DashboardServer.js +3 -6
  128. package/dist/dashboard/DashboardServer.js.map +1 -1
  129. package/dist/dashboard/index.d.ts +2 -0
  130. package/dist/dashboard/index.js +2 -0
  131. package/dist/dashboard/index.js.map +1 -0
  132. package/dist/dashboard/server.d.ts +52 -0
  133. package/dist/dashboard/server.js +83 -0
  134. package/dist/dashboard/server.js.map +1 -0
  135. package/dist/evolution/AutoDefectCreator.js +2 -4
  136. package/dist/evolution/AutoDefectCreator.js.map +1 -1
  137. package/dist/evolution/BehaviorTracker.js +3 -5
  138. package/dist/evolution/BehaviorTracker.js.map +1 -1
  139. package/dist/evolution/EvolutionEngine.js +3 -14
  140. package/dist/evolution/EvolutionEngine.js.map +1 -1
  141. package/dist/evolution/EvolutionEvaluator.js +1 -4
  142. package/dist/evolution/EvolutionEvaluator.js.map +1 -1
  143. package/dist/evolution/LessonValidator.js +0 -4
  144. package/dist/evolution/LessonValidator.js.map +1 -1
  145. package/dist/evolution/PatternExtractor.d.ts +40 -0
  146. package/dist/evolution/PatternExtractor.js +83 -0
  147. package/dist/evolution/PatternExtractor.js.map +1 -0
  148. package/dist/evolution/SkillCreator.d.ts +75 -0
  149. package/dist/evolution/SkillCreator.js +219 -0
  150. package/dist/evolution/SkillCreator.js.map +1 -0
  151. package/dist/fsm/FSMAgentBridge.js +11 -13
  152. package/dist/fsm/FSMAgentBridge.js.map +1 -1
  153. package/dist/guardrails/DetectorEnhanced.js +32 -30
  154. package/dist/guardrails/DetectorEnhanced.js.map +1 -1
  155. package/dist/guardrails/GateEvaluator.d.ts +18 -0
  156. package/dist/guardrails/GateEvaluator.js +129 -0
  157. package/dist/guardrails/GateEvaluator.js.map +1 -0
  158. package/dist/guardrails/Gateway.js +6 -7
  159. package/dist/guardrails/Gateway.js.map +1 -1
  160. package/dist/guardrails/ReviewEnforcer.d.ts +52 -0
  161. package/dist/guardrails/ReviewEnforcer.js +117 -0
  162. package/dist/guardrails/ReviewEnforcer.js.map +1 -0
  163. package/dist/guardrails/advancedDetectors.js +33 -31
  164. package/dist/guardrails/advancedDetectors.js.map +1 -1
  165. package/dist/guardrails/detectors.js +76 -16
  166. package/dist/guardrails/detectors.js.map +1 -1
  167. package/dist/hooks/HookDeployer.js +2 -3
  168. package/dist/hooks/HookDeployer.js.map +1 -1
  169. package/dist/hooks/HookGeneratorEnhanced.js +2 -3
  170. package/dist/hooks/HookGeneratorEnhanced.js.map +1 -1
  171. package/dist/index.d.ts +20 -2
  172. package/dist/index.js +19 -2
  173. package/dist/index.js.map +1 -1
  174. package/dist/knowledge/KnowledgeBase.d.ts +26 -0
  175. package/dist/knowledge/KnowledgeBase.js +109 -8
  176. package/dist/knowledge/KnowledgeBase.js.map +1 -1
  177. package/dist/knowledge/SQLiteKnowledgeBase.js +1 -3
  178. package/dist/knowledge/SQLiteKnowledgeBase.js.map +1 -1
  179. package/dist/knowledge/UbiquitousLanguageManager.d.ts +49 -0
  180. package/dist/knowledge/UbiquitousLanguageManager.js +133 -0
  181. package/dist/knowledge/UbiquitousLanguageManager.js.map +1 -0
  182. package/dist/routing/ModelRouter.js +0 -2
  183. package/dist/routing/ModelRouter.js.map +1 -1
  184. package/dist/skills/ExternalSkills.d.ts +3 -0
  185. package/dist/skills/ExternalSkills.js +20 -0
  186. package/dist/skills/ExternalSkills.js.map +1 -0
  187. package/dist/skills/GrillingSessionSkill.d.ts +65 -0
  188. package/dist/skills/GrillingSessionSkill.js +113 -0
  189. package/dist/skills/GrillingSessionSkill.js.map +1 -0
  190. package/dist/skills/GrillingTemplates.d.ts +7 -0
  191. package/dist/skills/GrillingTemplates.js +38 -0
  192. package/dist/skills/GrillingTemplates.js.map +1 -0
  193. package/dist/skills/SkillDiscovery.d.ts +68 -17
  194. package/dist/skills/SkillDiscovery.js +294 -115
  195. package/dist/skills/SkillDiscovery.js.map +1 -1
  196. package/dist/skills/SkillExecutor.js +1 -3
  197. package/dist/skills/SkillExecutor.js.map +1 -1
  198. package/dist/skills/SkillInstaller.d.ts +40 -0
  199. package/dist/skills/SkillInstaller.js +112 -0
  200. package/dist/skills/SkillInstaller.js.map +1 -0
  201. package/dist/skills/SkillRegistry.js +1 -2
  202. package/dist/skills/SkillRegistry.js.map +1 -1
  203. package/dist/skills/TriggerEngine.js +3 -5
  204. package/dist/skills/TriggerEngine.js.map +1 -1
  205. package/dist/skills/index.d.ts +3 -0
  206. package/dist/skills/index.js +3 -0
  207. package/dist/skills/index.js.map +1 -1
  208. package/dist/tasks/IssueTriageFSM.d.ts +26 -0
  209. package/dist/tasks/IssueTriageFSM.js +107 -0
  210. package/dist/tasks/IssueTriageFSM.js.map +1 -0
  211. package/dist/tasks/TaskEngine.js +1 -5
  212. package/dist/tasks/TaskEngine.js.map +1 -1
  213. package/dist/workflows/DAGBuilder.d.ts +52 -0
  214. package/dist/workflows/DAGBuilder.js +169 -0
  215. package/dist/workflows/DAGBuilder.js.map +1 -0
  216. package/dist/workflows/WorkflowExecutor.js +2 -4
  217. package/dist/workflows/WorkflowExecutor.js.map +1 -1
  218. package/dist/workflows/WorkflowOrchestrator.d.ts +48 -0
  219. package/dist/workflows/WorkflowOrchestrator.js +181 -0
  220. package/dist/workflows/WorkflowOrchestrator.js.map +1 -0
  221. package/dist/workflows/index.d.ts +2 -4
  222. package/dist/workflows/index.js +4 -4
  223. package/dist/workflows/index.js.map +1 -1
  224. package/package.json +2 -2
@@ -0,0 +1,129 @@
1
+ // SCALE Engine - Harness Engineering: 程序化质量门禁评估器
2
+ // 文章启发:"不可机器验证的约束是无效约束"
3
+ import { logger } from '../core/logger.js';
4
+ export class GateEvaluator {
5
+ static evaluate(conditionStr, payload) {
6
+ try {
7
+ const conditions = this.parseConditions(conditionStr);
8
+ const results = conditions.map(c => this.checkCondition(c, payload));
9
+ const passed = results.every(r => r.passed);
10
+ logger.debug({ conditionStr, passed }, 'Gate evaluated');
11
+ return passed;
12
+ }
13
+ catch (err) {
14
+ logger.error({ conditionStr, err }, 'Gate evaluation failed');
15
+ return false;
16
+ }
17
+ }
18
+ static parseConditions(conditionStr) {
19
+ const conditionPattern = /(\w+)\s*(==|!=|>=|<=|>|<)\s*(\d+|true|false|"[^"]*"|'[^']*')/g;
20
+ const conditions = [];
21
+ let match;
22
+ while ((match = conditionPattern.exec(conditionStr)) !== null) {
23
+ const field = match[1];
24
+ const operator = match[2];
25
+ let value = match[3];
26
+ if (value === 'true')
27
+ value = true;
28
+ else if (value === 'false')
29
+ value = false;
30
+ else if (/^\d+$/.test(value))
31
+ value = parseInt(value, 10);
32
+ else if (/^["']/.test(value))
33
+ value = value.slice(1, -1);
34
+ conditions.push({ field, operator, value });
35
+ }
36
+ return conditions;
37
+ }
38
+ static checkCondition(condition, payload) {
39
+ const { field, operator, value } = condition;
40
+ const actual = payload[field];
41
+ if (actual === undefined)
42
+ return { passed: false, reason: `字段 ${field} 未定义` };
43
+ let passed = false;
44
+ switch (operator) {
45
+ case '==':
46
+ passed = actual === value;
47
+ break;
48
+ case '!=':
49
+ passed = actual !== value;
50
+ break;
51
+ case '>=':
52
+ passed = typeof actual === 'number' && actual >= value;
53
+ break;
54
+ case '<=':
55
+ passed = typeof actual === 'number' && actual <= value;
56
+ break;
57
+ case '>':
58
+ passed = typeof actual === 'number' && actual > value;
59
+ break;
60
+ case '<':
61
+ passed = typeof actual === 'number' && actual < value;
62
+ break;
63
+ }
64
+ return { passed, reason: passed ? undefined : `${field}=${actual} 不满足 ${operator} ${value}` };
65
+ }
66
+ static checkHarnessGates(payload, requiredGates = ['ci-strict', 'coverage-80', 'review-passed', 'lint-clean']) {
67
+ const gateResults = [];
68
+ const payloadRecord = payload;
69
+ for (const gateId of requiredGates) {
70
+ const gate = this.HARNESS_GATES[gateId];
71
+ if (!gate)
72
+ continue;
73
+ if (gate.automatedCheck) {
74
+ const passed = this.evaluate(gate.automatedCheck, payloadRecord);
75
+ gateResults.push({ gate, passed, reason: passed ? undefined : `未满足 ${gate.automatedCheck}` });
76
+ }
77
+ else if (gate.conditions) {
78
+ const results = gate.conditions.map(c => this.checkCondition(c, payloadRecord));
79
+ const passed = results.every(r => r.passed);
80
+ gateResults.push({ gate, passed, reason: passed ? undefined : results.find(r => !r.passed)?.reason });
81
+ }
82
+ }
83
+ const passed = gateResults.filter(r => r.gate.required).every(r => r.passed);
84
+ return { passed, gateResults };
85
+ }
86
+ }
87
+ GateEvaluator.HARNESS_GATES = {
88
+ 'ci-strict': {
89
+ name: 'CI Strict Verification',
90
+ required: true,
91
+ automatedCheck: 'buildExitCode == 0 && testPassed == true && testTotal > 0 && testFailed == 0',
92
+ conditions: [
93
+ { field: 'buildExitCode', operator: '==', value: 0, description: '编译通过' },
94
+ { field: 'testPassed', operator: '==', value: true, description: '测试通过' },
95
+ { field: 'testTotal', operator: '>', value: 0, description: '测试数量>0' },
96
+ { field: 'testFailed', operator: '==', value: 0, description: '无失败测试' },
97
+ ],
98
+ passed: false,
99
+ },
100
+ 'coverage-80': {
101
+ name: 'Coverage Gate',
102
+ required: true,
103
+ automatedCheck: 'testCoverage >= 80',
104
+ conditions: [{ field: 'testCoverage', operator: '>=', value: 80, description: '覆盖率≥80%' }],
105
+ passed: false,
106
+ },
107
+ 'review-passed': {
108
+ name: 'Code Review Gate',
109
+ required: true,
110
+ automatedCheck: 'reviewPassed == true',
111
+ conditions: [{ field: 'reviewPassed', operator: '==', value: true, description: '评审通过' }],
112
+ passed: false,
113
+ },
114
+ 'lint-clean': {
115
+ name: 'Lint Gate',
116
+ required: true,
117
+ automatedCheck: 'lintStatus == "success"',
118
+ conditions: [{ field: 'lintStatus', operator: '==', value: 'success', description: 'Lint通过' }],
119
+ passed: false,
120
+ },
121
+ 'e2e-passed': {
122
+ name: 'E2E Verification Gate',
123
+ required: false,
124
+ automatedCheck: 'e2ePassed == true',
125
+ conditions: [{ field: 'e2ePassed', operator: '==', value: true, description: '端到端测试通过' }],
126
+ passed: false,
127
+ },
128
+ };
129
+ //# sourceMappingURL=GateEvaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GateEvaluator.js","sourceRoot":"","sources":["../../src/guardrails/GateEvaluator.ts"],"names":[],"mappings":"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"}
@@ -3,15 +3,14 @@
3
3
  // 设计参考:docs/03-CORE-MODULES.md §3.5
4
4
  import { logger } from '../core/logger.js';
5
5
  export class Gateway {
6
- eventBus;
7
- cache = new Map();
8
- detectors = {
9
- preTool: [],
10
- postTool: [],
11
- beforeStop: [],
12
- };
13
6
  constructor(eventBus) {
14
7
  this.eventBus = eventBus;
8
+ this.cache = new Map();
9
+ this.detectors = {
10
+ preTool: [],
11
+ postTool: [],
12
+ beforeStop: [],
13
+ };
15
14
  }
16
15
  registerDetector(detector, hook) {
17
16
  this.detectors[hook].push(detector);
@@ -1 +1 @@
1
- {"version":3,"file":"Gateway.js","sourceRoot":"","sources":["../../src/guardrails/Gateway.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,+BAA+B;AAC/B,oCAAoC;AAIpC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAmB1C,MAAM,OAAO,OAAO;IAQE;IAPZ,KAAK,GAAG,IAAI,GAAG,EAAmB,CAAA;IAClC,SAAS,GAAG;QAClB,OAAO,EAAE,EAAiB;QAC1B,QAAQ,EAAE,EAAiB;QAC3B,UAAU,EAAE,EAAiB;KAC9B,CAAA;IAED,YAAoB,QAAmB;QAAnB,aAAQ,GAAR,QAAQ,CAAW;IAAG,CAAC;IAE3C,gBAAgB,CAAC,QAAmB,EAAE,IAA2C;QAC/E,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;QACnC,MAAM,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,qBAAqB,CAAC,CAAA;IACpE,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,KAAmB;QAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YACzC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;YACrF,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACrB,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;oBAC9D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;oBACnI,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAA;gBAC/E,CAAC;gBACD,IAAI,MAAM,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;oBAC/B,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,CAAC,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAA;gBACrF,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;QACzG,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IACxB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,KAAsB;QACnC,IAAI,KAAK,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;YACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;QACpI,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAA;QAC3J,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YAC1C,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;QACxE,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAgB;QAC/B,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC;YAC5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAA;YACrF,IAAI,MAAM,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,KAAK,MAAM,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,CAAC,EAAE,CAAC;gBACpF,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,UAAU,EAAE,CAAA;YAC/E,CAAC;QACH,CAAC;QACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAA;IACxB,CAAC;CACF"}
1
+ {"version":3,"file":"Gateway.js","sourceRoot":"","sources":["../../src/guardrails/Gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { IArtifactStore } from '../artifact/store.js';
2
+ import type { IEventBus } from '../core/eventBus.js';
3
+ import type { IFSM } from '../artifact/fsm.js';
4
+ /**
5
+ * ReviewEnforcer - 编码完成后强制调用评审 Agent
6
+ *
7
+ * 文章证据:评审 Agent 发现了编码 Agent 遗漏的渠道判断逻辑(潜在线上故障)
8
+ *
9
+ * 工作流程:
10
+ * 1. Task 状态从 IN_PROGRESS → REVIEW_REQUIRED (新增状态)
11
+ * 2. 自动触发 code-reviewer agent 评审
12
+ * 3. 评审通过 → REVIEW_PASSED → DONE
13
+ * 4. 评审不通过 → REVIEW_FAILED → 回退到 IN_PROGRESS
14
+ */
15
+ export declare class ReviewEnforcer {
16
+ private store;
17
+ private eventBus;
18
+ private fsm;
19
+ constructor(store: IArtifactStore, eventBus: IEventBus, fsm: IFSM);
20
+ /**
21
+ * Harness: 检查是否需要强制评审
22
+ */
23
+ shouldEnforceReview(taskId: string): Promise<boolean>;
24
+ /**
25
+ * Harness: 强制评审入口
26
+ * 编码完成后自动触发,不依赖人工
27
+ */
28
+ enforceReview(taskId: string): Promise<ReviewResult>;
29
+ /**
30
+ * Harness: 自动回退机制
31
+ * 评审不通过时,自动回退到 IN_PROGRESS 状态
32
+ */
33
+ rollbackOnReviewFailure(taskId: string, reasons: string[]): Promise<void>;
34
+ /**
35
+ * Harness: 评审循环上限
36
+ * 文章启发:评审最多 2 轮,超出升级人工决策
37
+ */
38
+ checkReviewIteration(taskId: string): Promise<{
39
+ exceeded: boolean;
40
+ iteration: number;
41
+ }>;
42
+ }
43
+ export interface ReviewResult {
44
+ passed: boolean;
45
+ taskId: string;
46
+ reasons?: string[];
47
+ gateResults?: Array<{
48
+ gate: any;
49
+ passed: boolean;
50
+ reason?: string;
51
+ }>;
52
+ }
@@ -0,0 +1,117 @@
1
+ // SCALE Engine - Harness Engineering: 强制评审阶段
2
+ // 文章启发:"将做事的 Agent 和评判的 Agent 分开,是一个强有力的杠杆"
3
+ import { GateEvaluator } from '../guardrails/GateEvaluator.js';
4
+ import { logger } from '../core/logger.js';
5
+ /**
6
+ * ReviewEnforcer - 编码完成后强制调用评审 Agent
7
+ *
8
+ * 文章证据:评审 Agent 发现了编码 Agent 遗漏的渠道判断逻辑(潜在线上故障)
9
+ *
10
+ * 工作流程:
11
+ * 1. Task 状态从 IN_PROGRESS → REVIEW_REQUIRED (新增状态)
12
+ * 2. 自动触发 code-reviewer agent 评审
13
+ * 3. 评审通过 → REVIEW_PASSED → DONE
14
+ * 4. 评审不通过 → REVIEW_FAILED → 回退到 IN_PROGRESS
15
+ */
16
+ export class ReviewEnforcer {
17
+ constructor(store, eventBus, fsm) {
18
+ this.store = store;
19
+ this.eventBus = eventBus;
20
+ this.fsm = fsm;
21
+ }
22
+ /**
23
+ * Harness: 检查是否需要强制评审
24
+ */
25
+ async shouldEnforceReview(taskId) {
26
+ const task = await this.store.get(taskId);
27
+ if (!task)
28
+ return false;
29
+ // 已完成的任务不需要评审
30
+ if (task.status === 'DONE' || task.status === 'CANCELLED')
31
+ return false;
32
+ // IN_PROGRESS 状态的任务,检查是否修改了代码
33
+ if (task.status === 'IN_PROGRESS') {
34
+ const payload = task.payload;
35
+ // 有代码变更但未评审
36
+ if (payload.filesInvolved?.length > 0 && !payload.reviewPassed) {
37
+ return true;
38
+ }
39
+ }
40
+ return false;
41
+ }
42
+ /**
43
+ * Harness: 强制评审入口
44
+ * 编码完成后自动触发,不依赖人工
45
+ */
46
+ async enforceReview(taskId) {
47
+ const task = await this.store.get(taskId);
48
+ if (!task)
49
+ throw new Error('Task not found: ' + taskId);
50
+ logger.info({ taskId }, 'Enforcing mandatory review');
51
+ // 1. 发射评审事件(触发 code-reviewer agent)
52
+ this.eventBus.emit('review.required', {
53
+ taskId,
54
+ artifactId: taskId,
55
+ filesInvolved: task.payload.filesInvolved ?? [],
56
+ requiredChecks: [
57
+ '代码质量检查',
58
+ '安全漏洞扫描',
59
+ '业务逻辑验证',
60
+ '测试覆盖检查',
61
+ ],
62
+ });
63
+ // 2. 等待评审结果(简化版:直接检查 payload)
64
+ // 实际实现中应该等待 agent 完成评审并更新 payload
65
+ const payload = task.payload;
66
+ // 3. 检查 Harness Gates(程序化质量门禁)
67
+ const gateResult = GateEvaluator.checkHarnessGates(payload, ['ci-strict', 'coverage-80', 'lint-clean']);
68
+ // 4. 根据评审结果决定下一步
69
+ if (gateResult.passed && payload.reviewPassed) {
70
+ this.eventBus.emit('review.passed', { taskId, gateResults: gateResult.gateResults });
71
+ return { passed: true, taskId, gateResults: gateResult.gateResults };
72
+ }
73
+ else {
74
+ const reasons = gateResult.gateResults.filter(r => !r.passed).map(r => r.reason ?? r.gate.name);
75
+ this.eventBus.emit('review.failed', { taskId, reasons });
76
+ return { passed: false, taskId, reasons, gateResults: gateResult.gateResults };
77
+ }
78
+ }
79
+ /**
80
+ * Harness: 自动回退机制
81
+ * 评审不通过时,自动回退到 IN_PROGRESS 状态
82
+ */
83
+ async rollbackOnReviewFailure(taskId, reasons) {
84
+ const task = await this.store.get(taskId);
85
+ if (!task)
86
+ return;
87
+ logger.warn({ taskId, reasons }, 'Review failed, rolling back');
88
+ // 发射回退事件
89
+ this.eventBus.emit('task.review_failed', {
90
+ taskId,
91
+ previousStatus: task.status,
92
+ rollbackTo: 'IN_PROGRESS',
93
+ reasons,
94
+ });
95
+ // 更新 payload 记录失败原因
96
+ const payload = task.payload;
97
+ payload.reviewPassed = false;
98
+ // 触发 FSM transition(实际实现需要调用 fsm.transition)
99
+ // await this.fsm.transition(taskId, 'review_failed')
100
+ }
101
+ /**
102
+ * Harness: 评审循环上限
103
+ * 文章启发:评审最多 2 轮,超出升级人工决策
104
+ */
105
+ async checkReviewIteration(taskId) {
106
+ const events = await this.eventBus.query({
107
+ sessionId: '', // 需要 session context
108
+ types: ['review.required', 'review.passed', 'review.failed'],
109
+ filter: (e) => e.payload.taskId === taskId,
110
+ });
111
+ const reviewEvents = events.filter(e => e.type === 'review.required' || e.type === 'review.failed');
112
+ const iteration = reviewEvents.length;
113
+ // Harness: 最多 2 轮评审
114
+ return { exceeded: iteration >= 2, iteration };
115
+ }
116
+ }
117
+ //# sourceMappingURL=ReviewEnforcer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ReviewEnforcer.js","sourceRoot":"","sources":["../../src/guardrails/ReviewEnforcer.ts"],"names":[],"mappings":"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"}
@@ -5,21 +5,23 @@
5
5
  // 6. 危险命令检测器
6
6
  // ============================================================================
7
7
  export class DangerousCommandDetector {
8
- name = 'dangerous-command';
9
- patterns = [
10
- { pattern: /rm\s+-rf\s+[\/~]/, description: 'rm -rf on root/home' },
11
- { pattern: /rm\s+-rf\s+\*/, description: 'rm -rf wildcard' },
12
- { pattern: /DROP\s+(TABLE|DATABASE|SCHEMA)/i, description: 'SQL DROP' },
13
- { pattern: /TRUNCATE\s+TABLE/i, description: 'SQL TRUNCATE' },
14
- { pattern: /DELETE\s+FROM\s+\w+\s*;/i, description: 'SQL DELETE without WHERE' },
15
- { pattern: /ALTER\s+TABLE\s+\w+\s+DROP/i, description: 'SQL ALTER DROP column' },
16
- { pattern: /curl\s+.*\|\s*(bash|sh)/i, description: 'curl pipe to shell' },
17
- { pattern: /chmod\s+777/, description: 'chmod 777' },
18
- { pattern: />\s*\/dev\/sda/, description: 'write to device' },
19
- { pattern: /mkfs\./, description: 'format filesystem' },
20
- { pattern: /:(){ :\|:& };:/, description: 'fork bomb' },
21
- { pattern: /dd\s+if=.*of=\/dev\//, description: 'dd to device' },
22
- ];
8
+ constructor() {
9
+ this.name = 'dangerous-command';
10
+ this.patterns = [
11
+ { pattern: /rm\s+-rf\s+[\/~]/, description: 'rm -rf on root/home' },
12
+ { pattern: /rm\s+-rf\s+\*/, description: 'rm -rf wildcard' },
13
+ { pattern: /DROP\s+(TABLE|DATABASE|SCHEMA)/i, description: 'SQL DROP' },
14
+ { pattern: /TRUNCATE\s+TABLE/i, description: 'SQL TRUNCATE' },
15
+ { pattern: /DELETE\s+FROM\s+\w+\s*;/i, description: 'SQL DELETE without WHERE' },
16
+ { pattern: /ALTER\s+TABLE\s+\w+\s+DROP/i, description: 'SQL ALTER DROP column' },
17
+ { pattern: /curl\s+.*\|\s*(bash|sh)/i, description: 'curl pipe to shell' },
18
+ { pattern: /chmod\s+777/, description: 'chmod 777' },
19
+ { pattern: />\s*\/dev\/sda/, description: 'write to device' },
20
+ { pattern: /mkfs\./, description: 'format filesystem' },
21
+ { pattern: /:(){ :\|:& };:/, description: 'fork bomb' },
22
+ { pattern: /dd\s+if=.*of=\/dev\//, description: 'dd to device' },
23
+ ];
24
+ }
23
25
  async check(input, ctx) {
24
26
  if (input.tool !== 'Bash')
25
27
  return { triggered: false };
@@ -47,15 +49,17 @@ export class DangerousCommandDetector {
47
49
  // 7. 密钥泄露检测器
48
50
  // ============================================================================
49
51
  export class SecretLeakDetector {
50
- name = 'secret-leak';
51
- patterns = [
52
- { pattern: /['"]?[A-Za-z0-9+\/]{40}['"]?/, description: 'possible API key (40 chars)' },
53
- { pattern: /AKIA[0-9A-Z]{16}/, description: 'AWS Access Key ID' },
54
- { pattern: /-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----/, description: 'Private key' },
55
- { pattern: /sk-[a-zA-Z0-9]{48}/, description: 'OpenAI API key' },
56
- { pattern: /ghp_[a-zA-Z0-9]{36}/, description: 'GitHub PAT' },
57
- { pattern: /password\s*[:=]\s*['"][^'"]{8,}['"]/, description: 'hardcoded password' },
58
- ];
52
+ constructor() {
53
+ this.name = 'secret-leak';
54
+ this.patterns = [
55
+ { pattern: /['"]?[A-Za-z0-9+\/]{40}['"]?/, description: 'possible API key (40 chars)' },
56
+ { pattern: /AKIA[0-9A-Z]{16}/, description: 'AWS Access Key ID' },
57
+ { pattern: /-----BEGIN (RSA |EC |DSA )?PRIVATE KEY-----/, description: 'Private key' },
58
+ { pattern: /sk-[a-zA-Z0-9]{48}/, description: 'OpenAI API key' },
59
+ { pattern: /ghp_[a-zA-Z0-9]{36}/, description: 'GitHub PAT' },
60
+ { pattern: /password\s*[:=]\s*['"][^'"]{8,}['"]/, description: 'hardcoded password' },
61
+ ];
62
+ }
59
63
  async check(input, ctx) {
60
64
  if (!['Edit', 'Write', 'MultiEdit'].includes(input.tool))
61
65
  return { triggered: false };
@@ -104,8 +108,10 @@ export const BUILT_IN_ROLES = {
104
108
  },
105
109
  };
106
110
  export class RoleGateDetector {
107
- name = 'role-gate';
108
- currentRole = BUILT_IN_ROLES.implementer;
111
+ constructor() {
112
+ this.name = 'role-gate';
113
+ this.currentRole = BUILT_IN_ROLES.implementer;
114
+ }
109
115
  setRole(role) {
110
116
  this.currentRole = role;
111
117
  }
@@ -139,12 +145,8 @@ export class RoleGateDetector {
139
145
  // 9. ScopeCreep 检测器
140
146
  // ============================================================================
141
147
  export class ScopeCreepDetector {
142
- name = 'scope-creep';
143
- /** Max distinct files allowed per session before warning */
144
- maxFiles;
145
- /** Window in ms to track file edits */
146
- windowMs;
147
148
  constructor(opts = {}) {
149
+ this.name = 'scope-creep';
148
150
  this.maxFiles = opts.maxFiles ?? 15;
149
151
  this.windowMs = opts.windowMs ?? 10 * 60 * 1000; // 10 minutes
150
152
  }
@@ -1 +1 @@
1
- {"version":3,"file":"advancedDetectors.js","sourceRoot":"","sources":["../../src/guardrails/advancedDetectors.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"advancedDetectors.js","sourceRoot":"","sources":["../../src/guardrails/advancedDetectors.ts"],"names":[],"mappings":"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"}
@@ -4,9 +4,11 @@ import { createHash } from 'node:crypto';
4
4
  const hashArgs = (args) => createHash('md5').update(JSON.stringify(args)).digest('hex').slice(0, 8);
5
5
  // 1. 暴力重试检测
6
6
  export class BruteRetryDetector {
7
- name = 'brute-retry';
8
- windowMs = 3 * 60 * 1000;
9
- threshold = 3;
7
+ constructor() {
8
+ this.name = 'brute-retry';
9
+ this.windowMs = 3 * 60 * 1000;
10
+ this.threshold = 3;
11
+ }
10
12
  async check(input, ctx) {
11
13
  const key = `${input.sessionId}:${input.tool}:${hashArgs(input.args)}`;
12
14
  const history = ctx.cache.get(key) ?? [];
@@ -26,7 +28,9 @@ export class BruteRetryDetector {
26
28
  }
27
29
  // 2. 工具闲置检测
28
30
  export class IdleToolDetector {
29
- name = 'idle-tool';
31
+ constructor() {
32
+ this.name = 'idle-tool';
33
+ }
30
34
  async check(input, ctx) {
31
35
  if (!['Edit', 'Write', 'MultiEdit'].includes(input.tool))
32
36
  return { triggered: false };
@@ -55,7 +59,9 @@ export class IdleToolDetector {
55
59
  }
56
60
  // 3. 忙碌假象(来回反复修改同一文件)
57
61
  export class BusyLoopDetector {
58
- name = 'busy-loop';
62
+ constructor() {
63
+ this.name = 'busy-loop';
64
+ }
59
65
  async check(input, ctx) {
60
66
  if (input.tool !== 'Edit')
61
67
  return { triggered: false };
@@ -96,9 +102,12 @@ export class BusyLoopDetector {
96
102
  return { triggered: false };
97
103
  }
98
104
  }
99
- // 4. 声称完成但未验证
105
+ // 4. 声称完成但未验证(Harness Engineering 增强)
106
+ // 文章启发:"CI 通过但测试 0/0 是无效的"
100
107
  export class PrematureDoneDetector {
101
- name = 'premature-done';
108
+ constructor() {
109
+ this.name = 'premature-done';
110
+ }
102
111
  async check(input, ctx) {
103
112
  const edits = await ctx.eventBus.query({
104
113
  sessionId: input.sessionId,
@@ -107,6 +116,7 @@ export class PrematureDoneDetector {
107
116
  });
108
117
  if (edits.length === 0)
109
118
  return { triggered: false };
119
+ // Harness: 检查验证命令是否运行
110
120
  const verifications = await ctx.eventBus.query({
111
121
  sessionId: input.sessionId,
112
122
  types: ['tool.completed'],
@@ -115,15 +125,17 @@ export class PrematureDoneDetector {
115
125
  return p.tool === 'Bash' && /test|lint|build|typecheck/i.test(p.args.command ?? '');
116
126
  },
117
127
  });
128
+ // 情况1:完全未验证
118
129
  if (verifications.length === 0) {
119
130
  ctx.eventBus.emit('behavior.premature_done', { reason: 'no_verification' }, { sessionId: input.sessionId });
120
131
  return {
121
132
  triggered: true,
122
133
  severity: 'block',
123
134
  reason: '检测到「声称完成但未验证」:本会话修改了代码,但未运行任何 test/lint/build。请先运行验证命令。',
124
- suggestion: 'pnpm test (or your project test command)',
135
+ suggestion: 'pnpm test && pnpm lint && pnpm build',
125
136
  };
126
137
  }
138
+ // 情况2:验证在编辑之前(文章:Premature Victory Declaration)
127
139
  const lastVerify = verifications[0];
128
140
  const lastEdit = edits[0];
129
141
  if (lastVerify.timestamp < lastEdit.timestamp) {
@@ -133,19 +145,67 @@ export class PrematureDoneDetector {
133
145
  reason: '修改了代码但最后一次验证是修改之前运行的。请重新运行验证。',
134
146
  };
135
147
  }
148
+ // 情况3:Harness 新增 - 检查测试结果是否真正通过
149
+ // 文章启发:Agent 可能认为 "SUCCESS" 就通过,但实际测试 0/0
150
+ const testCmd = verifications.find(e => {
151
+ const p = e.payload;
152
+ return /test/i.test(p.args.command ?? '');
153
+ });
154
+ if (testCmd) {
155
+ const output = testCmd.payload.output ?? '';
156
+ // 检测测试 0/0 异常
157
+ if (/tests?\s*(0|no\s*tests?)/i.test(output) || /passed:\s*0/i.test(output)) {
158
+ ctx.eventBus.emit('behavior.premature_done', { reason: 'empty_tests' }, { sessionId: input.sessionId });
159
+ return {
160
+ triggered: true,
161
+ severity: 'block',
162
+ reason: '检测到「测试为空」:运行了测试命令但测试数为 0。请确保测试文件存在且被正确执行。',
163
+ suggestion: '检查测试文件是否存在,或添加测试用例',
164
+ };
165
+ }
166
+ // 检测失败测试
167
+ if (/failed:\s*[1-9]/i.test(output) || /FAIL/i.test(output)) {
168
+ ctx.eventBus.emit('behavior.premature_done', { reason: 'tests_failed' }, { sessionId: input.sessionId });
169
+ return {
170
+ triggered: true,
171
+ severity: 'block',
172
+ reason: '检测到「测试失败」:存在失败的测试,不能声称完成。',
173
+ suggestion: '修复失败的测试后重新运行',
174
+ };
175
+ }
176
+ }
177
+ // 情况4:Harness 新增 - 检查编译是否通过
178
+ const buildCmd = verifications.find(e => {
179
+ const p = e.payload;
180
+ return /build|compile|tsc/i.test(p.args.command ?? '');
181
+ });
182
+ if (buildCmd) {
183
+ const exitCode = buildCmd.payload.exitCode ?? 0;
184
+ if (exitCode !== 0) {
185
+ ctx.eventBus.emit('behavior.premature_done', { reason: 'build_failed' }, { sessionId: input.sessionId });
186
+ return {
187
+ triggered: true,
188
+ severity: 'block',
189
+ reason: '检测到「编译失败」:build 命令返回非零退出码。',
190
+ suggestion: '修复编译错误后重新构建',
191
+ };
192
+ }
193
+ }
136
194
  return { triggered: false };
137
195
  }
138
196
  }
139
197
  // 5. 甩锅检测
140
198
  export class BlameShiftDetector {
141
- name = 'blame-shift';
142
- patterns = [
143
- /可能是环境问题/i,
144
- /建议你?手动/i,
145
- /maybe (an?|the) (environment|version|setup)/i,
146
- /not sure why/i,
147
- /unable to (determine|figure out|resolve)/i,
148
- ];
199
+ constructor() {
200
+ this.name = 'blame-shift';
201
+ this.patterns = [
202
+ /可能是环境问题/i,
203
+ /建议你?手动/i,
204
+ /maybe (an?|the) (environment|version|setup)/i,
205
+ /not sure why/i,
206
+ /unable to (determine|figure out|resolve)/i,
207
+ ];
208
+ }
149
209
  async check(input, ctx) {
150
210
  const text = input.output ?? '';
151
211
  if (!this.patterns.some((p) => p.test(text)))