@ppdocs/mcp 2.6.31 → 2.7.2

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.
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * API URL 格式: http://localhost:20001/api/:projectId/:password/...
6
6
  */
7
- import type { NodeData, SearchResult, PathResult, BugfixRecord, Task, TaskSummary, TaskLogType, TaskExperience } from './types.js';
7
+ import type { NodeData, Task, TaskSummary, TaskLogType, TaskExperience } from './types.js';
8
8
  export interface ListNodesFilter {
9
9
  status?: 'incomplete' | 'complete' | 'fixing' | 'refactoring' | 'deprecated';
10
10
  minEdges?: number;
@@ -27,33 +27,17 @@ export declare class PpdocsApiClient {
27
27
  codeStyle?: string[];
28
28
  }): Promise<NodeData | null>;
29
29
  deleteNode(nodeId: string): Promise<boolean>;
30
- lockNode(nodeId: string, locked: boolean): Promise<NodeData | null>;
31
- searchNodes(keywords: string[], limit?: number): Promise<SearchResult[]>;
32
- findPath(startId: string, endId: string): Promise<PathResult | null>;
33
- getRelations(nodeId: string): Promise<Array<{
34
- nodeId: string;
35
- title: string;
36
- description: string;
37
- edgeType: string;
38
- direction: 'outgoing' | 'incoming';
39
- }>>;
40
- addBugfix(nodeId: string, bugfix: {
41
- issue: string;
42
- solution: string;
43
- impact?: string;
44
- }): Promise<BugfixRecord | null>;
30
+ getRulesApi(ruleType: string): Promise<string[]>;
31
+ saveRulesApi(ruleType: string, rules: string[]): Promise<boolean>;
45
32
  listTasks(status?: 'active' | 'archived'): Promise<TaskSummary[]>;
46
33
  getTask(taskId: string): Promise<Task | null>;
47
34
  createTask(task: {
48
35
  title: string;
49
36
  description: string;
50
37
  goals: string[];
51
- related_nodes?: string[];
52
38
  }, creator: string): Promise<Task>;
53
39
  addTaskLog(taskId: string, logType: TaskLogType, content: string): Promise<Task | null>;
54
40
  completeTask(taskId: string, experience: TaskExperience): Promise<Task | null>;
55
- getRulesApi(ruleType: string): Promise<string[]>;
56
- saveRulesApi(ruleType: string, rules: string[]): Promise<boolean>;
57
41
  }
58
42
  export declare function initClient(apiUrl: string): void;
59
43
  export declare function listNodes(_projectId: string, filter?: ListNodesFilter): Promise<NodeData[]>;
@@ -69,30 +53,14 @@ export declare function updateRoot(_projectId: string, updates: {
69
53
  codeStyle?: string[];
70
54
  }): Promise<NodeData | null>;
71
55
  export declare function deleteNode(_projectId: string, nodeId: string): Promise<boolean>;
72
- export declare function lockNode(_projectId: string, nodeId: string, locked: boolean): Promise<NodeData | null>;
73
- export declare function searchNodes(_projectId: string, keywords: string[], limit?: number): Promise<SearchResult[]>;
74
- export declare function findPath(_projectId: string, startId: string, endId: string): Promise<PathResult | null>;
75
- export declare function getRelations(_projectId: string, nodeId: string): Promise<Array<{
76
- nodeId: string;
77
- title: string;
78
- description: string;
79
- edgeType: string;
80
- direction: 'outgoing' | 'incoming';
81
- }>>;
82
- export declare function addBugfix(_projectId: string, nodeId: string, bugfix: {
83
- issue: string;
84
- solution: string;
85
- impact?: string;
86
- }): Promise<BugfixRecord | null>;
56
+ export declare function getRules(_projectId: string, ruleType: string): Promise<string[]>;
57
+ export declare function saveRules(_projectId: string, ruleType: string, rules: string[]): Promise<boolean>;
87
58
  export declare function listTasks(_projectId: string, status?: 'active' | 'archived'): Promise<TaskSummary[]>;
88
59
  export declare function getTask(_projectId: string, taskId: string): Promise<Task | null>;
89
60
  export declare function createTask(_projectId: string, task: {
90
61
  title: string;
91
62
  description: string;
92
63
  goals: string[];
93
- related_nodes?: string[];
94
64
  }, creator: string): Promise<Task>;
95
65
  export declare function addTaskLog(_projectId: string, taskId: string, logType: TaskLogType, content: string): Promise<Task | null>;
96
66
  export declare function completeTask(_projectId: string, taskId: string, experience: TaskExperience): Promise<Task | null>;
97
- export declare function getRules(_projectId: string, ruleType: string): Promise<string[]>;
98
- export declare function saveRules(_projectId: string, ruleType: string, rules: string[]): Promise<boolean>;
@@ -231,64 +231,27 @@ export class PpdocsApiClient {
231
231
  return false;
232
232
  }
233
233
  }
