@ppdocs/mcp 3.2.24 → 3.2.26
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
|
}
|
package/dist/tools/flowchart.js
CHANGED
|
@@ -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,15 @@ 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: bind sub-chart ID / auto-set on create_chart'),
|
|
53
|
+
title: z.string().optional().describe('create_chart: sub-chart title'),
|
|
54
|
+
parentChart: z.string().optional().describe('create_chart: parent chart ID (default main)'),
|
|
55
|
+
parentNode: z.string().optional().describe('create_chart: mount to parent node ID'),
|
|
56
|
+
// update_node: append doc entry
|
|
57
|
+
docSummary: z.string().optional().describe('update_node: doc summary (one-line)'),
|
|
58
|
+
docContent: z.string().optional().describe('update_node: doc content (full markdown)'),
|
|
59
|
+
// get_node: doc display control
|
|
60
|
+
fullDoc: z.boolean().optional().describe('get_node: show ALL doc entries in full (default false, only latest full)'),
|
|
52
61
|
// bind/unbind
|
|
53
62
|
files: z.array(z.string()).optional()
|
|
54
63
|
.describe('源代码文件路径 (bind/unbind)'),
|
|
@@ -128,15 +137,21 @@ export function registerFlowchartTools(server, ctx) {
|
|
|
128
137
|
if (target.lastUpdated)
|
|
129
138
|
lines.push(`🕐 最后更新: ${target.lastUpdated}`);
|
|
130
139
|
lines.push('');
|
|
131
|
-
// ========
|
|
132
|
-
if (showDoc && target.
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
+
// ======== node doc entries ========
|
|
141
|
+
if (showDoc && target.docEntries?.length) {
|
|
142
|
+
const entries = target.docEntries;
|
|
143
|
+
const showFullAll = decoded.fullDoc === true;
|
|
144
|
+
lines.push(`### 📖 Node Documentation (${entries.length} entries)`);
|
|
145
|
+
for (let i = 0; i < entries.length; i++) {
|
|
146
|
+
const e = entries[i];
|
|
147
|
+
const isLatest = i === entries.length - 1;
|
|
148
|
+
if (isLatest || showFullAll) {
|
|
149
|
+
lines.push(`\n**${e.version}** (${e.date})${isLatest ? ' ★LATEST' : ''}`);
|
|
150
|
+
lines.push(`> ${e.summary}`);
|
|
151
|
+
lines.push(e.content);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
lines.push(` ${e.version} (${e.date}): ${e.summary}`);
|
|
140
155
|
}
|
|
141
156
|
}
|
|
142
157
|
lines.push('');
|
|
@@ -281,6 +296,33 @@ export function registerFlowchartTools(server, ctx) {
|
|
|
281
296
|
node.output = decoded.output;
|
|
282
297
|
changes.push('output');
|
|
283
298
|
}
|
|
299
|
+
if (decoded.subFlowchart !== undefined) {
|
|
300
|
+
node.subFlowchart = decoded.subFlowchart;
|
|
301
|
+
changes.push('subFlowchart');
|
|
302
|
+
}
|
|
303
|
+
// append doc entry
|
|
304
|
+
if (decoded.docSummary || decoded.docContent) {
|
|
305
|
+
if (!decoded.docSummary || !decoded.docContent) {
|
|
306
|
+
return wrap('\u274c update_node: docSummary and docContent must both be provided');
|
|
307
|
+
}
|
|
308
|
+
const docEntries = node.docEntries || [];
|
|
309
|
+
// auto-increment version: v0.1, v0.2, ...
|
|
310
|
+
let nextVer = 0.1;
|
|
311
|
+
if (docEntries.length > 0) {
|
|
312
|
+
const lastVer = docEntries[docEntries.length - 1].version;
|
|
313
|
+
const num = parseFloat(lastVer.replace('v', ''));
|
|
314
|
+
if (!isNaN(num))
|
|
315
|
+
nextVer = Math.round((num + 0.1) * 10) / 10;
|
|
316
|
+
}
|
|
317
|
+
docEntries.push({
|
|
318
|
+
version: `v${nextVer.toFixed(1)}`,
|
|
319
|
+
date: new Date().toISOString(),
|
|
320
|
+
summary: decoded.docSummary,
|
|
321
|
+
content: decoded.docContent,
|
|
322
|
+
});
|
|
323
|
+
node.docEntries = docEntries;
|
|
324
|
+
changes.push(`docEntries(v${nextVer.toFixed(1)})`);
|
|
325
|
+
}
|
|
284
326
|
if (changes.length === 0)
|
|
285
327
|
return wrap('ℹ️ 无变更 — 请提供要更新的字段');
|
|
286
328
|
node.lastUpdated = new Date().toISOString();
|
|
@@ -314,10 +356,10 @@ export function registerFlowchartTools(server, ctx) {
|
|
|
314
356
|
boundFiles: [],
|
|
315
357
|
boundDirs: [],
|
|
316
358
|
boundTasks: [],
|
|
317
|
-
subFlowchart: null,
|
|
359
|
+
subFlowchart: n.subFlowchart || null,
|
|
318
360
|
position: null,
|
|
319
|
-
versions: [],
|
|
320
|
-
lastUpdated:
|
|
361
|
+
versions: [{ version: 'v1.0', date: new Date().toISOString(), changes: 'initial' }],
|
|
362
|
+
lastUpdated: new Date().toISOString(),
|
|
321
363
|
lastQueried: '',
|
|
322
364
|
}));
|
|
323
365
|
const fullEdges = (decoded.edges || []).map((e) => ({
|
|
@@ -479,6 +521,72 @@ export function registerFlowchartTools(server, ctx) {
|
|
|
479
521
|
const icon = isBind ? '🔗' : '⛓️';
|
|
480
522
|
return wrap(`${icon} ${isBind ? '绑定' : '解绑'}完成 [${decoded.nodeId}]: ${changes.join(', ')}`);
|
|
481
523
|
}
|
|
524
|
+
case 'create_chart': {
|
|
525
|
+
const newChartId = decoded.chartId;
|
|
526
|
+
if (!newChartId)
|
|
527
|
+
return wrap('❌ create_chart 需要 chartId (子图ID)');
|
|
528
|
+
if (newChartId === 'main')
|
|
529
|
+
return wrap('❌ 不能创建 main,主图已存在');
|
|
530
|
+
// 检查是否已存在
|
|
531
|
+
const existing = await client().getFlowchart(newChartId);
|
|
532
|
+
if (existing)
|
|
533
|
+
return wrap(`❌ 流程图 "${newChartId}" 已存在`);
|
|
534
|
+
const pChart = decoded.parentChart || 'main';
|
|
535
|
+
const pNode = decoded.parentNode;
|
|
536
|
+
// 构建子图数据
|
|
537
|
+
const subChartData = {
|
|
538
|
+
id: newChartId,
|
|
539
|
+
title: decoded.title || newChartId,
|
|
540
|
+
parentNode: pNode || null,
|
|
541
|
+
parentChart: pChart,
|
|
542
|
+
nodes: [],
|
|
543
|
+
edges: [],
|
|
544
|
+
};
|
|
545
|
+
// 如果提供了 nodes/edges,填充进去
|
|
546
|
+
if (decoded.nodes && decoded.nodes.length > 0) {
|
|
547
|
+
subChartData.nodes = decoded.nodes.map((n) => ({
|
|
548
|
+
id: n.id, label: n.label,
|
|
549
|
+
nodeType: n.nodeType || 'process', domain: n.domain || 'system',
|
|
550
|
+
input: n.input || [], output: n.output || [],
|
|
551
|
+
description: n.description || '', affiliation: n.affiliation || 'root',
|
|
552
|
+
boundDocs: [], boundFiles: [], boundDirs: [], boundTasks: [],
|
|
553
|
+
subFlowchart: null, position: null,
|
|
554
|
+
versions: [{ version: 'v1.0', date: new Date().toISOString(), changes: 'initial' }],
|
|
555
|
+
lastUpdated: new Date().toISOString(), lastQueried: '',
|
|
556
|
+
}));
|
|
557
|
+
}
|
|
558
|
+
if (decoded.edges && decoded.edges.length > 0) {
|
|
559
|
+
subChartData.edges = decoded.edges.map(e => ({
|
|
560
|
+
from: e.from, to: e.to, label: e.label || null, edgeType: e.edgeType || 'call',
|
|
561
|
+
}));
|
|
562
|
+
}
|
|
563
|
+
// 保存子图
|
|
564
|
+
await client().saveFlowchart(newChartId, subChartData);
|
|
565
|
+
// 自动更新父节点的 subFlowchart 引用
|
|
566
|
+
if (pNode) {
|
|
567
|
+
const parentChart = await client().getFlowchart(pChart);
|
|
568
|
+
if (parentChart) {
|
|
569
|
+
const parentNodeObj = (parentChart.nodes || []).find((n) => n.id === pNode);
|
|
570
|
+
if (parentNodeObj) {
|
|
571
|
+
parentNodeObj.subFlowchart = newChartId;
|
|
572
|
+
parentNodeObj.lastUpdated = new Date().toISOString();
|
|
573
|
+
await client().saveFlowchart(pChart, parentChart);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
const nodeCount = subChartData.nodes.length;
|
|
578
|
+
return wrap(`✅ 子图已创建: ${decoded.title || newChartId} [${newChartId}]\n父图: ${pChart}${pNode ? ` → 节点: ${pNode}` : ''}\n初始: ${nodeCount}节点`);
|
|
579
|
+
}
|
|
580
|
+
case 'delete_chart': {
|
|
581
|
+
const chartId = decoded.chartId;
|
|
582
|
+
if (!chartId)
|
|
583
|
+
return wrap('❌ delete_chart 需要 chartId');
|
|
584
|
+
if (chartId === 'main')
|
|
585
|
+
return wrap('❌ 不能删除主图 main');
|
|
586
|
+
// 后端自动级联: 清父节点引用 + 删子图的子图
|
|
587
|
+
await client().deleteFlowchart(chartId);
|
|
588
|
+
return wrap(`✅ 流程图已删除 [${chartId}] (子图已级联清理)`);
|
|
589
|
+
}
|
|
482
590
|
default:
|
|
483
591
|
return wrap(`❌ 未知 action: ${decoded.action}`);
|
|
484
592
|
}
|