@ppdocs/mcp 3.2.37 → 3.3.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 +1 -1
- package/dist/cli.js +2 -1
- package/dist/index.js +1 -15
- package/dist/storage/httpClient.d.ts +24 -22
- package/dist/storage/httpClient.js +50 -188
- package/dist/storage/types.d.ts +42 -0
- package/dist/tools/analyzer.d.ts +1 -1
- package/dist/tools/analyzer.js +8 -7
- package/dist/tools/discussion.js +3 -7
- package/dist/tools/files.d.ts +2 -3
- package/dist/tools/files.js +4 -21
- package/dist/tools/flowchart.js +4 -1
- package/dist/tools/index.d.ts +3 -3
- package/dist/tools/index.js +7 -5
- package/dist/tools/refs.d.ts +2 -0
- package/dist/tools/refs.js +123 -0
- package/dist/tools/tasks.js +2 -2
- package/dist/tools/workflow.d.ts +3 -0
- package/dist/tools/workflow.js +80 -0
- package/dist/utils.d.ts +0 -6
- package/dist/utils.js +0 -44
- package/package.json +1 -5
- package/templates/AGENT.md +3 -2
- package/templates/README.md +2 -2
- package/templates/commands/pp/diagnose.md +3 -3
- package/templates/commands/pp/review.md +9 -10
- package/templates/cursorrules.md +3 -2
- package/templates/hooks/SystemPrompt.md +6 -6
- package/templates/hooks/hook.py +52 -35
- package/templates/kiro-rules/ppdocs.md +3 -2
- package/dist/sync/beacon.d.ts +0 -26
- package/dist/sync/beacon.js +0 -186
- package/dist/tools/rules.d.ts +0 -7
- package/dist/tools/rules.js +0 -120
package/README.md
CHANGED
|
@@ -114,7 +114,7 @@ npx @ppdocs/mcp init -p <projectId> -k <key> --codex
|
|
|
114
114
|
| `kg_init` | 初始化项目连接与上下文 |
|
|
115
115
|
| `kg_status` | 查看项目仪表盘与流程图概况 |
|
|
116
116
|
| `kg_flowchart` | 统一的知识图谱入口,负责查询、更新、关系分析 |
|
|
117
|
-
| `
|
|
117
|
+
| `kg_workflow` | Markdown 文档工作流管理 |
|
|
118
118
|
| `kg_task` | 任务管理 |
|
|
119
119
|
| `kg_files` | 项目文件读写/上传下载 |
|
|
120
120
|
| `kg_discuss` | 讨论区 |
|
package/dist/cli.js
CHANGED
|
@@ -392,11 +392,12 @@ function generateMcpPermissions() {
|
|
|
392
392
|
'kg_status',
|
|
393
393
|
// 知识管理
|
|
394
394
|
'kg_projects',
|
|
395
|
-
'
|
|
395
|
+
'kg_workflow',
|
|
396
396
|
// 工作流
|
|
397
397
|
'kg_task',
|
|
398
398
|
'kg_files',
|
|
399
399
|
'kg_discuss',
|
|
400
|
+
'kg_ref',
|
|
400
401
|
// 流程图
|
|
401
402
|
'kg_flowchart',
|
|
402
403
|
// 协作
|
package/dist/index.js
CHANGED
|
@@ -45,21 +45,7 @@ async function main() {
|
|
|
45
45
|
});
|
|
46
46
|
const transport = new StdioServerTransport();
|
|
47
47
|
await server.connect(transport);
|
|
48
|
-
|
|
49
|
-
let beacon = null;
|
|
50
|
-
// 启动后台代码同步引擎 (Code Beacon) — 仅在有配置时启动
|
|
51
|
-
if (config) {
|
|
52
|
-
try {
|
|
53
|
-
const { SyncBeacon } = await import('./sync/beacon.js');
|
|
54
|
-
beacon = new SyncBeacon(process.cwd(), config.projectId);
|
|
55
|
-
beacon.start();
|
|
56
|
-
}
|
|
57
|
-
catch (err) {
|
|
58
|
-
console.error(`[Code Beacon] Failed to start:`, err);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
// 优雅关闭:进程退出时停止 watcher,防止上传截断
|
|
62
|
-
const shutdown = () => { beacon?.stop(); process.exit(0); };
|
|
48
|
+
const shutdown = () => { process.exit(0); };
|
|
63
49
|
process.on('SIGINT', shutdown);
|
|
64
50
|
process.on('SIGTERM', shutdown);
|
|
65
51
|
}
|
|
@@ -4,19 +4,31 @@
|
|
|
4
4
|
*
|
|
5
5
|
* API URL 格式: http://localhost:20099/api/:projectId/:password/...
|
|
6
6
|
*/
|
|
7
|
-
import type { Task, TaskSummary, TaskLogType, TaskExperience, FileInfo,
|
|
7
|
+
import type { Task, TaskSummary, TaskLogType, TaskExperience, FileInfo, WorkflowSummary, WorkflowDoc, WorkflowSelector, Reference } from './types.js';
|
|
8
8
|
export declare class PpdocsApiClient {
|
|
9
9
|
private baseUrl;
|
|
10
10
|
private serverUrl;
|
|
11
11
|
constructor(apiUrl: string);
|
|
12
12
|
private request;
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
listWorkflows(scope?: 'all' | 'global' | 'project'): Promise<WorkflowSummary[]>;
|
|
14
|
+
getWorkflow(workflowId: string, scope?: 'all' | 'global' | 'project'): Promise<WorkflowDoc | null>;
|
|
15
|
+
getWorkflowBatch(selectors: WorkflowSelector[]): Promise<WorkflowDoc[]>;
|
|
16
|
+
saveWorkflow(workflowId: string, input: {
|
|
17
|
+
scope: 'global' | 'project';
|
|
18
|
+
title: string;
|
|
19
|
+
description: string;
|
|
20
|
+
system: string;
|
|
21
|
+
keywords: string[];
|
|
22
|
+
minHits: number;
|
|
23
|
+
always: boolean;
|
|
24
|
+
content: string;
|
|
25
|
+
}): Promise<WorkflowDoc>;
|
|
26
|
+
deleteWorkflow(workflowId: string, scope: 'global' | 'project'): Promise<boolean>;
|
|
27
|
+
listReferences(): Promise<Reference[]>;
|
|
28
|
+
getReference(refId: string): Promise<Reference | null>;
|
|
29
|
+
saveReference(reference: Reference): Promise<boolean>;
|
|
30
|
+
deleteReference(refId: string): Promise<boolean>;
|
|
31
|
+
readReferenceFile(path: string): Promise<string>;
|
|
20
32
|
listTasks(status?: 'active' | 'archived'): Promise<TaskSummary[]>;
|
|
21
33
|
getTask(taskId: string, mode?: 'smart' | 'full'): Promise<Task | null>;
|
|
22
34
|
createTask(task: {
|
|
@@ -46,8 +58,6 @@ export declare class PpdocsApiClient {
|
|
|
46
58
|
description: string;
|
|
47
59
|
updatedAt: string;
|
|
48
60
|
}[]>;
|
|
49
|
-
/** 跨项目: 获取规则 */
|
|
50
|
-
crossGetRules(target: string, ruleType: string): Promise<string[]>;
|
|
51
61
|
/** 列出项目文件 */
|
|
52
62
|
listFiles(dir?: string): Promise<FileInfo[]>;
|
|
53
63
|
/** 读取项目文件 */
|
|
@@ -57,14 +67,6 @@ export declare class PpdocsApiClient {
|
|
|
57
67
|
localPath: string;
|
|
58
68
|
fileCount: number;
|
|
59
69
|
}>;
|
|
60
|
-
/** 上传本地目录或单文件到中心服务器 (打包 zip → POST) */
|
|
61
|
-
uploadFiles(localPath: string, remoteDir?: string): Promise<{
|
|
62
|
-
fileCount: number;
|
|
63
|
-
}>;
|
|
64
|
-
/** 上传已打包好的 zip 数据到本项目 files/ (供 Code Beacon 使用) */
|
|
65
|
-
uploadRawZip(zipData: Buffer | Uint8Array | any, remoteDir?: string): Promise<{
|
|
66
|
-
fileCount: number;
|
|
67
|
-
}>;
|
|
68
70
|
/** 跨项目: 列出文件 */
|
|
69
71
|
crossListFiles(target: string, dir?: string): Promise<FileInfo[]>;
|
|
70
72
|
/** 跨项目: 读取文件 */
|
|
@@ -95,6 +97,10 @@ export declare class PpdocsApiClient {
|
|
|
95
97
|
discussionReply(id: string, sender: string, content: string, msgSummary?: string, newSummary?: string): Promise<boolean>;
|
|
96
98
|
/** 完成讨论 (公开路由, 标记为 completed) */
|
|
97
99
|
discussionComplete(id: string): Promise<boolean>;
|
|
100
|
+
/** 归档关闭讨论 (需项目认证) */
|
|
101
|
+
discussionClose(id: string, conclusion: string): Promise<{
|
|
102
|
+
archived_path?: string;
|
|
103
|
+
}>;
|
|
98
104
|
/** 删除讨论 (公开路由) */
|
|
99
105
|
discussionDelete(id: string): Promise<boolean>;
|
|
100
106
|
/** 列出公共文件 */
|
|
@@ -112,10 +118,6 @@ export declare class PpdocsApiClient {
|
|
|
112
118
|
localPath: string;
|
|
113
119
|
fileCount: number;
|
|
114
120
|
}>;
|
|
115
|
-
/** 上传本地目录或单文件到公共文件池 */
|
|
116
|
-
publicFilesUpload(localPath: string, remoteDir?: string): Promise<{
|
|
117
|
-
fileCount: number;
|
|
118
|
-
}>;
|
|
119
121
|
meetingJoin(agentId: string, agentType: string): Promise<unknown>;
|
|
120
122
|
meetingLeave(agentId: string): Promise<unknown>;
|
|
121
123
|
meetingPost(agentId: string, content: string, msgType?: string): Promise<unknown>;
|
|
@@ -9,11 +9,6 @@
|
|
|
9
9
|
function cleanPath(p) {
|
|
10
10
|
return p.replace(/^\//, '');
|
|
11
11
|
}
|
|
12
|
-
/** 排除的目录 (与 Rust 端 EXCLUDED_DIRS 保持一致) */
|
|
13
|
-
const EXCLUDED_DIRS = new Set([
|
|
14
|
-
'node_modules', '.git', 'target', 'dist', 'build', '.next',
|
|
15
|
-
'__pycache__', '.venv', 'venv', '.idea', '.vs', '.vscode',
|
|
16
|
-
]);
|
|
17
12
|
/** 下载 zip 并解压到指定目录或 temp 目录 */
|
|
18
13
|
async function fetchAndExtractZip(url, localPath) {
|
|
19
14
|
const controller = new AbortController();
|
|
@@ -99,75 +94,64 @@ export class PpdocsApiClient {
|
|
|
99
94
|
clearTimeout(timeout);
|
|
100
95
|
}
|
|
101
96
|
}
|
|
102
|
-
// ============
|
|
103
|
-
async
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
return [];
|
|
109
|
-
}
|
|
97
|
+
// ============ 工作流 API ============
|
|
98
|
+
async listWorkflows(scope) {
|
|
99
|
+
const query = scope ? `?scope=${scope}` : '';
|
|
100
|
+
return this.request(`/workflows${query}`);
|
|
110
101
|
}
|
|
111
|
-
async
|
|
102
|
+
async getWorkflow(workflowId, scope) {
|
|
112
103
|
try {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
body: JSON.stringify(rules)
|
|
116
|
-
});
|
|
117
|
-
return true;
|
|
104
|
+
const query = scope ? `?scope=${scope}` : '';
|
|
105
|
+
return await this.request(`/workflows/${encodeURIComponent(workflowId)}${query}`);
|
|
118
106
|
}
|
|
119
107
|
catch {
|
|
120
|
-
return
|
|
108
|
+
return null;
|
|
121
109
|
}
|
|
122
110
|
}
|
|
123
|
-
async
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return {};
|
|
129
|
-
}
|
|
111
|
+
async getWorkflowBatch(selectors) {
|
|
112
|
+
return this.request('/workflows/batch', {
|
|
113
|
+
method: 'POST',
|
|
114
|
+
body: JSON.stringify(selectors),
|
|
115
|
+
});
|
|
130
116
|
}
|
|
131
|
-
async
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
});
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
117
|
+
async saveWorkflow(workflowId, input) {
|
|
118
|
+
return this.request(`/workflows/${encodeURIComponent(workflowId)}`, {
|
|
119
|
+
method: 'PUT',
|
|
120
|
+
body: JSON.stringify(input),
|
|
121
|
+
});
|
|
142
122
|
}
|
|
143
|
-
async
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
catch {
|
|
148
|
-
return {};
|
|
149
|
-
}
|
|
123
|
+
async deleteWorkflow(workflowId, scope) {
|
|
124
|
+
return this.request(`/workflows/${encodeURIComponent(workflowId)}?scope=${scope}`, {
|
|
125
|
+
method: 'DELETE',
|
|
126
|
+
});
|
|
150
127
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
catch {
|
|
156
|
-
return {};
|
|
157
|
-
}
|
|
128
|
+
// ============ 外部参考 API ============
|
|
129
|
+
async listReferences() {
|
|
130
|
+
return this.request('/refs');
|
|
158
131
|
}
|
|
159
|
-
async
|
|
132
|
+
async getReference(refId) {
|
|
160
133
|
try {
|
|
161
|
-
await this.request(
|
|
162
|
-
method: 'PUT',
|
|
163
|
-
body: JSON.stringify(meta)
|
|
164
|
-
});
|
|
165
|
-
return true;
|
|
134
|
+
return await this.request(`/refs/${encodeURIComponent(refId)}`);
|
|
166
135
|
}
|
|
167
136
|
catch {
|
|
168
|
-
return
|
|
137
|
+
return null;
|
|
169
138
|
}
|
|
170
139
|
}
|
|
140
|
+
async saveReference(reference) {
|
|
141
|
+
await this.request(`/refs/${encodeURIComponent(reference.id)}`, {
|
|
142
|
+
method: 'PUT',
|
|
143
|
+
body: JSON.stringify(reference),
|
|
144
|
+
});
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
async deleteReference(refId) {
|
|
148
|
+
return this.request(`/refs/${encodeURIComponent(refId)}`, {
|
|
149
|
+
method: 'DELETE',
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
async readReferenceFile(path) {
|
|
153
|
+
return this.request(`/refs/files/${cleanPath(path)}`);
|
|
154
|
+
}
|
|
171
155
|
// ============ 任务管理 ============
|
|
172
156
|
async listTasks(status) {
|
|
173
157
|
const query = status ? `?status=${status}` : '';
|
|
@@ -285,15 +269,6 @@ export class PpdocsApiClient {
|
|
|
285
269
|
async crossListProjects() {
|
|
286
270
|
return this.request('/cross/projects');
|
|
287
271
|
}
|
|
288
|
-
/** 跨项目: 获取规则 */
|
|
289
|
-
async crossGetRules(target, ruleType) {
|
|
290
|
-
try {
|
|
291
|
-
return await this.request(`/cross/${encodeURIComponent(target)}/rules/${ruleType}`);
|
|
292
|
-
}
|
|
293
|
-
catch {
|
|
294
|
-
return [];
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
272
|
// ============ 项目文件访问 ============
|
|
298
273
|
/** 列出项目文件 */
|
|
299
274
|
async listFiles(dir) {
|
|
@@ -308,74 +283,6 @@ export class PpdocsApiClient {
|
|
|
308
283
|
async download(remotePath, localPath) {
|
|
309
284
|
return fetchAndExtractZip(`${this.baseUrl}/files-download/${cleanPath(remotePath)}`, localPath);
|
|
310
285
|
}
|
|
311
|
-
/** 上传本地目录或单文件到中心服务器 (打包 zip → POST) */
|
|
312
|
-
async uploadFiles(localPath, remoteDir) {
|
|
313
|
-
const fs = await import('fs');
|
|
314
|
-
const path = await import('path');
|
|
315
|
-
const AdmZip = (await import('adm-zip')).default;
|
|
316
|
-
if (!fs.existsSync(localPath)) {
|
|
317
|
-
throw new Error(`本地路径不存在: ${localPath}`);
|
|
318
|
-
}
|
|
319
|
-
const zip = new AdmZip();
|
|
320
|
-
const stat = fs.statSync(localPath);
|
|
321
|
-
if (stat.isDirectory()) {
|
|
322
|
-
const addDir = (dirPath, zipPath) => {
|
|
323
|
-
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
324
|
-
if (entry.name.startsWith('.'))
|
|
325
|
-
continue;
|
|
326
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
327
|
-
if (entry.isDirectory()) {
|
|
328
|
-
if (EXCLUDED_DIRS.has(entry.name))
|
|
329
|
-
continue;
|
|
330
|
-
addDir(fullPath, zipPath ? `${zipPath}/${entry.name}` : entry.name);
|
|
331
|
-
}
|
|
332
|
-
else {
|
|
333
|
-
if (fs.statSync(fullPath).size > 10_485_760)
|
|
334
|
-
continue;
|
|
335
|
-
zip.addLocalFile(fullPath, zipPath || undefined);
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
addDir(localPath, '');
|
|
340
|
-
}
|
|
341
|
-
else {
|
|
342
|
-
if (stat.size > 10_485_760)
|
|
343
|
-
throw new Error('文件超过 10MB 限制');
|
|
344
|
-
zip.addLocalFile(localPath);
|
|
345
|
-
}
|
|
346
|
-
const buffer = zip.toBuffer();
|
|
347
|
-
if (buffer.length > 104_857_600) {
|
|
348
|
-
throw new Error('打包后超过 100MB 限制,请缩小目录范围');
|
|
349
|
-
}
|
|
350
|
-
const query = remoteDir ? `?dir=${encodeURIComponent(remoteDir)}` : '';
|
|
351
|
-
const response = await fetch(`${this.baseUrl}/files${query}`, {
|
|
352
|
-
method: 'POST',
|
|
353
|
-
headers: { 'Content-Type': 'application/octet-stream' },
|
|
354
|
-
body: new Uint8Array(buffer),
|
|
355
|
-
});
|
|
356
|
-
if (!response.ok) {
|
|
357
|
-
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
358
|
-
throw new Error(error.error || `HTTP ${response.status}`);
|
|
359
|
-
}
|
|
360
|
-
const result = await response.json();
|
|
361
|
-
return { fileCount: result.data?.fileCount || 0 };
|
|
362
|
-
}
|
|
363
|
-
// ============ 直接上传已打包的 ZIP ============
|
|
364
|
-
/** 上传已打包好的 zip 数据到本项目 files/ (供 Code Beacon 使用) */
|
|
365
|
-
async uploadRawZip(zipData, remoteDir) {
|
|
366
|
-
const query = remoteDir ? `?dir=${encodeURIComponent(remoteDir)}` : '';
|
|
367
|
-
const response = await fetch(`${this.baseUrl}/files${query}`, {
|
|
368
|
-
method: 'POST',
|
|
369
|
-
headers: { 'Content-Type': 'application/octet-stream' },
|
|
370
|
-
body: Buffer.isBuffer(zipData) ? new Uint8Array(zipData) : zipData,
|
|
371
|
-
});
|
|
372
|
-
if (!response.ok) {
|
|
373
|
-
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
374
|
-
throw new Error(error.error || `HTTP ${response.status}`);
|
|
375
|
-
}
|
|
376
|
-
const result = await response.json();
|
|
377
|
-
return { fileCount: result.data?.fileCount || 0 };
|
|
378
|
-
}
|
|
379
286
|
// ============ 跨项目文件访问 (只读) ============
|
|
380
287
|
/** 跨项目: 列出文件 */
|
|
381
288
|
async crossListFiles(target, dir) {
|
|
@@ -466,6 +373,13 @@ export class PpdocsApiClient {
|
|
|
466
373
|
method: 'POST',
|
|
467
374
|
});
|
|
468
375
|
}
|
|
376
|
+
/** 归档关闭讨论 (需项目认证) */
|
|
377
|
+
async discussionClose(id, conclusion) {
|
|
378
|
+
return this.request(`/discussions/${encodeURIComponent(id)}/close`, {
|
|
379
|
+
method: 'POST',
|
|
380
|
+
body: JSON.stringify({ conclusion }),
|
|
381
|
+
});
|
|
382
|
+
}
|
|
469
383
|
/** 删除讨论 (公开路由) */
|
|
470
384
|
async discussionDelete(id) {
|
|
471
385
|
return this.publicRequest(`/api/discussions/${encodeURIComponent(id)}`, {
|
|
@@ -506,58 +420,6 @@ export class PpdocsApiClient {
|
|
|
506
420
|
async publicFilesDownload(remotePath, localPath) {
|
|
507
421
|
return fetchAndExtractZip(`${this.serverUrl}/api/public-files/download/${cleanPath(remotePath)}`, localPath);
|
|
508
422
|
}
|
|
509
|
-
/** 上传本地目录或单文件到公共文件池 */
|
|
510
|
-
async publicFilesUpload(localPath, remoteDir) {
|
|
511
|
-
const fs = await import('fs');
|
|
512
|
-
const path = await import('path');
|
|
513
|
-
const AdmZip = (await import('adm-zip')).default;
|
|
514
|
-
if (!fs.existsSync(localPath)) {
|
|
515
|
-
throw new Error(`本地路径不存在: ${localPath}`);
|
|
516
|
-
}
|
|
517
|
-
const zip = new AdmZip();
|
|
518
|
-
const stat = fs.statSync(localPath);
|
|
519
|
-
if (stat.isDirectory()) {
|
|
520
|
-
const addDir = (dirPath, zipPath) => {
|
|
521
|
-
for (const entry of fs.readdirSync(dirPath, { withFileTypes: true })) {
|
|
522
|
-
if (entry.name.startsWith('.'))
|
|
523
|
-
continue;
|
|
524
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
525
|
-
if (entry.isDirectory()) {
|
|
526
|
-
if (EXCLUDED_DIRS.has(entry.name))
|
|
527
|
-
continue;
|
|
528
|
-
addDir(fullPath, zipPath ? `${zipPath}/${entry.name}` : entry.name);
|
|
529
|
-
}
|
|
530
|
-
else {
|
|
531
|
-
if (fs.statSync(fullPath).size > 10_485_760)
|
|
532
|
-
continue;
|
|
533
|
-
zip.addLocalFile(fullPath, zipPath || undefined);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
};
|
|
537
|
-
addDir(localPath, '');
|
|
538
|
-
}
|
|
539
|
-
else {
|
|
540
|
-
if (stat.size > 10_485_760)
|
|
541
|
-
throw new Error('文件超过 10MB 限制');
|
|
542
|
-
zip.addLocalFile(localPath);
|
|
543
|
-
}
|
|
544
|
-
const buffer = zip.toBuffer();
|
|
545
|
-
if (buffer.length > 104_857_600) {
|
|
546
|
-
throw new Error('打包后超过 100MB 限制');
|
|
547
|
-
}
|
|
548
|
-
const query = remoteDir ? `?dir=${encodeURIComponent(remoteDir)}` : '';
|
|
549
|
-
const response = await fetch(`${this.serverUrl}/api/public-files/upload${query}`, {
|
|
550
|
-
method: 'POST',
|
|
551
|
-
headers: { 'Content-Type': 'application/octet-stream' },
|
|
552
|
-
body: new Uint8Array(buffer),
|
|
553
|
-
});
|
|
554
|
-
if (!response.ok) {
|
|
555
|
-
const error = await response.json().catch(() => ({ error: response.statusText }));
|
|
556
|
-
throw new Error(error.error || `HTTP ${response.status}`);
|
|
557
|
-
}
|
|
558
|
-
const result = await response.json();
|
|
559
|
-
return { fileCount: result.data?.fileCount || 0 };
|
|
560
|
-
}
|
|
561
423
|
// ============ 多AI协作会议 ============
|
|
562
424
|
async meetingJoin(agentId, agentType) {
|
|
563
425
|
return this.request('/meeting/join', {
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -4,6 +4,48 @@ export interface RuleMeta {
|
|
|
4
4
|
min_hits: number;
|
|
5
5
|
always?: boolean;
|
|
6
6
|
}
|
|
7
|
+
export interface WorkflowSummary {
|
|
8
|
+
id: string;
|
|
9
|
+
scope: 'global' | 'project';
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
system: string;
|
|
13
|
+
keywords: string[];
|
|
14
|
+
minHits: number;
|
|
15
|
+
always: boolean;
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
}
|
|
18
|
+
export interface WorkflowDoc extends WorkflowSummary {
|
|
19
|
+
content: string;
|
|
20
|
+
}
|
|
21
|
+
export interface WorkflowSelector {
|
|
22
|
+
id: string;
|
|
23
|
+
scope?: 'global' | 'project';
|
|
24
|
+
}
|
|
25
|
+
export interface ReferenceLink {
|
|
26
|
+
url: string;
|
|
27
|
+
label: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ReferenceFile {
|
|
30
|
+
name: string;
|
|
31
|
+
path: string;
|
|
32
|
+
}
|
|
33
|
+
export interface AdoptedNode {
|
|
34
|
+
chartId: string;
|
|
35
|
+
nodeId: string;
|
|
36
|
+
nodeLabel: string;
|
|
37
|
+
}
|
|
38
|
+
export interface Reference {
|
|
39
|
+
id: string;
|
|
40
|
+
title: string;
|
|
41
|
+
summary: string;
|
|
42
|
+
links: ReferenceLink[];
|
|
43
|
+
files: ReferenceFile[];
|
|
44
|
+
scripts: ReferenceFile[];
|
|
45
|
+
adoptedBy: AdoptedNode[];
|
|
46
|
+
createdAt: string;
|
|
47
|
+
updatedAt: string;
|
|
48
|
+
}
|
|
7
49
|
export interface FileInfo {
|
|
8
50
|
name: string;
|
|
9
51
|
path: string;
|
package/dist/tools/analyzer.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 代码分析引擎工具 (3个)
|
|
3
3
|
* code_scan, code_smart_context, code_full_path
|
|
4
4
|
*
|
|
5
|
-
* code_smart_context: 代码+KG
|
|
5
|
+
* code_smart_context: 代码+KG文档/工作流全关联 (含影响范围)
|
|
6
6
|
* code_full_path: 两点间代码链路+共享KG文档
|
|
7
7
|
*/
|
|
8
8
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
package/dist/tools/analyzer.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* 代码分析引擎工具 (3个)
|
|
3
3
|
* code_scan, code_smart_context, code_full_path
|
|
4
4
|
*
|
|
5
|
-
* code_smart_context: 代码+KG
|
|
5
|
+
* code_smart_context: 代码+KG文档/工作流全关联 (含影响范围)
|
|
6
6
|
* code_full_path: 两点间代码链路+共享KG文档
|
|
7
7
|
*/
|
|
8
8
|
import { z } from 'zod';
|
|
@@ -33,7 +33,7 @@ export function registerAnalyzerTools(server, ctx) {
|
|
|
33
33
|
].join('\n'));
|
|
34
34
|
}));
|
|
35
35
|
// ===== code_smart_context: 代码+文档全关联上下文 =====
|
|
36
|
-
server.tool('code_smart_context', '🔍 代码+文档全关联上下文 —
|
|
36
|
+
server.tool('code_smart_context', '🔍 代码+文档全关联上下文 — 输入一个函数名,一次调用返回:代码依赖、关联文档、匹配工作流、活跃任务、影响范围摘要。需先运行 code_scan', {
|
|
37
37
|
projectPath: z.string().optional().describe('项目源码的绝对路径(不传则自动解析)'),
|
|
38
38
|
symbolName: z.string().describe('要查询的符号名称(如"handleLogin", "AuthService")'),
|
|
39
39
|
}, async (args) => safeTool(async () => {
|
|
@@ -75,11 +75,12 @@ export function registerAnalyzerTools(server, ctx) {
|
|
|
75
75
|
}
|
|
76
76
|
lines.push('');
|
|
77
77
|
}
|
|
78
|
-
//
|
|
79
|
-
if (smartCtx.
|
|
80
|
-
lines.push(`###
|
|
81
|
-
for (const
|
|
82
|
-
|
|
78
|
+
// 匹配工作流
|
|
79
|
+
if (smartCtx.matchedWorkflows.length > 0) {
|
|
80
|
+
lines.push(`### 📘 匹配工作流 (${smartCtx.matchedWorkflows.length})`);
|
|
81
|
+
for (const workflow of smartCtx.matchedWorkflows) {
|
|
82
|
+
const desc = workflow.description ? ` — ${workflow.description}` : '';
|
|
83
|
+
lines.push(` [${workflow.scope}/${workflow.system || 'general'}] ${workflow.title}${desc}`);
|
|
83
84
|
}
|
|
84
85
|
lines.push('');
|
|
85
86
|
}
|
package/dist/tools/discussion.js
CHANGED
|
@@ -233,13 +233,9 @@ export function registerDiscussionTools(server, ctx) {
|
|
|
233
233
|
if (brief && !isInitiator(brief, me, myPid)) {
|
|
234
234
|
return wrap(`🔒 无权限: 仅发起人 (${brief.initiator}) 可归档讨论\n你的身份: ${me}`);
|
|
235
235
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
catch { /* 忽略回复失败 */ }
|
|
241
|
-
await client().discussionComplete(decoded.id);
|
|
242
|
-
return wrap(`✅ 讨论已结案 (ID: ${decoded.id})\n📋 ${decoded.conclusion}`);
|
|
236
|
+
const result = await client().discussionClose(decoded.id, decoded.conclusion);
|
|
237
|
+
const archivePath = result?.archived_path ? `\n📦 已归档: ${result.archived_path}` : '';
|
|
238
|
+
return wrap(`✅ 讨论已结案并归档 (ID: ${decoded.id})\n📋 ${decoded.conclusion}${archivePath}`);
|
|
243
239
|
}
|
|
244
240
|
case 'delete': {
|
|
245
241
|
if (!decoded.id)
|
package/dist/tools/files.d.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 📁 kg_files (
|
|
3
|
-
*
|
|
4
|
-
* + 公共文件池: public_list, public_read, public_upload, public_download, public_delete
|
|
2
|
+
* 📁 kg_files — 文件浏览/读取/下载 (上传已移除,全部本地化)
|
|
3
|
+
* 公共文件池: public_list, public_read, public_download, public_delete, public_mkdir, public_rename
|
|
5
4
|
*/
|
|
6
5
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
6
|
export declare function registerFileTools(server: McpServer): void;
|
package/dist/tools/files.js
CHANGED
|
@@ -1,26 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 📁 kg_files (
|
|
3
|
-
*
|
|
4
|
-
* + 公共文件池: public_list, public_read, public_upload, public_download, public_delete
|
|
2
|
+
* 📁 kg_files — 文件浏览/读取/下载 (上传已移除,全部本地化)
|
|
3
|
+
* 公共文件池: public_list, public_read, public_download, public_delete, public_mkdir, public_rename
|
|
5
4
|
*/
|
|
6
5
|
import { z } from 'zod';
|
|
7
6
|
import { getClient } from '../storage/httpClient.js';
|
|
8
7
|
import { wrap, safeTool, crossPrefix, formatFileSize } from './shared.js';
|
|
9
8
|
export function registerFileTools(server) {
|
|
10
9
|
const client = () => getClient();
|
|
11
|
-
server.tool('kg_files', '📁 项目文件操作 —
|
|
12
|
-
action: z.enum(['list', 'read', '
|
|
10
|
+
server.tool('kg_files', '📁 项目文件操作 — 浏览目录、读取文件、下载。action: list(目录浏览)|read(读取文件)|download(下载文件)|public_list(公共文件池浏览)|public_read(读取公共文件)|public_download(下载公共文件)|public_delete(删除公共文件)|public_mkdir(创建公共池子目录)|public_rename(重命名公共文件)', {
|
|
11
|
+
action: z.enum(['list', 'read', 'download', 'public_list', 'public_read', 'public_download', 'public_delete', 'public_mkdir', 'public_rename'])
|
|
13
12
|
.describe('操作类型'),
|
|
14
13
|
path: z.string().optional()
|
|
15
14
|
.describe('文件路径 (read/download/public_read/public_download/public_delete/public_mkdir, 如"src/main.ts")'),
|
|
16
15
|
dir: z.string().optional()
|
|
17
16
|
.describe('子目录路径 (list/public_list, 如"src/components")'),
|
|
18
|
-
localDir: z.string().optional()
|
|
19
|
-
.describe('本地路径(目录或单文件) (upload/public_upload)'),
|
|
20
17
|
localPath: z.string().optional()
|
|
21
18
|
.describe('本地保存路径 (download/public_download)'),
|
|
22
|
-
remoteDir: z.string().optional()
|
|
23
|
-
.describe('远程目标子目录 (upload/public_upload)'),
|
|
24
19
|
newName: z.string().optional()
|
|
25
20
|
.describe('新名称 (public_rename)'),
|
|
26
21
|
targetProject: z.string().optional()
|
|
@@ -51,12 +46,6 @@ export function registerFileTools(server) {
|
|
|
51
46
|
const prefix = args.targetProject ? crossPrefix(args.targetProject) : '';
|
|
52
47
|
return wrap(`${prefix}📄 ${args.path}\n\n\`\`\`\n${content}\n\`\`\``);
|
|
53
48
|
}
|
|
54
|
-
case 'upload': {
|
|
55
|
-
if (!args.localDir)
|
|
56
|
-
return wrap('❌ upload 需要 localDir');
|
|
57
|
-
const result = await client().uploadFiles(args.localDir, args.remoteDir);
|
|
58
|
-
return wrap(`✅ 上传成功\n\n- 文件数量: ${result.fileCount}\n- 目标目录: ${args.remoteDir || '/'}`);
|
|
59
|
-
}
|
|
60
49
|
case 'download': {
|
|
61
50
|
if (!args.path)
|
|
62
51
|
return wrap('❌ download 需要 path');
|
|
@@ -85,12 +74,6 @@ export function registerFileTools(server) {
|
|
|
85
74
|
const content = await client().publicFilesRead(args.path);
|
|
86
75
|
return wrap(`📦 公共文件 ${args.path}\n\n\`\`\`\n${content}\n\`\`\``);
|
|
87
76
|
}
|
|
88
|
-
case 'public_upload': {
|
|
89
|
-
if (!args.localDir)
|
|
90
|
-
return wrap('❌ public_upload 需要 localDir');
|
|
91
|
-
const result = await client().publicFilesUpload(args.localDir, args.remoteDir);
|
|
92
|
-
return wrap(`✅ 已上传到公共文件池\n\n- 文件数量: ${result.fileCount}\n- 目标目录: ${args.remoteDir || '/'}`);
|
|
93
|
-
}
|
|
94
77
|
case 'public_download': {
|
|
95
78
|
if (!args.path)
|
|
96
79
|
return wrap('❌ public_download 需要 path');
|
package/dist/tools/flowchart.js
CHANGED
|
@@ -249,7 +249,10 @@ function findDirectedPath(chart, fromId, toId) {
|
|
|
249
249
|
}
|
|
250
250
|
export function registerFlowchartTools(server, _ctx) {
|
|
251
251
|
const client = () => getClient();
|
|
252
|
-
server.tool('kg_flowchart', '
|
|
252
|
+
server.tool('kg_flowchart', '🔀 逻辑流程图 — 项目知识图谱的核心。每个节点代表一个模块/函数/概念,节点可绑定文件、内嵌版本化文档。\n' +
|
|
253
|
+
'⚡ 开始任何任务前必须先查图谱:search 搜关键词 → get_node 看详情 → 有 subFlowchart 则递归下探。\n' +
|
|
254
|
+
'📝 完成修改后必须回写:bind 绑定文件 → update_node 更新描述和文档 → 新模块用 batch_add。\n' +
|
|
255
|
+
'actions: list|get|search|get_relations|find_path|get_node|update_node|delete_node|batch_add|bind|unbind|orphans|health|create_chart|delete_chart', {
|
|
253
256
|
action: z
|
|
254
257
|
.enum(['list', 'get', 'search', 'get_relations', 'find_path', 'get_node', 'update_node', 'delete_node', 'batch_add', 'bind', 'unbind', 'orphans', 'health', 'create_chart', 'delete_chart'])
|
|
255
258
|
.describe('action type'),
|
package/dist/tools/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP 工具注册入口
|
|
3
|
-
*
|
|
3
|
+
* 13 个工具, 7 个子模块
|
|
4
4
|
*
|
|
5
5
|
* 🔗 初始化: kg_init (1个)
|
|
6
6
|
* 📊 导航: kg_status (1个)
|
|
7
|
-
* 📚 知识: kg_projects,
|
|
8
|
-
* 📝 工作流: kg_task(任务记录), kg_files, kg_discuss(讨论区)
|
|
7
|
+
* 📚 知识: kg_projects, kg_workflow (2个)
|
|
8
|
+
* 📝 工作流: kg_task(任务记录), kg_files, kg_discuss(讨论区), kg_ref (4个)
|
|
9
9
|
* 🔀 关系核心: kg_flowchart(逻辑流程图 — 关系型知识锚点) (1个)
|
|
10
10
|
* 🔬 代码分析: code_scan, code_smart_context, code_full_path (3个)
|
|
11
11
|
* 🏛️ 协作: kg_meeting (1个)
|