234
- async lockNode(nodeId, locked) {
234
+ // ============ 规则 API (独立文件存储) ============
235
+ async getRulesApi(ruleType) {
235
236
  try {
236
- return await this.request(`/nodes/${nodeId}/lock`, {
237
- method: 'PUT',
238
- body: JSON.stringify({ locked })
239
- });
237
+ return await this.request(`/rules/${ruleType}`);
240
238
  }
241
239
  catch {
242
- return null;
240
+ return [];
243
241
  }
244
242
  }
245
- // ============ 搜索与路径 ============
246
- async searchNodes(keywords, limit = 20) {
247
- return this.request('/search', {
248
- method: 'POST',
249
- body: JSON.stringify({ keywords, limit })
250
- });
251
- }
252
- async findPath(startId, endId) {
243
+ async saveRulesApi(ruleType, rules) {
253
244
  try {
254
- return await this.request('/path', {
255
- method: 'POST',
256
- body: JSON.stringify({ start_id: startId, end_id: endId })
245
+ await this.request(`/rules/${ruleType}`, {
246
+ method: 'PUT',
247
+ body: JSON.stringify(rules)
257
248
  });
249
+ return true;
258
250
  }
259
251
  catch {
260
- return null;
252
+ return false;
261
253
  }
262
254
  }
263
- async getRelations(nodeId) {
264
- const result = await this.request(`/relations/${nodeId}`);
265
- // 转换字段名 (API 返回 type,前端期望 edgeType)
266
- return result.map(r => ({
267
- nodeId: r.nodeId,
268
- title: r.title,
269
- description: r.description,
270
- edgeType: r.type,
271
- direction: r.direction
272
- }));
273
- }
274
- // ============ Bugfix ============
275
- async addBugfix(nodeId, bugfix) {
276
- // 添加 bugfix 需要先获取节点,追加 bugfix,然后更新
277
- const node = await this.getNode(nodeId);
278
- if (!node || node.locked)
279
- return null;
280
- const newBugfix = {
281
- id: `bug-${Date.now()}`,
282
- date: new Date().toISOString(),
283
- issue: bugfix.issue,
284
- solution: bugfix.solution,
285
- impact: bugfix.impact
286
- };
287
- const updated = await this.updateNode(nodeId, {
288
- bugfixes: [newBugfix, ...(node.bugfixes || [])].slice(0, 20)
289
- });
290
- return updated ? newBugfix : null;
291
- }
292
255
  // ============ 任务管理 ============
293
256
  async listTasks(status) {
294
257
  const query = status ? `?status=${status}` : '';
@@ -309,7 +272,7 @@ export class PpdocsApiClient {
309
272
  detail: {
310
273
  description: task.description,
311
274
  goals: task.goals,
312
- related_nodes: task.related_nodes || []
275
+ related_nodes: []
313
276
  }
314
277
  };
315
278
  return this.request('/tasks', {
@@ -339,27 +302,6 @@ export class PpdocsApiClient {
339
302
  return null;
340
303
  }
341
304
  }
342
- // ============ 规则 API (独立文件存储) ============
343
- async getRulesApi(ruleType) {
344
- try {
345
- return await this.request(`/rules/${ruleType}`);
346
- }
347
- catch {
348
- return [];
349
- }
350
- }
351
- async saveRulesApi(ruleType, rules) {
352
- try {
353
- await this.request(`/rules/${ruleType}`, {
354
- method: 'PUT',
355
- body: JSON.stringify(rules)
356
- });
357
- return true;
358
- }
359
- catch {
360
- return false;
361
- }
362
- }
363
305
  }
364
306
  // ============ 模块级 API (兼容现有 tools/index.ts) ============
365
307
  let client = null;
@@ -391,20 +333,12 @@ export async function updateRoot(_projectId, updates) {
391
333
  export async function deleteNode(_projectId, nodeId) {
392
334
  return getClient().deleteNode(nodeId);
393
335
  }
394
- export async function lockNode(_projectId, nodeId, locked) {
395
- return getClient().lockNode(nodeId, locked);
396
- }
397
- export async function searchNodes(_projectId, keywords, limit) {
398
- return getClient().searchNodes(keywords, limit);
399
- }
400
- export async function findPath(_projectId, startId, endId) {
401
- return getClient().findPath(startId, endId);
402
- }
403
- export async function getRelations(_projectId, nodeId) {
404
- return getClient().getRelations(nodeId);
336
+ // ============ 规则管理 (独立文件存储) ============
337
+ export async function getRules(_projectId, ruleType) {
338
+ return getClient().getRulesApi(ruleType);
405
339
  }
406
- export async function addBugfix(_projectId, nodeId, bugfix) {
407
- return getClient().addBugfix(nodeId, bugfix);
340
+ export async function saveRules(_projectId, ruleType, rules) {
341
+ return getClient().saveRulesApi(ruleType, rules);
408
342
  }
409
343
  // ============ 任务管理 ============
410
344
  export async function listTasks(_projectId, status) {
@@ -422,10 +356,3 @@ export async function addTaskLog(_projectId, taskId, logType, content) {
422
356
  export async function completeTask(_projectId, taskId, experience) {
423
357
  return getClient().completeTask(taskId, experience);
424
358
  }
425
- // ============ 规则管理 (独立文件存储) ============
426
- export async function getRules(_projectId, ruleType) {
427
- return getClient().getRulesApi(ruleType);
428
- }
429
- export async function saveRules(_projectId, ruleType, rules) {
430
- return getClient().saveRulesApi(ruleType, rules);
431
- }
@@ -75,25 +75,20 @@ export interface SearchResult {
75
75
  score: number;
76
76
  matches: string[];
77
77
  }
78
- export interface PathResult {
79
- path: NodeData[];
80
- edges: Edge[];
81
- }
82
78
  export type TaskLogType = 'progress' | 'issue' | 'solution' | 'reference';
83
79
  export interface TaskLog {
84
80
  time: string;
85
81
  log_type: TaskLogType;
86
82
  content: string;
87
83
  }
88
- export interface TaskReference {
89
- title: string;
90
- url?: string;
91
- }
92
84
  export interface TaskExperience {
93
85
  summary: string;
94
86
  difficulties: string[];
95
87
  solutions: string[];
96
- references: TaskReference[];
88
+ references: Array<{
89
+ title: string;
90
+ url?: string;
91
+ }>;
97
92
  }
98
93
  export interface TaskDetail {
99
94
  description: string;
@@ -12,53 +12,10 @@ export declare function wrap(text: string): {
12
12
  text: string;
13
13
  }[];
14
14
  };
15
- interface RelationItem {
16
- id: string;
17
- title: string;
18
- edge: string;
19
- }
20
- /**
21
- * 递归获取节点的上下游关系
22
- */
23
- export declare function fetchRelations(projectId: string, nodeId: string, maxDepth: number): Promise<{
24
- outgoing: RelationItem[];
25
- incoming: RelationItem[];
26
- }>;
27
- interface SearchResultItem {
28
- id: string;
29
- title: string;
30
- tags: string[];
31
- status: string;
32
- summary: string;
33
- score: string;
34
- matchType: 'hybrid' | 'semantic' | 'keyword';
35
- }
36
- /**
37
- * 融合关键词和语义搜索结果
38
- */
39
- export declare function mergeSearchResults(keywordResults: Array<{
40
- id: string;
41
- title: string;
42
- tags: string[];
43
- status: string;
44
- summary: string;
45
- score: number;
46
- }>, semanticResults: Array<{
47
- id: string;
48
- title: string;
49
- tags: string[];
50
- status: string;
51
- summary: string;
52
- similarity: number;
53
- }>, mode: 'hybrid' | 'keyword' | 'semantic', limit: number): SearchResultItem[];
54
15
  /**
55
16
  * 格式化节点为 Markdown 输出
56
17
  */
57
18
  export declare function formatNodeMarkdown(node: NodeData): string[];
58
- /**
59
- * 格式化关系输出
60
- */
61
- export declare function formatRelationsMarkdown(outgoing: RelationItem[], incoming: RelationItem[]): string[];
62
19
  interface TreeNode {
63
20
  name: string;
64
21
  type: 'folder' | 'node';
@@ -2,7 +2,6 @@
2
2
  * MCP 工具辅助函数
3
3
  * 提取自 index.ts,避免重复代码
4
4
  */
5
- import * as storage from '../storage/httpClient.js';
6
5
  // ==================== 通用包装 ====================
7
6
  /**
8
7
  * 包装返回结果为 MCP 格式
@@ -10,92 +9,6 @@ import * as storage from '../storage/httpClient.js';
10
9
  export function wrap(text) {
11
10
  return { content: [{ type: 'text', text }] };
12
11
  }
13
- /**
14
- * 递归获取节点的上下游关系
15
- */
16
- export async function fetchRelations(projectId, nodeId, maxDepth) {
17
- const visited = new Set();
18
- const outgoing = [];
19
- const incoming = [];
20
- async function recurse(currentNodeId, currentDepth, direction) {
21
- if (currentDepth > maxDepth || visited.has(`${currentNodeId}-${direction}`))
22
- return;
23
- visited.add(`${currentNodeId}-${direction}`);
24
- const relations = await storage.getRelations(projectId, currentNodeId);
25
- for (const r of relations) {
26
- if (r.direction === 'outgoing' && (direction === 'outgoing' || direction === 'both')) {
27
- if (!outgoing.some(o => o.id === r.nodeId)) {
28
- outgoing.push({ id: r.nodeId, title: r.title, edge: r.edgeType });
29
- await recurse(r.nodeId, currentDepth + 1, 'outgoing');
30
- }
31
- }
32
- if (r.direction === 'incoming' && (direction === 'incoming' || direction === 'both')) {
33
- if (!incoming.some(i => i.id === r.nodeId)) {
34
- incoming.push({ id: r.nodeId, title: r.title, edge: r.edgeType });
35
- await recurse(r.nodeId, currentDepth + 1, 'incoming');
36
- }
37
- }
38
- }
39
- }
40
- await recurse(nodeId, 1, 'both');
41
- return { outgoing, incoming };
42
- }
43
- /**
44
- * 融合关键词和语义搜索结果
45
- */
46
- export function mergeSearchResults(keywordResults, semanticResults, mode, limit) {
47
- const scoreMap = new Map();
48
- // 合并关键词结果
49
- for (const r of keywordResults) {
50
- scoreMap.set(r.id, {
51
- id: r.id,
52
- title: r.title,
53
- tags: r.tags,
54
- status: r.status,
55
- summary: r.summary,
56
- keywordScore: r.score,
57
- semanticScore: 0
58
- });
59
- }
60
- // 合并语义结果
61
- for (const r of semanticResults) {
62
- const existing = scoreMap.get(r.id);
63
- if (existing) {
64
- existing.semanticScore = r.similarity;
65
- }
66
- else {
67
- scoreMap.set(r.id, {
68
- id: r.id,
69
- title: r.title,
70
- tags: r.tags,
71
- status: r.status,
72
- summary: r.summary,
73
- keywordScore: 0,
74
- semanticScore: r.similarity
75
- });
76
- }
77
- }
78
- // 计算综合得分并排序
79
- const combined = Array.from(scoreMap.values()).map(item => {
80
- // 混合权重: 语义 0.6 + 关键词 0.4
81
- const finalScore = mode === 'keyword' ? item.keywordScore
82
- : mode === 'semantic' ? item.semanticScore
83
- : item.semanticScore * 0.6 + item.keywordScore * 0.4;
84
- return { ...item, finalScore };
85
- });
86
- combined.sort((a, b) => b.finalScore - a.finalScore);
87
- const topResults = combined.slice(0, limit);
88
- return topResults.map(r => ({
89
- id: r.id,
90
- title: r.title,
91
- tags: r.tags,
92
- status: r.status,
93
- summary: r.summary,
94
- score: `${Math.round(r.finalScore * 100)}%`,
95
- matchType: (r.keywordScore > 0 && r.semanticScore > 0 ? 'hybrid'
96
- : r.semanticScore > 0 ? 'semantic' : 'keyword')
97
- }));
98
- }
99
12
  // ==================== 节点格式化 ====================
100
13
  /**
101
14
  * 格式化节点为 Markdown 输出
@@ -154,23 +67,6 @@ export function formatNodeMarkdown(node) {
154
67
  }
155
68
  return lines;
156
69
  }
157
- /**
158
- * 格式化关系输出
159
- */
160
- export function formatRelationsMarkdown(outgoing, incoming) {
161
- const lines = [];
162
- if (outgoing.length > 0 || incoming.length > 0) {
163
- lines.push('**上下游关系**');
164
- if (outgoing.length > 0) {
165
- lines.push(`- 依赖 (${outgoing.length}): ${outgoing.map(o => o.title).join(', ')}`);
166
- }
167
- if (incoming.length > 0) {
168
- lines.push(`- 被依赖 (${incoming.length}): ${incoming.map(i => i.title).join(', ')}`);
169
- }
170
- lines.push('');
171
- }
172
- return lines;
173
- }
174
70
  /**
175
71
  * 构建目录树结构
176
72
  */
@@ -1,9 +1,8 @@
1
1
  import { z } from 'zod';
2
2
  import * as storage from '../storage/httpClient.js';
3
- import { decodeUnicodeEscapes, decodeObjectStrings, getRules, RULE_TYPE_LABELS } from '../utils.js';
4
- import * as vector from '../vector/index.js';
5
- // vectorManager 已弃用,向量索引由 Tauri 后端自动维护
6
- import { wrap, fetchRelations, mergeSearchResults, formatNodeMarkdown, formatRelationsMarkdown, buildDirectoryTree, formatTreeText, countTreeNodes } from './helpers.js';
3
+ import { decodeObjectStrings, getRules, RULE_TYPE_LABELS } from '../utils.js';
4
+ // 向量搜索已迁移至 Tauri 后端,通过 HTTP API 调用
5
+ import { wrap, formatNodeMarkdown, buildDirectoryTree, formatTreeText, countTreeNodes } from './helpers.js';
7
6
  export function registerTools(server, projectId, _user) {
8
7
  // 1. 创建节点
9
8
  server.tool('kg_create_node', '创建知识节点。type: logic=逻辑/函数, data=数据结构, intro=概念介绍。⚠️ tags至少提供3个分类标签', {
@@ -139,129 +138,9 @@ export function registerTools(server, projectId, _user) {
139
138
  }
140
139
  return wrap(`✅ ${RULE_TYPE_LABELS[decoded.ruleType]}已保存 (${decoded.rules.length} 条)`);
141
140
  });
142
- // 4. 锁定节点 (只能锁定,解锁需用户在前端手动操作)
143
- server.tool('kg_lock_node', '锁定节点(锁定后只能读取,解锁需用户在前端手动操作)', {
141
+ // 5. 读取单个节点详情
142
+ server.tool('kg_read_node', '读取单个节点的完整内容(描述、关联文件、依赖、历史记录)', {
144
143
  nodeId: z.string().describe('节点ID')
145
- }, async (args) => {
146
- const node = await storage.lockNode(projectId, args.nodeId, true); // 强制锁定
147
- return wrap(node ? JSON.stringify(node, null, 2) : '操作失败');
148
- });
149
- // 5. 搜索节点 (混合检索: 向量语义 + 关键词)
150
- server.tool('kg_search', '智能搜索节点(语义+关键词混合)。支持中英文语义匹配,空白关键词[""]返回全部节点', {
151
- keywords: z.array(z.string()).describe('搜索词列表(⚠️建议3个以上关键词提高准确率),支持语义匹配(如"登录"可找到auth)'),
152
- limit: z.number().optional().describe('返回数量(默认10)'),
153
- mode: z.enum(['hybrid', 'keyword', 'semantic']).optional().describe('搜索模式: hybrid=混合(默认), keyword=仅关键词, semantic=仅语义')
154
- }, async (args) => {
155
- const limit = args.limit || 10;
156
- const mode = (args.mode || 'hybrid');
157
- const query = args.keywords.filter(k => k.trim()).join(' ');
158
- // 空白关键词返回全部
159
- if (!query) {
160
- const results = await storage.searchNodes(projectId, args.keywords, limit);
161
- const output = results.map(r => ({
162
- id: r.node.id,
163
- title: r.node.title,
164
- tags: r.node.categories || [],
165
- status: r.node.status,
166
- summary: r.node.summary || '',
167
- hitRate: `${Math.round(r.score)}%`
168
- }));
169
- return wrap(`${JSON.stringify(output, null, 2)}\n\n💡 需要详细内容请使用 kg_read_node(nodeId) 获取节点详情`);
170
- }
171
- // 获取关键词结果
172
- let keywordResults = [];
173
- if (mode === 'hybrid' || mode === 'keyword') {
174
- const kResults = await storage.searchNodes(projectId, args.keywords, limit * 2);
175
- keywordResults = kResults.map(r => ({
176
- id: r.node.id,
177
- title: r.node.title,
178
- tags: r.node.categories || [],
179
- status: r.node.status,
180
- summary: r.node.summary || '',
181
- score: r.score / 100
182
- }));
183
- }
184
- // 获取语义结果 (需补全节点信息)
185
- let semanticResults = [];
186
- if (mode === 'hybrid' || mode === 'semantic') {
187
- try {
188
- // 向量索引由 Tauri 后端自动维护,MCP 直接读取
189
- const rawSemantic = await vector.semanticSearch(projectId, query, limit * 2);
190
- // 补全节点信息 (关键词结果中已有的复用,没有的获取)
191
- const keywordMap = new Map(keywordResults.map(r => [r.id, r]));
192
- for (const r of rawSemantic) {
193
- const existing = keywordMap.get(r.id);
194
- if (existing) {
195
- semanticResults.push({ ...existing, similarity: r.similarity });
196
- }
197
- else {
198
- const node = await storage.getNode(projectId, r.id);
199
- if (node) {
200
- semanticResults.push({
201
- id: r.id,
202
- title: r.title,
203
- tags: node.categories || [],
204
- status: node.status,
205
- summary: node.summary || '',
206
- similarity: r.similarity
207
- });
208
- }
209
- }
210
- }
211
- }
212
- catch (e) {
213
- console.warn('[kg_search] Semantic search failed:', e);
214
- }
215
- }
216
- // 融合排序
217
- const output = mergeSearchResults(keywordResults, semanticResults, mode, limit);
218
- const json = JSON.stringify(output, null, 2);
219
- return wrap(`${json}\n\n💡 需要详细内容请使用 kg_read_node(nodeId) 获取节点详情\n🔍 搜索模式: ${mode}`);
220
- });
221
- // 6. 路径查找
222
- server.tool('kg_find_path', '查找两节点间的依赖路径', {
223
- startId: z.string().describe('起点节点ID'),
224
- endId: z.string().describe('终点节点ID')
225
- }, async (args) => {
226
- const result = await storage.findPath(projectId, args.startId, args.endId);
227
- if (!result)
228
- return wrap('未找到路径');
229
- const output = {
230
- pathLength: result.path.length,
231
- nodes: result.path.map(n => ({ id: n.id, title: n.title, type: n.type })),
232
- edges: result.edges.map(e => ({ from: e.source, to: e.target, type: e.type }))
233
- };
234
- return wrap(JSON.stringify(output, null, 2));
235
- });
236
- // 7. 列出节点 (支持过滤)
237
- server.tool('kg_list_nodes', '列出节点,支持按状态/连接数过滤。maxEdges=0 可查孤立节点', {
238
- status: z.enum(['incomplete', 'complete', 'fixing', 'refactoring', 'deprecated']).optional().describe('状态过滤'),
239
- minEdges: z.number().optional().describe('最小连接数(含)'),
240
- maxEdges: z.number().optional().describe('最大连接数(含),0=孤立节点')
241
- }, async (args) => {
242
- const filter = (args.status || args.minEdges !== undefined || args.maxEdges !== undefined)
243
- ? { status: args.status, minEdges: args.minEdges, maxEdges: args.maxEdges }
244
- : undefined;
245
- const nodes = await storage.listNodes(projectId, filter);
246
- const output = nodes.map(n => ({ id: n.id, title: n.title, type: n.type, status: n.status, locked: n.locked, summary: n.summary || '' }));
247
- return wrap(JSON.stringify(output, null, 2));
248
- });
249
- // 8. 查询节点关系网 (支持多层)
250
- server.tool('kg_get_relations', '获取节点的上下游关系(谁依赖它/它依赖谁),支持多层查询', {
251
- nodeId: z.string().describe('节点ID'),
252
- depth: z.number().min(1).max(3).optional().describe('查询层数(默认1,最大3)')
253
- }, async (args) => {
254
- const maxDepth = Math.min(args.depth || 1, 3);
255
- const { outgoing, incoming } = await fetchRelations(projectId, args.nodeId, maxDepth);
256
- if (outgoing.length === 0 && incoming.length === 0) {
257
- return wrap('该节点没有任何连线');
258
- }
259
- return wrap(JSON.stringify({ outgoing, incoming }, null, 2));
260
- });
261
- // 9. 读取单个节点详情
262
- server.tool('kg_read_node', '读取单个节点的完整内容(描述、关联文件、依赖、历史记录),可选包含上下游关系', {
263
- nodeId: z.string().describe('节点ID'),
264
- depth: z.number().min(0).max(3).optional().describe('关系查询层数(0=不含关系,1-3=含上下游关系,默认0)')
265
144
  }, async (args) => {
266
145
  const node = await storage.getNode(projectId, args.nodeId);
267
146
  if (!node) {
@@ -269,147 +148,109 @@ export function registerTools(server, projectId, _user) {
269
148
  }
270
149
  // 格式化节点基础信息
271
150
  const lines = formatNodeMarkdown(node);
272
- // 上下游关系 (depth > 0 时获取)
273
- const depth = args.depth || 0;
274
- if (depth > 0) {
275
- const { outgoing, incoming } = await fetchRelations(projectId, args.nodeId, depth);
276
- lines.push(...formatRelationsMarkdown(outgoing, incoming));
277
- }
278
151
  return wrap(lines.join('\n'));
279
152
  });
280
153
  // 10. 获取知识库树状图
281
154
  server.tool('kg_get_tree', '获取知识库的目录树结构(按 path 分组)', {}, async () => {
282
- const nodes = await storage.listNodes(projectId);
283
- const tree = buildDirectoryTree(nodes);
284
- const treeText = formatTreeText(tree);
285
- const nodeCount = countTreeNodes(tree);
286
- return wrap(`共 ${nodeCount} 个节点\n\n${treeText}`);
155
+ try {
156
+ const nodes = await storage.listNodes(projectId);
157
+ const tree = buildDirectoryTree(nodes);
158
+ const treeText = formatTreeText(tree);
159
+ const nodeCount = countTreeNodes(tree);
160
+ return wrap(`共 ${nodeCount} 个节点\n\n${treeText}`);
161
+ }
162
+ catch (e) {
163
+ return wrap(JSON.stringify({
164
+ error: '无法获取知识库结构',
165
+ message: String(e),
166
+ tip: '请确保软件端已启动'
167
+ }, null, 2));
168
+ }
287
169
  });
288
- // ===================== 任务管理工具 =====================
289
- // 11. 创建任务
290
- server.tool('task_create', '创建开发任务,记录目标和关联节点', {
170
+ // ===================== 任务管理 =====================
171
+ // 7. 创建任务
172
+ server.tool('task_create', '创建开发任务', {
291
173
  title: z.string().describe('任务标题'),
292
174
  description: z.string().describe('任务描述(Markdown)'),
293
- goals: z.array(z.string()).optional().describe('目标清单'),
294
- related_nodes: z.array(z.string()).optional().describe('关联节点ID')
175
+ goals: z.array(z.string()).optional().describe('目标清单')
295
176
  }, async (args) => {
296
- // 解码 Unicode 转义 (修复 MCP 传参中文乱码)
297
177
  const decoded = decodeObjectStrings(args);
298
178
  const task = await storage.createTask(projectId, {
299
179
  title: decoded.title,
300
180
  description: decoded.description,
301
- goals: decoded.goals || [],
302
- related_nodes: decoded.related_nodes
181
+ goals: decoded.goals || []
303
182
  }, _user);
304
183
  return wrap(JSON.stringify(task, null, 2));
305
184
  });
306
- // 11. 列出任务
307
- server.tool('task_list', '列出任务(active=进行中,archived=已归档)', {
308
- status: z.enum(['active', 'archived']).optional().describe('状态筛选')
185
+ // 8. 读取任务 (按名字搜索,支持当前/历史)
186
+ server.tool('task_get', '读取任务详情(按名字搜索,支持当前任务和历史任务)', {
187
+ title: z.string().describe('任务名称(模糊匹配)'),
188
+ status: z.enum(['active', 'archived', 'all']).optional().describe('状态筛选: active=进行中, archived=已归档, all=全部(默认)')
309
189
  }, async (args) => {
310
- const tasks = await storage.listTasks(projectId, args.status);
311
- const output = tasks.map(t => ({
190
+ const status = args.status || 'all';
191
+ const searchTitle = args.title.toLowerCase();
192
+ // 获取任务列表
193
+ let tasks;
194
+ if (status === 'all') {
195
+ const [active, archived] = await Promise.all([
196
+ storage.listTasks(projectId, 'active'),
197
+ storage.listTasks(projectId, 'archived')
198
+ ]);
199
+ tasks = [...active, ...archived];
200
+ }
201
+ else {
202
+ tasks = await storage.listTasks(projectId, status);
203
+ }
204
+ // 按名字模糊匹配
205
+ const matched = tasks.filter(t => t.title.toLowerCase().includes(searchTitle));
206
+ if (matched.length === 0) {
207
+ return wrap(`未找到匹配 "${args.title}" 的任务`);
208
+ }
209
+ // 如果只有一个匹配,返回完整详情
210
+ if (matched.length === 1) {
211
+ const task = await storage.getTask(projectId, matched[0].id);
212
+ return wrap(task ? JSON.stringify(task, null, 2) : '任务详情获取失败');
213
+ }
214
+ // 多个匹配,返回列表让用户选择
215
+ const list = matched.map(t => ({
312
216
  id: t.id,
313
217
  title: t.title,
314
218
  status: t.status,
315
219
  creator: t.creator,
316
- created_at: t.created_at,
317
- last_log: t.last_log
220
+ created_at: t.created_at
318
221
  }));
319
- return wrap(JSON.stringify(output, null, 2));
222
+ return wrap(`找到 ${matched.length} 个匹配任务:\n${JSON.stringify(list, null, 2)}\n\n请提供更精确的任务名称`);
320
223
  });
321
- // 12. 获取任务详情
322
- server.tool('task_get', '获取任务完整信息(含全部日志)', {
323
- taskId: z.string().describe('任务ID')
324
- }, async (args) => {
325
- const task = await storage.getTask(projectId, args.taskId);
326
- if (!task) {
327
- return wrap('任务不存在');
328
- }
329
- return wrap(JSON.stringify(task, null, 2));
330
- });
331
- // 13. 添加任务日志
332
- server.tool('task_add_log', '记录任务进展/问题/方案/参考', {
224
+ // 9. 更新任务 (添加日志)
225
+ server.tool('task_update', '更新任务(添加进展日志)', {
333
226
  taskId: z.string().describe('任务ID'),
334
- log_type: z.enum(['progress', 'issue', 'solution', 'reference']).describe('日志类型'),
227
+ log_type: z.enum(['progress', 'issue', 'solution', 'reference']).describe('日志类型: progress=进展, issue=问题, solution=方案, reference=参考'),
335
228
  content: z.string().describe('日志内容(Markdown)')
336
229
  }, async (args) => {
337
- // 解码 Unicode 转义 (修复 MCP 传参中文乱码)
338
- const decodedContent = decodeUnicodeEscapes(args.content);
339
- const task = await storage.addTaskLog(projectId, args.taskId, args.log_type, decodedContent);
230
+ const decoded = decodeObjectStrings(args);
231
+ const task = await storage.addTaskLog(projectId, args.taskId, decoded.log_type, decoded.content);
340
232
  if (!task) {
341
- return wrap('添加失败(任务不存在或已归档)');
233
+ return wrap('更新失败(任务不存在或已归档)');
342
234
  }
343
- return wrap(`日志已添加,任务共有 ${task.logs.length} 条日志`);
235
+ return wrap(`✅ 日志已添加,任务共有 ${task.logs.length} 条日志`);
344
236
  });
345
- // 14. 完成任务
346
- server.tool('task_complete', '完成任务并归档,填写经验总结', {
237
+ // 10. 归档任务
238
+ server.tool('task_archive', '归档任务(完成并填写经验总结)', {
347
239
  taskId: z.string().describe('任务ID'),
348
240
  summary: z.string().describe('经验总结(Markdown)'),
349
241
  difficulties: z.array(z.string()).optional().describe('遇到的困难'),
350
- solutions: z.array(z.string()).optional().describe('解决方案'),
351
- references: z.array(z.object({
352
- title: z.string(),
353
- url: z.string().optional()
354
- })).optional().describe('参考资料')
242
+ solutions: z.array(z.string()).optional().describe('解决方案')
355
243
  }, async (args) => {
356
- // 解码 Unicode 转义 (修复 MCP 传参中文乱码)
357
- const decoded = decodeObjectStrings({
358
- summary: args.summary,
359
- difficulties: args.difficulties || [],
360
- solutions: args.solutions || [],
361
- references: args.references || []
244
+ const decoded = decodeObjectStrings(args);
245
+ const task = await storage.completeTask(projectId, args.taskId, {
246
+ summary: decoded.summary,
247
+ difficulties: decoded.difficulties || [],
248
+ solutions: decoded.solutions || [],
249
+ references: []
362
250
  });
363
- const task = await storage.completeTask(projectId, args.taskId, decoded);
364
251
  if (!task) {
365
- return wrap('完成失败(任务不存在或已归档)');
252
+ return wrap('归档失败(任务不存在或已归档)');
366
253
  }
367
- return wrap(`任务已完成归档: ${task.title}`);
368
- });
369
- // 15. 查询文件关联的节点
370
- server.tool('kg_find_by_file', '查询哪些节点绑定了指定文件(删除/重命名前检查)', {
371
- filePath: z.string().describe('文件相对路径,如 src/utils/format.ts')
372
- }, async (args) => {
373
- const nodes = await storage.listNodes(projectId);
374
- const filePath = args.filePath.replace(/\\/g, '/'); // 统一为正斜杠
375
- // 查找所有绑定了该文件的节点
376
- const boundBy = [];
377
- for (const node of nodes) {
378
- if (node.relatedFiles && node.relatedFiles.length > 0) {
379
- // 检查是否包含该文件 (支持部分匹配)
380
- const hasFile = node.relatedFiles.some(f => {
381
- const normalizedF = f.replace(/\\/g, '/');
382
- return normalizedF === filePath ||
383
- normalizedF.endsWith('/' + filePath) ||
384
- filePath.endsWith('/' + normalizedF);
385
- });
386
- if (hasFile) {
387
- boundBy.push({
388
- id: node.id,
389
- title: node.title,
390
- type: node.type,
391
- status: node.status
392
- });
393
- }
394
- }
395
- }
396
- const result = {
397
- file: filePath,
398
- boundBy,
399
- message: boundBy.length > 0
400
- ? `⚠️ 该文件被 ${boundBy.length} 个节点引用,删除前请更新节点`
401
- : '✅ 该文件无 KG 引用,可安全操作'
402
- };
403
- return wrap(JSON.stringify(result, null, 2));
404
- });
405
- // ===================== 向量索引管理 =====================
406
- // 注意: 向量索引由 Tauri 后端自动维护,MCP 只提供只读查询
407
- // 16. 查看索引状态 (只读)
408
- server.tool('kg_index_stats', '查看向量索引状态', {}, async () => {
409
- const stats = await vector.getIndexStats(projectId);
410
- return wrap(JSON.stringify({
411
- ...stats,
412
- tip: '向量索引由软件端自动维护,节点增删改时自动更新'
413
- }, null, 2));
254
+ return wrap(`✅ 任务已归档: ${task.title}`);
414
255
  });
415
256
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ppdocs/mcp",
3
- "version": "2.6.31",
3
+ "version": "2.7.2",
4
4
  "description": "ppdocs MCP Server - Knowledge Graph for Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -30,7 +30,6 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@modelcontextprotocol/sdk": "^1.0.0",
33
- "@xenova/transformers": "^2.17.2",
34
33
  "proper-lockfile": "^4.1.2",
35
34
  "zod": "^4.1.13"
36
35
  },
@@ -0,0 +1,82 @@
1
+ # 🔍 "Deep-Trace" Diagnostic Protocol (深层溯源诊断协议)
2
+
3
+ 核心理念:**先在宏观地图(图谱)上定位,再在微观战场(代码)上排查,绝不盲目翻看代码。**
4
+
5
+ ---
6
+
7
+ ### 1.第一阶段:知识锚定 (Knowledge Anchoring) ⚓️
8
+ 🔹 **核心目标**:在动手之前,通过 PPDocs 明确“正确应该是什么样”。
9
+ ✏️ **动作**:
10
+ * **查询图谱**:输入问题关键词,提取标准业务逻辑。
11
+ * **建立基准**:以图谱中的描述作为“真理标准 (Truth)”。
12
+ × **禁区**:
13
+ * 禁止在未查询图谱前,直接跳入代码库阅读(防止陷入细节泥潭)。
14
+
15
+ ### 2.第二阶段:抽象映射 (Abstract Mapping) 🗺️
16
+ 🔹 **核心目标**:利用链式思维 (CoT),绘制高层级逻辑流。
17
+ ✏️ **动作**:
18
+ * **绘制流程**:忽略实现细节,仅画出模块间的输入/输出流转(数据流)。
19
+ * **可视化**:生成 ASCII 或 Mermaid 流程图,展示当前链路。
20
+ * **标记疑点**:在流程图上圈出逻辑可能断裂的节点。
21
+
22
+ ### 3.第三阶段:靶点锁定 (Target Locking) 🎯
23
+ 🔹 **核心目标**:将问题范围从“整个项目”缩小到“单一节点”。
24
+ ✏️ **动作**:
25
+ * **定位区域**:确定问题具体发生在 PPDocs 的哪个 `Node`(节点)或 `Edge`(连线)上。
26
+ * **隔离上下文**:只关注该节点的前置依赖(Pre-requisites)和后置影响(Post-effects)。
27
+
28
+ ### 4.第三阶段:双层取证 (Dual-Layer Forensics) 🕵️
29
+ 🔹 **核心目标**:对比“理论(图谱)”与“现实(代码)”的差异。
30
+ ✏️ **动作**:
31
+ * **左眼看图谱**:阅读 PPDocs 中该节点的逻辑定义。
32
+ * **右眼看代码**:审查该节点对应的实际代码实现。
33
+ * **寻找裂痕**:
34
+ * 🔴 **代码错误 (Bug)**:图谱逻辑正确,代码实现错误。
35
+ * 🟠 **设计缺陷 (Design Flaw)**:代码符合图谱,但结果依然错误(图谱本身逻辑有误)。
36
+ * 🟡 **文档脱节 (Sync Issue)**:代码逻辑正确且有效,但图谱未记载(需同步)。
37
+
38
+ ### 5.第五阶段:分析结案 (Verdict) 📝
39
+ 🔹 **核心目标**:输出可执行的诊断报告。
40
+ ✏️ **动作**:
41
+ * 输出标准化的**《问题诊断报告》**。
42
+ * **流转**:将报告作为输入,传递给 **[任务方案生成工作流]** 进行修复。
43
+
44
+ ---
45
+
46
+ ### 📊 诊断逻辑可视化图解 (ASCII)
47
+
48
+ ```text
49
+ +-------------------------+
50
+ | 🚨 问题触发 (Issue) |
51
+ +------------+------------+
52
+ |
53
+ v
54
+ +------------+------------+
55
+ | ⚓️ 知识锚定 (PPDocs) | <--- 获取标准逻辑 (Truth)
56
+ +------------+------------+
57
+ |
58
+ v
59
+ [ 🗺️ 抽象逻辑层 ]
60
+ +-------------------------+
61
+ | Step1 -> Step2 ... | (绘制链式流程)
62
+ | | |
63
+ | [ ? ] <---------+--- 🎯 锁定可疑节点
64
+ +-----------+-------------+
65
+ |
66
+ v
67
+ +-----------+-------------+
68
+ | 🕵️ 双层取证 (Compare) |
69
+ +-----+-------------+-----+
70
+ | |
71
+ (📜 PPDocs) vs (💻 Code)
72
+ | |
73
+ +------+------+
74
+ |
75
+ v
76
+ /-------+-------\
77
+ / 根本原因? \
78
+ v v
79
+ +--------------+ +--------------+
80
+ | 🐛 代码 Bug | | 📐 设计/文档错 |
81
+ | (Fix Code) | | (Fix Graph) |
82
+ +--------------+ +--------------+
@@ -0,0 +1,84 @@
1
+ # ⚡️ "Ockham's Blade" Execution Protocol (奥卡姆之刃执行协议)
2
+
3
+ 该工作流旨在执行已确认的方案。核心原则:**拒绝冗余,一行搞定,模块解耦,逻辑确权。**
4
+
5
+ ---
6
+
7
+ ### 1.第一阶段:逻辑确权 (Knowledge Anchor) 🧠
8
+ 🔹 **核心目标**:消除所有不确定性,确保逻辑绝对正确。
9
+ ✏️ **动作**:
10
+ * 解析任务需求。
11
+ * 遇到模糊逻辑,立即查询**知识图谱 (Knowledge Graph)** 确认标准流程。
12
+ × **禁区**:
13
+ * 禁止基于猜测编写代码。
14
+ * 禁止模糊定义的变量。
15
+
16
+ ### 2.第二阶段:架构定义 (Structure & Taxonomy) 🏗️
17
+ 🔹 **核心目标**:目录清晰,分类准确,模块独立。
18
+ ✏️ **动作**:
19
+ * 构建标准目录树 (Directory Tree)。
20
+ * 定义原子化模块 (Atomic Modules)。
21
+ * 确保接口通用,支持复用调用。
22
+ × **禁区**:
23
+ * 禁止模块间产生强耦合 (Zero Coupling)。
24
+ * 禁止混乱的文件层级。
25
+
26
+ ### 3.第三阶段:极简实现 (Minimalist Coding) 🚀
27
+ 🔹 **核心目标**:不造轮子,极致压缩代码行数。
28
+ ✏️ **动作**:
29
+ * 最大化调用现有库与复用功能。
30
+ * 利用链式调用、推导式等语法特性。
31
+ × **禁区**:
32
+ * **能一行代码解决的问题,严格禁止使用第二行。**
33
+ * 禁止重复造轮子 (DRY Principle)。
34
+
35
+ ### 4.第四阶段:最终交付 (Delivery) 📦
36
+ 🔹 **核心目标**:输出可直接运行、可维护的成果。
37
+ ✏️ **动作**:
38
+ * 输出标准化的文件结构。
39
+ * 交付模块化源码。
40
+
41
+ ---
42
+
43
+ ### 📊 执行逻辑可视化图解 (ASCII)
44
+
45
+ ```text
46
+ +-----------------------+
47
+ | 🚀 任务启动 (Start) |
48
+ +-----------+-----------+
49
+ |
50
+ v
51
+ +-----------+-----------+
52
+ | 🧠 逻辑是否清晰? | <-----+
53
+ +-----------+-----------+ |
54
+ (❌ NO) | (✅ YES) |
55
+ | v |
56
+ +------+-----+ +----------------+ |
57
+ | 🔍 查图谱 | | 🏗️ 架构设计 | |
58
+ +------------+ +-------+--------+ |
59
+ | |
60
+ v |
61
+ +-------+--------+ |
62
+ | ♻️ 存在轮子? | |
63
+ +-------+--------+ |
64
+ / \ |
65
+ (YES)/ \(NO)
66
+ v v
67
+ +-------+-------+ +-------+-------+
68
+ | ✏️ 直接调用 | | ✏️ 原子编写 |
69
+ +-------+-------+ +-------+-------+
70
+ | |
71
+ +----------+-----------+
72
+ |
73
+ v
74
+ +-------+-------+
75
+ | 📏 极简审查 | <-----+
76
+ +-------+-------+ |
77
+ | |
78
+ /-----------+----------\ |
79
+ / 是否多于一行? \ |
80
+ v v |
81
+ +-------+-------+ +-------+--+----+
82
+ | ✅ 达标 | | × 删减 (Trim) |
83
+ | (Delivery) | | 压缩代码 |
84
+ +---------------+ +---------------+
@@ -0,0 +1,87 @@
1
+ # 🛡️ "Sentinel-4" 多智能体审计协议 任务成果审查或代码审查
2
+
3
+ 本工作流启用**4个独立智能体**并行工作,对任务成果进行“死刑级”严格审查。
4
+
5
+ ---
6
+
7
+ ### 1.智能体部署 (Agent Deployment) 🤖
8
+ 四个专家智能体同时介入,各司其职:
9
+
10
+ #### 🕵️ 智能体 A:逻辑审计官 (Logic Auditor)
11
+ * **职责**:对照预期目标。
12
+ * **检查点**:
13
+ * 🔹 流程是否完全闭环?
14
+ * 🔹 是否存在逻辑断层?
15
+
16
+ #### 🧹 智能体 B:代码清洁工 (Code Janitor)
17
+ * **职责**:通过静态分析寻找“垃圾”。
18
+ * **检查点**:
19
+ * × **死代码 (Dead Code)**:检测未被调用的函数/变量。
20
+ * × **新旧混合**:确保没有注释掉的旧逻辑残留。
21
+ * × **冗余**:消除任何重复逻辑。
22
+
23
+ #### ⚡ 智能体 C:极简架构师 (Minimalist Architect)
24
+ * **职责**:强制执行“单行原则”与模块化。
25
+ * **检查点**:
26
+ * 🔹 **解耦**:模块之间是否彻底分离?
27
+ * 🔹 **行数**:两行能写完的,是否用了三行?(臃肿判定)
28
+
29
+ #### 📚 智能体 D:知识图谱守护者 (Graph Keeper)
30
+ * **职责**:真理一致性校验。
31
+ * **检查点**:
32
+ * × **偏差**:代码逻辑是否违背了知识图谱中的标准定义?
33
+
34
+ ---
35
+
36
+ ### 2.综合裁决 (Synthesis & Verdict) ⚖️
37
+ * **汇总**:收集 4 个智能体的 Flag(报错)。
38
+ * **判定**:
39
+ * 只要有 **1个** 智能体亮红灯 🔴 -> **驳回重构**。
40
+ * 全员亮绿灯 🟢 -> **生成最终报告**。
41
+
42
+ ---
43
+
44
+ ### 3.最终交付:审查报告 (Final Report) 📝
45
+ 报告将以“简单自然语言 + 可视化图标”输出:
46
+ * **状态**:✅ 通过 / ❌ 驳回
47
+ * **评分**:代码纯净度 (0-100%)
48
+ * **风险点**:(如果有)
49
+ * **改进建议**:(针对性优化)
50
+
51
+ ---
52
+
53
+ ### 📊 审计流程可视化图解 (ASCII)
54
+
55
+ ```text
56
+ +----------------------+
57
+ | 📦 提交任务成果 |
58
+ +----------+-----------+
59
+ |
60
+ v
61
+ +----------+-----------+
62
+ | ⚡ 并行分发 |
63
+ +----------+-----------+
64
+ / / | \ \
65
+ v v v v v
66
+ +--------+ +--------+ +--------+ +--------+
67
+ | 🕵️ A | | 🧹 B | | ⚡ C | | 📚 D |
68
+ | 逻辑 | | 代码 | | 极简 | | 图谱 |
69
+ +--------+ +--------+ +--------+ +--------+
70
+ | | | |
71
+ +--------+--------+--------+
72
+ |
73
+ v
74
+ +--------+--------+
75
+ | ⚖️ 综合裁决 |
76
+ +--------+--------+
77
+ |
78
+ /-------+-------\
79
+ / 发现问题? \
80
+ v v
81
+ +-----------+ +------------+
82
+ | ❌ 驳回 | | 📝 生成报告 |
83
+ | (Reject) | | (Success) |
84
+ +-----------+ +------------+
85
+ |
86
+ v
87
+ (To: Iteration Loop)
@@ -0,0 +1,90 @@
1
+ # 🔄 "Neuro-Link" Synchronization Protocol (神经链路同步协议)
2
+
3
+ 本工作流旨在解决**“代码与图谱脱节”**的问题。
4
+ 无论是**新项目初始化**,还是**既有代码的变更**,必须强制同步至 PPDocs MCP,确保 AI 的记忆永远是最新的。
5
+
6
+ ---
7
+
8
+ ### 1.第一阶段:差异嗅探 (Delta Recognition) 📡
9
+ 🔹 **核心目标**:识别代码现实与图谱记忆之间的偏差。
10
+ ✏️ **动作**:
11
+ * **扫描代码库**:检测新增文件、修改的函数、重构的类。
12
+ * **查询图谱**:读取 PPDocs 当前状态。
13
+ * **计算差异**:生成 `Diff Report` (例如:代码有 Function A,图谱里没有)。
14
+ × **禁区**:
15
+ * 禁止忽略任何细微的逻辑变更。
16
+ * 禁止在未对比图谱的情况下盲目写入。
17
+
18
+ ### 2.第二阶段:语义映射 (Semantic Mapping) 🧠
19
+ 🔹 **核心目标**:将冰冷的代码翻译为可视化的知识节点。
20
+ ✏️ **动作**:
21
+ * **逻辑提取**:AI 阅读代码,提炼核心业务逻辑(非逐行翻译,而是意译)。
22
+ * **节点定义**:将逻辑转换为 PPDocs 的 `Node` (节点) 和 `Document` (文档) 格式。
23
+ * **关系构建**:确定新节点与旧节点之间的连线 (Edge/Relationship)。
24
+ × **禁区**:
25
+ * 禁止生成无意义的节点(如 "Variable X changed")。
26
+ * 必须通过节点连线体现代码的模块化关系。
27
+
28
+ ### 3.第三阶段:图谱注入 (Graph Injection) 💉
29
+ 🔹 **核心目标**:调用 MCP 接口,实施持久化存储。
30
+ ✏️ **动作**:
31
+ * **PPDocs 调用**:使用 MCP 工具执行增删改操作 (CRUD)。
32
+ * `Create_Node`: 新增模块。
33
+ * `Update_Link`: 变更逻辑依赖。
34
+ * `Delete_Node`: 清除废弃代码的幽灵节点。
35
+ * **原子化提交**:确保每次同步都是完整的,不会留下“断头”节点。
36
+ × **禁区**:
37
+ * 禁止手动修改数据,必须通过 MCP 工具。
38
+ * 禁止产生孤立节点 (Orphan Nodes)。
39
+
40
+ ### 4.第四阶段:记忆回溯验证 (Memory Re-check) 🛡️
41
+ 🔹 **核心目标**:确保 AI 真的“记住”了。
42
+ ✏️ **动作**:
43
+ * **反向查询**:向 PPDocs 提问刚才更新的逻辑。
44
+ * **一致性校验**:如果 PPDocs 的回答与代码逻辑一致,标记为 ✅ Synced。
45
+ * **可视化确认**:输出 ASCII 或 Mermaid 结构图供人类确认。
46
+
47
+ ---
48
+
49
+ ### 📊 同步逻辑可视化图解 (ASCII)
50
+
51
+ ```text
52
+ +-------------------------+
53
+ | 💻 代码变更 / 新项目启动 |
54
+ +-----------+-------------+
55
+ |
56
+ v
57
+ +-----------+-------------+
58
+ | 📡 差异嗅探 (Sniffer) | <---- PPDocs Current State
59
+ +-----------+-------------+
60
+ |
61
+ v
62
+ /-------+-------\
63
+ / 存在偏差? \
64
+ v v
65
+ (🚫 NO: 结束) (❗ YES: 需要同步)
66
+ |
67
+ v
68
+ +---------+---------+
69
+ | 🧠 语义映射分析 |
70
+ | (Code -> Knowledge)|
71
+ +---------+---------+
72
+ |
73
+ v
74
+ +---------+---------+
75
+ | 💉 PPDocs 注入 |
76
+ | (Call MCP Tools) |
77
+ +---------+---------+
78
+ |
79
+ v
80
+ +---------+---------+
81
+ | 🛡️ 记忆回溯验证 |
82
+ +---------+---------+
83
+ |
84
+ /-----------+----------\
85
+ / AI能否准确复述? \
86
+ v v
87
+ +-------+-------+ +-------+-------+
88
+ | ✅ 同步完成 | | ❌ 失败重试 |
89
+ | (Persistent) | | (Retry Loop) |
90
+ +---------------+ +---------------+
@@ -0,0 +1,62 @@
1
+ # 🛡️ "Zero-Defect Genesis" Protocol (零缺陷创生协议)
2
+
3
+ 这是一个严格的**“设计-审查-迭代”**自动化流程。只有通过所有安全检查的方案,才会最终呈现给您。
4
+
5
+ ---
6
+
7
+ ### 1.第一阶段:启动设计 (Design) 💡
8
+ * **动作**:接收任务目标。
9
+ * **执行**:生成初步的逻辑架构与执行步骤。
10
+ * **目标**:先有一个可行草稿。
11
+
12
+ ### 2.第二阶段:深度审查 (The Audit) 🧐
13
+ 在此阶段,方案必须经过**三道关卡**的严苛检查:
14
+ 1. 🎯 **预期核对**:方案能否 100% 达成既定目标?
15
+ 2. 🧩 **模块化检查**:结构是否清晰?是否像积木一样解耦,便于维护?
16
+ 3. 🛡️ **无害化验证**:是否引入了新的 Bug 或副作用?
17
+
18
+ ### 3.第三阶段:循环验证 (The Loop) 🔄
19
+ * ❌ **如果验证失败 (Fail)**:
20
+ * 触发**自动修复机制**。
21
+ * 针对审查出的问题进行修改。
22
+ * **回退**至第二阶段重新审查。
23
+ * ✅ **如果验证通过 (Pass)**:
24
+ * 锁定当前版本,进入交付通道。
25
+
26
+ ### 4.第四阶段:最终交付 (Final Output) 🎉
27
+ * **输出**:经得起推敲的、模块化的、无错的最终方案。
28
+ * **动作**:展示给您进行最终确认。
29
+
30
+ ---
31
+
32
+ ### 📊 流程可视化图解 (ASCII)
33
+
34
+ ```text
35
+ +----------------------------+
36
+ | 💡 START: 初步方案设计 |
37
+ +-------------+--------------+
38
+ |
39
+ v
40
+ +-------------+--------------+
41
+ | 🧐 深度审查机制 |
42
+ |----------------------------|
43
+ | 1. 🎯 预期核对 (Target) |
44
+ | 2. 🧩 结构检查 (Modular) |
45
+ | 3. 🛡️ 风险排除 (Safety) |
46
+ +-------------+--------------+
47
+ |
48
+ v
49
+ /-------+-------\
50
+ / 验证结论? \
51
+ /-------------------\
52
+ / \
53
+ (❌ 失败: FAIL) (✅ 通过: PASS)
54
+ | |
55
+ v v
56
+ +-------+-------+ +-------+-------+
57
+ | 🛠️ 迭代修复 | | 🎉 最终交付 |
58
+ | (Auto-Fix) | | (Final Output)|
59
+ +-------+-------+ +---------------+
60
+ |
61
+ | (🔄 Return to Audit)
62
+ +-------------------------^