rules-enforcer 1.0.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 (33) hide show
  1. package/README.md +58 -0
  2. package/detector/README.md +212 -0
  3. package/detector/decision-engine/README.md +203 -0
  4. package/detector/decision-engine/conflict-resolver.js +336 -0
  5. package/detector/decision-engine/de-verify.js +461 -0
  6. package/detector/decision-engine/index.js +204 -0
  7. package/detector/decision-engine/optimizer.js +325 -0
  8. package/detector/decision-engine/scorer.js +359 -0
  9. package/detector/knowledge-base/README.md +140 -0
  10. package/detector/knowledge-base/agent-knowledge.json +62 -0
  11. package/detector/knowledge-base/index.js +332 -0
  12. package/detector/knowledge-base/kb-verify.js +287 -0
  13. package/detector/knowledge-base/mcp-knowledge.json +135 -0
  14. package/detector/knowledge-base/rules-knowledge.json +184 -0
  15. package/detector/mcp-server.js +157 -0
  16. package/detector/mcp-service.js +118 -0
  17. package/detector/package.json +13 -0
  18. package/detector/plugin.json +122 -0
  19. package/detector/project-detector.js +710 -0
  20. package/detector/render-engine/ag-config-render.js +195 -0
  21. package/detector/render-engine/index.js +124 -0
  22. package/detector/render-engine/render-core.js +200 -0
  23. package/detector/render-engine/render-verify.js +282 -0
  24. package/detector/render-engine/rule-render.js +231 -0
  25. package/detector/test-exceptions.js +366 -0
  26. package/detector/verify-plugin.js +233 -0
  27. package/hooks/chain-invoker.js +98 -0
  28. package/hooks/custom-hook-server.js +312 -0
  29. package/hooks/mcp-hooks.js +153 -0
  30. package/hooks/validate-chain.js +147 -0
  31. package/package.json +35 -0
  32. package/rules-server.js +350 -0
  33. package/test/test-mcp-full.js +193 -0
