@ppdocs/mcp 2.7.1 → 2.8.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/dist/storage/httpClient.d.ts +27 -101
- package/dist/storage/httpClient.js +107 -274
- package/dist/storage/types.d.ts +27 -64
- package/dist/storage/types.js +1 -1
- package/dist/tools/helpers.d.ts +9 -30
- package/dist/tools/helpers.js +37 -161
- package/dist/tools/index.js +143 -320
- package/package.json +1 -1
- package/templates/commands/pp/DiagnosticProtocol.md +82 -0
- package/templates/commands/pp/Execution_Task.md +84 -0
- package/templates/commands/pp/Sentinel_4.md +87 -0
- package/templates/commands/pp/SynchronizationProtocol.md +90 -0
- package/templates/commands/pp/Zero_Defec_Genesis.md +62 -0
|
@@ -4,129 +4,55 @@
|
|
|
4
4
|
*
|
|
5
5
|
* API URL 格式: http://localhost:20001/api/:projectId/:password/...
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
import type { DocData, DocNode, DocSearchResult, Task, TaskSummary, TaskLogType, TaskExperience } from './types.js';
|
|
8
|
+
interface TreeNode {
|
|
9
|
+
path: string;
|
|
10
|
+
name: string;
|
|
11
|
+
summary?: string;
|
|
12
|
+
isDir: boolean;
|
|
13
|
+
children?: TreeNode[];
|
|
12
14
|
}
|
|
13
15
|
export declare class PpdocsApiClient {
|
|
14
16
|
private baseUrl;
|
|
15
17
|
constructor(apiUrl: string);
|
|
16
18
|
private request;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
codeStyle?: string[];
|
|
28
|
-
}): Promise<NodeData | null>;
|
|
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>;
|
|
19
|
+
listDocs(): Promise<DocNode[]>;
|
|
20
|
+
getDoc(docPath: string): Promise<DocData | null>;
|
|
21
|
+
createDoc(docPath: string, doc: Partial<DocData>): Promise<DocData>;
|
|
22
|
+
updateDoc(docPath: string, updates: Partial<DocData>): Promise<DocData | null>;
|
|
23
|
+
deleteDoc(docPath: string): Promise<boolean>;
|
|
24
|
+
searchDocs(keywords: string[], limit?: number): Promise<DocSearchResult[]>;
|
|
25
|
+
/** 获取目录树结构 */
|
|
26
|
+
getTree(): Promise<TreeNode[]>;
|
|
27
|
+
getRulesApi(ruleType: string): Promise<string[]>;
|
|
28
|
+
saveRulesApi(ruleType: string, rules: string[]): Promise<boolean>;
|
|
45
29
|
listTasks(status?: 'active' | 'archived'): Promise<TaskSummary[]>;
|
|
46
30
|
getTask(taskId: string): Promise<Task | null>;
|
|
47
31
|
createTask(task: {
|
|
48
32
|
title: string;
|
|
49
33
|
description: string;
|
|
50
34
|
goals: string[];
|
|
51
|
-
related_nodes?: string[];
|
|
52
35
|
}, creator: string): Promise<Task>;
|
|
53
36
|
addTaskLog(taskId: string, logType: TaskLogType, content: string): Promise<Task | null>;
|
|
54
37
|
completeTask(taskId: string, experience: TaskExperience): Promise<Task | null>;
|
|
55
|
-
getRulesApi(ruleType: string): Promise<string[]>;
|
|
56
|
-
saveRulesApi(ruleType: string, rules: string[]): Promise<boolean>;
|
|
57
|
-
vectorSearch(query: string, limit: number, mode: string): Promise<Array<{
|
|
58
|
-
id: string;
|
|
59
|
-
title: string;
|
|
60
|
-
score: number;
|
|
61
|
-
match_type: string;
|
|
62
|
-
keyword_score: number;
|
|
63
|
-
semantic_score: number;
|
|
64
|
-
}>>;
|
|
65
|
-
vectorStats(): Promise<{
|
|
66
|
-
model_downloaded: boolean;
|
|
67
|
-
model_loaded: boolean;
|
|
68
|
-
model_path: string;
|
|
69
|
-
index_count: number;
|
|
70
|
-
}>;
|
|
71
38
|
}
|
|
72
39
|
export declare function initClient(apiUrl: string): void;
|
|
73
|
-
export declare function
|
|
74
|
-
export declare function
|
|
75
|
-
export declare function
|
|
76
|
-
export declare function
|
|
77
|
-
export declare function
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
reviewRules?: string[];
|
|
83
|
-
codeStyle?: string[];
|
|
84
|
-
}): Promise<NodeData | null>;
|
|
85
|
-
export declare function deleteNode(_projectId: string, nodeId: string): Promise<boolean>;
|
|
86
|
-
export declare function lockNode(_projectId: string, nodeId: string, locked: boolean): Promise<NodeData | null>;
|
|
87
|
-
export declare function searchNodes(_projectId: string, keywords: string[], limit?: number): Promise<SearchResult[]>;
|
|
88
|
-
export declare function findPath(_projectId: string, startId: string, endId: string): Promise<PathResult | null>;
|
|
89
|
-
export declare function getRelations(_projectId: string, nodeId: string): Promise<Array<{
|
|
90
|
-
nodeId: string;
|
|
91
|
-
title: string;
|
|
92
|
-
description: string;
|
|
93
|
-
edgeType: string;
|
|
94
|
-
direction: 'outgoing' | 'incoming';
|
|
95
|
-
}>>;
|
|
96
|
-
export declare function addBugfix(_projectId: string, nodeId: string, bugfix: {
|
|
97
|
-
issue: string;
|
|
98
|
-
solution: string;
|
|
99
|
-
impact?: string;
|
|
100
|
-
}): Promise<BugfixRecord | null>;
|
|
40
|
+
export declare function listDocs(_projectId: string): Promise<DocNode[]>;
|
|
41
|
+
export declare function getDoc(_projectId: string, docPath: string): Promise<DocData | null>;
|
|
42
|
+
export declare function createDoc(_projectId: string, docPath: string, doc: Partial<DocData>): Promise<DocData>;
|
|
43
|
+
export declare function updateDoc(_projectId: string, docPath: string, updates: Partial<DocData>): Promise<DocData | null>;
|
|
44
|
+
export declare function deleteDoc(_projectId: string, docPath: string): Promise<boolean>;
|
|
45
|
+
export declare function searchDocs(_projectId: string, keywords: string[], limit?: number): Promise<DocSearchResult[]>;
|
|
46
|
+
export declare function getTree(_projectId: string): Promise<TreeNode[]>;
|
|
47
|
+
export declare function getRules(_projectId: string, ruleType: string): Promise<string[]>;
|
|
48
|
+
export declare function saveRules(_projectId: string, ruleType: string, rules: string[]): Promise<boolean>;
|
|
101
49
|
export declare function listTasks(_projectId: string, status?: 'active' | 'archived'): Promise<TaskSummary[]>;
|
|
102
50
|
export declare function getTask(_projectId: string, taskId: string): Promise<Task | null>;
|
|
103
51
|
export declare function createTask(_projectId: string, task: {
|
|
104
52
|
title: string;
|
|
105
53
|
description: string;
|
|
106
54
|
goals: string[];
|
|
107
|
-
related_nodes?: string[];
|
|
108
55
|
}, creator: string): Promise<Task>;
|
|
109
56
|
export declare function addTaskLog(_projectId: string, taskId: string, logType: TaskLogType, content: string): Promise<Task | null>;
|
|
110
57
|
export declare function completeTask(_projectId: string, taskId: string, experience: TaskExperience): Promise<Task | null>;
|
|
111
|
-
export
|
|
112
|
-
export declare function saveRules(_projectId: string, ruleType: string, rules: string[]): Promise<boolean>;
|
|
113
|
-
/** 向量搜索结果 */
|
|
114
|
-
export interface VectorSearchResult {
|
|
115
|
-
id: string;
|
|
116
|
-
title: string;
|
|
117
|
-
score: number;
|
|
118
|
-
match_type: string;
|
|
119
|
-
keyword_score: number;
|
|
120
|
-
semantic_score: number;
|
|
121
|
-
}
|
|
122
|
-
/** 向量索引状态 */
|
|
123
|
-
export interface VectorStats {
|
|
124
|
-
model_downloaded: boolean;
|
|
125
|
-
model_loaded: boolean;
|
|
126
|
-
model_path: string;
|
|
127
|
-
index_count: number;
|
|
128
|
-
}
|
|
129
|
-
/** 混合搜索 (关键词 + 语义) */
|
|
130
|
-
export declare function vectorSearch(_projectId: string, query: string, limit: number, mode: 'hybrid' | 'keyword' | 'semantic'): Promise<VectorSearchResult[]>;
|
|
131
|
-
/** 获取向量索引状态 */
|
|
132
|
-
export declare function vectorStats(_projectId: string): Promise<VectorStats>;
|
|
58
|
+
export type { TreeNode };
|
|
@@ -4,58 +4,38 @@
|
|
|
4
4
|
*
|
|
5
5
|
* API URL 格式: http://localhost:20001/api/:projectId/:password/...
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const collides = (x, y) => nodes.some(n => Math.abs(n.x - x) < SMART_NODE_GAP && Math.abs(n.y - y) < SMART_NODE_GAP * 0.6);
|
|
37
|
-
if (!collides(cx, cy))
|
|
38
|
-
return { x: Math.round(cx), y: Math.round(cy) };
|
|
39
|
-
// 4. 螺旋搜索
|
|
40
|
-
const dirs = [[1, 0], [0, 1], [-1, 0], [0, -1]];
|
|
41
|
-
let x = cx, y = cy, step = 1, dir = 0, steps = 0, turns = 0;
|
|
42
|
-
for (let i = 0; i < SMART_SEARCH_RADIUS * SMART_SEARCH_RADIUS * 4; i++) {
|
|
43
|
-
x += dirs[dir][0] * SMART_NODE_GAP;
|
|
44
|
-
y += dirs[dir][1] * SMART_NODE_GAP * 0.6;
|
|
45
|
-
steps++;
|
|
46
|
-
if (!collides(x, y))
|
|
47
|
-
return { x: Math.round(x), y: Math.round(y) };
|
|
48
|
-
if (steps >= step) {
|
|
49
|
-
steps = 0;
|
|
50
|
-
dir = (dir + 1) % 4;
|
|
51
|
-
if (++turns >= 2) {
|
|
52
|
-
turns = 0;
|
|
53
|
-
step++;
|
|
54
|
-
}
|
|
7
|
+
/** 从扁平文档列表构建目录树 */
|
|
8
|
+
function buildTree(docs) {
|
|
9
|
+
const root = [];
|
|
10
|
+
const pathMap = new Map();
|
|
11
|
+
// 按路径深度排序,确保父目录先处理
|
|
12
|
+
const sorted = [...docs].sort((a, b) => {
|
|
13
|
+
const depthA = (a.path.match(/\//g) || []).length;
|
|
14
|
+
const depthB = (b.path.match(/\//g) || []).length;
|
|
15
|
+
return depthA - depthB;
|
|
16
|
+
});
|
|
17
|
+
for (const doc of sorted) {
|
|
18
|
+
const node = {
|
|
19
|
+
path: doc.path,
|
|
20
|
+
name: doc.name,
|
|
21
|
+
summary: doc.summary,
|
|
22
|
+
isDir: doc.isDir,
|
|
23
|
+
children: doc.isDir ? [] : undefined
|
|
24
|
+
};
|
|
25
|
+
// 找父路径
|
|
26
|
+
const lastSlash = doc.path.lastIndexOf('/');
|
|
27
|
+
const parentPath = lastSlash > 0 ? doc.path.substring(0, lastSlash) : '';
|
|
28
|
+
if (parentPath && pathMap.has(parentPath)) {
|
|
29
|
+
pathMap.get(parentPath).children.push(node);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
root.push(node);
|
|
33
|
+
}
|
|
34
|
+
if (doc.isDir) {
|
|
35
|
+
pathMap.set(doc.path, node);
|
|
55
36
|
}
|
|
56
37
|
}
|
|
57
|
-
|
|
58
|
-
return { x: Math.round(maxX + SMART_NODE_GAP), y: Math.round(cy) };
|
|
38
|
+
return root;
|
|
59
39
|
}
|
|
60
40
|
// API 客户端类
|
|
61
41
|
export class PpdocsApiClient {
|
|
@@ -98,91 +78,51 @@ export class PpdocsApiClient {
|
|
|
98
78
|
clearTimeout(timeout);
|
|
99
79
|
}
|
|
100
80
|
}
|
|
101
|
-
// ============
|
|
102
|
-
async
|
|
103
|
-
|
|
104
|
-
if (!filter)
|
|
105
|
-
return nodes;
|
|
106
|
-
// 计算每个节点的连接数 (入边+出边)
|
|
107
|
-
const edgeCounts = new Map();
|
|
108
|
-
nodes.forEach(n => edgeCounts.set(n.id, 0));
|
|
109
|
-
nodes.forEach(n => {
|
|
110
|
-
(n.dependencies || []).forEach(dep => {
|
|
111
|
-
// 出边: 当前节点依赖别人
|
|
112
|
-
edgeCounts.set(n.id, (edgeCounts.get(n.id) || 0) + 1);
|
|
113
|
-
// 入边: 被依赖的节点 (按 signature 匹配)
|
|
114
|
-
const target = nodes.find(t => t.signature?.toLowerCase() === dep.name.toLowerCase());
|
|
115
|
-
if (target)
|
|
116
|
-
edgeCounts.set(target.id, (edgeCounts.get(target.id) || 0) + 1);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
// 过滤
|
|
120
|
-
return nodes.filter(n => {
|
|
121
|
-
if (filter.status && n.status !== filter.status)
|
|
122
|
-
return false;
|
|
123
|
-
const edges = edgeCounts.get(n.id) || 0;
|
|
124
|
-
if (filter.minEdges !== undefined && edges < filter.minEdges)
|
|
125
|
-
return false;
|
|
126
|
-
if (filter.maxEdges !== undefined && edges > filter.maxEdges)
|
|
127
|
-
return false;
|
|
128
|
-
return true;
|
|
129
|
-
});
|
|
81
|
+
// ============ 文档操作 ============
|
|
82
|
+
async listDocs() {
|
|
83
|
+
return this.request('/docs');
|
|
130
84
|
}
|
|
131
|
-
async
|
|
85
|
+
async getDoc(docPath) {
|
|
132
86
|
try {
|
|
133
|
-
|
|
87
|
+
// 移除开头的斜杠,API 路径会自动处理
|
|
88
|
+
const cleanPath = docPath.replace(/^\//, '');
|
|
89
|
+
return await this.request(`/docs/${cleanPath}`);
|
|
134
90
|
}
|
|
135
91
|
catch {
|
|
136
92
|
return null;
|
|
137
93
|
}
|
|
138
94
|
}
|
|
139
|
-
async
|
|
140
|
-
|
|
141
|
-
let x = node.x ?? 0;
|
|
142
|
-
let y = node.y ?? 0;
|
|
143
|
-
// 如果未指定位置,自动计算
|
|
144
|
-
if (node.x === undefined && node.y === undefined) {
|
|
145
|
-
const existingNodes = await this.listNodes();
|
|
146
|
-
const pos = computeSmartPosition(node.dependencies, existingNodes);
|
|
147
|
-
x = pos.x;
|
|
148
|
-
y = pos.y;
|
|
149
|
-
}
|
|
95
|
+
async createDoc(docPath, doc) {
|
|
96
|
+
const cleanPath = docPath.replace(/^\//, '');
|
|
150
97
|
const payload = {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
categories: node.categories || [],
|
|
160
|
-
description: node.description || '',
|
|
161
|
-
dependencies: node.dependencies || [],
|
|
162
|
-
relatedFiles: node.relatedFiles || [],
|
|
163
|
-
createdAt: new Date().toISOString(),
|
|
164
|
-
updatedAt: new Date().toISOString(),
|
|
165
|
-
lastAccessedAt: new Date().toISOString(),
|
|
166
|
-
versions: [],
|
|
167
|
-
bugfixes: []
|
|
98
|
+
summary: doc.summary || '',
|
|
99
|
+
content: doc.content || '',
|
|
100
|
+
versions: doc.versions || [{
|
|
101
|
+
version: 0.1,
|
|
102
|
+
date: new Date().toISOString(),
|
|
103
|
+
changes: '初始创建'
|
|
104
|
+
}],
|
|
105
|
+
bugfixes: doc.bugfixes || []
|
|
168
106
|
};
|
|
169
|
-
return this.request(
|
|
107
|
+
return this.request(`/docs/${cleanPath}`, {
|
|
170
108
|
method: 'POST',
|
|
171
109
|
body: JSON.stringify(payload)
|
|
172
110
|
});
|
|
173
111
|
}
|
|
174
|
-
async
|
|
175
|
-
// 先获取现有节点,合并更新
|
|
176
|
-
const existing = await this.getNode(nodeId);
|
|
177
|
-
if (!existing)
|
|
178
|
-
return null;
|
|
179
|
-
const payload = {
|
|
180
|
-
...existing,
|
|
181
|
-
...updates,
|
|
182
|
-
updatedAt: new Date().toISOString()
|
|
183
|
-
};
|
|
112
|
+
async updateDoc(docPath, updates) {
|
|
184
113
|
try {
|
|
185
|
-
|
|
114
|
+
const cleanPath = docPath.replace(/^\//, '');
|
|
115
|
+
// 先获取现有文档
|
|
116
|
+
const existing = await this.getDoc(docPath);
|
|
117
|
+
if (!existing)
|
|
118
|
+
return null;
|
|
119
|
+
const payload = {
|
|
120
|
+
summary: updates.summary ?? existing.summary,
|
|
121
|
+
content: updates.content ?? existing.content,
|
|
122
|
+
versions: updates.versions ?? existing.versions,
|
|
123
|
+
bugfixes: updates.bugfixes ?? existing.bugfixes
|
|
124
|
+
};
|
|
125
|
+
return await this.request(`/docs/${cleanPath}`, {
|
|
186
126
|
method: 'PUT',
|
|
187
127
|
body: JSON.stringify(payload)
|
|
188
128
|
});
|
|
@@ -191,104 +131,48 @@ export class PpdocsApiClient {
|
|
|
191
131
|
return null;
|
|
192
132
|
}
|
|
193
133
|
}
|
|
194
|
-
async
|
|
195
|
-
// 专用根节点更新,支持所有规则字段
|
|
196
|
-
const root = await this.getNode('root');
|
|
197
|
-
if (!root)
|
|
198
|
-
return null;
|
|
199
|
-
if (root.locked)
|
|
200
|
-
return null; // 锁定时拒绝
|
|
201
|
-
// 构建更新载荷 (只传入有值的字段)
|
|
202
|
-
const payload = { updatedAt: new Date().toISOString() };
|
|
203
|
-
if (updates.title !== undefined)
|
|
204
|
-
payload.title = updates.title;
|
|
205
|
-
if (updates.description !== undefined)
|
|
206
|
-
payload.description = updates.description;
|
|
207
|
-
if (updates.userStyles !== undefined)
|
|
208
|
-
payload.userStyles = updates.userStyles;
|
|
209
|
-
if (updates.testRules !== undefined)
|
|
210
|
-
payload.testRules = updates.testRules;
|
|
211
|
-
if (updates.reviewRules !== undefined)
|
|
212
|
-
payload.reviewRules = updates.reviewRules;
|
|
213
|
-
if (updates.codeStyle !== undefined)
|
|
214
|
-
payload.codeStyle = updates.codeStyle;
|
|
134
|
+
async deleteDoc(docPath) {
|
|
215
135
|
try {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
body: JSON.stringify({ ...root, ...payload })
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
catch {
|
|
222
|
-
return null;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
async deleteNode(nodeId) {
|
|
226
|
-
try {
|
|
227
|
-
await this.request(`/nodes/${nodeId}`, { method: 'DELETE' });
|
|
136
|
+
const cleanPath = docPath.replace(/^\//, '');
|
|
137
|
+
await this.request(`/docs/${cleanPath}`, { method: 'DELETE' });
|
|
228
138
|
return true;
|
|
229
139
|
}
|
|
230
140
|
catch {
|
|
231
141
|
return false;
|
|
232
142
|
}
|
|
233
143
|
}
|
|
234
|
-
async
|
|
144
|
+
async searchDocs(keywords, limit = 20) {
|
|
145
|
+
return this.request('/docs/search', {
|
|
146
|
+
method: 'POST',
|
|
147
|
+
body: JSON.stringify({ keywords, limit })
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/** 获取目录树结构 */
|
|
151
|
+
async getTree() {
|
|
152
|
+
const docs = await this.listDocs();
|
|
153
|
+
return buildTree(docs);
|
|
154
|
+
}
|
|
155
|
+
// ============ 规则 API ============
|
|
156
|
+
async getRulesApi(ruleType) {
|
|
235
157
|
try {
|
|
236
|
-
return await this.request(`/
|
|
237
|
-
method: 'PUT',
|
|
238
|
-
body: JSON.stringify({ locked })
|
|
239
|
-
});
|
|
158
|
+
return await this.request(`/rules/${ruleType}`);
|
|
240
159
|
}
|
|
241
160
|
catch {
|
|
242
|
-
return
|
|
161
|
+
return [];
|
|
243
162
|
}
|
|
244
163
|
}
|
|
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) {
|
|
164
|
+
async saveRulesApi(ruleType, rules) {
|
|
253
165
|
try {
|
|
254
|
-
|
|
255
|
-
method: '
|
|
256
|
-
body: JSON.stringify(
|
|
166
|
+
await this.request(`/rules/${ruleType}`, {
|
|
167
|
+
method: 'PUT',
|
|
168
|
+
body: JSON.stringify(rules)
|
|
257
169
|
});
|
|
170
|
+
return true;
|
|
258
171
|
}
|
|
259
172
|
catch {
|
|
260
|
-
return
|
|
173
|
+
return false;
|
|
261
174
|
}
|
|
262
175
|
}
|
|
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
176
|
// ============ 任务管理 ============
|
|
293
177
|
async listTasks(status) {
|
|
294
178
|
const query = status ? `?status=${status}` : '';
|
|
@@ -309,7 +193,7 @@ export class PpdocsApiClient {
|
|
|
309
193
|
detail: {
|
|
310
194
|
description: task.description,
|
|
311
195
|
goals: task.goals,
|
|
312
|
-
related_nodes:
|
|
196
|
+
related_nodes: []
|
|
313
197
|
}
|
|
314
198
|
};
|
|
315
199
|
return this.request('/tasks', {
|
|
@@ -339,39 +223,8 @@ export class PpdocsApiClient {
|
|
|
339
223
|
return null;
|
|
340
224
|
}
|
|
341
225
|
}
|
|
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
|
-
// ============ 向量搜索 API ============
|
|
364
|
-
async vectorSearch(query, limit, mode) {
|
|
365
|
-
return this.request('/vector/search', {
|
|
366
|
-
method: 'POST',
|
|
367
|
-
body: JSON.stringify({ query, limit, mode })
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
async vectorStats() {
|
|
371
|
-
return this.request('/vector/stats');
|
|
372
|
-
}
|
|
373
226
|
}
|
|
374
|
-
// ============ 模块级 API
|
|
227
|
+
// ============ 模块级 API ============
|
|
375
228
|
let client = null;
|
|
376
229
|
export function initClient(apiUrl) {
|
|
377
230
|
client = new PpdocsApiClient(apiUrl);
|
|
@@ -382,39 +235,34 @@ function getClient() {
|
|
|
382
235
|
}
|
|
383
236
|
return client;
|
|
384
237
|
}
|
|
385
|
-
//
|
|
386
|
-
export async function
|
|
387
|
-
return getClient().
|
|
238
|
+
// ============ 文档管理 ============
|
|
239
|
+
export async function listDocs(_projectId) {
|
|
240
|
+
return getClient().listDocs();
|
|
388
241
|
}
|
|
389
|
-
export async function
|
|
390
|
-
return getClient().
|
|
242
|
+
export async function getDoc(_projectId, docPath) {
|
|
243
|
+
return getClient().getDoc(docPath);
|
|
391
244
|
}
|
|
392
|
-
export async function
|
|
393
|
-
return getClient().
|
|
245
|
+
export async function createDoc(_projectId, docPath, doc) {
|
|
246
|
+
return getClient().createDoc(docPath, doc);
|
|
394
247
|
}
|
|
395
|
-
export async function
|
|
396
|
-
return getClient().
|
|
248
|
+
export async function updateDoc(_projectId, docPath, updates) {
|
|
249
|
+
return getClient().updateDoc(docPath, updates);
|
|
397
250
|
}
|
|
398
|
-
export async function
|
|
399
|
-
return getClient().
|
|
251
|
+
export async function deleteDoc(_projectId, docPath) {
|
|
252
|
+
return getClient().deleteDoc(docPath);
|
|
400
253
|
}
|
|
401
|
-
export async function
|
|
402
|
-
return getClient().
|
|
254
|
+
export async function searchDocs(_projectId, keywords, limit) {
|
|
255
|
+
return getClient().searchDocs(keywords, limit);
|
|
403
256
|
}
|
|
404
|
-
export async function
|
|
405
|
-
return getClient().
|
|
257
|
+
export async function getTree(_projectId) {
|
|
258
|
+
return getClient().getTree();
|
|
406
259
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
export async function findPath(_projectId, startId, endId) {
|
|
411
|
-
return getClient().findPath(startId, endId);
|
|
412
|
-
}
|
|
413
|
-
export async function getRelations(_projectId, nodeId) {
|
|
414
|
-
return getClient().getRelations(nodeId);
|
|
260
|
+
// ============ 规则管理 ============
|
|
261
|
+
export async function getRules(_projectId, ruleType) {
|
|
262
|
+
return getClient().getRulesApi(ruleType);
|
|
415
263
|
}
|
|
416
|
-
export async function
|
|
417
|
-
return getClient().
|
|
264
|
+
export async function saveRules(_projectId, ruleType, rules) {
|
|
265
|
+
return getClient().saveRulesApi(ruleType, rules);
|
|
418
266
|
}
|
|
419
267
|
// ============ 任务管理 ============
|
|
420
268
|
export async function listTasks(_projectId, status) {
|
|
@@ -432,18 +280,3 @@ export async function addTaskLog(_projectId, taskId, logType, content) {
|
|
|
432
280
|
export async function completeTask(_projectId, taskId, experience) {
|
|
433
281
|
return getClient().completeTask(taskId, experience);
|
|
434
282
|
}
|
|
435
|
-
// ============ 规则管理 (独立文件存储) ============
|
|
436
|
-
export async function getRules(_projectId, ruleType) {
|
|
437
|
-
return getClient().getRulesApi(ruleType);
|
|
438
|
-
}
|
|
439
|
-
export async function saveRules(_projectId, ruleType, rules) {
|
|
440
|
-
return getClient().saveRulesApi(ruleType, rules);
|
|
441
|
-
}
|
|
442
|
-
/** 混合搜索 (关键词 + 语义) */
|
|
443
|
-
export async function vectorSearch(_projectId, query, limit, mode) {
|
|
444
|
-
return getClient().vectorSearch(query, limit, mode);
|
|
445
|
-
}
|
|
446
|
-
/** 获取向量索引状态 */
|
|
447
|
-
export async function vectorStats(_projectId) {
|
|
448
|
-
return getClient().vectorStats();
|
|
449
|
-
}
|