bmall-mcp 1.7.0 → 1.8.1
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/README.md +15 -0
- package/dist/tools/requirements/index.d.ts.map +1 -1
- package/dist/tools/requirements/index.js +52 -12
- package/dist/tools/requirements/index.js.map +1 -1
- package/dist/tools/requirements/requirement-processor.d.ts +9 -0
- package/dist/tools/requirements/requirement-processor.d.ts.map +1 -1
- package/dist/tools/requirements/requirement-processor.js +67 -0
- package/dist/tools/requirements/requirement-processor.js.map +1 -1
- package/docs/generate-requirements-usage.md +3 -3
- package/package.json +1 -1
- package/src/tools/requirements/index.ts +62 -17
- package/src/tools/requirements/requirement-processor.ts +75 -0
package/README.md
CHANGED
|
@@ -204,6 +204,21 @@ src/
|
|
|
204
204
|
|
|
205
205
|
## Changelog
|
|
206
206
|
|
|
207
|
+
### v1.8.1 (2026-03-16)
|
|
208
|
+
- ✅ 新增 generate_requirements 工具详细调试日志
|
|
209
|
+
- ✅ 添加环境信息输出(工作目录、平台、主目录)
|
|
210
|
+
- ✅ 添加文件路径解析日志(绝对路径/相对路径)
|
|
211
|
+
- ✅ 添加文件操作日志(读取、目录创建、写入)
|
|
212
|
+
- ✅ 添加完整错误堆栈信息
|
|
213
|
+
- ✅ 优化错误诊断能力
|
|
214
|
+
|
|
215
|
+
### v1.8.0 (2026-03-16)
|
|
216
|
+
- ✅ 完善后端文档处理逻辑:添加智能缓存机制
|
|
217
|
+
- ✅ 新增后端文档缓存函数:saveBackendDocument、tryReadSavedBackend
|
|
218
|
+
- ✅ 优化后端文档处理流程:支持文件和网页两种形式的缓存
|
|
219
|
+
- ✅ 统一文档管理:所有输入材料(PRD、设计稿、后端文档)都支持智能缓存
|
|
220
|
+
- ✅ 更新使用文档:明确后端文档缓存机制和处理流程
|
|
221
|
+
|
|
207
222
|
### v1.7.0 (2026-03-16)
|
|
208
223
|
- ✅ 优化设计稿处理逻辑:统一保存设计稿内容到 design-doc.md
|
|
209
224
|
- ✅ 添加设计稿智能缓存:自动检测已保存的设计稿,避免重复读取
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/requirements/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/requirements/index.ts"],"names":[],"mappings":"AAsBA,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,0BAA0B;IAClC,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;QACvB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,aAAa,CAAC,EAAE;QACd,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAmCD,wBAAsB,oBAAoB,CACxC,MAAM,EAAE,0BAA0B,GACjC,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,iBAAiB,CAAC;QAClD,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH,CAAC,CAuJD"}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
-
import
|
|
2
|
+
import * as os from "os";
|
|
3
|
+
import { processRequirementDocument, tryReadSavedRequirement, tryReadSavedDesign, tryReadSavedBackend } from "./requirement-processor.js";
|
|
4
|
+
/**
|
|
5
|
+
* 调试日志输出
|
|
6
|
+
*/
|
|
7
|
+
function debugLog(message, data) {
|
|
8
|
+
const timestamp = new Date().toISOString();
|
|
9
|
+
const logMessage = `[DEBUG ${timestamp}] ${message}${data ? '\n' + JSON.stringify(data, null, 2) : ''}`;
|
|
10
|
+
console.error(logMessage);
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* 验证必填参数
|
|
5
14
|
*/
|
|
@@ -20,6 +29,12 @@ function validateRequiredParams(params) {
|
|
|
20
29
|
return { valid: true };
|
|
21
30
|
}
|
|
22
31
|
export async function generateRequirements(params) {
|
|
32
|
+
debugLog(`generateRequirements 开始`, {
|
|
33
|
+
params,
|
|
34
|
+
cwd: process.cwd(),
|
|
35
|
+
platform: os.platform(),
|
|
36
|
+
homedir: os.homedir()
|
|
37
|
+
});
|
|
23
38
|
try {
|
|
24
39
|
// 1. 验证必填参数
|
|
25
40
|
const validation = validateRequiredParams(params);
|
|
@@ -28,12 +43,15 @@ export async function generateRequirements(params) {
|
|
|
28
43
|
}
|
|
29
44
|
// 2. 处理需求文档输入
|
|
30
45
|
// 2.1 优先尝试读取已保存的 origin-requirement.md(智能缓存)
|
|
46
|
+
debugLog(`尝试读取已保存的需求文档`, { featureName: params.featureName });
|
|
31
47
|
const savedContent = await tryReadSavedRequirement(params.featureName);
|
|
32
48
|
if (!savedContent) {
|
|
49
|
+
debugLog(`未找到缓存,处理需求文档输入`);
|
|
33
50
|
// 2.2 没有缓存,处理需求文档输入
|
|
34
51
|
const requirementResult = await processRequirementDocument(params.requirementSource, params.featureName);
|
|
35
52
|
// 2.2.1 如果需要执行操作(读取 PDF/网页),直接返回
|
|
36
53
|
if (!requirementResult.success) {
|
|
54
|
+
debugLog(`需求文档处理失败`, { requirementResult });
|
|
37
55
|
return {
|
|
38
56
|
success: false,
|
|
39
57
|
message: requirementResult.message,
|
|
@@ -42,6 +60,9 @@ export async function generateRequirements(params) {
|
|
|
42
60
|
}
|
|
43
61
|
// 2.2.2 需求文档已读取并保存(Markdown 文件)
|
|
44
62
|
}
|
|
63
|
+
else {
|
|
64
|
+
debugLog(`找到缓存文档`, { contentLength: savedContent.length });
|
|
65
|
+
}
|
|
45
66
|
// 3. 检查设计稿
|
|
46
67
|
let designSourceInfo = "";
|
|
47
68
|
if (params.designSource) {
|
|
@@ -72,24 +93,35 @@ export async function generateRequirements(params) {
|
|
|
72
93
|
// 4. 处理后端文档
|
|
73
94
|
let backendSourceInfo = "";
|
|
74
95
|
if (params.backendSource) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
// 4.1 优先尝试读取已保存的后端文档
|
|
97
|
+
const savedBackend = await tryReadSavedBackend(params.featureName);
|
|
98
|
+
if (!savedBackend) {
|
|
99
|
+
// 4.2 没有缓存,处理后端文档
|
|
100
|
+
const backendResult = await processRequirementDocument(params.backendSource, params.featureName, "backend-doc.md");
|
|
101
|
+
if (!backendResult.success) {
|
|
102
|
+
return {
|
|
103
|
+
success: false,
|
|
104
|
+
message: backendResult.message,
|
|
105
|
+
needsAction: backendResult.needsAction,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
// 4.2.1 文件类型已保存,返回信息
|
|
109
|
+
if (params.backendSource.type === "file") {
|
|
110
|
+
backendSourceInfo = `**后端文档位置**:.specs/requirements/${params.featureName}/backend-doc.md\n`;
|
|
111
|
+
}
|
|
112
|
+
else if (params.backendSource.type === "url") {
|
|
113
|
+
backendSourceInfo = `**后端文档网页**:${params.backendSource.url || "后端文档网页 URL 未提供"}(请使用 Chrome DevTools MCP 读取并保存到 .specs/requirements/${params.featureName}/backend-doc.md)\n`;
|
|
114
|
+
}
|
|
85
115
|
}
|
|
86
|
-
else
|
|
116
|
+
else {
|
|
117
|
+
// 4.3 使用已保存的后端文档
|
|
87
118
|
backendSourceInfo = `**后端文档位置**:.specs/requirements/${params.featureName}/backend-doc.md\n`;
|
|
88
119
|
}
|
|
89
120
|
}
|
|
90
121
|
// 5. 生成分析提示词
|
|
91
122
|
const outputPath = `.specs/requirements/${params.featureName}/requirements.md`;
|
|
92
123
|
const originDocPath = `.specs/requirements/${params.featureName}/origin-requirement.md`;
|
|
124
|
+
debugLog(`生成输出路径`, { outputPath, originDocPath });
|
|
93
125
|
let message = "📝 需求文档已准备完毕\n\n";
|
|
94
126
|
message += `**原始文档位置**:${originDocPath}\n`;
|
|
95
127
|
if (designSourceInfo) {
|
|
@@ -100,6 +132,7 @@ export async function generateRequirements(params) {
|
|
|
100
132
|
}
|
|
101
133
|
message += `**目标输出位置**:${outputPath}\n\n`;
|
|
102
134
|
message += buildAnalysisPrompt(originDocPath, outputPath, params.designSource, params.backendSource);
|
|
135
|
+
debugLog(`返回分析提示词`);
|
|
103
136
|
return {
|
|
104
137
|
success: false,
|
|
105
138
|
message,
|
|
@@ -110,6 +143,13 @@ export async function generateRequirements(params) {
|
|
|
110
143
|
};
|
|
111
144
|
}
|
|
112
145
|
catch (error) {
|
|
146
|
+
debugLog(`发生错误`, {
|
|
147
|
+
error: error instanceof Error ? {
|
|
148
|
+
message: error.message,
|
|
149
|
+
stack: error.stack,
|
|
150
|
+
name: error.name
|
|
151
|
+
} : String(error)
|
|
152
|
+
});
|
|
113
153
|
if (error instanceof McpError) {
|
|
114
154
|
throw error;
|
|
115
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/requirements/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/requirements/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -36,5 +36,14 @@ export declare function saveDesignDocument(featureName: string, designContent: s
|
|
|
36
36
|
* 尝试读取已保存的设计稿文档
|
|
37
37
|
*/
|
|
38
38
|
export declare function tryReadSavedDesign(featureName: string): Promise<string | null>;
|
|
39
|
+
/**
|
|
40
|
+
* 保存后端文档内容到文件
|
|
41
|
+
* 用于保存从 PDF/网页读取的后端文档内容
|
|
42
|
+
*/
|
|
43
|
+
export declare function saveBackendDocument(featureName: string, backendContent: string): Promise<void>;
|
|
44
|
+
/**
|
|
45
|
+
* 尝试读取已保存的后端文档
|
|
46
|
+
*/
|
|
47
|
+
export declare function tryReadSavedBackend(featureName: string): Promise<string | null>;
|
|
39
48
|
export {};
|
|
40
49
|
//# sourceMappingURL=requirement-processor.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirement-processor.d.ts","sourceRoot":"","sources":["../../../src/tools/requirements/requirement-processor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"requirement-processor.d.ts","sourceRoot":"","sources":["../../../src/tools/requirements/requirement-processor.ts"],"names":[],"mappings":"AAcA,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE;QACZ,IAAI,EAAE,UAAU,GAAG,UAAU,GAAG,iBAAiB,CAAC;QAClD,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC;CACH;AAED,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,iBAAiB,EAAE,iBAAiB,GAAG,SAAS,EAChD,WAAW,EAAE,MAAM,EACnB,cAAc,GAAE,MAAgC,GAC/C,OAAO,CAAC,aAAa,CAAC,CAkHxB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAYxB"}
|
|
@@ -1,10 +1,28 @@
|
|
|
1
1
|
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import * as fs from "fs/promises";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
/**
|
|
6
|
+
* 调试日志输出
|
|
7
|
+
*/
|
|
8
|
+
function debugLog(message, data) {
|
|
9
|
+
const timestamp = new Date().toISOString();
|
|
10
|
+
const logMessage = `[DEBUG ${timestamp}] ${message}${data ? '\n' + JSON.stringify(data, null, 2) : ''}`;
|
|
11
|
+
console.error(logMessage);
|
|
12
|
+
}
|
|
3
13
|
/**
|
|
4
14
|
* 步骤 2:处理需求文档输入
|
|
5
15
|
* 这是整体流程的第二步,专门处理需求文档
|
|
6
16
|
*/
|
|
7
17
|
export async function processRequirementDocument(requirementSource, featureName, outputFileName = "origin-requirement.md") {
|
|
18
|
+
debugLog(`processRequirementDocument 开始`, {
|
|
19
|
+
requirementSource,
|
|
20
|
+
featureName,
|
|
21
|
+
outputFileName,
|
|
22
|
+
cwd: process.cwd(),
|
|
23
|
+
platform: os.platform(),
|
|
24
|
+
homedir: os.homedir()
|
|
25
|
+
});
|
|
8
26
|
// 2.1 校验是否提供了需求文档
|
|
9
27
|
if (!requirementSource) {
|
|
10
28
|
return {
|
|
@@ -26,10 +44,12 @@ export async function processRequirementDocument(requirementSource, featureName,
|
|
|
26
44
|
// 2.2 处理文件类型
|
|
27
45
|
if (requirementSource.type === "file") {
|
|
28
46
|
const filePath = requirementSource.path;
|
|
47
|
+
debugLog(`处理文件类型`, { filePath });
|
|
29
48
|
if (!filePath) {
|
|
30
49
|
throw new McpError(-32602, "文件路径不能为空");
|
|
31
50
|
}
|
|
32
51
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
52
|
+
debugLog(`文件扩展名`, { ext });
|
|
33
53
|
// 2.2.1 PDF 文件 - 返回读取指令
|
|
34
54
|
if (ext === "pdf") {
|
|
35
55
|
const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
|
|
@@ -49,12 +69,23 @@ export async function processRequirementDocument(requirementSource, featureName,
|
|
|
49
69
|
// 2.2.2 Markdown 文件 - 保存到固定位置
|
|
50
70
|
if (ext === "md" || ext === "markdown") {
|
|
51
71
|
const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
|
|
72
|
+
debugLog(`准备保存 Markdown 文件`, {
|
|
73
|
+
inputPath: filePath,
|
|
74
|
+
outputPath: outputMdPath,
|
|
75
|
+
isAbsolute: path.isAbsolute(filePath),
|
|
76
|
+
resolvedPath: path.resolve(filePath)
|
|
77
|
+
});
|
|
52
78
|
// 读取 Markdown 内容
|
|
53
79
|
const content = await fs.readFile(filePath, "utf-8");
|
|
80
|
+
debugLog(`成功读取文件内容`, { contentLength: content.length });
|
|
54
81
|
// 保存到固定位置
|
|
55
82
|
const outputDir = outputMdPath.substring(0, outputMdPath.lastIndexOf("/"));
|
|
83
|
+
debugLog(`准备创建目录`, { outputDir });
|
|
56
84
|
await fs.mkdir(outputDir, { recursive: true });
|
|
85
|
+
debugLog(`目录创建成功`, { outputDir });
|
|
86
|
+
debugLog(`准备写入文件`, { outputPath: outputMdPath });
|
|
57
87
|
await fs.writeFile(outputMdPath, content, "utf-8");
|
|
88
|
+
debugLog(`文件写入成功`, { outputPath: outputMdPath });
|
|
58
89
|
return {
|
|
59
90
|
success: true,
|
|
60
91
|
content,
|
|
@@ -109,11 +140,15 @@ export async function tryReadSavedRequirement(featureName) {
|
|
|
109
140
|
* 用于保存从 Figma MCP 读取的设计稿内容
|
|
110
141
|
*/
|
|
111
142
|
export async function saveDesignDocument(featureName, designContent) {
|
|
143
|
+
debugLog(`saveDesignDocument 开始`, { featureName });
|
|
112
144
|
const designDocPath = `.specs/requirements/${featureName}/design-doc.md`;
|
|
113
145
|
const outputDir = designDocPath.substring(0, designDocPath.lastIndexOf("/"));
|
|
146
|
+
debugLog(`设计稿准备创建目录`, { outputDir });
|
|
114
147
|
await fs.mkdir(outputDir, { recursive: true });
|
|
148
|
+
debugLog(`设计稿目录创建成功`);
|
|
115
149
|
await fs.writeFile(designDocPath, designContent, "utf-8");
|
|
116
150
|
console.log(`✅ 设计稿已保存到: ${designDocPath}`);
|
|
151
|
+
debugLog(`设计稿文件写入成功`, { outputPath: designDocPath });
|
|
117
152
|
}
|
|
118
153
|
/**
|
|
119
154
|
* 尝试读取已保存的设计稿文档
|
|
@@ -132,4 +167,36 @@ export async function tryReadSavedDesign(featureName) {
|
|
|
132
167
|
}
|
|
133
168
|
return null;
|
|
134
169
|
}
|
|
170
|
+
/**
|
|
171
|
+
* 保存后端文档内容到文件
|
|
172
|
+
* 用于保存从 PDF/网页读取的后端文档内容
|
|
173
|
+
*/
|
|
174
|
+
export async function saveBackendDocument(featureName, backendContent) {
|
|
175
|
+
debugLog(`saveBackendDocument 开始`, { featureName });
|
|
176
|
+
const backendDocPath = `.specs/requirements/${featureName}/backend-doc.md`;
|
|
177
|
+
const outputDir = backendDocPath.substring(0, backendDocPath.lastIndexOf("/"));
|
|
178
|
+
debugLog(`后端文档准备创建目录`, { outputDir });
|
|
179
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
180
|
+
debugLog(`后端文档目录创建成功`);
|
|
181
|
+
await fs.writeFile(backendDocPath, backendContent, "utf-8");
|
|
182
|
+
console.log(`✅ 后端文档已保存到: ${backendDocPath}`);
|
|
183
|
+
debugLog(`后端文档文件写入成功`, { outputPath: backendDocPath });
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 尝试读取已保存的后端文档
|
|
187
|
+
*/
|
|
188
|
+
export async function tryReadSavedBackend(featureName) {
|
|
189
|
+
const savedBackendPath = `.specs/requirements/${featureName}/backend-doc.md`;
|
|
190
|
+
try {
|
|
191
|
+
const savedContent = await fs.readFile(savedBackendPath, "utf-8");
|
|
192
|
+
if (savedContent) {
|
|
193
|
+
console.log(`✅ 使用已保存的后端文档: ${savedBackendPath}`);
|
|
194
|
+
return savedContent;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
// 文件不存在
|
|
199
|
+
}
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
135
202
|
//# sourceMappingURL=requirement-processor.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"requirement-processor.js","sourceRoot":"","sources":["../../../src/tools/requirements/requirement-processor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"requirement-processor.js","sourceRoot":"","sources":["../../../src/tools/requirements/requirement-processor.ts"],"names":[],"mappings":"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"}
|
|
@@ -152,7 +152,7 @@ AI 负责:
|
|
|
152
152
|
}
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
**返回**:同流程 1
|
|
155
|
+
**返回**:同流程 1(无设计稿信息,后端文档已缓存)
|
|
156
156
|
|
|
157
157
|
**AI 执行**:
|
|
158
158
|
1. 读取 `.specs/requirements/voice-recording/origin-requirement.md`
|
|
@@ -338,9 +338,9 @@ AI 负责:
|
|
|
338
338
|
**AI 执行**:
|
|
339
339
|
1. 使用 Figma MCP 工具读取设计稿,保存到 `.specs/requirements/voice-recording/design-doc.md`
|
|
340
340
|
2. 使用 Chrome DevTools MCP 读取后端文档网页,保存到 `.specs/requirements/voice-recording/backend-doc.md`
|
|
341
|
-
3.
|
|
341
|
+
3. 重新调用工具(工具会使用已保存的设计稿和后端文档)
|
|
342
342
|
|
|
343
|
-
**第 3 次调用**:同流程 1
|
|
343
|
+
**第 3 次调用**:同流程 1(所有文档已缓存)
|
|
344
344
|
|
|
345
345
|
---
|
|
346
346
|
|
package/package.json
CHANGED
|
@@ -1,11 +1,25 @@
|
|
|
1
1
|
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
import * as fs from "fs/promises";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as os from "os";
|
|
2
5
|
import {
|
|
3
6
|
processRequirementDocument,
|
|
4
7
|
tryReadSavedRequirement,
|
|
5
8
|
saveDesignDocument,
|
|
6
|
-
tryReadSavedDesign
|
|
9
|
+
tryReadSavedDesign,
|
|
10
|
+
saveBackendDocument,
|
|
11
|
+
tryReadSavedBackend
|
|
7
12
|
} from "./requirement-processor.js";
|
|
8
13
|
|
|
14
|
+
/**
|
|
15
|
+
* 调试日志输出
|
|
16
|
+
*/
|
|
17
|
+
function debugLog(message: string, data?: any) {
|
|
18
|
+
const timestamp = new Date().toISOString();
|
|
19
|
+
const logMessage = `[DEBUG ${timestamp}] ${message}${data ? '\n' + JSON.stringify(data, null, 2) : ''}`;
|
|
20
|
+
console.error(logMessage);
|
|
21
|
+
}
|
|
22
|
+
|
|
9
23
|
interface RequirementSource {
|
|
10
24
|
type: "file" | "url";
|
|
11
25
|
path?: string;
|
|
@@ -70,6 +84,13 @@ export async function generateRequirements(
|
|
|
70
84
|
instruction: string;
|
|
71
85
|
};
|
|
72
86
|
}> {
|
|
87
|
+
debugLog(`generateRequirements 开始`, {
|
|
88
|
+
params,
|
|
89
|
+
cwd: process.cwd(),
|
|
90
|
+
platform: os.platform(),
|
|
91
|
+
homedir: os.homedir()
|
|
92
|
+
});
|
|
93
|
+
|
|
73
94
|
try {
|
|
74
95
|
// 1. 验证必填参数
|
|
75
96
|
const validation = validateRequiredParams(params);
|
|
@@ -80,8 +101,10 @@ export async function generateRequirements(
|
|
|
80
101
|
// 2. 处理需求文档输入
|
|
81
102
|
|
|
82
103
|
// 2.1 优先尝试读取已保存的 origin-requirement.md(智能缓存)
|
|
104
|
+
debugLog(`尝试读取已保存的需求文档`, { featureName: params.featureName });
|
|
83
105
|
const savedContent = await tryReadSavedRequirement(params.featureName);
|
|
84
106
|
if (!savedContent) {
|
|
107
|
+
debugLog(`未找到缓存,处理需求文档输入`);
|
|
85
108
|
// 2.2 没有缓存,处理需求文档输入
|
|
86
109
|
const requirementResult = await processRequirementDocument(
|
|
87
110
|
params.requirementSource,
|
|
@@ -90,6 +113,7 @@ export async function generateRequirements(
|
|
|
90
113
|
|
|
91
114
|
// 2.2.1 如果需要执行操作(读取 PDF/网页),直接返回
|
|
92
115
|
if (!requirementResult.success) {
|
|
116
|
+
debugLog(`需求文档处理失败`, { requirementResult });
|
|
93
117
|
return {
|
|
94
118
|
success: false,
|
|
95
119
|
message: requirementResult.message!,
|
|
@@ -98,6 +122,8 @@ export async function generateRequirements(
|
|
|
98
122
|
}
|
|
99
123
|
|
|
100
124
|
// 2.2.2 需求文档已读取并保存(Markdown 文件)
|
|
125
|
+
} else {
|
|
126
|
+
debugLog(`找到缓存文档`, { contentLength: savedContent.length });
|
|
101
127
|
}
|
|
102
128
|
|
|
103
129
|
// 3. 检查设计稿
|
|
@@ -136,23 +162,33 @@ export async function generateRequirements(
|
|
|
136
162
|
// 4. 处理后端文档
|
|
137
163
|
let backendSourceInfo = "";
|
|
138
164
|
if (params.backendSource) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
params.featureName,
|
|
142
|
-
"backend-doc.md"
|
|
143
|
-
);
|
|
165
|
+
// 4.1 优先尝试读取已保存的后端文档
|
|
166
|
+
const savedBackend = await tryReadSavedBackend(params.featureName);
|
|
144
167
|
|
|
145
|
-
if (!
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
168
|
+
if (!savedBackend) {
|
|
169
|
+
// 4.2 没有缓存,处理后端文档
|
|
170
|
+
const backendResult = await processRequirementDocument(
|
|
171
|
+
params.backendSource,
|
|
172
|
+
params.featureName,
|
|
173
|
+
"backend-doc.md"
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
if (!backendResult.success) {
|
|
177
|
+
return {
|
|
178
|
+
success: false,
|
|
179
|
+
message: backendResult.message!,
|
|
180
|
+
needsAction: backendResult.needsAction,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// 4.2.1 文件类型已保存,返回信息
|
|
185
|
+
if (params.backendSource.type === "file") {
|
|
186
|
+
backendSourceInfo = `**后端文档位置**:.specs/requirements/${params.featureName}/backend-doc.md\n`;
|
|
187
|
+
} else if (params.backendSource.type === "url") {
|
|
188
|
+
backendSourceInfo = `**后端文档网页**:${params.backendSource.url || "后端文档网页 URL 未提供"}(请使用 Chrome DevTools MCP 读取并保存到 .specs/requirements/${params.featureName}/backend-doc.md)\n`;
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
// 4.3 使用已保存的后端文档
|
|
156
192
|
backendSourceInfo = `**后端文档位置**:.specs/requirements/${params.featureName}/backend-doc.md\n`;
|
|
157
193
|
}
|
|
158
194
|
}
|
|
@@ -160,6 +196,7 @@ export async function generateRequirements(
|
|
|
160
196
|
// 5. 生成分析提示词
|
|
161
197
|
const outputPath = `.specs/requirements/${params.featureName}/requirements.md`;
|
|
162
198
|
const originDocPath = `.specs/requirements/${params.featureName}/origin-requirement.md`;
|
|
199
|
+
debugLog(`生成输出路径`, { outputPath, originDocPath });
|
|
163
200
|
|
|
164
201
|
let message = "📝 需求文档已准备完毕\n\n";
|
|
165
202
|
message += `**原始文档位置**:${originDocPath}\n`;
|
|
@@ -172,6 +209,7 @@ export async function generateRequirements(
|
|
|
172
209
|
message += `**目标输出位置**:${outputPath}\n\n`;
|
|
173
210
|
message += buildAnalysisPrompt(originDocPath, outputPath, params.designSource, params.backendSource);
|
|
174
211
|
|
|
212
|
+
debugLog(`返回分析提示词`);
|
|
175
213
|
return {
|
|
176
214
|
success: false,
|
|
177
215
|
message,
|
|
@@ -181,6 +219,13 @@ export async function generateRequirements(
|
|
|
181
219
|
},
|
|
182
220
|
};
|
|
183
221
|
} catch (error) {
|
|
222
|
+
debugLog(`发生错误`, {
|
|
223
|
+
error: error instanceof Error ? {
|
|
224
|
+
message: error.message,
|
|
225
|
+
stack: error.stack,
|
|
226
|
+
name: error.name
|
|
227
|
+
} : String(error)
|
|
228
|
+
});
|
|
184
229
|
if (error instanceof McpError) {
|
|
185
230
|
throw error;
|
|
186
231
|
}
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import * as fs from "fs/promises";
|
|
3
|
+
import * as path from "path";
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* 调试日志输出
|
|
8
|
+
*/
|
|
9
|
+
function debugLog(message: string, data?: any) {
|
|
10
|
+
const timestamp = new Date().toISOString();
|
|
11
|
+
const logMessage = `[DEBUG ${timestamp}] ${message}${data ? '\n' + JSON.stringify(data, null, 2) : ''}`;
|
|
12
|
+
console.error(logMessage);
|
|
13
|
+
}
|
|
3
14
|
|
|
4
15
|
interface RequirementSource {
|
|
5
16
|
type: "file" | "url";
|
|
@@ -32,6 +43,14 @@ export async function processRequirementDocument(
|
|
|
32
43
|
featureName: string,
|
|
33
44
|
outputFileName: string = "origin-requirement.md"
|
|
34
45
|
): Promise<ProcessResult> {
|
|
46
|
+
debugLog(`processRequirementDocument 开始`, {
|
|
47
|
+
requirementSource,
|
|
48
|
+
featureName,
|
|
49
|
+
outputFileName,
|
|
50
|
+
cwd: process.cwd(),
|
|
51
|
+
platform: os.platform(),
|
|
52
|
+
homedir: os.homedir()
|
|
53
|
+
});
|
|
35
54
|
// 2.1 校验是否提供了需求文档
|
|
36
55
|
if (!requirementSource) {
|
|
37
56
|
return {
|
|
@@ -54,11 +73,13 @@ export async function processRequirementDocument(
|
|
|
54
73
|
// 2.2 处理文件类型
|
|
55
74
|
if (requirementSource.type === "file") {
|
|
56
75
|
const filePath = requirementSource.path;
|
|
76
|
+
debugLog(`处理文件类型`, { filePath });
|
|
57
77
|
if (!filePath) {
|
|
58
78
|
throw new McpError(-32602, "文件路径不能为空");
|
|
59
79
|
}
|
|
60
80
|
|
|
61
81
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
82
|
+
debugLog(`文件扩展名`, { ext });
|
|
62
83
|
|
|
63
84
|
// 2.2.1 PDF 文件 - 返回读取指令
|
|
64
85
|
if (ext === "pdf") {
|
|
@@ -80,14 +101,26 @@ export async function processRequirementDocument(
|
|
|
80
101
|
// 2.2.2 Markdown 文件 - 保存到固定位置
|
|
81
102
|
if (ext === "md" || ext === "markdown") {
|
|
82
103
|
const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
|
|
104
|
+
debugLog(`准备保存 Markdown 文件`, {
|
|
105
|
+
inputPath: filePath,
|
|
106
|
+
outputPath: outputMdPath,
|
|
107
|
+
isAbsolute: path.isAbsolute(filePath),
|
|
108
|
+
resolvedPath: path.resolve(filePath)
|
|
109
|
+
});
|
|
83
110
|
|
|
84
111
|
// 读取 Markdown 内容
|
|
85
112
|
const content = await fs.readFile(filePath, "utf-8");
|
|
113
|
+
debugLog(`成功读取文件内容`, { contentLength: content.length });
|
|
86
114
|
|
|
87
115
|
// 保存到固定位置
|
|
88
116
|
const outputDir = outputMdPath.substring(0, outputMdPath.lastIndexOf("/"));
|
|
117
|
+
debugLog(`准备创建目录`, { outputDir });
|
|
89
118
|
await fs.mkdir(outputDir, { recursive: true });
|
|
119
|
+
debugLog(`目录创建成功`, { outputDir });
|
|
120
|
+
|
|
121
|
+
debugLog(`准备写入文件`, { outputPath: outputMdPath });
|
|
90
122
|
await fs.writeFile(outputMdPath, content, "utf-8");
|
|
123
|
+
debugLog(`文件写入成功`, { outputPath: outputMdPath });
|
|
91
124
|
|
|
92
125
|
return {
|
|
93
126
|
success: true,
|
|
@@ -153,11 +186,15 @@ export async function saveDesignDocument(
|
|
|
153
186
|
featureName: string,
|
|
154
187
|
designContent: string
|
|
155
188
|
): Promise<void> {
|
|
189
|
+
debugLog(`saveDesignDocument 开始`, { featureName });
|
|
156
190
|
const designDocPath = `.specs/requirements/${featureName}/design-doc.md`;
|
|
157
191
|
const outputDir = designDocPath.substring(0, designDocPath.lastIndexOf("/"));
|
|
192
|
+
debugLog(`设计稿准备创建目录`, { outputDir });
|
|
158
193
|
await fs.mkdir(outputDir, { recursive: true });
|
|
194
|
+
debugLog(`设计稿目录创建成功`);
|
|
159
195
|
await fs.writeFile(designDocPath, designContent, "utf-8");
|
|
160
196
|
console.log(`✅ 设计稿已保存到: ${designDocPath}`);
|
|
197
|
+
debugLog(`设计稿文件写入成功`, { outputPath: designDocPath });
|
|
161
198
|
}
|
|
162
199
|
|
|
163
200
|
/**
|
|
@@ -178,3 +215,41 @@ export async function tryReadSavedDesign(
|
|
|
178
215
|
}
|
|
179
216
|
return null;
|
|
180
217
|
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* 保存后端文档内容到文件
|
|
221
|
+
* 用于保存从 PDF/网页读取的后端文档内容
|
|
222
|
+
*/
|
|
223
|
+
export async function saveBackendDocument(
|
|
224
|
+
featureName: string,
|
|
225
|
+
backendContent: string
|
|
226
|
+
): Promise<void> {
|
|
227
|
+
debugLog(`saveBackendDocument 开始`, { featureName });
|
|
228
|
+
const backendDocPath = `.specs/requirements/${featureName}/backend-doc.md`;
|
|
229
|
+
const outputDir = backendDocPath.substring(0, backendDocPath.lastIndexOf("/"));
|
|
230
|
+
debugLog(`后端文档准备创建目录`, { outputDir });
|
|
231
|
+
await fs.mkdir(outputDir, { recursive: true });
|
|
232
|
+
debugLog(`后端文档目录创建成功`);
|
|
233
|
+
await fs.writeFile(backendDocPath, backendContent, "utf-8");
|
|
234
|
+
console.log(`✅ 后端文档已保存到: ${backendDocPath}`);
|
|
235
|
+
debugLog(`后端文档文件写入成功`, { outputPath: backendDocPath });
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* 尝试读取已保存的后端文档
|
|
240
|
+
*/
|
|
241
|
+
export async function tryReadSavedBackend(
|
|
242
|
+
featureName: string
|
|
243
|
+
): Promise<string | null> {
|
|
244
|
+
const savedBackendPath = `.specs/requirements/${featureName}/backend-doc.md`;
|
|
245
|
+
try {
|
|
246
|
+
const savedContent = await fs.readFile(savedBackendPath, "utf-8");
|
|
247
|
+
if (savedContent) {
|
|
248
|
+
console.log(`✅ 使用已保存的后端文档: ${savedBackendPath}`);
|
|
249
|
+
return savedContent;
|
|
250
|
+
}
|
|
251
|
+
} catch (error) {
|
|
252
|
+
// 文件不存在
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|