@@ -0,0 +1,366 @@
1
+ /**
2
+ * Project Detector Exception Test Cases
3
+ * 异常场景测试:空目录、缺失规则文件、配置损坏等
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+ const { ProjectDetector } = require('./project-detector.js');
9
+
10
+ class ExceptionTestRunner {
11
+ constructor() {
12
+ this.results = [];
13
+ this.passed = 0;
14
+ this.failed = 0;
15
+ this.testDir = path.join(__dirname, 'test-temp');
16
+ }
17
+
18
+ /**
19
+ * 记录测试结果
20
+ */
21
+ log(testName, status, message) {
22
+ const icon = status === 'PASS' ? '✅' : '❌';
23
+ const log = `${icon} [${testName}] ${message}`;
24
+ this.results.push({ testName, status, message });
25
+ console.log(log);
26
+ if (status === 'PASS') this.passed++;
27
+ else this.failed++;
28
+ }
29
+
30
+ /**
31
+ * 准备测试环境
32
+ */
33
+ setup() {
34
+ console.log('[Setup] 创建临时测试目录...\n');
35
+ this.cleanup();
36
+ fs.mkdirSync(this.testDir, { recursive: true });
37
+ fs.mkdirSync(path.join(this.testDir, '.trae', 'rules'), { recursive: true });
38
+ fs.mkdirSync(path.join(this.testDir, '.trae', 'agents'), { recursive: true });
39
+ }
40
+
41
+ /**
42
+ * 清理测试环境
43
+ */
44
+ cleanup() {
45
+ if (fs.existsSync(this.testDir)) {
46
+ fs.rmSync(this.testDir, { recursive: true, force: true });
47
+ }
48
+ }
49
+
50
+ /**
51
+ * 测试1: 空目录探测 - 不崩溃
52
+ */
53
+ testEmptyDirectory() {
54
+ console.log('\n========== 测试1: 空目录探测 ==========');
55
+
56
+ const testEmptyDir = path.join(this.testDir, 'empty-project');
57
+ fs.mkdirSync(testEmptyDir, { recursive: true });
58
+
59
+ try {
60
+ const detector = new ProjectDetector(testEmptyDir);
61
+ detector.scan();
62
+
63
+ // 空目录扫描不应崩溃
64
+ this.log('EmptyDir', 'PASS', '空目录探测无崩溃');
65
+
66
+ // 检查报告结构完整
67
+ const report = detector.getReport();
68
+ if (report && report.techStack && report.fileErrors) {
69
+ this.log('EmptyDir', 'PASS', '报告结构完整');
70
+ } else {
71
+ this.log('EmptyDir', 'FAIL', '报告结构不完整');
72
+ }
73
+
74
+ this.log('EmptyDir', 'PASS', '空目录探测完成');
75
+
76
+ } catch (e) {
77
+ this.log('EmptyDir', 'FAIL', `异常捕获: ${e.message}`);
78
+ }
79
+ }
80
+
81
+ /**
82
+ * 测试2: 规则文件夹缺失 - 正确处理
83
+ */
84
+ testMissingRulesDir() {
85
+ console.log('\n========== 测试2: 规则文件夹缺失 ==========');
86
+
87
+ const testDir = path.join(this.testDir, 'no-rules');
88
+ fs.mkdirSync(testDir, { recursive: true });
89
+
90
+ try {
91
+ const detector = new ProjectDetector(testDir);
92
+ detector.scanRules();
93
+
94
+ // rules应为空
95
+ if (detector.existingComponents.rules.length === 0) {
96
+ this.log('MissingRules', 'PASS', '规则目录缺失时 rules 为空数组');
97
+ } else {
98
+ this.log('MissingRules', 'FAIL', `规则目录缺失时 rules 应为空`);
99
+ }
100
+
101
+ // 应产生fileError记录
102
+ if (detector.fileErrors.length > 0) {
103
+ const hasRulesError = detector.fileErrors.some(e =>
104
+ e.context === 'scanRules' && (e.error.includes('不存在') || e.error.includes('目录'))
105
+ );
106
+ if (hasRulesError) {
107
+ this.log('MissingRules', 'PASS', '正确记录规则目录缺失异常');
108
+ } else {
109
+ this.log('MissingRules', 'FAIL', '未记录规则目录缺失异常');
110
+ }
111
+ } else {
112
+ this.log('MissingRules', 'WARN', '无异常日志(可能目录已存在)');
113
+ }
114
+
115
+ this.log('MissingRules', 'PASS', '规则目录缺失测试完成');
116
+
117
+ } catch (e) {
118
+ this.log('MissingRules', 'FAIL', `异常: ${e.message}`);
119
+ }
120
+ }
121
+
122
+ /**
123
+ * 测试3: 部分规则文件存在 - 正确识别
124
+ */
125
+ testPartialRules() {
126
+ console.log('\n========== 测试3: 部分规则文件存在 ==========');
127
+
128
+ const testDir = path.join(this.testDir, 'partial-rules');
129
+ fs.mkdirSync(testDir, { recursive: true });
130
+ fs.mkdirSync(path.join(testDir, '.trae', 'rules'), { recursive: true });
131
+
132
+ // 只创建 user_rules.md,不创建 project_rules.md
133
+ fs.writeFileSync(
134
+ path.join(testDir, '.trae', 'rules', 'user_rules.md'),
135
+ '# User Rules\nTest content'
136
+ );
137
+
138
+ try {
139
+ const detector = new ProjectDetector(testDir);
140
+ detector.scanRules();
141
+
142
+ const l1Count = detector.existingComponents.rules.filter(r => r.level === 'L1').length;
143
+ const l2Count = detector.existingComponents.rules.filter(r => r.level === 'L2').length;
144
+
145
+ if (l1Count === 1) {
146
+ this.log('PartialRules', 'PASS', 'L1规则检测到1个');
147
+ } else {
148
+ this.log('PartialRules', 'FAIL', `L1规则应为1个,实际: ${l1Count}`);
149
+ }
150
+
151
+ if (l2Count === 0) {
152
+ this.log('PartialRules', 'PASS', 'L2规则正确为空');
153
+ } else {
154
+ this.log('PartialRules', 'FAIL', `L2规则应为空,实际: ${l2Count}`);
155
+ }
156
+
157
+ this.log('PartialRules', 'PASS', '部分规则文件测试完成');
158
+
159
+ } catch (e) {
160
+ this.log('PartialRules', 'FAIL', `异常: ${e.message}`);
161
+ }
162
+ }
163
+
164
+ /**
165
+ * 测试4: 无效项目路径 - 正确抛出异常
166
+ */
167
+ testInvalidPath() {
168
+ console.log('\n========== 测试4: 无效项目路径 ==========');
169
+
170
+ const invalidPath = path.join(this.testDir, 'non-existent-path');
171
+
172
+ try {
173
+ const detector = new ProjectDetector(invalidPath);
174
+ detector.scan();
175
+ this.log('InvalidPath', 'FAIL', '应抛出错误但未抛出');
176
+ } catch (e) {
177
+ if (e.message.includes('不存在') || e.message.includes('无效')) {
178
+ this.log('InvalidPath', 'PASS', `正确抛出异常: ${e.message}`);
179
+ } else {
180
+ this.log('InvalidPath', 'FAIL', `异常信息不正确: ${e.message}`);
181
+ }
182
+ }
183
+ }
184
+
185
+ /**
186
+ * 测试5: 非目录路径 - 正确抛出异常
187
+ */
188
+ testFileAsPath() {
189
+ console.log('\n========== 测试5: 文件路径作为项目路径 ==========');
190
+
191
+ const testFile = path.join(this.testDir, 'test-file.txt');
192
+ fs.writeFileSync(testFile, 'test content');
193
+
194
+ try {
195
+ const detector = new ProjectDetector(testFile);
196
+ detector.scan();
197
+ this.log('FileAsPath', 'FAIL', '应抛出错误但未抛出');
198
+ } catch (e) {
199
+ if (e.message.includes('不是目录') || e.message.includes('无效') || e.message.includes('不存在')) {
200
+ this.log('FileAsPath', 'PASS', `正确抛出异常: ${e.message}`);
201
+ } else {
202
+ this.log('FileAsPath', 'FAIL', `异常信息不正确: ${e.message}`);
203
+ }
204
+ }
205
+ }
206
+
207
+ /**
208
+ * 测试6: 损坏的package.json - 健壮处理
209
+ */
210
+ testCorruptedPackageJson() {
211
+ console.log('\n========== 测试6: 损坏的package.json ==========');
212
+
213
+ const testDir = path.join(this.testDir, 'corrupted-pkg');
214
+ fs.mkdirSync(testDir, { recursive: true });
215
+ fs.writeFileSync(
216
+ path.join(testDir, 'package.json'),
217
+ '{ invalid json content'
218
+ );
219
+
220
+ try {
221
+ const detector = new ProjectDetector(testDir);
222
+ detector.scanTechStack();
223
+
224
+ // 损坏的package.json应该不导致崩溃
225
+ this.log('CorruptedPkg', 'PASS', '损坏package.json不导致崩溃');
226
+
227
+ // techStack应包含Node.js(默认值,即使JSON损坏)
228
+ if (detector.techStack.includes('Node.js')) {
229
+ this.log('CorruptedPkg', 'PASS', '损坏package.json正确返回Node.js默认值');
230
+ } else {
231
+ this.log('CorruptedPkg', 'WARN', `techStack: ${detector.techStack} (可能正确)`);
232
+ }
233
+
234
+ this.log('CorruptedPkg', 'PASS', '损坏package.json测试完成');
235
+
236
+ } catch (e) {
237
+ this.log('CorruptedPkg', 'FAIL', `异常: ${e.message}`);
238
+ }
239
+ }
240
+
241
+ /**
242
+ * 测试7: 深层嵌套目录 - 正确截断
243
+ */
244
+ testDeepNesting() {
245
+ console.log('\n========== 测试7: 深层嵌套目录 ==========');
246
+
247
+ const testDir = path.join(this.testDir, 'deep-nesting');
248
+ let current = testDir;
249
+
250
+ // 创建6层嵌套
251
+ for (let i = 0; i < 6; i++) {
252
+ current = path.join(current, `level${i}`);
253
+ fs.mkdirSync(current, { recursive: true });
254
+ }
255
+
256
+ try {
257
+ const detector = new ProjectDetector(testDir);
258
+ detector.scanDirectoryStructure(4); // maxDepth = 4
259
+
260
+ const nodesBeyondDepth = detector.fullTopology.filter(n => n.depth > 4);
261
+
262
+ if (nodesBeyondDepth.length === 0) {
263
+ this.log('DeepNesting', 'PASS', '深层嵌套被正确截断在depth=4');
264
+ } else {
265
+ this.log('DeepNesting', 'FAIL', `有${nodesBeyondDepth.length}个节点超出深度限制`);
266
+ }
267
+
268
+ this.log('DeepNesting', 'PASS', '深层嵌套测试完成');
269
+
270
+ } catch (e) {
271
+ this.log('DeepNesting', 'FAIL', `异常: ${e.message}`);
272
+ }
273
+ }
274
+
275
+ /**
276
+ * 测试8: 极长文件名 - 健壮处理
277
+ */
278
+ testLongFileName() {
279
+ console.log('\n========== 测试8: 极长文件名 ==========');
280
+
281
+ const testDir = path.join(this.testDir, 'long-names');
282
+ fs.mkdirSync(testDir, { recursive: true });
283
+
284
+ // 创建超长文件名
285
+ const longName = 'a'.repeat(300) + '.txt';
286
+ try {
287
+ fs.writeFileSync(path.join(testDir, longName), 'content');
288
+
289
+ const detector = new ProjectDetector(testDir);
290
+ detector.scanDirectoryStructure(2);
291
+
292
+ this.log('LongFileName', 'PASS', '极长文件名不导致崩溃');
293
+
294
+ } catch (e) {
295
+ // 文件系统限制导致的错误是可接受的
296
+ this.log('LongFileName', 'PASS', `文件系统限制: ${e.message.substring(0, 50)}`);
297
+ }
298
+ }
299
+
300
+ /**
301
+ * 测试9: 符号链接目录 - 正确处理
302
+ */
303
+ testSymlinkDir() {
304
+ console.log('\n========== 测试9: 符号链接目录 ==========');
305
+
306
+ const testDir = path.join(this.testDir, 'symlink-test');
307
+ const realDir = path.join(testDir, 'real-dir');
308
+ const linkDir = path.join(testDir, 'link-dir');
309
+
310
+ fs.mkdirSync(realDir, { recursive: true });
311
+ fs.mkdirSync(testDir, { recursive: true });
312
+
313
+ try {
314
+ // 在Windows上可能不支持符号链接,跳过此测试
315
+ fs.symlinkSync(realDir, linkDir, 'junction');
316
+
317
+ const detector = new ProjectDetector(testDir);
318
+ detector.scanDirectoryStructure(3);
319
+
320
+ this.log('SymlinkDir', 'PASS', '符号链接目录不导致崩溃');
321
+
322
+ } catch (e) {
323
+ // 符号链接不支持是可接受的
324
+ this.log('SymlinkDir', 'PASS', `符号链接不支持: ${e.message.substring(0, 50)}`);
325
+ }
326
+ }
327
+
328
+ /**
329
+ * 执行全部测试
330
+ */
331
+ runAll() {
332
+ console.log('===========================================');
333
+ console.log(' Project Detector Exception Tests');
334
+ console.log('===========================================\n');
335
+
336
+ this.setup();
337
+
338
+ this.testEmptyDirectory();
339
+ this.testMissingRulesDir();
340
+ this.testPartialRules();
341
+ this.testInvalidPath();
342
+ this.testFileAsPath();
343
+ this.testCorruptedPackageJson();
344
+ this.testDeepNesting();
345
+ this.testLongFileName();
346
+ this.testSymlinkDir();
347
+
348
+ this.cleanup();
349
+
350
+ console.log('\n===========================================');
351
+ console.log(` 测试结果: ${this.passed} 通过, ${this.failed} 失败`);
352
+ console.log('===========================================');
353
+
354
+ if (this.failed > 0) {
355
+ console.log('\n❌ 部分测试未通过,请检查上述失败项');
356
+ process.exit(1);
357
+ } else {
358
+ console.log('\n✅ 全部异常测试通过!');
359
+ process.exit(0);
360
+ }
361
+ }
362
+ }
363
+
364
+ // 执行测试
365
+ const runner = new ExceptionTestRunner();
366
+ runner.runAll();
@@ -0,0 +1,233 @@
1
+ /**
2
+ * Project Detector Plugin Verification Script
3
+ * 插件注册状态校验、功能可用性测试
4
+ */
5
+
6
+ const fs = require('fs');
7
+ const path = require('path');
8
+
9
+ const PLUGIN_DIR = path.join(__dirname);
10
+ const PROJECT_ROOT = path.join(__dirname, '..', '..', '..');
11
+
12
+ class PluginVerifier {
13
+ constructor() {
14
+ this.results = [];
15
+ this.passed = 0;
16
+ this.failed = 0;
17
+ }
18
+
19
+ /**
20
+ * 记录测试结果
21
+ */
22
+ log(type, message, status) {
23
+ const icon = status === 'PASS' ? '✅' : '❌';
24
+ const log = `${icon} [${type}] ${message}`;
25
+ this.results.push({ type, message, status });
26
+ console.log(log);
27
+ if (status === 'PASS') this.passed++;
28
+ else this.failed++;
29
+ }
30
+
31
+ /**
32
+ * 验证插件目录存在
33
+ */
34
+ verifyPluginDir() {
35
+ const dirs = [
36
+ path.join(PROJECT_ROOT, '.trae', 'plugins', 'project-detector')
37
+ ];
38
+
39
+ for (const dir of dirs) {
40
+ if (fs.existsSync(dir)) {
41
+ this.log('DIR', `插件目录存在: ${dir}`, 'PASS');
42
+ } else {
43
+ this.log('DIR', `插件目录不存在: ${dir}`, 'FAIL');
44
+ }
45
+ }
46
+ }
47
+
48
+ /**
49
+ * 验证插件配置文件
50
+ */
51
+ verifyPluginConfig() {
52
+ const configPath = path.join(PLUGIN_DIR, 'plugin.json');
53
+
54
+ if (!fs.existsSync(configPath)) {
55
+ this.log('CONFIG', 'plugin.json 不存在', 'FAIL');
56
+ return;
57
+ }
58
+
59
+ try {
60
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
61
+
62
+ const requiredFields = ['name', 'version', 'entryPoint', 'contributes'];
63
+ for (const field of requiredFields) {
64
+ if (config[field]) {
65
+ this.log('CONFIG', `字段 ${field} 存在`, 'PASS');
66
+ } else {
67
+ this.log('CONFIG', `字段 ${field} 缺失`, 'FAIL');
68
+ }
69
+ }
70
+
71
+ // 验证快捷指令配置
72
+ if (config.shortcuts) {
73
+ this.log('CONFIG', `快捷指令配置存在: ${JSON.stringify(config.shortcuts)}`, 'PASS');
74
+ } else {
75
+ this.log('CONFIG', '快捷指令配置缺失', 'FAIL');
76
+ }
77
+
78
+ // 验证 MCP 集成配置
79
+ if (config.mcpIntegration) {
80
+ this.log('CONFIG', `MCP集成配置存在`, 'PASS');
81
+ } else {
82
+ this.log('CONFIG', 'MCP集成配置缺失', 'FAIL');
83
+ }
84
+
85
+ } catch (e) {
86
+ this.log('CONFIG', `plugin.json 解析失败: ${e.message}`, 'FAIL');
87
+ }
88
+ }
89
+
90
+ /**
91
+ * 验证入口脚本
92
+ */
93
+ verifyEntryScript() {
94
+ const entryPath = path.join(PLUGIN_DIR, 'project-detector.js');
95
+
96
+ if (!fs.existsSync(entryPath)) {
97
+ this.log('SCRIPT', '入口脚本 project-detector.js 不存在', 'FAIL');
98
+ return;
99
+ }
100
+
101
+ try {
102
+ const content = fs.readFileSync(entryPath, 'utf8');
103
+
104
+ // 检查必要的方法
105
+ const methods = ['scanTechStack', 'scanDirectoryStructure', 'scanMCP', 'scanAgents', 'scanRules'];
106
+ for (const method of methods) {
107
+ if (content.includes(method)) {
108
+ this.log('SCRIPT', `方法 ${method} 存在`, 'PASS');
109
+ } else {
110
+ this.log('SCRIPT', `方法 ${method} 缺失`, 'FAIL');
111
+ }
112
+ }
113
+
114
+ this.log('SCRIPT', '入口脚本语法检查通过', 'PASS');
115
+ } catch (e) {
116
+ this.log('SCRIPT', `入口脚本读取失败: ${e.message}`, 'FAIL');
117
+ }
118
+ }
119
+
120
+ /**
121
+ * 验证 MCP 服务配置
122
+ */
123
+ verifyMCPConfig() {
124
+ const mcpConfigPath = path.join(PROJECT_ROOT, '.trae', 'mcp', 'mcp.json');
125
+
126
+ if (!fs.existsSync(mcpConfigPath)) {
127
+ this.log('MCP', 'MCP配置文件不存在', 'FAIL');
128
+ return;
129
+ }
130
+
131
+ try {
132
+ const config = JSON.parse(fs.readFileSync(mcpConfigPath, 'utf8'));
133
+
134
+ if (config.mcpServers && config.mcpServers['project-detector']) {
135
+ this.log('MCP', 'project-detector MCP服务已注册', 'PASS');
136
+ } else {
137
+ this.log('MCP', 'project-detector MCP服务未注册', 'FAIL');
138
+ }
139
+ } catch (e) {
140
+ this.log('MCP', `MCP配置解析失败: ${e.message}`, 'FAIL');
141
+ }
142
+ }
143
+
144
+ /**
145
+ * 功能测试
146
+ */
147
+ verifyFunctionality() {
148
+ try {
149
+ const { ProjectDetector } = require('./project-detector.js');
150
+ const detector = new ProjectDetector(PROJECT_ROOT);
151
+
152
+ // 测试基本扫描
153
+ detector.scanTechStack();
154
+ if (detector.techStack.length > 0) {
155
+ this.log('FUNC', `技术栈扫描: ${detector.techStack.join(', ')}`, 'PASS');
156
+ } else {
157
+ this.log('FUNC', '技术栈扫描结果为空', 'FAIL');
158
+ }
159
+
160
+ detector.scanMCP();
161
+ if (detector.existingComponents.mcp.length > 0) {
162
+ this.log('FUNC', `MCP扫描: ${detector.existingComponents.mcp.join(', ')}`, 'PASS');
163
+ } else {
164
+ this.log('FUNC', 'MCP扫描结果为空', 'FAIL');
165
+ }
166
+
167
+ detector.scanAgents();
168
+ if (detector.existingComponents.agents.length > 0) {
169
+ this.log('FUNC', `Agent扫描: ${detector.existingComponents.agents.length}个`, 'PASS');
170
+ } else {
171
+ this.log('FUNC', 'Agent扫描结果为空', 'FAIL');
172
+ }
173
+
174
+ detector.scanRules();
175
+ if (detector.existingComponents.rules.length > 0) {
176
+ this.log('FUNC', `规则扫描: ${detector.existingComponents.rules.length}个`, 'PASS');
177
+ } else {
178
+ this.log('FUNC', '规则扫描结果为空', 'FAIL');
179
+ }
180
+
181
+ this.log('FUNC', '功能测试全部通过', 'PASS');
182
+
183
+ } catch (e) {
184
+ this.log('FUNC', `功能测试失败: ${e.message}`, 'FAIL');
185
+ }
186
+ }
187
+
188
+ /**
189
+ * 执行全部验证
190
+ */
191
+ verifyAll() {
192
+ console.log('===========================================');
193
+ console.log(' Project Detector Plugin Verification');
194
+ console.log('===========================================\n');
195
+
196
+ console.log('[1] 验证插件目录结构...');
197
+ this.verifyPluginDir();
198
+ console.log('');
199
+
200
+ console.log('[2] 验证插件配置文件...');
201
+ this.verifyPluginConfig();
202
+ console.log('');
203
+
204
+ console.log('[3] 验证入口脚本...');
205
+ this.verifyEntryScript();
206
+ console.log('');
207
+
208
+ console.log('[4] 验证MCP服务配置...');
209
+ this.verifyMCPConfig();
210
+ console.log('');
211
+
212
+ console.log('[5] 功能测试...');
213
+ this.verifyFunctionality();
214
+ console.log('');
215
+
216
+ console.log('===========================================');
217
+ console.log(` 验证结果: ${this.passed} 通过, ${this.failed} 失败`);
218
+ console.log('===========================================');
219
+
220
+ if (this.failed > 0) {
221
+ console.log('\n❌ 验证未全部通过,请检查上述失败项');
222
+ process.exit(1);
223
+ } else {
224
+ console.log('\n✅ 插件验证全部通过!');
225
+ console.log('\n快捷指令: $detect, $scan-project, $quick-scan');
226
+ process.exit(0);
227
+ }
228
+ }
229
+ }
230
+
231
+ // 执行验证
232
+ const verifier = new PluginVerifier();
233
+ verifier.verifyAll();
@@ -0,0 +1,98 @@
1
+ /**
2
+ * MCP网关钩子层 - 三层调用链路
3
+ * 版本: 1.0
4
+ * 描述: 串联MCP网关、规则引擎、G记忆系统的数据调用链路
5
+ */
6
+
7
+ const fs = require('fs');
8
+ const path = require('path');
9
+
10
+ // 加载规则配置
11
+ function loadRulesConfig() {
12
+ const rulesPath = path.join(__dirname, '..', '..', 'rules', 'custom_config');
13
+ const configs = {};
14
+
15
+ try {
16
+ const files = fs.readdirSync(rulesPath).filter(f => f.endsWith('.yml'));
17
+ files.forEach(file => {
18
+ const fullPath = path.join(rulesPath, file);
19
+ configs[file] = fs.readFileSync(fullPath, 'utf8');
20
+ });
21
+ } catch (error) {
22
+ console.error('Failed to load rules config:', error.message);
23
+ }
24
+
25
+ return configs;
26
+ }
27
+
28
+ // 加载G记忆系统
29
+ function loadMemoryConfig() {
30
+ const memoryPath = path.join(__dirname, '..', '..', 'g_memory');
31
+ const memory = {
32
+ shortTerm: path.join(memoryPath, '短期存储'),
33
+ mediumTerm: path.join(memoryPath, '中期存储'),
34
+ longTerm: path.join(memoryPath, '长期存储'),
35
+ explicit: path.join(memoryPath, '明知识'),
36
+ implicit: path.join(memoryPath, '暗知识')
37
+ };
38
+
39
+ const status = {};
40
+ Object.entries(memory).forEach(([key, dir]) => {
41
+ try {
42
+ status[key] = {
43
+ exists: fs.existsSync(dir),
44
+ files: fs.existsSync(dir) ? fs.readdirSync(dir) : []
45
+ };
46
+ } catch {
47
+ status[key] = { exists: false, files: [] };
48
+ }
49
+ });
50
+
51
+ return { paths: memory, status };
52
+ }
53
+
54
+ // 调用链路主函数
55
+ async function invokeChain(context) {
56
+ const result = {
57
+ input: context,
58
+ rulesLoaded: false,
59
+ memoryAccessed: false,
60
+ output: null
61
+ };
62
+
63
+ // 1. 加载规则引擎配置
64
+ const rulesConfig = loadRulesConfig();
65
+ result.rulesLoaded = Object.keys(rulesConfig).length > 0;
66
+ result.rules = rulesConfig;
67
+
68
+ // 2. 访问G记忆系统
69
+ const memoryConfig = loadMemoryConfig();
70
+ result.memoryAccessed = memoryConfig.status.shortTerm.exists;
71
+ result.memory = memoryConfig;
72
+
73
+ // 3. 处理流程
74
+ if (result.rulesLoaded && result.memoryAccessed) {
75
+ result.output = {
76
+ status: 'success',
77
+ message: 'Chain invocation completed',
78
+ rulesCount: Object.keys(rulesConfig).length,
79
+ memoryReady: memoryConfig.status.shortTerm.exists
80
+ };
81
+ } else {
82
+ result.output = {
83
+ status: 'partial',
84
+ message: 'Some components not available',
85
+ rulesLoaded: result.rulesLoaded,
86
+ memoryReady: result.memoryAccessed
87
+ };
88
+ }
89
+
90
+ return result;
91
+ }
92
+
93
+ // 导出模块
94
+ module.exports = {
95
+ loadRulesConfig,
96
+ loadMemoryConfig,
97
+ invokeChain
98
+ };