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.
- package/README.md +58 -0
- package/detector/README.md +212 -0
- package/detector/decision-engine/README.md +203 -0
- package/detector/decision-engine/conflict-resolver.js +336 -0
- package/detector/decision-engine/de-verify.js +461 -0
- package/detector/decision-engine/index.js +204 -0
- package/detector/decision-engine/optimizer.js +325 -0
- package/detector/decision-engine/scorer.js +359 -0
- package/detector/knowledge-base/README.md +140 -0
- package/detector/knowledge-base/agent-knowledge.json +62 -0
- package/detector/knowledge-base/index.js +332 -0
- package/detector/knowledge-base/kb-verify.js +287 -0
- package/detector/knowledge-base/mcp-knowledge.json +135 -0
- package/detector/knowledge-base/rules-knowledge.json +184 -0
- package/detector/mcp-server.js +157 -0
- package/detector/mcp-service.js +118 -0
- package/detector/package.json +13 -0
- package/detector/plugin.json +122 -0
- package/detector/project-detector.js +710 -0
- package/detector/render-engine/ag-config-render.js +195 -0
- package/detector/render-engine/index.js +124 -0
- package/detector/render-engine/render-core.js +200 -0
- package/detector/render-engine/render-verify.js +282 -0
- package/detector/render-engine/rule-render.js +231 -0
- package/detector/test-exceptions.js +366 -0
- package/detector/verify-plugin.js +233 -0
- package/hooks/chain-invoker.js +98 -0
- package/hooks/custom-hook-server.js +312 -0
- package/hooks/mcp-hooks.js +153 -0
- package/hooks/validate-chain.js +147 -0
- package/package.json +35 -0
- package/rules-server.js +350 -0
- package/test/test-mcp-full.js +193 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
const readline = require('readline');
|
|
2
|
+
const { stdin, stdout } = require('process');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
const TRAE_DIR = path.join(__dirname, '..', '..');
|
|
7
|
+
const CUSTOM_CONFIG_DIR = path.join(TRAE_DIR, '.trae', 'rules', 'custom_config');
|
|
8
|
+
const G_MEMORY_DIR = path.join(TRAE_DIR, '.trae', 'g_memory');
|
|
9
|
+
const DATABASE_DIR = path.join(TRAE_DIR, '.trae', 'database');
|
|
10
|
+
|
|
11
|
+
function loadCustomRules() {
|
|
12
|
+
try {
|
|
13
|
+
const files = fs.readdirSync(CUSTOM_CONFIG_DIR).filter(f => f.endsWith('.yml'));
|
|
14
|
+
const rules = {};
|
|
15
|
+
files.forEach(file => {
|
|
16
|
+
rules[file] = fs.readFileSync(path.join(CUSTOM_CONFIG_DIR, file), 'utf8');
|
|
17
|
+
});
|
|
18
|
+
return rules;
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.error('Failed to load custom rules:', err.message);
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function checkGMemory() {
|
|
26
|
+
try {
|
|
27
|
+
const subdirs = ['短期记忆', '中期记忆', '长期记忆', '明知识', '暗知识'];
|
|
28
|
+
const status = {};
|
|
29
|
+
subdirs.forEach(dir => {
|
|
30
|
+
const dirPath = path.join(G_MEMORY_DIR, dir);
|
|
31
|
+
status[dir] = {
|
|
32
|
+
exists: fs.existsSync(dirPath),
|
|
33
|
+
files: fs.existsSync(dirPath) ? fs.readdirSync(dirPath) : []
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
return status;
|
|
37
|
+
} catch (err) {
|
|
38
|
+
console.error('Failed to check G memory:', err.message);
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function initSQLite() {
|
|
44
|
+
try {
|
|
45
|
+
const sqlPath = path.join(DATABASE_DIR, 'init-db.sql');
|
|
46
|
+
const dbPath = path.join(DATABASE_DIR, 'rzero-test.db');
|
|
47
|
+
|
|
48
|
+
if (!fs.existsSync(sqlPath)) {
|
|
49
|
+
return { success: false, error: 'init-db.sql not found' };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const sqlContent = fs.readFileSync(sqlPath, 'utf8');
|
|
53
|
+
|
|
54
|
+
// 删除旧测试数据库(如果存在)
|
|
55
|
+
if (fs.existsSync(dbPath)) {
|
|
56
|
+
fs.unlinkSync(dbPath);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 使用Node.js内置模块执行基础验证
|
|
60
|
+
const statements = sqlContent.split(';').map(s => s.trim()).filter(s => s.length > 0 && !s.startsWith('--'));
|
|
61
|
+
|
|
62
|
+
return {
|
|
63
|
+
success: true,
|
|
64
|
+
dbPath: dbPath,
|
|
65
|
+
statements: statements.length,
|
|
66
|
+
sqlContentLength: sqlContent.length
|
|
67
|
+
};
|
|
68
|
+
} catch (err) {
|
|
69
|
+
console.error('Failed to init SQLite:', err.message);
|
|
70
|
+
return { success: false, error: err.message };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function writeToGMemory(storageLevel, filename, content) {
|
|
75
|
+
try {
|
|
76
|
+
const subdirs = ['短期记忆', '中期记忆', '长期记忆', '明知识', '暗知识'];
|
|
77
|
+
if (!subdirs.includes(storageLevel)) {
|
|
78
|
+
return { success: false, error: 'Invalid storage level' };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const dirPath = path.join(G_MEMORY_DIR, storageLevel);
|
|
82
|
+
if (!fs.existsSync(dirPath)) {
|
|
83
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const filePath = path.join(dirPath, filename);
|
|
87
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
88
|
+
|
|
89
|
+
return { success: true, filePath: filePath };
|
|
90
|
+
} catch (err) {
|
|
91
|
+
console.error('Failed to write to G memory:', err.message);
|
|
92
|
+
return { success: false, error: err.message };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function readFromGMemory(storageLevel, filename) {
|
|
97
|
+
try {
|
|
98
|
+
const subdirs = ['短期记忆', '中期记忆', '长期记忆', '明知识', '暗知识'];
|
|
99
|
+
if (!subdirs.includes(storageLevel)) {
|
|
100
|
+
return { success: false, error: 'Invalid storage level' };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const dirPath = path.join(G_MEMORY_DIR, storageLevel);
|
|
104
|
+
const filePath = path.join(dirPath, filename);
|
|
105
|
+
|
|
106
|
+
if (!fs.existsSync(filePath)) {
|
|
107
|
+
return { success: false, error: 'File not found' };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
111
|
+
return { success: true, content: content };
|
|
112
|
+
} catch (err) {
|
|
113
|
+
console.error('Failed to read from G memory:', err.message);
|
|
114
|
+
return { success: false, error: err.message };
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const rl = readline.createInterface({
|
|
119
|
+
input: stdin,
|
|
120
|
+
output: stdout,
|
|
121
|
+
terminal: false
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
rl.on('line', (input) => {
|
|
125
|
+
try {
|
|
126
|
+
const request = JSON.parse(input);
|
|
127
|
+
const { id, method, params } = request;
|
|
128
|
+
let response;
|
|
129
|
+
|
|
130
|
+
if (method === 'initialize') {
|
|
131
|
+
response = {
|
|
132
|
+
jsonrpc: "2.0",
|
|
133
|
+
id: id,
|
|
134
|
+
result: {
|
|
135
|
+
protocolVersion: "2024-11-05",
|
|
136
|
+
capabilities: {
|
|
137
|
+
tools: {}
|
|
138
|
+
},
|
|
139
|
+
serverInfo: {
|
|
140
|
+
name: "custom-hooks",
|
|
141
|
+
version: "1.0.0"
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
} else if (method === 'notifications/initialized') {
|
|
146
|
+
return;
|
|
147
|
+
} else if (method === 'tools/list') {
|
|
148
|
+
response = {
|
|
149
|
+
jsonrpc: "2.0",
|
|
150
|
+
id: id,
|
|
151
|
+
result: {
|
|
152
|
+
tools: [
|
|
153
|
+
{
|
|
154
|
+
name: "load_custom_rules",
|
|
155
|
+
description: "加载.trae/rules/custom_config下自定义规则配置",
|
|
156
|
+
inputSchema: {
|
|
157
|
+
type: "object",
|
|
158
|
+
properties: {}
|
|
159
|
+
}
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "check_g_memory",
|
|
163
|
+
description: "检查.trae/g_memory下五级目录状态",
|
|
164
|
+
inputSchema: {
|
|
165
|
+
type: "object",
|
|
166
|
+
properties: {}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
name: "init_sqlite",
|
|
171
|
+
description: "初始化SQLite数据库,执行init-db.sql",
|
|
172
|
+
inputSchema: {
|
|
173
|
+
type: "object",
|
|
174
|
+
properties: {}
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
name: "write_to_g_memory",
|
|
179
|
+
description: "向G记忆系统指定目录写入文件",
|
|
180
|
+
inputSchema: {
|
|
181
|
+
type: "object",
|
|
182
|
+
properties: {
|
|
183
|
+
storageLevel: { type: "string", description: "存储层级:短期记忆/中期记忆/长期记忆/明知识/暗知识" },
|
|
184
|
+
filename: { type: "string", description: "文件名" },
|
|
185
|
+
content: { type: "string", description: "文件内容" }
|
|
186
|
+
},
|
|
187
|
+
required: ["storageLevel", "filename", "content"]
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
name: "read_from_g_memory",
|
|
192
|
+
description: "从G记忆系统指定目录读取文件",
|
|
193
|
+
inputSchema: {
|
|
194
|
+
type: "object",
|
|
195
|
+
properties: {
|
|
196
|
+
storageLevel: { type: "string", description: "存储层级" },
|
|
197
|
+
filename: { type: "string", description: "文件名" }
|
|
198
|
+
},
|
|
199
|
+
required: ["storageLevel", "filename"]
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
]
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
} else if (method === 'tools/call') {
|
|
206
|
+
const toolName = params?.name;
|
|
207
|
+
const toolArgs = params?.arguments || {};
|
|
208
|
+
|
|
209
|
+
if (toolName === 'load_custom_rules') {
|
|
210
|
+
const rules = loadCustomRules();
|
|
211
|
+
response = {
|
|
212
|
+
jsonrpc: "2.0",
|
|
213
|
+
id: id,
|
|
214
|
+
result: {
|
|
215
|
+
content: [
|
|
216
|
+
{
|
|
217
|
+
type: "text",
|
|
218
|
+
text: JSON.stringify({ success: true, rules: rules, count: Object.keys(rules).length })
|
|
219
|
+
}
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
} else if (toolName === 'check_g_memory') {
|
|
224
|
+
const memoryStatus = checkGMemory();
|
|
225
|
+
response = {
|
|
226
|
+
jsonrpc: "2.0",
|
|
227
|
+
id: id,
|
|
228
|
+
result: {
|
|
229
|
+
content: [
|
|
230
|
+
{
|
|
231
|
+
type: "text",
|
|
232
|
+
text: JSON.stringify({ success: true, status: memoryStatus })
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
}
|
|
236
|
+
};
|
|
237
|
+
} else if (toolName === 'init_sqlite') {
|
|
238
|
+
const result = initSQLite();
|
|
239
|
+
response = {
|
|
240
|
+
jsonrpc: "2.0",
|
|
241
|
+
id: id,
|
|
242
|
+
result: {
|
|
243
|
+
content: [
|
|
244
|
+
{
|
|
245
|
+
type: "text",
|
|
246
|
+
text: JSON.stringify(result)
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
} else if (toolName === 'write_to_g_memory') {
|
|
252
|
+
const result = writeToGMemory(toolArgs.storageLevel, toolArgs.filename, toolArgs.content);
|
|
253
|
+
response = {
|
|
254
|
+
jsonrpc: "2.0",
|
|
255
|
+
id: id,
|
|
256
|
+
result: {
|
|
257
|
+
content: [
|
|
258
|
+
{
|
|
259
|
+
type: "text",
|
|
260
|
+
text: JSON.stringify(result)
|
|
261
|
+
}
|
|
262
|
+
]
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
} else if (toolName === 'read_from_g_memory') {
|
|
266
|
+
const result = readFromGMemory(toolArgs.storageLevel, toolArgs.filename);
|
|
267
|
+
response = {
|
|
268
|
+
jsonrpc: "2.0",
|
|
269
|
+
id: id,
|
|
270
|
+
result: {
|
|
271
|
+
content: [
|
|
272
|
+
{
|
|
273
|
+
type: "text",
|
|
274
|
+
text: JSON.stringify(result)
|
|
275
|
+
}
|
|
276
|
+
]
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
} else {
|
|
280
|
+
response = {
|
|
281
|
+
jsonrpc: "2.0",
|
|
282
|
+
id: id,
|
|
283
|
+
error: {
|
|
284
|
+
code: -32601,
|
|
285
|
+
message: 'Tool not found'
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
} else {
|
|
290
|
+
response = {
|
|
291
|
+
jsonrpc: "2.0",
|
|
292
|
+
id: id,
|
|
293
|
+
error: {
|
|
294
|
+
code: -32601,
|
|
295
|
+
message: 'Method not found'
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
stdout.write(JSON.stringify(response) + '\n');
|
|
301
|
+
} catch (error) {
|
|
302
|
+
console.error('Error:', error.message);
|
|
303
|
+
stdout.write(JSON.stringify({
|
|
304
|
+
jsonrpc: "2.0",
|
|
305
|
+
id: null,
|
|
306
|
+
error: {
|
|
307
|
+
code: -32603,
|
|
308
|
+
message: 'Internal error'
|
|
309
|
+
}
|
|
310
|
+
}) + '\n');
|
|
311
|
+
}
|
|
312
|
+
});
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP网关钩子层 - 内置钩子框架
|
|
3
|
+
* 版本: 1.0
|
|
4
|
+
* 依据: 03_genkit_middleware_ref.md Genkit中间件官方文档
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
|
|
10
|
+
// 内置钩子类型定义
|
|
11
|
+
const HOOK_TYPES = {
|
|
12
|
+
PRE_PROCESS: 'pre_process',
|
|
13
|
+
POST_PROCESS: 'post_process',
|
|
14
|
+
ON_ERROR: 'on_error',
|
|
15
|
+
ON_APPROVAL: 'on_approval'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// 钩子执行器
|
|
19
|
+
class HookExecutor {
|
|
20
|
+
constructor() {
|
|
21
|
+
this.hooks = {};
|
|
22
|
+
this.initialize();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
initialize() {
|
|
26
|
+
Object.values(HOOK_TYPES).forEach(type => {
|
|
27
|
+
this.hooks[type] = [];
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 注册钩子
|
|
32
|
+
register(type, hook) {
|
|
33
|
+
if (!this.hooks[type]) {
|
|
34
|
+
this.hooks[type] = [];
|
|
35
|
+
}
|
|
36
|
+
this.hooks[type].push({
|
|
37
|
+
id: `${type}_${Date.now()}`,
|
|
38
|
+
fn: hook,
|
|
39
|
+
enabled: true
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 执行钩子链
|
|
44
|
+
async execute(type, context) {
|
|
45
|
+
const hooks = this.hooks[type] || [];
|
|
46
|
+
let result = context;
|
|
47
|
+
|
|
48
|
+
for (const hook of hooks) {
|
|
49
|
+
if (hook.enabled) {
|
|
50
|
+
try {
|
|
51
|
+
result = await hook.fn(result);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
console.error(`Hook ${hook.id} error:`, error.message);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// 预处理器钩子
|
|
63
|
+
const preProcessHooks = [
|
|
64
|
+
{
|
|
65
|
+
id: 'load_rules',
|
|
66
|
+
name: '加载规则引擎配置',
|
|
67
|
+
description: '从规则引擎层加载最新规则',
|
|
68
|
+
async execute(context) {
|
|
69
|
+
const rulesPath = path.join(__dirname, '..', '..', 'rules', 'custom_config');
|
|
70
|
+
try {
|
|
71
|
+
const rulesConfig = fs.readdirSync(rulesPath).filter(f => f.endsWith('.yml'));
|
|
72
|
+
context.loadedRules = rulesConfig;
|
|
73
|
+
return context;
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error('Failed to load rules:', error.message);
|
|
76
|
+
return context;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'check_memory',
|
|
82
|
+
name: '检查G记忆系统状态',
|
|
83
|
+
description: '验证记忆系统可用性',
|
|
84
|
+
async execute(context) {
|
|
85
|
+
const memoryPath = path.join(__dirname, '..', '..', 'g_memory');
|
|
86
|
+
const subdirs = ['短期存储', '中期存储', '长期存储', '明知识', '暗知识'];
|
|
87
|
+
const available = subdirs.filter(d => {
|
|
88
|
+
try {
|
|
89
|
+
return fs.existsSync(path.join(memoryPath, d));
|
|
90
|
+
} catch {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
context.memoryStatus = { available, total: subdirs.length };
|
|
95
|
+
return context;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
// 错误处理钩子
|
|
101
|
+
const errorHooks = [
|
|
102
|
+
{
|
|
103
|
+
id: 'log_error',
|
|
104
|
+
name: '错误日志记录',
|
|
105
|
+
description: '将错误信息写入记忆系统长期存储',
|
|
106
|
+
async execute(error, context) {
|
|
107
|
+
const memoryPath = path.join(__dirname, '..', '..', 'g_memory', '长期存储');
|
|
108
|
+
const errorLogPath = path.join(memoryPath, 'error_log.json');
|
|
109
|
+
|
|
110
|
+
let errors = [];
|
|
111
|
+
try {
|
|
112
|
+
if (fs.existsSync(errorLogPath)) {
|
|
113
|
+
errors = JSON.parse(fs.readFileSync(errorLogPath, 'utf8'));
|
|
114
|
+
}
|
|
115
|
+
} catch {}
|
|
116
|
+
|
|
117
|
+
errors.push({
|
|
118
|
+
timestamp: new Date().toISOString(),
|
|
119
|
+
message: error.message,
|
|
120
|
+
stack: error.stack,
|
|
121
|
+
context: context
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
fs.writeFileSync(errorLogPath, JSON.stringify(errors, null, 2));
|
|
126
|
+
} catch {}
|
|
127
|
+
return error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
];
|
|
131
|
+
|
|
132
|
+
// 工具审批钩子
|
|
133
|
+
const approvalHooks = [
|
|
134
|
+
{
|
|
135
|
+
id: 'security_check',
|
|
136
|
+
name: '安全规则检查',
|
|
137
|
+
description: '依据security-constraints.yml检查操作权限',
|
|
138
|
+
async execute(toolName, context) {
|
|
139
|
+
const securityPath = path.join(__dirname, '..', '规则引擎层', 'security-constraints.yml');
|
|
140
|
+
const allowed = ['read', 'write', 'compute', 'reason'];
|
|
141
|
+
return { approved: allowed.includes(toolName), toolName };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
// 导出钩子模块
|
|
147
|
+
module.exports = {
|
|
148
|
+
HookExecutor,
|
|
149
|
+
HOOK_TYPES,
|
|
150
|
+
preProcessHooks,
|
|
151
|
+
errorHooks,
|
|
152
|
+
approvalHooks
|
|
153
|
+
};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP网关钩子层 - 流程验证脚本
|
|
3
|
+
* 版本: 1.0
|
|
4
|
+
* 描述: 验证MCP、规则引擎、G记忆三层调用链路连通性
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const path = require('path');
|
|
8
|
+
|
|
9
|
+
// 验证各层目录
|
|
10
|
+
function validateDirectories() {
|
|
11
|
+
const traeDir = path.join(__dirname, '..', '..');
|
|
12
|
+
const projectRoot = path.join(traeDir, '..');
|
|
13
|
+
const required = [
|
|
14
|
+
{ name: 'rules/custom_config', path: path.join(traeDir, 'rules', 'custom_config') },
|
|
15
|
+
{ name: 'mcp/custom_hook', path: path.join(traeDir, 'mcp', 'custom_hook') },
|
|
16
|
+
{ name: 'g_memory', path: path.join(traeDir, 'g_memory') },
|
|
17
|
+
{ name: 'database', path: path.join(traeDir, 'database') },
|
|
18
|
+
{ name: 'docs', path: path.join(projectRoot, 'docs') }
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
const results = [];
|
|
22
|
+
|
|
23
|
+
for (const dir of required) {
|
|
24
|
+
const exists = require('fs').existsSync(dir.path);
|
|
25
|
+
results.push({ name: dir.name, path: dir.path, exists });
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return results;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// 验证配置文件
|
|
32
|
+
function validateConfigFiles() {
|
|
33
|
+
const traeDir = path.join(__dirname, '..', '..');
|
|
34
|
+
const configs = [
|
|
35
|
+
{ path: path.join(traeDir, 'rules', 'custom_config', 'rules-config.yml'), name: '规则顶层配置' },
|
|
36
|
+
{ path: path.join(traeDir, 'rules', 'custom_config', 'agent-constraints.yml'), name: 'Agent约束' },
|
|
37
|
+
{ path: path.join(traeDir, 'rules', 'custom_config', 'security-constraints.yml'), name: '安全约束' },
|
|
38
|
+
{ path: path.join(traeDir, 'mcp', 'custom_hook', 'mcp-hooks.js'), name: 'MCP钩子模块' },
|
|
39
|
+
{ path: path.join(traeDir, 'mcp', 'custom_hook', 'chain-invoker.js'), name: '调用链路' },
|
|
40
|
+
{ path: path.join(traeDir, 'database', 'init-db.sql'), name: 'SQLite初始化' }
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
const results = [];
|
|
44
|
+
|
|
45
|
+
for (const cfg of configs) {
|
|
46
|
+
const fullPath = cfg.path;
|
|
47
|
+
const fs = require('fs');
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const exists = fs.existsSync(fullPath);
|
|
51
|
+
const size = exists ? fs.statSync(fullPath).size : 0;
|
|
52
|
+
results.push({
|
|
53
|
+
name: cfg.name,
|
|
54
|
+
path: cfg.path,
|
|
55
|
+
exists,
|
|
56
|
+
size,
|
|
57
|
+
valid: exists && size > 0
|
|
58
|
+
});
|
|
59
|
+
} catch (error) {
|
|
60
|
+
results.push({
|
|
61
|
+
name: cfg.name,
|
|
62
|
+
path: cfg.path,
|
|
63
|
+
exists: false,
|
|
64
|
+
size: 0,
|
|
65
|
+
valid: false,
|
|
66
|
+
error: error.message
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return results;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// 验证G记忆子目录
|
|
75
|
+
function validateMemoryDirectories() {
|
|
76
|
+
const baseDir = path.join(__dirname, '..', '..', 'g_memory');
|
|
77
|
+
const subdirs = ['短期存储', '中期存储', '长期存储', '明知识', '暗知识'];
|
|
78
|
+
const fs = require('fs');
|
|
79
|
+
|
|
80
|
+
const results = [];
|
|
81
|
+
|
|
82
|
+
for (const dir of subdirs) {
|
|
83
|
+
const fullPath = path.join(baseDir, dir);
|
|
84
|
+
const exists = fs.existsSync(fullPath);
|
|
85
|
+
results.push({ name: dir, exists, path: fullPath });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return results;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 执行验证
|
|
92
|
+
function runValidation() {
|
|
93
|
+
console.log('='.repeat(60));
|
|
94
|
+
console.log('MCP三层调用链路验证报告');
|
|
95
|
+
console.log('='.repeat(60));
|
|
96
|
+
console.log('');
|
|
97
|
+
|
|
98
|
+
console.log('【1】顶层目录验证');
|
|
99
|
+
console.log('-'.repeat(60));
|
|
100
|
+
const dirs = validateDirectories();
|
|
101
|
+
dirs.forEach(d => {
|
|
102
|
+
const status = d.exists ? 'PASS' : 'FAIL';
|
|
103
|
+
console.log(` [${status}] ${d.name}`);
|
|
104
|
+
});
|
|
105
|
+
console.log('');
|
|
106
|
+
|
|
107
|
+
console.log('【2】配置文件验证');
|
|
108
|
+
console.log('-'.repeat(60));
|
|
109
|
+
const configs = validateConfigFiles();
|
|
110
|
+
configs.forEach(c => {
|
|
111
|
+
const status = c.valid ? 'PASS' : 'FAIL';
|
|
112
|
+
console.log(` [${status}] ${c.name} (${c.size} bytes)`);
|
|
113
|
+
});
|
|
114
|
+
console.log('');
|
|
115
|
+
|
|
116
|
+
console.log('【3】G记忆系统子目录验证');
|
|
117
|
+
console.log('-'.repeat(60));
|
|
118
|
+
const memory = validateMemoryDirectories();
|
|
119
|
+
memory.forEach(m => {
|
|
120
|
+
const status = m.exists ? 'PASS' : 'FAIL';
|
|
121
|
+
console.log(` [${status}] ${m.name}`);
|
|
122
|
+
});
|
|
123
|
+
console.log('');
|
|
124
|
+
|
|
125
|
+
// 汇总
|
|
126
|
+
const allDirsPass = dirs.every(d => d.exists);
|
|
127
|
+
const allConfigsPass = configs.every(c => c.valid);
|
|
128
|
+
const allMemoryPass = memory.every(m => m.exists);
|
|
129
|
+
|
|
130
|
+
console.log('【4】验证汇总');
|
|
131
|
+
console.log('-'.repeat(60));
|
|
132
|
+
console.log(` 顶层目录: ${allDirsPass ? 'PASS' : 'FAIL'}`);
|
|
133
|
+
console.log(` 配置文件: ${allConfigsPass ? 'PASS' : 'FAIL'}`);
|
|
134
|
+
console.log(` 记忆目录: ${allMemoryPass ? 'PASS' : 'FAIL'}`);
|
|
135
|
+
console.log('');
|
|
136
|
+
|
|
137
|
+
const overallPass = allDirsPass && allConfigsPass && allMemoryPass;
|
|
138
|
+
console.log('='.repeat(60));
|
|
139
|
+
console.log(`最终结果: ${overallPass ? 'PASS - 三层链路验证通过' : 'FAIL - 存在问题'}`);
|
|
140
|
+
console.log('='.repeat(60));
|
|
141
|
+
|
|
142
|
+
return overallPass;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 执行
|
|
146
|
+
const result = runValidation();
|
|
147
|
+
process.exit(result ? 0 : 1);
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rules-enforcer",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "R-Zero Rules Engine MCP Server - L1/L2/L3 rules validation, custom hooks, and project detection",
|
|
5
|
+
"main": "rules-server.js",
|
|
6
|
+
"type": "commonjs",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"start": "node rules-server.js",
|
|
9
|
+
"test": "node test/test-mcp-full.js"
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"mcp",
|
|
13
|
+
"rules-engine",
|
|
14
|
+
"validation",
|
|
15
|
+
"trae",
|
|
16
|
+
"ai",
|
|
17
|
+
"llm"
|
|
18
|
+
],
|
|
19
|
+
"author": "",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": ""
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"rules-server.js",
|
|
27
|
+
"hooks/**/*",
|
|
28
|
+
"detector/**/*",
|
|
29
|
+
"test/**/*",
|
|
30
|
+
"README.md"
|
|
31
|
+
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=16.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|