@ppdocs/mcp 3.6.0 → 3.7.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.
@@ -92,17 +92,13 @@ export function registerDocQueryTools(server, _ctx) {
92
92
  .slice(0, decoded.limit ?? 10);
93
93
  if (matches.length === 0)
94
94
  return wrap(`No docs matched: ${rawQuery}`);
95
- const lines = [`Doc search: "${rawQuery}" (${matches.length} results)`, ''];
96
- for (const { chart, node } of matches) {
95
+ const rows = matches.map(({ chart, node }) => {
97
96
  const docCount = node.docEntries?.length ?? 0;
98
97
  const latest = docCount > 0 ? node.docEntries[docCount - 1] : null;
99
- lines.push(`- **${node.label}** [${chart.id}/${node.id}] history=${docCount}`);
100
- if (latest)
101
- lines.push(` current: ${shortDate(latest.date)} — ${latest.summary}`);
102
- if (node.description)
103
- lines.push(` desc: ${node.description.slice(0, 80)}${node.description.length > 80 ? '...' : ''}`);
104
- }
105
- return wrap(lines.join('\n'));
98
+ const summary = latest ? latest.summary.substring(0, 50) : (node.description?.substring(0, 50) || '');
99
+ return `| ${node.label} | ${chart.id}/${node.id} | ${docCount} | ${latest ? shortDate(latest.date).slice(5) : '-'} | ${summary} |`;
100
+ }).join('\n');
101
+ return wrap(`Doc search: "${rawQuery}" (${matches.length} results)\n\n| 节点 | 图谱 | 文档数 | 日期 | 摘要 |\n|:-----|:-----|:-------|:-----|:-----|\n${rows}`);
106
102
  }
107
103
  case 'list': {
108
104
  const charts = decoded.chartId
@@ -113,30 +109,43 @@ export function registerDocQueryTools(server, _ctx) {
113
109
  .map((n) => ({ chart, node: n })));
114
110
  if (nodesWithDocs.length === 0)
115
111
  return wrap('No nodes with documentation found.');
116
- const lines = [`Documented nodes: ${nodesWithDocs.length}`, ''];
117
- for (const { chart, node } of nodesWithDocs) {
112
+ const rows = nodesWithDocs.map(({ chart, node }) => {
118
113
  const docCount = node.docEntries?.length ?? 0;
119
114
  const latest = docCount > 0 ? node.docEntries[docCount - 1] : null;
120
- const latestInfo = latest ? ` | ${shortDate(latest.date)} ${latest.summary}` : '';
121
- lines.push(`- ${node.label} [${chart.id}/${node.id}] history=${docCount}${latestInfo}`);
122
- }
123
- return wrap(lines.join('\n'));
115
+ const summary = latest ? latest.summary.substring(0, 50) : '';
116
+ return `| ${node.label} | ${chart.id}/${node.id} | ${docCount} | ${latest ? shortDate(latest.date).slice(5) : '-'} | ${summary} |`;
117
+ }).join('\n');
118
+ return wrap(`Documented nodes: ${nodesWithDocs.length}\n\n| 节点 | 图谱 | 文档数 | 日期 | 摘要 |\n|:-----|:-----|:-------|:-----|:-----|\n${rows}`);
124
119
  }
