@ppdocs/mcp 3.2.36 → 3.2.37
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 +53 -27
- package/dist/tools/flowchart.js +244 -3
- package/dist/tools/rules.d.ts +2 -3
- package/dist/tools/rules.js +2 -3
- package/package.json +1 -1
- package/templates/commands/init.md +3 -3
- package/templates/commands/pp/diagnose.md +3 -3
- package/templates/commands/pp/init.md +9 -18
- package/templates/commands/pp/sync.md +10 -12
- package/templates/hooks/SystemPrompt.md +14 -14
package/README.md
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
ppdocs MCP 是一个 [Model Context Protocol](https://modelcontextprotocol.io/) 服务器,让 Claude 能够在对话中构建和查询项目知识图谱。
|
|
10
10
|
|
|
11
|
+
当前 MCP 采用 `flowchart-first` 模型:节点、关系、绑定文件、任务关联和节点文档统一收敛到 `kg_flowchart(action:"...")`,不再维护独立的 `kg_doc` / `kg_search` / `kg_create_node` 一组旧接口。
|
|
12
|
+
|
|
11
13
|
```
|
|
12
14
|
┌─────────────┐ MCP ┌─────────────┐ HTTP ┌─────────────┐
|
|
13
15
|
│ Claude AI │ ──────────── │ @ppdocs/mcp │ ────────── │ ppdocs 桌面 │
|
|
@@ -105,28 +107,55 @@ npx @ppdocs/mcp init -p <projectId> -k <key> --codex
|
|
|
105
107
|
|
|
106
108
|
## 工具列表
|
|
107
109
|
|
|
108
|
-
###
|
|
110
|
+
### 核心工具
|
|
109
111
|
|
|
110
112
|
| 工具 | 说明 |
|
|
111
113
|
|------|------|
|
|
112
|
-
| `
|
|
113
|
-
| `
|
|
114
|
-
| `
|
|
115
|
-
| `
|
|
116
|
-
| `
|
|
117
|
-
| `
|
|
118
|
-
| `
|
|
119
|
-
| `
|
|
114
|
+
| `kg_init` | 初始化项目连接与上下文 |
|
|
115
|
+
| `kg_status` | 查看项目仪表盘与流程图概况 |
|
|
116
|
+
| `kg_flowchart` | 统一的知识图谱入口,负责查询、更新、关系分析 |
|
|
117
|
+
| `kg_rules` | 规则管理 |
|
|
118
|
+
| `kg_task` | 任务管理 |
|
|
119
|
+
| `kg_files` | 项目文件读写/上传下载 |
|
|
120
|
+
| `kg_discuss` | 讨论区 |
|
|
121
|
+
| `kg_meeting` | 多 AI 协作会议 |
|
|
122
|
+
| `code_scan` | 代码扫描 |
|
|
123
|
+
| `code_smart_context` | 获取符号的智能上下文 |
|
|
124
|
+
| `code_full_path` | 获取两个符号之间的全路径 |
|
|
125
|
+
|
|
126
|
+
### `kg_flowchart` actions
|
|
127
|
+
|
|
128
|
+
| action | 说明 |
|
|
129
|
+
|------|------|
|
|
130
|
+
| `list` | 列出所有流程图 |
|
|
131
|
+
| `get` | 获取指定流程图的节点与连线 |
|
|
132
|
+
| `search` | 按关键词搜索节点、节点文档与绑定资源 |
|
|
133
|
+
| `get_relations` | 查看某节点的入边/出边关系 |
|
|
134
|
+
| `find_path` | 查找两个节点之间的有向路径 |
|
|
135
|
+
| `get_node` | 获取节点详情、关联层级、绑定资源与文档 |
|
|
136
|
+
| `update_node` | 更新节点信息并追加节点文档版本 |
|
|
137
|
+
| `delete_node` | 删除节点 |
|
|
138
|
+
| `batch_add` | 批量新增节点与连线 |
|
|
139
|
+
| `bind` / `unbind` | 绑定或解绑文件、目录、文档、任务 |
|
|
140
|
+
| `orphans` | 检查孤立参考文档 |
|
|
141
|
+
| `health` | 查看节点健康度 |
|
|
142
|
+
| `create_chart` | 创建子图并绑定到父节点 |
|
|
143
|
+
| `delete_chart` | 删除子图 |
|
|
144
|
+
|
|
145
|
+
### 常用示例
|
|
120
146
|
|
|
121
|
-
|
|
147
|
+
```bash
|
|
148
|
+
# 搜索相关节点
|
|
149
|
+
kg_flowchart(action:"search", query:"flowchart storage")
|
|
122
150
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
151
|
+
# 查看节点详情
|
|
152
|
+
kg_flowchart(action:"get_node", chartId:"main", nodeId:"n_storage", expand:2, includeDoc:true, includeFiles:true)
|
|
153
|
+
|
|
154
|
+
# 追加节点文档
|
|
155
|
+
kg_flowchart(action:"update_node", chartId:"main", nodeId:"n_storage",
|
|
156
|
+
docSummary:"补充存储层职责",
|
|
157
|
+
docContent:"## 职责\n...\n## 关键流程\n...")
|
|
158
|
+
```
|
|
130
159
|
|
|
131
160
|
---
|
|
132
161
|
|
|
@@ -178,18 +207,15 @@ npx @ppdocs/mcp init -p <projectId> -k <key> --codex
|
|
|
178
207
|
|
|
179
208
|
## 更新日志
|
|
180
209
|
|
|
181
|
-
###
|
|
182
|
-
-
|
|
183
|
-
-
|
|
210
|
+
### v3.2.36
|
|
211
|
+
- 统一为 `flowchart-first` MCP 接口模型
|
|
212
|
+
- `kg_flowchart` 新增 `search` / `get_relations` / `find_path`
|
|
213
|
+
- 文档与模板改为使用 `kg_flowchart(action:"...")`,不再引用旧 `kg_doc` / `kg_search` 等独立接口
|
|
184
214
|
|
|
185
215
|
### v2.5.0
|
|
186
|
-
-
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
|
|
190
|
-
### v2.4.0
|
|
191
|
-
- 🛡️ `kg_lock_node` 只能锁定,解锁需前端手动操作
|
|
192
|
-
- ⚡ 后端自动记录操作日志
|
|
216
|
+
- 新增 CLI init 命令,自动安装工作流模板
|
|
217
|
+
- 支持 Codex 模式 (`--codex`)
|
|
218
|
+
- 构建时自动复制模板
|
|
193
219
|
|
|
194
220
|
### v2.3.0
|
|
195
221
|
- 新增任务管理功能
|
package/dist/tools/flowchart.js
CHANGED
|
@@ -135,14 +135,130 @@ function collectNeighborLayers(chart, startNodeId, maxDepth) {
|
|
|
135
135
|
}
|
|
136
136
|
return layers;
|
|
137
137
|
}
|
|
138
|
+
function normalizeText(value) {
|
|
139
|
+
return (value ?? '').trim().toLowerCase();
|
|
140
|
+
}
|
|
141
|
+
function scoreNodeMatch(node, terms) {
|
|
142
|
+
const label = normalizeText(node.label);
|
|
143
|
+
const id = normalizeText(node.id);
|
|
144
|
+
const description = normalizeText(node.description);
|
|
145
|
+
const nodeType = normalizeText(node.nodeType);
|
|
146
|
+
const domain = normalizeText(node.domain);
|
|
147
|
+
const inputs = ensureArray(node.input).join(' ').toLowerCase();
|
|
148
|
+
const outputs = ensureArray(node.output).join(' ').toLowerCase();
|
|
149
|
+
const files = ensureArray(node.boundFiles).join(' ').toLowerCase();
|
|
150
|
+
const dirs = ensureArray(node.boundDirs).join(' ').toLowerCase();
|
|
151
|
+
const docs = ensureArray(node.boundDocs).join(' ').toLowerCase();
|
|
152
|
+
const tasks = ensureArray(node.boundTasks).join(' ').toLowerCase();
|
|
153
|
+
const docEntries = (node.docEntries ?? [])
|
|
154
|
+
.flatMap((entry) => [entry.summary, entry.content])
|
|
155
|
+
.join(' ')
|
|
156
|
+
.toLowerCase();
|
|
157
|
+
let score = 0;
|
|
158
|
+
let matchedTerms = 0;
|
|
159
|
+
for (const term of terms) {
|
|
160
|
+
let matched = false;
|
|
161
|
+
if (label === term || id === term) {
|
|
162
|
+
score += 120;
|
|
163
|
+
matched = true;
|
|
164
|
+
}
|
|
165
|
+
else if (label.includes(term)) {
|
|
166
|
+
score += 80;
|
|
167
|
+
matched = true;
|
|
168
|
+
}
|
|
169
|
+
else if (id.includes(term)) {
|
|
170
|
+
score += 70;
|
|
171
|
+
matched = true;
|
|
172
|
+
}
|
|
173
|
+
if (description.includes(term)) {
|
|
174
|
+
score += 40;
|
|
175
|
+
matched = true;
|
|
176
|
+
}
|
|
177
|
+
if (nodeType.includes(term) || domain.includes(term)) {
|
|
178
|
+
score += 25;
|
|
179
|
+
matched = true;
|
|
180
|
+
}
|
|
181
|
+
if (inputs.includes(term) || outputs.includes(term)) {
|
|
182
|
+
score += 20;
|
|
183
|
+
matched = true;
|
|
184
|
+
}
|
|
185
|
+
if (files.includes(term) || dirs.includes(term)) {
|
|
186
|
+
score += 18;
|
|
187
|
+
matched = true;
|
|
188
|
+
}
|
|
189
|
+
if (docs.includes(term) || tasks.includes(term)) {
|
|
190
|
+
score += 15;
|
|
191
|
+
matched = true;
|
|
192
|
+
}
|
|
193
|
+
if (docEntries.includes(term)) {
|
|
194
|
+
score += 10;
|
|
195
|
+
matched = true;
|
|
196
|
+
}
|
|
197
|
+
if (matched) {
|
|
198
|
+
matchedTerms += 1;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
if (matchedTerms === 0) {
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
return score + matchedTerms * 100;
|
|
205
|
+
}
|
|
206
|
+
function collectNodeRelations(chart, nodeId) {
|
|
207
|
+
const nodeMap = new Map(chart.nodes.map((node) => [node.id, node]));
|
|
208
|
+
const incoming = chart.edges
|
|
209
|
+
.filter((edge) => edge.to === nodeId)
|
|
210
|
+
.map((edge) => ({ edge, node: nodeMap.get(edge.from) }));
|
|
211
|
+
const outgoing = chart.edges
|
|
212
|
+
.filter((edge) => edge.from === nodeId)
|
|
213
|
+
.map((edge) => ({ edge, node: nodeMap.get(edge.to) }));
|
|
214
|
+
return { incoming, outgoing };
|
|
215
|
+
}
|
|
216
|
+
function findDirectedPath(chart, fromId, toId) {
|
|
217
|
+
if (fromId === toId) {
|
|
218
|
+
return [];
|
|
219
|
+
}
|
|
220
|
+
const visited = new Set([fromId]);
|
|
221
|
+
const queue = [fromId];
|
|
222
|
+
const prev = new Map();
|
|
223
|
+
while (queue.length > 0) {
|
|
224
|
+
const current = queue.shift();
|
|
225
|
+
const nextEdges = chart.edges.filter((edge) => edge.from === current);
|
|
226
|
+
for (const edge of nextEdges) {
|
|
227
|
+
if (visited.has(edge.to)) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
visited.add(edge.to);
|
|
231
|
+
prev.set(edge.to, { parent: current, edge });
|
|
232
|
+
if (edge.to === toId) {
|
|
233
|
+
const path = [];
|
|
234
|
+
let cursor = toId;
|
|
235
|
+
while (cursor !== fromId) {
|
|
236
|
+
const step = prev.get(cursor);
|
|
237
|
+
if (!step) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
path.push(step.edge);
|
|
241
|
+
cursor = step.parent;
|
|
242
|
+
}
|
|
243
|
+
return path.reverse();
|
|
244
|
+
}
|
|
245
|
+
queue.push(edge.to);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
138
250
|
export function registerFlowchartTools(server, _ctx) {
|
|
139
251
|
const client = () => getClient();
|
|
140
|
-
server.tool('kg_flowchart', 'Logical flowchart operations: list|get|get_node|update_node|delete_node|batch_add|bind|unbind|orphans|health|create_chart|delete_chart', {
|
|
252
|
+
server.tool('kg_flowchart', 'Logical flowchart operations: list|get|search|get_relations|find_path|get_node|update_node|delete_node|batch_add|bind|unbind|orphans|health|create_chart|delete_chart', {
|
|
141
253
|
action: z
|
|
142
|
-
.enum(['list', 'get', 'get_node', 'update_node', 'delete_node', 'batch_add', 'bind', 'unbind', 'orphans', 'health', 'create_chart', 'delete_chart'])
|
|
254
|
+
.enum(['list', 'get', 'search', 'get_relations', 'find_path', 'get_node', 'update_node', 'delete_node', 'batch_add', 'bind', 'unbind', 'orphans', 'health', 'create_chart', 'delete_chart'])
|
|
143
255
|
.describe('action type'),
|
|
144
256
|
chartId: z.string().optional().describe('chart id, default main'),
|
|
145
|
-
nodeId: z.string().optional().describe('node id for get_node/update_node/delete_node/bind/unbind'),
|
|
257
|
+
nodeId: z.string().optional().describe('node id for get_relations/get_node/update_node/delete_node/bind/unbind'),
|
|
258
|
+
query: z.string().optional().describe('search query for action=search'),
|
|
259
|
+
fromId: z.string().optional().describe('start node id for action=find_path'),
|
|
260
|
+
toId: z.string().optional().describe('target node id for action=find_path'),
|
|
261
|
+
limit: z.number().optional().describe('search result limit, default 10'),
|
|
146
262
|
expand: z.number().optional().describe('get_node expansion depth, default 3'),
|
|
147
263
|
includeDocs: z.boolean().optional().describe('show bound docs in get_node, default true'),
|
|
148
264
|
includeTasks: z.boolean().optional().describe('show bound tasks in get_node, default true'),
|
|
@@ -200,6 +316,131 @@ export function registerFlowchartTools(server, _ctx) {
|
|
|
200
316
|
].filter((line) => line.length > 0);
|
|
201
317
|
return wrap(lines.join('\n'));
|
|
202
318
|
}
|
|
319
|
+
case 'search': {
|
|
320
|
+
const rawQuery = decoded.query?.trim();
|
|
321
|
+
if (!rawQuery) {
|
|
322
|
+
return wrap('search requires query.');
|
|
323
|
+
}
|
|
324
|
+
const terms = rawQuery
|
|
325
|
+
.toLowerCase()
|
|
326
|
+
.split(/\s+/)
|
|
327
|
+
.filter(Boolean);
|
|
328
|
+
const charts = decoded.chartId
|
|
329
|
+
? [(await client().getFlowchart(decoded.chartId))].filter((item) => Boolean(item))
|
|
330
|
+
: await (async () => {
|
|
331
|
+
const briefs = (await client().listFlowcharts());
|
|
332
|
+
const loaded = await Promise.all(briefs.map(async (brief) => (await client().getFlowchart(brief.id))));
|
|
333
|
+
return loaded.filter((item) => Boolean(item));
|
|
334
|
+
})();
|
|
335
|
+
const matches = charts
|
|
336
|
+
.flatMap((chart) => chart.nodes.map((rawNode) => {
|
|
337
|
+
const node = ensureNodeShape(rawNode);
|
|
338
|
+
return {
|
|
339
|
+
chart,
|
|
340
|
+
node,
|
|
341
|
+
score: scoreNodeMatch(node, terms),
|
|
342
|
+
};
|
|
343
|
+
}))
|
|
344
|
+
.filter((item) => item.score > 0)
|
|
345
|
+
.sort((a, b) => b.score - a.score)
|
|
346
|
+
.slice(0, Math.max(1, decoded.limit ?? 10));
|
|
347
|
+
if (matches.length === 0) {
|
|
348
|
+
return wrap(`No flowchart nodes matched query: ${rawQuery}`);
|
|
349
|
+
}
|
|
350
|
+
const lines = [
|
|
351
|
+
`Search results for: ${rawQuery}`,
|
|
352
|
+
'',
|
|
353
|
+
...matches.map(({ chart, node }) => {
|
|
354
|
+
const badges = [
|
|
355
|
+
node.domain ? `domain=${node.domain}` : '',
|
|
356
|
+
node.nodeType ? `type=${node.nodeType}` : '',
|
|
357
|
+
node.subFlowchart ? `sub=${node.subFlowchart}` : '',
|
|
358
|
+
].filter(Boolean);
|
|
359
|
+
const suffix = badges.length > 0 ? ` | ${badges.join(' ')}` : '';
|
|
360
|
+
const description = node.description ? ` | ${node.description}` : '';
|
|
361
|
+
return `- ${node.label} [${chart.id}/${node.id}]${suffix}${description}`;
|
|
362
|
+
}),
|
|
363
|
+
];
|
|
364
|
+
return wrap(lines.join('\n'));
|
|
365
|
+
}
|
|
366
|
+
case 'get_relations': {
|
|
367
|
+
const chartId = decoded.chartId || 'main';
|
|
368
|
+
if (!decoded.nodeId) {
|
|
369
|
+
return wrap('get_relations requires nodeId.');
|
|
370
|
+
}
|
|
371
|
+
const chart = (await client().getFlowchart(chartId));
|
|
372
|
+
if (!chart) {
|
|
373
|
+
return wrap(`Flowchart not found: ${chartId}`);
|
|
374
|
+
}
|
|
375
|
+
const nodeMap = new Map(chart.nodes.map((node) => [node.id, node]));
|
|
376
|
+
const node = nodeMap.get(decoded.nodeId);
|
|
377
|
+
if (!node) {
|
|
378
|
+
return wrap(`Node not found: ${decoded.nodeId} in ${chartId}`);
|
|
379
|
+
}
|
|
380
|
+
const relations = collectNodeRelations(chart, decoded.nodeId);
|
|
381
|
+
const lines = [
|
|
382
|
+
`Relations: ${node.label} [${chartId}/${node.id}]`,
|
|
383
|
+
`Incoming: ${relations.incoming.length}`,
|
|
384
|
+
`Outgoing: ${relations.outgoing.length}`,
|
|
385
|
+
];
|
|
386
|
+
if (relations.incoming.length > 0) {
|
|
387
|
+
lines.push('', 'Incoming edges:');
|
|
388
|
+
relations.incoming.forEach(({ edge, node: source }) => {
|
|
389
|
+
lines.push(`- ${source?.label ?? edge.from} [${edge.from}] -> ${node.label} [${edge.to}]${edge.label ? ` (${edge.label})` : ''}${edge.edgeType ? ` [${edge.edgeType}]` : ''}`);
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
if (relations.outgoing.length > 0) {
|
|
393
|
+
lines.push('', 'Outgoing edges:');
|
|
394
|
+
relations.outgoing.forEach(({ edge, node: target }) => {
|
|
395
|
+
lines.push(`- ${node.label} [${edge.from}] -> ${target?.label ?? edge.to} [${edge.to}]${edge.label ? ` (${edge.label})` : ''}${edge.edgeType ? ` [${edge.edgeType}]` : ''}`);
|
|
396
|
+
});
|
|
397
|
+
}
|
|
398
|
+
const linked = new Set([
|
|
399
|
+
...relations.incoming.map(({ edge }) => edge.from),
|
|
400
|
+
...relations.outgoing.map(({ edge }) => edge.to),
|
|
401
|
+
]);
|
|
402
|
+
if (linked.size > 0) {
|
|
403
|
+
lines.push('', `Linked nodes: ${linked.size}`);
|
|
404
|
+
}
|
|
405
|
+
return wrap(lines.join('\n'));
|
|
406
|
+
}
|
|
407
|
+
case 'find_path': {
|
|
408
|
+
const chartId = decoded.chartId || 'main';
|
|
409
|
+
if (!decoded.fromId || !decoded.toId) {
|
|
410
|
+
return wrap('find_path requires fromId and toId.');
|
|
411
|
+
}
|
|
412
|
+
const chart = (await client().getFlowchart(chartId));
|
|
413
|
+
if (!chart) {
|
|
414
|
+
return wrap(`Flowchart not found: ${chartId}`);
|
|
415
|
+
}
|
|
416
|
+
const nodeMap = new Map(chart.nodes.map((node) => [node.id, node]));
|
|
417
|
+
const fromNode = nodeMap.get(decoded.fromId);
|
|
418
|
+
const toNode = nodeMap.get(decoded.toId);
|
|
419
|
+
if (!fromNode || !toNode) {
|
|
420
|
+
return wrap(`find_path could not resolve nodes in ${chartId}: from=${decoded.fromId} to=${decoded.toId}`);
|
|
421
|
+
}
|
|
422
|
+
const path = findDirectedPath(chart, decoded.fromId, decoded.toId);
|
|
423
|
+
if (path === null) {
|
|
424
|
+
return wrap(`No directed path found: [${chartId}/${decoded.fromId}] -> [${chartId}/${decoded.toId}]`);
|
|
425
|
+
}
|
|
426
|
+
if (path.length === 0) {
|
|
427
|
+
return wrap(`Path resolved: ${fromNode.label} [${fromNode.id}] (same node)`);
|
|
428
|
+
}
|
|
429
|
+
const lines = [
|
|
430
|
+
`Directed path: ${fromNode.label} [${fromNode.id}] -> ${toNode.label} [${toNode.id}]`,
|
|
431
|
+
`Hops: ${path.length}`,
|
|
432
|
+
'',
|
|
433
|
+
];
|
|
434
|
+
let current = fromNode;
|
|
435
|
+
path.forEach((edge, index) => {
|
|
436
|
+
const nextNode = nodeMap.get(edge.to);
|
|
437
|
+
lines.push(`${index + 1}. ${current.label} [${edge.from}] -> ${nextNode?.label ?? edge.to} [${edge.to}]${edge.label ? ` (${edge.label})` : ''}${edge.edgeType ? ` [${edge.edgeType}]` : ''}`);
|
|
438
|
+
if (nextNode) {
|
|
439
|
+
current = nextNode;
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
return wrap(lines.join('\n'));
|
|
443
|
+
}
|
|
203
444
|
case 'get_node': {
|
|
204
445
|
const chartId = decoded.chartId || 'main';
|
|
205
446
|
if (!decoded.nodeId) {
|
package/dist/tools/rules.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 📏 kg_rules
|
|
3
|
-
*
|
|
4
|
-
* 删除: kg_get_global_rules_meta, kg_save_global_rules_meta (管理员操作)
|
|
2
|
+
* 📏 kg_rules
|
|
3
|
+
* 统一规则入口: get | save | get_meta | save_meta | delete
|
|
5
4
|
*/
|
|
6
5
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
6
|
import { type McpContext } from './shared.js';
|
package/dist/tools/rules.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 📏 kg_rules
|
|
3
|
-
*
|
|
4
|
-
* 删除: kg_get_global_rules_meta, kg_save_global_rules_meta (管理员操作)
|
|
2
|
+
* 📏 kg_rules
|
|
3
|
+
* 统一规则入口: get | save | get_meta | save_meta | delete
|
|
5
4
|
*/
|
|
6
5
|
import { z } from 'zod';
|
|
7
6
|
import { getClient } from '../storage/httpClient.js';
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@ description: 初始化知识图谱:100%扫描代码库,为每个模块创建
|
|
|
4
4
|
|
|
5
5
|
# /init 项目初始化
|
|
6
6
|
|
|
7
|
-
执行 `
|
|
7
|
+
执行 `kg_task(action:"create", title:"项目初始化: [项目名]")` → 递归扫描全部代码文件 → 逐文件审查创建节点 → 每处理5个文件调用 `kg_task(action:"update", log_type:"progress")` 同步进度 → 全部完成后 `kg_task(action:"archive")` 输出统计报告
|
|
8
8
|
|
|
9
9
|
## 扫描规则
|
|
10
10
|
|
|
@@ -84,11 +84,11 @@ flowchart TB
|
|
|
84
84
|
|
|
85
85
|
## 进度同步
|
|
86
86
|
|
|
87
|
-
每处理5个文件或完成1个目录后,调用 `
|
|
87
|
+
每处理5个文件或完成1个目录后,调用 `kg_task(action:"update", log_type:"progress", content:"已处理: [文件列表], 创建节点: N个")`
|
|
88
88
|
|
|
89
89
|
## 完成输出
|
|
90
90
|
|
|
91
|
-
`
|
|
91
|
+
`kg_task(action:"archive")` 时输出完整统计:
|
|
92
92
|
|
|
93
93
|
```markdown
|
|
94
94
|
| 统计项 | 数量 |
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
|
|
20
20
|
**1.1 建立全景**
|
|
21
21
|
```
|
|
22
|
-
|
|
23
|
-
kg_flowchart(action:"get") → 主图结构 (
|
|
22
|
+
kg_flowchart(action:"list") → 知识图谱列表
|
|
23
|
+
kg_flowchart(action:"get") → 主图结构 (模块 + 连线)
|
|
24
24
|
kg_rules(action:"get", ruleType:"errorAnalysis") → 错误分析规则
|
|
25
25
|
```
|
|
26
26
|
|
|
@@ -162,7 +162,7 @@ L2: 2个间接调用方可能受影响
|
|
|
162
162
|
|
|
163
163
|
| 阶段 | 工具 | 用途 |
|
|
164
164
|
|:---|:---|:---|
|
|
165
|
-
| 锚定 | `
|
|
165
|
+
| 锚定 | `kg_flowchart(list/get)` | 全景鸟瞰 |
|
|
166
166
|
| 锚定 | `kg_flowchart(get)` | 主图结构 |
|
|
167
167
|
| 锚定 | `kg_rules(get)` | 分析规则 |
|
|
168
168
|
| 下探 | `kg_flowchart(get_node, expand:N)` | 节点详情+上下游 |
|
|
@@ -27,10 +27,10 @@
|
|
|
27
27
|
|
|
28
28
|
### Phase 0: 环境准备
|
|
29
29
|
```
|
|
30
|
-
kg_init()
|
|
31
|
-
kg_status()
|
|
32
|
-
|
|
33
|
-
kg_flowchart(action:"
|
|
30
|
+
kg_init() → 连接项目上下文
|
|
31
|
+
kg_status() → 查看仪表盘 (流程图/任务/状态)
|
|
32
|
+
kg_flowchart(action:"list") → 已有流程图列表
|
|
33
|
+
kg_flowchart(action:"get") → 主图结构总览
|
|
34
34
|
```
|
|
35
35
|
如果已有图谱 → 提示用户选择: 增量补充 or 重建
|
|
36
36
|
|
|
@@ -125,27 +125,18 @@ kg_flowchart(action:"bind", nodeId:"n_graph_store",
|
|
|
125
125
|
dirs:["src-tauri/src/storage/"])
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
-
**3.2
|
|
128
|
+
**3.2 写入节点内置文档 (`docEntries`)**
|
|
129
129
|
```
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
/模块/前端/FlowchartView → 对应 n_flowchart_view
|
|
134
|
-
/架构/事件驱动 → 对应架构决策
|
|
135
|
-
/功能/知识图谱编辑 → 对应用户功能
|
|
136
|
-
|
|
137
|
-
kg_doc(action:"create",
|
|
138
|
-
path:"/模块/后端/graph_store",
|
|
139
|
-
summary:"项目/文档/规则/搜索的核心存储, JSON持久化",
|
|
140
|
-
content:"## 职责\n...\n## 公开API\n...\n## 文件路径\n...",
|
|
141
|
-
bindTo:"n_graph_store")
|
|
130
|
+
kg_flowchart(action:"update_node", chartId:"sub_storage", nodeId:"n_graph_store",
|
|
131
|
+
docSummary:"项目/规则/流程图数据持久化核心",
|
|
132
|
+
docContent:"## 职责\n...\n## 公开 API\n...\n## 文件路径\n- src-tauri/src/storage/graph_store.rs")
|
|
142
133
|
```
|
|
143
134
|
|
|
144
135
|
### Phase 4: 健康验证
|
|
145
136
|
```
|
|
146
137
|
kg_flowchart(action:"orphans") → 孤立节点 (应为0)
|
|
147
138
|
kg_flowchart(action:"health") → 冷热分布
|
|
148
|
-
|
|
139
|
+
kg_flowchart(action:"get") → 全景确认节点覆盖与连线
|
|
149
140
|
kg_status() → 最终仪表盘
|
|
150
141
|
```
|
|
151
142
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
| **代码即真理** | 代码与图谱冲突时以 Git 状态为准, 强制覆写 |
|
|
8
8
|
| **层级感知** | 变更定位到具体子图层级, 逐层向上验证影响链 |
|
|
9
9
|
| **最小变更** | 只更新有差异的节点/文档, 不做无意义的全量覆写 |
|
|
10
|
-
| **创建即关联** | 新增节点必须 bind 源码 +
|
|
10
|
+
| **创建即关联** | 新增节点必须 bind 源码 + 写入节点文档, 无孤立资产 |
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
**1.1 获取图谱现状**
|
|
31
31
|
```
|
|
32
32
|
kg_init() → 确保项目连接
|
|
33
|
-
kg_tree() → 文档全景
|
|
34
33
|
kg_flowchart(action:"list") → 所有流程图
|
|
35
34
|
kg_flowchart(action:"get") → 主图节点+连线
|
|
35
|
+
kg_flowchart(action:"search", query:"关键词") → 快速定位相关节点
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
**1.2 获取代码变更**
|
|
@@ -106,12 +106,10 @@ all 模式:
|
|
|
106
106
|
3. 绑定源码:
|
|
107
107
|
kg_flowchart(action:"bind", nodeId:"n_xxx", files:["src/..."])
|
|
108
108
|
|
|
109
|
-
4.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
content:"## 职责\n...\n## 公开API\n...\n## 文件路径\n...",
|
|
114
|
-
bindTo:"n_xxx")
|
|
109
|
+
4. 写入节点文档:
|
|
110
|
+
kg_flowchart(action:"update_node", chartId:目标子图, nodeId:"n_xxx",
|
|
111
|
+
docSummary:"一句话职责",
|
|
112
|
+
docContent:"## 职责\n...\n## 公开API\n...\n## 文件路径\n...")
|
|
115
113
|
```
|
|
116
114
|
|
|
117
115
|
**3.2 处理 [MOD] — 更新节点**
|
|
@@ -126,8 +124,9 @@ all 模式:
|
|
|
126
124
|
docSummary:"更新后的摘要")
|
|
127
125
|
|
|
128
126
|
3. 追加版本记录:
|
|
129
|
-
|
|
130
|
-
|
|
127
|
+
kg_flowchart(action:"update_node", chartId:目标子图, nodeId:"n_xxx",
|
|
128
|
+
docSummary:"本次变更摘要",
|
|
129
|
+
docContent:"更新后的详细文档")
|
|
131
130
|
|
|
132
131
|
4. 检查连线是否需要更新:
|
|
133
132
|
code_context(filePath) → 新的import列表
|
|
@@ -142,7 +141,6 @@ all 模式:
|
|
|
142
141
|
|
|
143
142
|
选项B - 彻底删除:
|
|
144
143
|
kg_flowchart(action:"delete_node", nodeId:"n_xxx")
|
|
145
|
-
kg_doc(action:"delete", path:"/模块/.../xxx")
|
|
146
144
|
```
|
|
147
145
|
|
|
148
146
|
**3.4 处理 [DRIFT] — 路径漂移**
|
|
@@ -177,7 +175,7 @@ kg_task(action:"update", taskId:"当前任务", log_type:"progress",
|
|
|
177
175
|
```
|
|
178
176
|
kg_flowchart(action:"orphans") → 全局孤立节点 (应为0)
|
|
179
177
|
kg_flowchart(action:"health") → 冷热分布
|
|
180
|
-
|
|
178
|
+
kg_flowchart(action:"get") → 节点覆盖确认
|
|
181
179
|
```
|
|
182
180
|
|
|
183
181
|
### Phase 5: 交付报告
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
| 原则 | 要求 |
|
|
8
8
|
|:---|:---|
|
|
9
9
|
| **知识图谱中心** | 方案制定前检索图谱+代码双重验证;任务结束提示沉淀至图谱 |
|
|
10
|
-
| **任务驱动开发** | 复杂任务必须 `
|
|
10
|
+
| **任务驱动开发** | 复杂任务必须 `kg_task(action:"create")`;过程记录 `kg_task(action:"update")`;完成 `kg_task(action:"archive")` |
|
|
11
11
|
| **规则引用** | 编码前读 `codeStyle`;测试前读 `testRules`;审查前读 `reviewRules` |
|
|
12
12
|
| **绝对真实性** | 禁用 faker/模拟数据,必须真实环境验证 |
|
|
13
13
|
| **沟通可视化** | 禁纯文字/Mermaid代码;强制 ASCII流程图 + Markdown表格 |
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
|
|
18
18
|
## 任务生命周期
|
|
19
19
|
```
|
|
20
|
-
|
|
20
|
+
kg_task(action:"create") → kg_task(action:"update", log_type:"progress|issue|solution|reference") → kg_task(action:"archive")
|
|
21
21
|
```
|
|
22
22
|
| 日志类型 | 用途 | 示例 |
|
|
23
23
|
|:---|:---|:---|
|
|
@@ -32,24 +32,24 @@ task_create → task_add_log(progress/issue/solution/reference) → task_complet
|
|
|
32
32
|
|
|
33
33
|
### Step 1: 分析与澄清
|
|
34
34
|
1. 接收需求,识别意图
|
|
35
|
-
2. `
|
|
36
|
-
3. `
|
|
35
|
+
2. `kg_flowchart(action:"search", query:"关键词")` 检索现有节点/历史坑点
|
|
36
|
+
3. `kg_rules(action:"get")` 获取项目规则
|
|
37
37
|
4. 有歧义则列选项供用户选择
|
|
38
38
|
|
|
39
39
|
**输出**: 需求确认清单 (表格)
|
|
40
40
|
|
|
41
41
|
### Step 2: 逻辑设计
|
|
42
42
|
1. 结合图谱+代码设计方案
|
|
43
|
-
2. `
|
|
43
|
+
2. `kg_rules(action:"get", ruleType:"codeStyle")` 确认编码规范
|
|
44
44
|
3. 检查现有复用函数,拒绝重复建设
|
|
45
|
-
4. 大型任务: `
|
|
45
|
+
4. 大型任务: `kg_task(action:"create")`
|
|
46
46
|
|
|
47
47
|
**输出**: ASCII流程图 + 对比表 + 子任务列表
|
|
48
48
|
**里程碑**: 等待用户确认 (不写代码)
|
|
49
49
|
|
|
50
50
|
### Step 3: 模块化编码
|
|
51
51
|
**前置**: 用户确认方案
|
|
52
|
-
1. `
|
|
52
|
+
1. `kg_task(action:"update", log_type:"progress", content:"开始编码")`
|
|
53
53
|
2. 优先编写/更新工具函数,再业务组装
|
|
54
54
|
3. 遵循 codeStyle 规则
|
|
55
55
|
4. 清理现场,无残留代码
|
|
@@ -57,19 +57,19 @@ task_create → task_add_log(progress/issue/solution/reference) → task_complet
|
|
|
57
57
|
**输出**: 结构清晰的代码
|
|
58
58
|
|
|
59
59
|
### Step 4: 真实验证
|
|
60
|
-
1. `
|
|
60
|
+
1. `kg_rules(action:"get", ruleType:"testRules")` 获取测试规则
|
|
61
61
|
2. 在 `tests/` 对应目录创建测试
|
|
62
62
|
3. 真实环境运行,验证输出
|
|
63
|
-
4. 失败时: `
|
|
63
|
+
4. 失败时: `kg_task(action:"update", log_type:"issue", content:"xxx失败")` → 回溯Step2
|
|
64
64
|
|
|
65
65
|
**严禁**: "测试环境所以失败"借口
|
|
66
66
|
|
|
67
67
|
### Step 5: 审查与沉淀
|
|
68
|
-
1. `
|
|
68
|
+
1. `kg_rules(action:"get", ruleType:"reviewRules")` 获取审查规则
|
|
69
69
|
2. 审查目录结构/代码简洁度
|
|
70
|
-
3. 发现BUG → `
|
|
71
|
-
4. 新逻辑 → `
|
|
72
|
-
5. `
|
|
70
|
+
3. 发现BUG → `kg_flowchart(action:"update_node")` 回写节点说明与文档
|
|
71
|
+
4. 新逻辑 → `kg_flowchart(action:"batch_add")` 新增节点,或 `kg_flowchart(action:"update_node")` 追加文档/版本
|
|
72
|
+
5. `kg_task(action:"archive", summary, difficulties, solutions)`
|
|
73
73
|
|
|
74
74
|
**输出**: 交付确认 + 图谱更新清单
|
|
75
75
|
|
|
@@ -78,7 +78,7 @@ task_create → task_add_log(progress/issue/solution/reference) → task_complet
|
|
|
78
78
|
## 异常处理
|
|
79
79
|
| 场景 | 反应 |
|
|
80
80
|
|:---|:---|
|
|
81
|
-
| Step4 测试失败 | 停止 → 分析日志 →
|
|
81
|
+
| Step4 测试失败 | 停止 → 分析日志 → `kg_task(action:"update", log_type:"issue")` → 回溯Step2 → 修正 → 重测 |
|
|
82
82
|
| 发现历史BUG | 读取节点 bugfixes 参考历史方案 |
|
|
83
83
|
| 重复造轮子 | 终止 → 指出现有实现 → 要求复用 |
|
|
84
84
|
|