@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 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: 20001, api: 'localhost', codex: false };
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: 20001)
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
- await syncKnowledgeBase(cwd, apiUrl, opts.sync);
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:20001/api/:projectId/:password/...
5
+ * API URL 格式: http://localhost:20099/api/:projectId/:password/...
6
6
  */
7
- import type { DocData, DocNode, Task, TaskSummary, TaskLogType, TaskExperience, FileInfo, RuleMeta } from './types.js';
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:20001/api/:projectId/:password/...
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:20001/api/projectId/password
94
- serverUrl; // http://localhost:20001
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 {
@@ -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[];
@@ -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, ctx: McpContext): void;
3
+ export declare function registerFlowchartTools(server: McpServer, _ctx: McpContext): void;