@ppdocs/mcp 3.2.34 → 3.2.36
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/cli.js +4 -48
- package/dist/storage/httpClient.d.ts +2 -27
- package/dist/storage/httpClient.js +3 -132
- package/dist/storage/types.d.ts +0 -28
- package/dist/storage/types.js +1 -1
- package/dist/tools/flowchart.d.ts +1 -5
- package/dist/tools/flowchart.js +406 -454
- package/dist/tools/index.d.ts +3 -3
- package/dist/tools/index.js +10 -13
- package/dist/tools/kg_status.d.ts +1 -1
- package/dist/tools/kg_status.js +6 -20
- package/dist/tools/projects.d.ts +2 -3
- package/dist/tools/projects.js +2 -3
- package/dist/tools/shared.d.ts +0 -12
- package/dist/tools/shared.js +0 -59
- package/package.json +1 -1
- package/templates/AGENT.md +63 -38
- package/templates/cursorrules.md +63 -153
- package/templates/kiro-rules/ppdocs.md +63 -142
- package/dist/agent.d.ts +0 -6
- package/dist/agent.js +0 -130
- package/dist/tools/docs.d.ts +0 -8
- package/dist/tools/docs.js +0 -285
- package/dist/tools/helpers.d.ts +0 -37
- package/dist/tools/helpers.js +0 -94
- package/dist/vector/index.d.ts +0 -56
- package/dist/vector/index.js +0 -228
- package/dist/vector/manager.d.ts +0 -48
- package/dist/vector/manager.js +0 -250
- package/dist/web/server.d.ts +0 -43
- package/dist/web/server.js +0 -808
- package/dist/web/ui.d.ts +0 -5
- package/dist/web/ui.js +0 -642
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@ import { PpdocsApiClient } from './storage/httpClient.js';
|
|
|
11
11
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
const TEMPLATES_DIR = path.join(__dirname, '..', 'templates');
|
|
13
13
|
function parseArgs(args) {
|
|
14
|
-
const opts = { port:
|
|
14
|
+
const opts = { port: 20099, api: 'localhost', codex: false };
|
|
15
15
|
for (let i = 0; i < args.length; i++) {
|
|
16
16
|
const arg = args[i];
|
|
17
17
|
if (arg === '-p' || arg === '--project') {
|
|
@@ -100,7 +100,7 @@ Options:
|
|
|
100
100
|
-p, --project Project ID (required)
|
|
101
101
|
-k, --key API key (required)
|
|
102
102
|
-u, --user User name for logs (optional, auto-generated)
|
|
103
|
-
--port API port (default:
|
|
103
|
+
--port API port (default: 20099)
|
|
104
104
|
--api API host (default: localhost)
|
|
105
105
|
--codex Codex mode: generate AGENTS.md instead of .claude/
|
|
106
106
|
--from <id> Pull IDE configs from a template project
|
|
@@ -208,9 +208,9 @@ async function initProject(opts) {
|
|
|
208
208
|
if (opts.from) {
|
|
209
209
|
await pullTemplateProject(cwd, apiUrl, opts.from);
|
|
210
210
|
}
|
|
211
|
-
// --sync:
|
|
211
|
+
// --sync: 旧文档同步已废弃 (文档现在内嵌在流程图节点中)
|
|
212
212
|
if (opts.sync) {
|
|
213
|
-
|
|
213
|
+
console.log(`⚠️ --sync is deprecated. Documents are now embedded in flowchart nodes.`);
|
|
214
214
|
}
|
|
215
215
|
console.log(`
|
|
216
216
|
🎉 Done! ppdocs MCP configured for project: ${opts.project}
|
|
@@ -236,48 +236,6 @@ async function pullTemplateProject(cwd, apiUrl, templateId) {
|
|
|
236
236
|
console.log(`⚠️ Failed to pull from template project: ${e}`);
|
|
237
237
|
}
|
|
238
238
|
}
|
|
239
|
-
/** 从源项目同步知识库文档到本地 ./docs/ppdocs/ */
|
|
240
|
-
async function syncKnowledgeBase(cwd, apiUrl, sourceId) {
|
|
241
|
-
console.log(`📚 Syncing knowledge base from project: ${sourceId}...`);
|
|
242
|
-
try {
|
|
243
|
-
const client = new PpdocsApiClient(apiUrl);
|
|
244
|
-
const docs = await client.crossListDocs(sourceId);
|
|
245
|
-
const docNodes = docs.filter(d => !d.isDir);
|
|
246
|
-
if (docNodes.length === 0) {
|
|
247
|
-
console.log(`⚠️ Project "${sourceId}" has no knowledge base documents`);
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
const docsDir = path.join(cwd, 'docs', 'ppdocs', sourceId);
|
|
251
|
-
fs.mkdirSync(docsDir, { recursive: true });
|
|
252
|
-
let synced = 0;
|
|
253
|
-
for (const node of docNodes) {
|
|
254
|
-
const doc = await client.crossGetDoc(sourceId, node.path);
|
|
255
|
-
if (!doc)
|
|
256
|
-
continue;
|
|
257
|
-
// 将文档路径转为本地文件路径 (e.g. "/前端/组件/Modal" → "前端/组件/Modal.md")
|
|
258
|
-
const safePath = node.path.replace(/^\//, '').replace(/[<>:"|?*]/g, '_');
|
|
259
|
-
const localFile = path.join(docsDir, `${safePath}.md`);
|
|
260
|
-
const localDir = path.dirname(localFile);
|
|
261
|
-
if (!fs.existsSync(localDir)) {
|
|
262
|
-
fs.mkdirSync(localDir, { recursive: true });
|
|
263
|
-
}
|
|
264
|
-
// 生成 Markdown 文件内容
|
|
265
|
-
const content = [
|
|
266
|
-
`# ${node.name}`,
|
|
267
|
-
'',
|
|
268
|
-
doc.summary ? `> ${doc.summary}` : '',
|
|
269
|
-
'',
|
|
270
|
-
doc.content || '',
|
|
271
|
-
].filter(Boolean).join('\n');
|
|
272
|
-
fs.writeFileSync(localFile, content, 'utf-8');
|
|
273
|
-
synced++;
|
|
274
|
-
}
|
|
275
|
-
console.log(`✅ Synced ${synced} documents from "${sourceId}" to docs/ppdocs/${sourceId}/`);
|
|
276
|
-
}
|
|
277
|
-
catch (e) {
|
|
278
|
-
console.log(`⚠️ Failed to sync knowledge base: ${e}`);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
239
|
/** 检测命令是否存在 */
|
|
282
240
|
function commandExists(cmd) {
|
|
283
241
|
try {
|
|
@@ -432,9 +390,7 @@ function generateMcpPermissions() {
|
|
|
432
390
|
// 初始化 + 导航
|
|
433
391
|
'kg_init',
|
|
434
392
|
'kg_status',
|
|
435
|
-
'kg_tree',
|
|
436
393
|
// 知识管理
|
|
437
|
-
'kg_doc',
|
|
438
394
|
'kg_projects',
|
|
439
395
|
'kg_rules',
|
|
440
396
|
// 工作流
|
|
@@ -2,30 +2,14 @@
|
|
|
2
2
|
* ppdocs MCP HTTP API Client
|
|
3
3
|
* 通过 HTTP API 调用主程序,替代直接文件访问
|
|
4
4
|
*
|
|
5
|
-
* API URL 格式: http://localhost:
|
|
5
|
+
* API URL 格式: http://localhost:20099/api/:projectId/:password/...
|
|
6
6
|
*/
|
|
7
|
-
import type {
|
|
8
|
-
interface TreeNode {
|
|
9
|
-
path: string;
|
|
10
|
-
name: string;
|
|
11
|
-
summary?: string;
|
|
12
|
-
isDir: boolean;
|
|
13
|
-
children?: TreeNode[];
|
|
14
|
-
}
|
|
7
|
+
import type { Task, TaskSummary, TaskLogType, TaskExperience, FileInfo, RuleMeta } from './types.js';
|
|
15
8
|
export declare class PpdocsApiClient {
|
|
16
9
|
private baseUrl;
|
|
17
10
|
private serverUrl;
|
|
18
11
|
constructor(apiUrl: string);
|
|
19
12
|
private request;
|
|
20
|
-
listDocs(): Promise<DocNode[]>;
|
|
21
|
-
getDoc(docPath: string): Promise<DocData | null>;
|
|
22
|
-
createDoc(docPath: string, doc: Partial<DocData>): Promise<DocData>;
|
|
23
|
-
updateDoc(docPath: string, updates: Partial<DocData>): Promise<DocData | null>;
|
|
24
|
-
deleteDoc(docPath: string): Promise<boolean>;
|
|
25
|
-
/** 按状态筛选文档 */
|
|
26
|
-
getDocsByStatus(statusList: string[]): Promise<DocNode[]>;
|
|
27
|
-
/** 获取目录树结构 */
|
|
28
|
-
getTree(): Promise<TreeNode[]>;
|
|
29
13
|
getRulesApi(ruleType: string): Promise<string[]>;
|
|
30
14
|
saveRulesApi(ruleType: string, rules: string[]): Promise<boolean>;
|
|
31
15
|
getRulesMeta(): Promise<Record<string, RuleMeta>>;
|
|
@@ -62,14 +46,6 @@ export declare class PpdocsApiClient {
|
|
|
62
46
|
description: string;
|
|
63
47
|
updatedAt: string;
|
|
64
48
|
}[]>;
|
|
65
|
-
/** 跨项目: 列出文档 */
|
|
66
|
-
crossListDocs(target: string): Promise<DocNode[]>;
|
|
67
|
-
/** 跨项目: 获取文档 */
|
|
68
|
-
crossGetDoc(target: string, docPath: string): Promise<DocData | null>;
|
|
69
|
-
/** 跨项目: 获取目录树 */
|
|
70
|
-
crossGetTree(target: string): Promise<TreeNode[]>;
|
|
71
|
-
/** 跨项目: 按状态筛选文档 */
|
|
72
|
-
crossGetDocsByStatus(target: string, statusList: string[]): Promise<DocNode[]>;
|
|
73
49
|
/** 跨项目: 获取规则 */
|
|
74
50
|
crossGetRules(target: string, ruleType: string): Promise<string[]>;
|
|
75
51
|
/** 列出项目文件 */
|
|
@@ -149,4 +125,3 @@ export declare class PpdocsApiClient {
|
|
|
149
125
|
}
|
|
150
126
|
export declare function initClient(apiUrl: string): void;
|
|
151
127
|
export declare function getClient(): PpdocsApiClient;
|
|
152
|
-
export type { TreeNode };
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* ppdocs MCP HTTP API Client
|
|
3
3
|
* 通过 HTTP API 调用主程序,替代直接文件访问
|
|
4
4
|
*
|
|
5
|
-
* API URL 格式: http://localhost:
|
|
5
|
+
* API URL 格式: http://localhost:20099/api/:projectId/:password/...
|
|
6
6
|
*/
|
|
7
7
|
// ============ 工具函数 ============
|
|
8
8
|
/** 清理路径前缀斜杠 */
|
|
@@ -55,43 +55,10 @@ async function fetchAndExtractZip(url, localPath) {
|
|
|
55
55
|
clearTimeout(timeout);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
/** 从扁平文档列表构建目录树 */
|
|
59
|
-
function buildTree(docs) {
|
|
60
|
-
const root = [];
|
|
61
|
-
const pathMap = new Map();
|
|
62
|
-
// 按路径深度排序,确保父目录先处理
|
|
63
|
-
const sorted = [...docs].sort((a, b) => {
|
|
64
|
-
const depthA = (a.path.match(/\//g) || []).length;
|
|
65
|
-
const depthB = (b.path.match(/\//g) || []).length;
|
|
66
|
-
return depthA - depthB;
|
|
67
|
-
});
|
|
68
|
-
for (const doc of sorted) {
|
|
69
|
-
const node = {
|
|
70
|
-
path: doc.path,
|
|
71
|
-
name: doc.name,
|
|
72
|
-
summary: doc.summary,
|
|
73
|
-
isDir: doc.isDir,
|
|
74
|
-
children: doc.isDir ? [] : undefined
|
|
75
|
-
};
|
|
76
|
-
// 找父路径
|
|
77
|
-
const lastSlash = doc.path.lastIndexOf('/');
|
|
78
|
-
const parentPath = lastSlash > 0 ? doc.path.substring(0, lastSlash) : '';
|
|
79
|
-
if (parentPath && pathMap.has(parentPath)) {
|
|
80
|
-
pathMap.get(parentPath).children.push(node);
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
root.push(node);
|
|
84
|
-
}
|
|
85
|
-
if (doc.isDir) {
|
|
86
|
-
pathMap.set(doc.path, node);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return root;
|
|
90
|
-
}
|
|
91
58
|
// API 客户端类
|
|
92
59
|
export class PpdocsApiClient {
|
|
93
|
-
baseUrl; // http://localhost:
|
|
94
|
-
serverUrl; // http://localhost:
|
|
60
|
+
baseUrl; // http://localhost:20099/api/projectId/password
|
|
61
|
+
serverUrl; // http://localhost:20099
|
|
95
62
|
constructor(apiUrl) {
|
|
96
63
|
this.baseUrl = apiUrl.replace(/\/$/, '');
|
|
97
64
|
// 从 /api/projectId/password 提取服务器根地址
|
|
@@ -132,77 +99,6 @@ export class PpdocsApiClient {
|
|
|
132
99
|
clearTimeout(timeout);
|
|
133
100
|
}
|
|
134
101
|
}
|
|
135
|
-
// ============ 文档操作 ============
|
|
136
|
-
async listDocs() {
|
|
137
|
-
return this.request('/docs');
|
|
138
|
-
}
|
|
139
|
-
async getDoc(docPath) {
|
|
140
|
-
try {
|
|
141
|
-
return await this.request(`/docs/${cleanPath(docPath)}`);
|
|
142
|
-
}
|
|
143
|
-
catch {
|
|
144
|
-
return null;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
async createDoc(docPath, doc) {
|
|
148
|
-
const payload = {
|
|
149
|
-
summary: doc.summary || '',
|
|
150
|
-
content: doc.content || '',
|
|
151
|
-
versions: doc.versions || [{
|
|
152
|
-
version: 0.1,
|
|
153
|
-
date: new Date().toISOString(),
|
|
154
|
-
changes: '初始创建'
|
|
155
|
-
}],
|
|
156
|
-
bugfixes: doc.bugfixes || [],
|
|
157
|
-
status: doc.status || '已完成'
|
|
158
|
-
};
|
|
159
|
-
return this.request(`/docs/${cleanPath(docPath)}`, {
|
|
160
|
-
method: 'POST',
|
|
161
|
-
body: JSON.stringify(payload)
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
async updateDoc(docPath, updates) {
|
|
165
|
-
try {
|
|
166
|
-
const existing = await this.getDoc(docPath);
|
|
167
|
-
if (!existing)
|
|
168
|
-
return null;
|
|
169
|
-
const payload = {
|
|
170
|
-
summary: updates.summary ?? existing.summary,
|
|
171
|
-
content: updates.content ?? existing.content,
|
|
172
|
-
versions: updates.versions ?? existing.versions,
|
|
173
|
-
bugfixes: updates.bugfixes ?? existing.bugfixes,
|
|
174
|
-
status: updates.status ?? existing.status ?? '已完成'
|
|
175
|
-
};
|
|
176
|
-
return await this.request(`/docs/${cleanPath(docPath)}`, {
|
|
177
|
-
method: 'PUT',
|
|
178
|
-
body: JSON.stringify(payload)
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
catch {
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
async deleteDoc(docPath) {
|
|
186
|
-
try {
|
|
187
|
-
await this.request(`/docs/${cleanPath(docPath)}`, { method: 'DELETE' });
|
|
188
|
-
return true;
|
|
189
|
-
}
|
|
190
|
-
catch {
|
|
191
|
-
return false;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
/** 按状态筛选文档 */
|
|
195
|
-
async getDocsByStatus(statusList) {
|
|
196
|
-
return this.request('/docs/by-status', {
|
|
197
|
-
method: 'POST',
|
|
198
|
-
body: JSON.stringify({ status_list: statusList })
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
/** 获取目录树结构 */
|
|
202
|
-
async getTree() {
|
|
203
|
-
const docs = await this.listDocs();
|
|
204
|
-
return buildTree(docs);
|
|
205
|
-
}
|
|
206
102
|
// ============ 规则 API ============
|
|
207
103
|
async getRulesApi(ruleType) {
|
|
208
104
|
try {
|
|
@@ -389,31 +285,6 @@ export class PpdocsApiClient {
|
|
|
389
285
|
async crossListProjects() {
|
|
390
286
|
return this.request('/cross/projects');
|
|
391
287
|
}
|
|
392
|
-
/** 跨项目: 列出文档 */
|
|
393
|
-
async crossListDocs(target) {
|
|
394
|
-
return this.request(`/cross/${encodeURIComponent(target)}/docs`);
|
|
395
|
-
}
|
|
396
|
-
/** 跨项目: 获取文档 */
|
|
397
|
-
async crossGetDoc(target, docPath) {
|
|
398
|
-
try {
|
|
399
|
-
return await this.request(`/cross/${encodeURIComponent(target)}/docs/${cleanPath(docPath)}`);
|
|
400
|
-
}
|
|
401
|
-
catch {
|
|
402
|
-
return null;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
/** 跨项目: 获取目录树 */
|
|
406
|
-
async crossGetTree(target) {
|
|
407
|
-
const docs = await this.crossListDocs(target);
|
|
408
|
-
return buildTree(docs);
|
|
409
|
-
}
|
|
410
|
-
/** 跨项目: 按状态筛选文档 */
|
|
411
|
-
async crossGetDocsByStatus(target, statusList) {
|
|
412
|
-
return this.request(`/cross/${encodeURIComponent(target)}/docs/by-status`, {
|
|
413
|
-
method: 'POST',
|
|
414
|
-
body: JSON.stringify({ status_list: statusList })
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
288
|
/** 跨项目: 获取规则 */
|
|
418
289
|
async crossGetRules(target, ruleType) {
|
|
419
290
|
try {
|
package/dist/storage/types.d.ts
CHANGED
|
@@ -1,31 +1,3 @@
|
|
|
1
|
-
/** 版本记录 */
|
|
2
|
-
export interface VersionRecord {
|
|
3
|
-
version: number;
|
|
4
|
-
date: string;
|
|
5
|
-
changes: string;
|
|
6
|
-
}
|
|
7
|
-
/** 错误修复记录 */
|
|
8
|
-
export interface BugfixRecord {
|
|
9
|
-
date: string;
|
|
10
|
-
issue: string;
|
|
11
|
-
solution: string;
|
|
12
|
-
}
|
|
13
|
-
/** 文档数据 (5个核心字段) */
|
|
14
|
-
export interface DocData {
|
|
15
|
-
summary: string;
|
|
16
|
-
content: string;
|
|
17
|
-
versions: VersionRecord[];
|
|
18
|
-
bugfixes: BugfixRecord[];
|
|
19
|
-
status?: string;
|
|
20
|
-
}
|
|
21
|
-
/** 文档节点 (含路径信息,用于列表展示) */
|
|
22
|
-
export interface DocNode {
|
|
23
|
-
path: string;
|
|
24
|
-
name: string;
|
|
25
|
-
summary: string;
|
|
26
|
-
isDir: boolean;
|
|
27
|
-
status?: string;
|
|
28
|
-
}
|
|
29
1
|
export interface RuleMeta {
|
|
30
2
|
label: string;
|
|
31
3
|
keywords: string[];
|
package/dist/storage/types.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
// ppdocs -
|
|
1
|
+
// ppdocs - 类型定义
|
|
2
2
|
export {};
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 🔀 kg_flowchart — 逻辑流程图批量操作
|
|
3
|
-
* AI 一次提交所有节点+边, 后端原子处理, 返回孤立检测结果
|
|
4
|
-
*/
|
|
5
1
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
6
2
|
import { type McpContext } from './shared.js';
|
|
7
|
-
export declare function registerFlowchartTools(server: McpServer,
|
|
3
|
+
export declare function registerFlowchartTools(server: McpServer, _ctx: McpContext): void;
|