125
120
  case 'read': {
126
121
  if (!decoded.nodeId)
127
122
  return wrap('read requires nodeId.');
128
- const chartId = decoded.chartId || 'main';
129
- const chart = (await getClient().getFlowchart(chartId));
123
+ let chart = null;
124
+ let foundChartId = decoded.chartId || '';
125
+ if (foundChartId) {
126
+ chart = (await getClient().getFlowchart(foundChartId));
127
+ }
128
+ else {
129
+ // 不指定 chartId 时自动搜全部图
130
+ const all = await loadAllCharts();
131
+ for (const c of all) {
132
+ if (c.nodes.some(n => n.id === decoded.nodeId)) {
133
+ chart = c;
134
+ foundChartId = c.id;
135
+ break;
136
+ }
137
+ }
138
+ }
130
139
  if (!chart)
131
- return wrap(`Flowchart not found: ${chartId}`);
140
+ return wrap(`Node not found: ${decoded.nodeId}${decoded.chartId ? ` in ${decoded.chartId}` : ' (searched all charts)'}`);
132
141
  const node = chart.nodes.find((n) => n.id === decoded.nodeId);
133
142
  if (!node)
134
- return wrap(`Node not found: ${decoded.nodeId} in ${chartId}`);
143
+ return wrap(`Node not found: ${decoded.nodeId} in ${foundChartId}`);
135
144
  const entries = node.docEntries ?? [];
136
145
  // history=true → 列出历史记录(标题+日期)
137
146
  if (decoded.history) {
138
147
  if (entries.length === 0)
139
- return wrap(`No history for ${node.label} [${chartId}/${decoded.nodeId}]`);
148
+ return wrap(`No history for ${node.label} [${foundChartId}/${decoded.nodeId}]`);
140
149
  const lines = [`## ${node.label} — history (${entries.length})`, ''];
141
150
  for (let i = entries.length - 1; i >= 0; i--) {
142
151
  const e = entries[i];
@@ -162,7 +171,7 @@ export function registerDocQueryTools(server, _ctx) {
162
171
  return wrap(lines.join('\n'));
163
172
  }
164
173
  // 默认: 返回当前文档 (description + 最新 docEntry)
165
- const lines = [`## ${node.label} [${chartId}/${node.id}]`, ''];
174
+ const lines = [`## ${node.label} [${foundChartId}/${node.id}]`, ''];
166
175
  if (node.description) {
167
176
  lines.push(node.description, '');
168
177
  }
@@ -6,16 +6,20 @@ import { wrap, safeTool } from './shared.js';
6
6
  export function registerStatusTool(server, ctx) {
7
7
  const client = () => getClient();
8
8
  server.tool('kg_status', '📊 项目速览仪表盘 — 一键了解项目健康。返回: 流程图节点数、活跃任务数、最近变更。每次对话开始建议首先调用', {}, async () => safeTool(async () => {
9
- const [charts, activeTasks] = await Promise.all([
9
+ const [charts, activeTasks, discussions] = await Promise.all([
10
10
  client().listFlowcharts(),
11
11
  client().listTasks('active'),
12
+ client().discussionList().catch(() => []),
12
13
  ]);
13
14
  const nodeCount = charts.reduce((sum, c) => sum + (c.nodeCount || 0), 0);
15
+ const activeDiscussions = discussions.filter((d) => d.status === 'active');
14
16
  const lines = [
15
17
  `📊 项目速览 [${ctx.projectId}]`,
18
+ `🆔 身份: ${ctx.user}${ctx.agentId !== 'default' ? ':' + ctx.agentId : ''}`,
16
19
  ``,
17
20
  `🔀 流程图: ${charts.length} 张 | 📦 节点: ${nodeCount} 个`,
18
21
  `📝 活跃任务: ${activeTasks.length} 个`,
22
+ `📨 活跃讨论: ${activeDiscussions.length} 个`,
19
23
  ];
20
24
  if (activeTasks.length > 0) {
21
25
  lines.push(``, `🔧 进行中的任务:`);
@@ -97,8 +97,13 @@ export function registerTaskTools(server, ctx) {
97
97
  }
98
98
  if (tasks.length === 0)
99
99
  return wrap(`📋 ${status === 'archived' ? '归档' : '活跃'}任务为空`);
100
- const list = tasks.map(t => `• [${t.status}] ${t.title}\n ID: ${t.id} | 更新: ${t.updated_at.split('T')[0]} | ${t.last_log || ''}`).join('\n');
101
- return wrap(`📋 ${tasks.length} 个任务:\n\n${list}`);
100
+ const rows = tasks.map(t => {
101
+ const icon = t.status === 'active' ? '🟢' : '⚪';
102
+ const date = t.updated_at?.split('T')[0]?.slice(5) || '';
103
+ const log = (t.last_log || '').substring(0, 40);
104
+ return `| ${icon} | ${t.title} | ${t.id} | ${date} | ${log} |`;
105
+ }).join('\n');
106
+ return wrap(`📋 共 ${tasks.length} 个任务\n\n| 状态 | 标题 | ID | 更新 | 最近日志 |\n|:-----|:-----|:---|:-----|:---------|\n${rows}`);
102
107
  }
103
108
  // 有 taskId = 获取详情 (结构化摘要)
104
109
  if (decoded.taskId) {
@@ -145,7 +150,24 @@ export function registerTaskTools(server, ctx) {
145
150
  const task = await client().getTask(matched[0].id, 'smart');
146
151
  if (!task)
147
152
  return wrap('任务详情获取失败');
148
- return wrap(`📝 ${task.title}\nID: ${task.id} | 状态: ${task.status}`);
153
+ const lines = [
154
+ `📝 ${task.title}`,
155
+ `ID: ${task.id} | 状态: ${task.status}`,
156
+ `创建: ${task.created_at?.split('T')[0] || ''}`,
157
+ ];
158
+ if (task.detail?.description)
159
+ lines.push(`\n📋 ${task.detail.description}`);
160
+ if (task.detail?.goals?.length) {
161
+ lines.push(`\n🎯 验收标准:`);
162
+ task.detail.goals.forEach((g, i) => lines.push(` ${i + 1}. ☐ ${g}`));
163
+ }
164
+ if (task.logs?.length) {
165
+ lines.push(`\n📊 进度日志 (${task.logs.length}条, 最近3条):`);
166
+ for (const log of task.logs.slice(-3)) {
167
+ lines.push(` [${log.log_type}] ${log.time?.split('T')[0] || ''}: ${log.content?.substring(0, 120)}`);
168
+ }
169
+ }
170
+ return wrap(lines.join('\n'));
149
171
  }
150
172
  const list = matched.map(t => `• [${t.status}] ${t.title}\n ID: ${t.id}`).join('\n');
151
173
  return wrap(`找到 ${matched.length} 个匹配任务:\n\n${list}\n\n请使用 taskId 获取详情`);
@@ -166,8 +188,7 @@ export function registerTaskTools(server, ctx) {
166
188
  : ' (无验收标准)';
167
189
  return wrap(`✅ 进度已记录 [${lastLog?.log_type || 'progress'}]\n` +
168
190
  `📋 ${task.title} | 日志: ${task.logs.length}条\n` +
169
- `\n🎯 验收标准:\n${goalsDisplay}\n` +
170
- `\n⚠️ 提示: 每完成一个步骤请立即追加进度,确保时间线完整`);
191
+ `\n🎯 验收标准:\n${goalsDisplay}`);
171
192
  }
172
193
  case 'archive': {
173
194
  if (!decoded.taskId)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ppdocs/mcp",
3
- "version": "3.6.0",
3
+ "version": "3.7.0",
4
4
  "description": "ppdocs MCP Server - Knowledge Graph for Claude",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",