@ppdocs/mcp 3.2.23 → 3.2.25

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.
@@ -51,6 +51,8 @@ export declare class PpdocsApiClient {
51
51
  updateFlowchartNode(chartId: string, nodeId: string, node: unknown, changeDesc?: string): Promise<unknown>;
52
52
  /** 原子删除单个节点 (后端自动清理关联边) */
53
53
  deleteFlowchartNode(chartId: string, nodeId: string): Promise<unknown>;
54
+ /** 删除流程图 (后端自动级联删子图+清父节点引用) */
55
+ deleteFlowchart(chartId: string): Promise<unknown>;
54
56
  getFlowchartOrphans(): Promise<unknown[]>;
55
57
  getFlowchartHealth(): Promise<unknown[]>;
56
58
  /** 列出所有可访问的项目 */
@@ -372,6 +372,12 @@ export class PpdocsApiClient {
372
372
  method: 'DELETE'
373
373
  });
374
374
  }
375
+ /** 删除流程图 (后端自动级联删子图+清父节点引用) */
376
+ async deleteFlowchart(chartId) {
377
+ return this.request(`/flowcharts/${chartId}`, {
378
+ method: 'DELETE'
379
+ });
380
+ }
375
381
  async getFlowchartOrphans() {
376
382
  return this.request('/flowcharts/orphans');
377
383
  }
@@ -24,8 +24,8 @@ const EdgeSchema = z.object({
24
24
  });
25
25
  export function registerFlowchartTools(server, ctx) {
26
26
  const client = () => getClient();
27
- server.tool('kg_flowchart', '🔀 逻辑流程图(关系型知识锚点) — action: list|get|get_node(★爆炸式上下文)|update_node|delete_node|batch_add|bind|unbind|orphans|health', {
28
- action: z.enum(['list', 'get', 'get_node', 'update_node', 'delete_node', 'batch_add', 'bind', 'unbind', 'orphans', 'health'])
27
+ server.tool('kg_flowchart', '🔀 逻辑流程图(关系型知识锚点) — action: list|get|get_node(★爆炸式上下文)|update_node|delete_node|batch_add|bind|unbind|orphans|health|create_chart|delete_chart', {
28
+ action: z.enum(['list', 'get', 'get_node', 'update_node', 'delete_node', 'batch_add', 'bind', 'unbind', 'orphans', 'health', 'create_chart', 'delete_chart'])
29
29
  .describe('操作类型'),
30
30
  chartId: z.string().optional()
31
31
  .describe('流程图ID (默认"main")'),
@@ -49,6 +49,10 @@ export function registerFlowchartTools(server, ctx) {
49
49
  domain: z.string().optional().describe('update_node: 新领域'),
50
50
  input: z.array(z.string()).optional().describe('update_node: 新输入 / bind的源代码文件'),
51
51
  output: z.array(z.string()).optional().describe('update_node: 新输出'),
52
+ subFlowchart: z.string().optional().describe('update_node: 绑定子图ID / create_chart时自动设置'),
53
+ title: z.string().optional().describe('create_chart: 子图标题'),
54
+ parentChart: z.string().optional().describe('create_chart: 父图ID (默认main)'),
55
+ parentNode: z.string().optional().describe('create_chart: 挂载到父图的哪个节点ID'),
52
56
  // bind/unbind
53
57
  files: z.array(z.string()).optional()
54
58
  .describe('源代码文件路径 (bind/unbind)'),
@@ -250,39 +254,46 @@ export function registerFlowchartTools(server, ctx) {
250
254
  const chartId = decoded.chartId || 'main';
251
255
  if (!decoded.nodeId)
252
256
  return wrap('❌ update_node 需要 nodeId');
253
- // 构建待更新的节点字段
254
- const updates = { id: decoded.nodeId };
257
+ const chart = await client().getFlowchart(chartId);
258
+ if (!chart)
259
+ return wrap(`❌ 流程图 "${chartId}" 不存在`);
260
+ const node = (chart.nodes || []).find((n) => n.id === decoded.nodeId);
261
+ if (!node)
262
+ return wrap(`❌ 节点 "${decoded.nodeId}" 不存在`);
255
263
  const changes = [];
256
264
  if (decoded.label !== undefined) {
257
- updates.label = decoded.label;
265
+ node.label = decoded.label;
258
266
  changes.push('label');
259
267
  }
260
268
  if (decoded.description !== undefined) {
261
- updates.description = decoded.description;
269
+ node.description = decoded.description;
262
270
  changes.push('description');
263
271
  }
264
272
  if (decoded.nodeType !== undefined) {
265
- updates.nodeType = decoded.nodeType;
273
+ node.nodeType = decoded.nodeType;
266
274
  changes.push('nodeType');
267
275
  }
268
276
  if (decoded.domain !== undefined) {
269
- updates.domain = decoded.domain;
277
+ node.domain = decoded.domain;
270
278
  changes.push('domain');
271
279
  }
272
280
  if (decoded.input !== undefined) {
273
- updates.input = decoded.input;
281
+ node.input = decoded.input;
274
282
  changes.push('input');
275
283
  }
276
284
  if (decoded.output !== undefined) {
277
- updates.output = decoded.output;
285
+ node.output = decoded.output;
278
286
  changes.push('output');
279
287
  }
288
+ if (decoded.subFlowchart !== undefined) {
289
+ node.subFlowchart = decoded.subFlowchart;
290
+ changes.push('subFlowchart');
291
+ }
280
292
  if (changes.length === 0)
281
293
  return wrap('ℹ️ 无变更 — 请提供要更新的字段');
282
- updates.lastUpdated = new Date().toISOString();
283
- // 原子调用: PUT /flowcharts/:chartId/nodes/:nodeId
284
- await client().updateFlowchartNode(chartId, decoded.nodeId, updates, `MCP更新: ${changes.join(', ')}`);
285
- return wrap(`✅ 节点已更新: ${decoded.label || decoded.nodeId} [${chartId}/${decoded.nodeId}]\n更新字段: ${changes.join(', ')}`);
294
+ node.lastUpdated = new Date().toISOString();
295
+ await client().saveFlowchart(chartId, chart);
296
+ return wrap(`✅ 节点已更新: ${node.label} [${chartId}/${decoded.nodeId}]\n更新字段: ${changes.join(', ')}`);
286
297
  }
287
298
  case 'delete_node': {
288
299
  const chartId = decoded.chartId || 'main';
@@ -311,7 +322,7 @@ export function registerFlowchartTools(server, ctx) {
311
322
  boundFiles: [],
312
323
  boundDirs: [],
313
324
  boundTasks: [],
314
- subFlowchart: null,
325
+ subFlowchart: n.subFlowchart || null,
315
326
  position: null,
316
327
  versions: [],
317
328
  lastUpdated: '',
@@ -476,6 +487,70 @@ export function registerFlowchartTools(server, ctx) {
476
487
  const icon = isBind ? '🔗' : '⛓️';
477
488
  return wrap(`${icon} ${isBind ? '绑定' : '解绑'}完成 [${decoded.nodeId}]: ${changes.join(', ')}`);
478
489
  }
490
+ case 'create_chart': {
491
+ const newChartId = decoded.chartId;
492
+ if (!newChartId)
493
+ return wrap('❌ create_chart 需要 chartId (子图ID)');
494
+ if (newChartId === 'main')
495
+ return wrap('❌ 不能创建 main,主图已存在');
496
+ // 检查是否已存在
497
+ const existing = await client().getFlowchart(newChartId);
498
+ if (existing)
499
+ return wrap(`❌ 流程图 "${newChartId}" 已存在`);
500
+ const pChart = decoded.parentChart || 'main';
501
+ const pNode = decoded.parentNode;
502
+ // 构建子图数据
503
+ const subChartData = {
504
+ id: newChartId,
505
+ title: decoded.title || newChartId,
506
+ parentNode: pNode || null,
507
+ parentChart: pChart,
508
+ nodes: [],
509
+ edges: [],
510
+ };
511
+ // 如果提供了 nodes/edges,填充进去
512
+ if (decoded.nodes && decoded.nodes.length > 0) {
513
+ subChartData.nodes = decoded.nodes.map((n) => ({
514
+ id: n.id, label: n.label,
515
+ nodeType: n.nodeType || 'process', domain: n.domain || 'system',
516
+ input: n.input || [], output: n.output || [],
517
+ description: n.description || '', affiliation: n.affiliation || 'root',
518
+ boundDocs: [], boundFiles: [], boundDirs: [], boundTasks: [],
519
+ subFlowchart: null, position: null, versions: [], lastUpdated: '', lastQueried: '',
520
+ }));
521
+ }
522
+ if (decoded.edges && decoded.edges.length > 0) {
523
+ subChartData.edges = decoded.edges.map(e => ({
524
+ from: e.from, to: e.to, label: e.label || null, edgeType: e.edgeType || 'call',
525
+ }));
526
+ }
527
+ // 保存子图
528
+ await client().saveFlowchart(newChartId, subChartData);
529
+ // 自动更新父节点的 subFlowchart 引用
530
+ if (pNode) {
531
+ const parentChart = await client().getFlowchart(pChart);
532
+ if (parentChart) {
533
+ const parentNodeObj = (parentChart.nodes || []).find((n) => n.id === pNode);
534
+ if (parentNodeObj) {
535
+ parentNodeObj.subFlowchart = newChartId;
536
+ parentNodeObj.lastUpdated = new Date().toISOString();
537
+ await client().saveFlowchart(pChart, parentChart);
538
+ }
539
+ }
540
+ }
541
+ const nodeCount = subChartData.nodes.length;
542
+ return wrap(`✅ 子图已创建: ${decoded.title || newChartId} [${newChartId}]\n父图: ${pChart}${pNode ? ` → 节点: ${pNode}` : ''}\n初始: ${nodeCount}节点`);
543
+ }
544
+ case 'delete_chart': {
545
+ const chartId = decoded.chartId;
546
+ if (!chartId)
547
+ return wrap('❌ delete_chart 需要 chartId');
548
+ if (chartId === 'main')
549
+ return wrap('❌ 不能删除主图 main');
550
+ // 后端自动级联: 清父节点引用 + 删子图的子图
551
+ await client().deleteFlowchart(chartId);
552
+ return wrap(`✅ 流程图已删除 [${chartId}] (子图已级联清理)`);
553
+ }
479
554
  default:
480
555
  return wrap(`❌ 未知 action: ${decoded.action}`);
481
556
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ppdocs/mcp",
3
- "version": "3.2.23",
3
+ "version": "3.2.25",
4
4
  "description": "ppdocs MCP Server - Knowledge Graph for Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",