bmall-mcp 1.8.1 → 1.8.2
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 +7 -0
- package/dist/tools/requirements/index.d.ts.map +1 -1
- package/dist/tools/requirements/index.js +22 -10
- package/dist/tools/requirements/index.js.map +1 -1
- package/dist/tools/requirements/requirement-processor.d.ts +15 -5
- package/dist/tools/requirements/requirement-processor.d.ts.map +1 -1
- package/dist/tools/requirements/requirement-processor.js +59 -18
- package/dist/tools/requirements/requirement-processor.js.map +1 -1
- package/package.json +1 -1
- package/src/tools/requirements/index.ts +27 -10
- package/src/tools/requirements/requirement-processor.ts +67 -18
package/README.md
CHANGED
|
@@ -204,6 +204,13 @@ src/
|
|
|
204
204
|
|
|
205
205
|
## Changelog
|
|
206
206
|
|
|
207
|
+
### v1.8.2 (2026-03-16)
|
|
208
|
+
- ✅ 修复工作目录问题:MCP 在根目录 `/` 运行时无法创建 `.specs` 目录
|
|
209
|
+
- ✅ 新增项目根目录自动识别:从输入文件的绝对路径智能提取项目根目录
|
|
210
|
+
- ✅ 优化路径处理:所有输出路径使用绝对路径,避免相对路径的依赖问题
|
|
211
|
+
- ✅ 完善 getProjectRoot 函数:支持从 `.specs` 路径自动识别项目根目录
|
|
212
|
+
- ✅ 更新所有文件操作函数:使用 buildOutputPath 生成绝对路径
|
|
213
|
+
|
|
207
214
|
### v1.8.1 (2026-03-16)
|
|
208
215
|
- ✅ 新增 generate_requirements 工具详细调试日志
|
|
209
216
|
- ✅ 添加环境信息输出(工作目录、平台、主目录)
|
|
@@ -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":"AAwBA,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,CAsKD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { McpError } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
import * as os from "os";
|
|
3
|
-
import { processRequirementDocument, tryReadSavedRequirement, tryReadSavedDesign, tryReadSavedBackend } from "./requirement-processor.js";
|
|
3
|
+
import { processRequirementDocument, tryReadSavedRequirement, tryReadSavedDesign, tryReadSavedBackend, getProjectRoot, buildOutputPath } from "./requirement-processor.js";
|
|
4
4
|
/**
|
|
5
5
|
* 调试日志输出
|
|
6
6
|
*/
|
|
@@ -42,9 +42,15 @@ export async function generateRequirements(params) {
|
|
|
42
42
|
return validation.error;
|
|
43
43
|
}
|
|
44
44
|
// 2. 处理需求文档输入
|
|
45
|
+
// 2.0 计算项目根目录(从输入路径提取)
|
|
46
|
+
let projectRoot = process.cwd();
|
|
47
|
+
if (params.requirementSource.type === "file" && params.requirementSource.path) {
|
|
48
|
+
projectRoot = getProjectRoot(params.requirementSource.path);
|
|
49
|
+
}
|
|
50
|
+
debugLog(`计算项目根目录`, { projectRoot, cwd: process.cwd() });
|
|
45
51
|
// 2.1 优先尝试读取已保存的 origin-requirement.md(智能缓存)
|
|
46
|
-
debugLog(`尝试读取已保存的需求文档`, { featureName: params.featureName });
|
|
47
|
-
const savedContent = await tryReadSavedRequirement(params.featureName);
|
|
52
|
+
debugLog(`尝试读取已保存的需求文档`, { featureName: params.featureName, projectRoot });
|
|
53
|
+
const savedContent = await tryReadSavedRequirement(params.featureName, projectRoot);
|
|
48
54
|
if (!savedContent) {
|
|
49
55
|
debugLog(`未找到缓存,处理需求文档输入`);
|
|
50
56
|
// 2.2 没有缓存,处理需求文档输入
|
|
@@ -71,6 +77,9 @@ export async function generateRequirements(params) {
|
|
|
71
77
|
if (!savedDesign) {
|
|
72
78
|
// 3.2 没有缓存,处理设计稿
|
|
73
79
|
if (params.designSource.type === "file") {
|
|
80
|
+
// 从设计稿路径重新计算项目根目录
|
|
81
|
+
const designProjectRoot = getProjectRoot(params.designSource.path);
|
|
82
|
+
debugLog(`设计稿项目根目录`, { designProjectRoot });
|
|
74
83
|
const designResult = await processRequirementDocument(params.designSource, params.featureName, "design-doc.md");
|
|
75
84
|
if (!designResult.success) {
|
|
76
85
|
return {
|
|
@@ -79,7 +88,7 @@ export async function generateRequirements(params) {
|
|
|
79
88
|
needsAction: designResult.needsAction,
|
|
80
89
|
};
|
|
81
90
|
}
|
|
82
|
-
designSourceInfo =
|
|
91
|
+
designSourceInfo = `**设计稿位置**:${buildOutputPath(params.featureName, "design-doc.md", designProjectRoot)}\n`;
|
|
83
92
|
}
|
|
84
93
|
else if (params.designSource.type === "figma") {
|
|
85
94
|
designSourceInfo = `**设计稿链接**:${params.designSource.url || "Figma 链接未提供"}(请使用 Figma MCP 读取并保存到 .specs/requirements/${params.featureName}/design-doc.md)\n`;
|
|
@@ -87,7 +96,7 @@ export async function generateRequirements(params) {
|
|
|
87
96
|
}
|
|
88
97
|
else {
|
|
89
98
|
// 3.3 使用已保存的设计稿
|
|
90
|
-
designSourceInfo =
|
|
99
|
+
designSourceInfo = `**设计稿位置**:${buildOutputPath(params.featureName, "design-doc.md", projectRoot)}\n`;
|
|
91
100
|
}
|
|
92
101
|
}
|
|
93
102
|
// 4. 处理后端文档
|
|
@@ -97,6 +106,9 @@ export async function generateRequirements(params) {
|
|
|
97
106
|
const savedBackend = await tryReadSavedBackend(params.featureName);
|
|
98
107
|
if (!savedBackend) {
|
|
99
108
|
// 4.2 没有缓存,处理后端文档
|
|
109
|
+
// 从后端文档路径重新计算项目根目录
|
|
110
|
+
const backendProjectRoot = getProjectRoot(params.backendSource.path);
|
|
111
|
+
debugLog(`后端文档项目根目录`, { backendProjectRoot });
|
|
100
112
|
const backendResult = await processRequirementDocument(params.backendSource, params.featureName, "backend-doc.md");
|
|
101
113
|
if (!backendResult.success) {
|
|
102
114
|
return {
|
|
@@ -107,7 +119,7 @@ export async function generateRequirements(params) {
|
|
|
107
119
|
}
|
|
108
120
|
// 4.2.1 文件类型已保存,返回信息
|
|
109
121
|
if (params.backendSource.type === "file") {
|
|
110
|
-
backendSourceInfo =
|
|
122
|
+
backendSourceInfo = `**后端文档位置**:${buildOutputPath(params.featureName, "backend-doc.md", backendProjectRoot)}\n`;
|
|
111
123
|
}
|
|
112
124
|
else if (params.backendSource.type === "url") {
|
|
113
125
|
backendSourceInfo = `**后端文档网页**:${params.backendSource.url || "后端文档网页 URL 未提供"}(请使用 Chrome DevTools MCP 读取并保存到 .specs/requirements/${params.featureName}/backend-doc.md)\n`;
|
|
@@ -115,13 +127,13 @@ export async function generateRequirements(params) {
|
|
|
115
127
|
}
|
|
116
128
|
else {
|
|
117
129
|
// 4.3 使用已保存的后端文档
|
|
118
|
-
backendSourceInfo =
|
|
130
|
+
backendSourceInfo = `**后端文档位置**:${buildOutputPath(params.featureName, "backend-doc.md", projectRoot)}\n`;
|
|
119
131
|
}
|
|
120
132
|
}
|
|
121
133
|
// 5. 生成分析提示词
|
|
122
|
-
const outputPath =
|
|
123
|
-
const originDocPath =
|
|
124
|
-
debugLog(`生成输出路径`, { outputPath, originDocPath });
|
|
134
|
+
const outputPath = buildOutputPath(params.featureName, "requirements.md", projectRoot);
|
|
135
|
+
const originDocPath = buildOutputPath(params.featureName, "origin-requirement.md", projectRoot);
|
|
136
|
+
debugLog(`生成输出路径`, { outputPath, originDocPath, projectRoot });
|
|
125
137
|
let message = "📝 需求文档已准备完毕\n\n";
|
|
126
138
|
message += `**原始文档位置**:${originDocPath}\n`;
|
|
127
139
|
if (designSourceInfo) {
|
|
@@ -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;AAG9D,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,EACL,0BAA0B,EAC1B,uBAAuB,EAEvB,kBAAkB,EAElB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/tools/requirements/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 从输入路径获取项目根目录
|
|
3
|
+
* 如果输入路径是绝对路径,返回该路径的项目根目录
|
|
4
|
+
* 否则使用当前工作目录
|
|
5
|
+
*/
|
|
6
|
+
export declare function getProjectRoot(inputPath: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* 构建输出路径(使用绝对路径)
|
|
9
|
+
*/
|
|
10
|
+
export declare function buildOutputPath(featureName: string, fileName: string, projectRoot: string): string;
|
|
1
11
|
interface RequirementSource {
|
|
2
12
|
type: "file" | "url";
|
|
3
13
|
path?: string;
|
|
@@ -26,24 +36,24 @@ export declare function processRequirementDocument(requirementSource: Requiremen
|
|
|
26
36
|
* 尝试读取已保存的需求文档
|
|
27
37
|
* 如果用户之前已经按照指令保存了文件,优先使用已保存的内容
|
|
28
38
|
*/
|
|
29
|
-
export declare function tryReadSavedRequirement(featureName: string): Promise<string | null>;
|
|
39
|
+
export declare function tryReadSavedRequirement(featureName: string, projectRoot?: string): Promise<string | null>;
|
|
30
40
|
/**
|
|
31
41
|
* 保存设计稿内容到文件
|
|
32
42
|
* 用于保存从 Figma MCP 读取的设计稿内容
|
|
33
43
|
*/
|
|
34
|
-
export declare function saveDesignDocument(featureName: string, designContent: string): Promise<void>;
|
|
44
|
+
export declare function saveDesignDocument(featureName: string, designContent: string, projectRoot?: string): Promise<void>;
|
|
35
45
|
/**
|
|
36
46
|
* 尝试读取已保存的设计稿文档
|
|
37
47
|
*/
|
|
38
|
-
export declare function tryReadSavedDesign(featureName: string): Promise<string | null>;
|
|
48
|
+
export declare function tryReadSavedDesign(featureName: string, projectRoot?: string): Promise<string | null>;
|
|
39
49
|
/**
|
|
40
50
|
* 保存后端文档内容到文件
|
|
41
51
|
* 用于保存从 PDF/网页读取的后端文档内容
|
|
42
52
|
*/
|
|
43
|
-
export declare function saveBackendDocument(featureName: string, backendContent: string): Promise<void>;
|
|
53
|
+
export declare function saveBackendDocument(featureName: string, backendContent: string, projectRoot?: string): Promise<void>;
|
|
44
54
|
/**
|
|
45
55
|
* 尝试读取已保存的后端文档
|
|
46
56
|
*/
|
|
47
|
-
export declare function tryReadSavedBackend(featureName: string): Promise<string | null>;
|
|
57
|
+
export declare function tryReadSavedBackend(featureName: string, projectRoot?: string): Promise<string | null>;
|
|
48
58
|
export {};
|
|
49
59
|
//# 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":"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,
|
|
1
|
+
{"version":3,"file":"requirement-processor.d.ts","sourceRoot":"","sources":["../../../src/tools/requirements/requirement-processor.ts"],"names":[],"mappings":"AAcA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAexD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAElG;AAED,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,CAyHxB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcxB;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcxB;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAWf;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,WAAW,EAAE,MAAM,EACnB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcxB"}
|
|
@@ -10,6 +10,33 @@ function debugLog(message, data) {
|
|
|
10
10
|
const logMessage = `[DEBUG ${timestamp}] ${message}${data ? '\n' + JSON.stringify(data, null, 2) : ''}`;
|
|
11
11
|
console.error(logMessage);
|
|
12
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* 从输入路径获取项目根目录
|
|
15
|
+
* 如果输入路径是绝对路径,返回该路径的项目根目录
|
|
16
|
+
* 否则使用当前工作目录
|
|
17
|
+
*/
|
|
18
|
+
export function getProjectRoot(inputPath) {
|
|
19
|
+
if (path.isAbsolute(inputPath)) {
|
|
20
|
+
// 对于绝对路径,我们假设项目根目录是 .specs 的父目录
|
|
21
|
+
// 例如:/path/to/project/.specs/requirements/xxx
|
|
22
|
+
// 我们需要找到 /path/to/project
|
|
23
|
+
const parts = inputPath.split(path.sep);
|
|
24
|
+
const specsIndex = parts.indexOf('.specs');
|
|
25
|
+
if (specsIndex > 0) {
|
|
26
|
+
return parts.slice(0, specsIndex).join(path.sep);
|
|
27
|
+
}
|
|
28
|
+
// 如果没有找到 .specs,返回文件所在目录
|
|
29
|
+
return path.dirname(inputPath);
|
|
30
|
+
}
|
|
31
|
+
// 对于相对路径,使用当前工作目录
|
|
32
|
+
return process.cwd();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 构建输出路径(使用绝对路径)
|
|
36
|
+
*/
|
|
37
|
+
export function buildOutputPath(featureName, fileName, projectRoot) {
|
|
38
|
+
return path.join(projectRoot, '.specs', 'requirements', featureName, fileName);
|
|
39
|
+
}
|
|
13
40
|
/**
|
|
14
41
|
* 步骤 2:处理需求文档输入
|
|
15
42
|
* 这是整体流程的第二步,专门处理需求文档
|
|
@@ -52,7 +79,8 @@ export async function processRequirementDocument(requirementSource, featureName,
|
|
|
52
79
|
debugLog(`文件扩展名`, { ext });
|
|
53
80
|
// 2.2.1 PDF 文件 - 返回读取指令
|
|
54
81
|
if (ext === "pdf") {
|
|
55
|
-
const
|
|
82
|
+
const projectRoot = getProjectRoot(filePath);
|
|
83
|
+
const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
|
|
56
84
|
return {
|
|
57
85
|
success: false,
|
|
58
86
|
message: `📄 检测到 PDF 文件
|
|
@@ -68,10 +96,12 @@ export async function processRequirementDocument(requirementSource, featureName,
|
|
|
68
96
|
}
|
|
69
97
|
// 2.2.2 Markdown 文件 - 保存到固定位置
|
|
70
98
|
if (ext === "md" || ext === "markdown") {
|
|
71
|
-
const
|
|
99
|
+
const projectRoot = getProjectRoot(filePath);
|
|
100
|
+
const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
|
|
72
101
|
debugLog(`准备保存 Markdown 文件`, {
|
|
73
102
|
inputPath: filePath,
|
|
74
103
|
outputPath: outputMdPath,
|
|
104
|
+
projectRoot,
|
|
75
105
|
isAbsolute: path.isAbsolute(filePath),
|
|
76
106
|
resolvedPath: path.resolve(filePath)
|
|
77
107
|
});
|
|
@@ -79,7 +109,7 @@ export async function processRequirementDocument(requirementSource, featureName,
|
|
|
79
109
|
const content = await fs.readFile(filePath, "utf-8");
|
|
80
110
|
debugLog(`成功读取文件内容`, { contentLength: content.length });
|
|
81
111
|
// 保存到固定位置
|
|
82
|
-
const outputDir =
|
|
112
|
+
const outputDir = path.dirname(outputMdPath);
|
|
83
113
|
debugLog(`准备创建目录`, { outputDir });
|
|
84
114
|
await fs.mkdir(outputDir, { recursive: true });
|
|
85
115
|
debugLog(`目录创建成功`, { outputDir });
|
|
@@ -101,7 +131,10 @@ export async function processRequirementDocument(requirementSource, featureName,
|
|
|
101
131
|
if (!url) {
|
|
102
132
|
throw new McpError(-32602, "网页 URL 不能为空");
|
|
103
133
|
}
|
|
104
|
-
|
|
134
|
+
// 对于 URL,使用当前工作目录作为项目根目录
|
|
135
|
+
const projectRoot = process.cwd();
|
|
136
|
+
const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
|
|
137
|
+
debugLog(`处理网页 URL`, { url, projectRoot, outputMdPath });
|
|
105
138
|
return {
|
|
106
139
|
success: false,
|
|
107
140
|
message: `🌐 检测到网页 URL
|
|
@@ -121,8 +154,10 @@ export async function processRequirementDocument(requirementSource, featureName,
|
|
|
121
154
|
* 尝试读取已保存的需求文档
|
|
122
155
|
* 如果用户之前已经按照指令保存了文件,优先使用已保存的内容
|
|
123
156
|
*/
|
|
124
|
-
export async function tryReadSavedRequirement(featureName) {
|
|
125
|
-
const
|
|
157
|
+
export async function tryReadSavedRequirement(featureName, projectRoot) {
|
|
158
|
+
const root = projectRoot || process.cwd();
|
|
159
|
+
const savedRequirementPath = buildOutputPath(featureName, "origin-requirement.md", root);
|
|
160
|
+
debugLog(`尝试读取已保存的需求文档`, { featureName, projectRoot: root, savedRequirementPath });
|
|
126
161
|
try {
|
|
127
162
|
const savedContent = await fs.readFile(savedRequirementPath, "utf-8");
|
|
128
163
|
if (savedContent) {
|
|
@@ -139,10 +174,11 @@ export async function tryReadSavedRequirement(featureName) {
|
|
|
139
174
|
* 保存设计稿内容到文件
|
|
140
175
|
* 用于保存从 Figma MCP 读取的设计稿内容
|
|
141
176
|
*/
|
|
142
|
-
export async function saveDesignDocument(featureName, designContent) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
177
|
+
export async function saveDesignDocument(featureName, designContent, projectRoot) {
|
|
178
|
+
const root = projectRoot || process.cwd();
|
|
179
|
+
debugLog(`saveDesignDocument 开始`, { featureName, projectRoot: root });
|
|
180
|
+
const designDocPath = buildOutputPath(featureName, "design-doc.md", root);
|
|
181
|
+
const outputDir = path.dirname(designDocPath);
|
|
146
182
|
debugLog(`设计稿准备创建目录`, { outputDir });
|
|
147
183
|
await fs.mkdir(outputDir, { recursive: true });
|
|
148
184
|
debugLog(`设计稿目录创建成功`);
|
|
@@ -153,8 +189,10 @@ export async function saveDesignDocument(featureName, designContent) {
|
|
|
153
189
|
/**
|
|
154
190
|
* 尝试读取已保存的设计稿文档
|
|
155
191
|
*/
|
|
156
|
-
export async function tryReadSavedDesign(featureName) {
|
|
157
|
-
const
|
|
192
|
+
export async function tryReadSavedDesign(featureName, projectRoot) {
|
|
193
|
+
const root = projectRoot || process.cwd();
|
|
194
|
+
const savedDesignPath = buildOutputPath(featureName, "design-doc.md", root);
|
|
195
|
+
debugLog(`尝试读取已保存的设计稿`, { featureName, projectRoot: root, savedDesignPath });
|
|
158
196
|
try {
|
|
159
197
|
const savedContent = await fs.readFile(savedDesignPath, "utf-8");
|
|
160
198
|
if (savedContent) {
|
|
@@ -171,10 +209,11 @@ export async function tryReadSavedDesign(featureName) {
|
|
|
171
209
|
* 保存后端文档内容到文件
|
|
172
210
|
* 用于保存从 PDF/网页读取的后端文档内容
|
|
173
211
|
*/
|
|
174
|
-
export async function saveBackendDocument(featureName, backendContent) {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const
|
|
212
|
+
export async function saveBackendDocument(featureName, backendContent, projectRoot) {
|
|
213
|
+
const root = projectRoot || process.cwd();
|
|
214
|
+
debugLog(`saveBackendDocument 开始`, { featureName, projectRoot: root });
|
|
215
|
+
const backendDocPath = buildOutputPath(featureName, "backend-doc.md", root);
|
|
216
|
+
const outputDir = path.dirname(backendDocPath);
|
|
178
217
|
debugLog(`后端文档准备创建目录`, { outputDir });
|
|
179
218
|
await fs.mkdir(outputDir, { recursive: true });
|
|
180
219
|
debugLog(`后端文档目录创建成功`);
|
|
@@ -185,8 +224,10 @@ export async function saveBackendDocument(featureName, backendContent) {
|
|
|
185
224
|
/**
|
|
186
225
|
* 尝试读取已保存的后端文档
|
|
187
226
|
*/
|
|
188
|
-
export async function tryReadSavedBackend(featureName) {
|
|
189
|
-
const
|
|
227
|
+
export async function tryReadSavedBackend(featureName, projectRoot) {
|
|
228
|
+
const root = projectRoot || process.cwd();
|
|
229
|
+
const savedBackendPath = buildOutputPath(featureName, "backend-doc.md", root);
|
|
230
|
+
debugLog(`尝试读取已保存的后端文档`, { featureName, projectRoot: root, savedBackendPath });
|
|
190
231
|
try {
|
|
191
232
|
const savedContent = await fs.readFile(savedBackendPath, "utf-8");
|
|
192
233
|
if (savedContent) {
|
|
@@ -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;AAClC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AAEzB;;GAEG;AACH,SAAS,QAAQ,CAAC,OAAe,EAAE,IAAU;IAC3C,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,MAAM,UAAU,GAAG,UAAU,SAAS,KAAK,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACxG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AAC5B,CAAC;AAwBD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAC9C,iBAAgD,EAChD,WAAmB,EACnB,iBAAyB,uBAAuB;IAEhD,QAAQ,CAAC,+BAA+B,EAAE;QACxC,iBAAiB;QACjB,WAAW;QACX,cAAc;QACd,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;QACvB,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE;KACtB,CAAC,CAAC;IACH,kBAAkB;IAClB,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACvB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE;;;;;;;8BAOe;YACxB,WAAW,EAAE;gBACX,IAAI,EAAE,iBAAiB;gBACvB,WAAW,EAAE,oFAAoF;aAClG;SACF,CAAC;IACJ,CAAC;IAED,aAAa;IACb,IAAI,iBAAiB,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC;QACxC,QAAQ,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QACjC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,QAAQ,CAAC,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;QACzC,CAAC;QAED,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,CAAC;QACrD,QAAQ,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;QAE3B,wBAAwB;QACxB,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAClB,MAAM,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"requirement-processor.js","sourceRoot":"","sources":["../../../src/tools/requirements/requirement-processor.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -8,7 +8,9 @@ import {
|
|
|
8
8
|
saveDesignDocument,
|
|
9
9
|
tryReadSavedDesign,
|
|
10
10
|
saveBackendDocument,
|
|
11
|
-
tryReadSavedBackend
|
|
11
|
+
tryReadSavedBackend,
|
|
12
|
+
getProjectRoot,
|
|
13
|
+
buildOutputPath
|
|
12
14
|
} from "./requirement-processor.js";
|
|
13
15
|
|
|
14
16
|
/**
|
|
@@ -100,9 +102,16 @@ export async function generateRequirements(
|
|
|
100
102
|
|
|
101
103
|
// 2. 处理需求文档输入
|
|
102
104
|
|
|
105
|
+
// 2.0 计算项目根目录(从输入路径提取)
|
|
106
|
+
let projectRoot = process.cwd();
|
|
107
|
+
if (params.requirementSource.type === "file" && params.requirementSource.path) {
|
|
108
|
+
projectRoot = getProjectRoot(params.requirementSource.path);
|
|
109
|
+
}
|
|
110
|
+
debugLog(`计算项目根目录`, { projectRoot, cwd: process.cwd() });
|
|
111
|
+
|
|
103
112
|
// 2.1 优先尝试读取已保存的 origin-requirement.md(智能缓存)
|
|
104
|
-
debugLog(`尝试读取已保存的需求文档`, { featureName: params.featureName });
|
|
105
|
-
const savedContent = await tryReadSavedRequirement(params.featureName);
|
|
113
|
+
debugLog(`尝试读取已保存的需求文档`, { featureName: params.featureName, projectRoot });
|
|
114
|
+
const savedContent = await tryReadSavedRequirement(params.featureName, projectRoot);
|
|
106
115
|
if (!savedContent) {
|
|
107
116
|
debugLog(`未找到缓存,处理需求文档输入`);
|
|
108
117
|
// 2.2 没有缓存,处理需求文档输入
|
|
@@ -135,6 +144,10 @@ export async function generateRequirements(
|
|
|
135
144
|
if (!savedDesign) {
|
|
136
145
|
// 3.2 没有缓存,处理设计稿
|
|
137
146
|
if (params.designSource.type === "file") {
|
|
147
|
+
// 从设计稿路径重新计算项目根目录
|
|
148
|
+
const designProjectRoot = getProjectRoot(params.designSource.path!);
|
|
149
|
+
debugLog(`设计稿项目根目录`, { designProjectRoot });
|
|
150
|
+
|
|
138
151
|
const designResult = await processRequirementDocument(
|
|
139
152
|
params.designSource as any,
|
|
140
153
|
params.featureName,
|
|
@@ -149,13 +162,13 @@ export async function generateRequirements(
|
|
|
149
162
|
};
|
|
150
163
|
}
|
|
151
164
|
|
|
152
|
-
designSourceInfo =
|
|
165
|
+
designSourceInfo = `**设计稿位置**:${buildOutputPath(params.featureName, "design-doc.md", designProjectRoot)}\n`;
|
|
153
166
|
} else if (params.designSource.type === "figma") {
|
|
154
167
|
designSourceInfo = `**设计稿链接**:${params.designSource.url || "Figma 链接未提供"}(请使用 Figma MCP 读取并保存到 .specs/requirements/${params.featureName}/design-doc.md)\n`;
|
|
155
168
|
}
|
|
156
169
|
} else {
|
|
157
170
|
// 3.3 使用已保存的设计稿
|
|
158
|
-
designSourceInfo =
|
|
171
|
+
designSourceInfo = `**设计稿位置**:${buildOutputPath(params.featureName, "design-doc.md", projectRoot)}\n`;
|
|
159
172
|
}
|
|
160
173
|
}
|
|
161
174
|
|
|
@@ -167,6 +180,10 @@ export async function generateRequirements(
|
|
|
167
180
|
|
|
168
181
|
if (!savedBackend) {
|
|
169
182
|
// 4.2 没有缓存,处理后端文档
|
|
183
|
+
// 从后端文档路径重新计算项目根目录
|
|
184
|
+
const backendProjectRoot = getProjectRoot(params.backendSource.path!);
|
|
185
|
+
debugLog(`后端文档项目根目录`, { backendProjectRoot });
|
|
186
|
+
|
|
170
187
|
const backendResult = await processRequirementDocument(
|
|
171
188
|
params.backendSource,
|
|
172
189
|
params.featureName,
|
|
@@ -183,20 +200,20 @@ export async function generateRequirements(
|
|
|
183
200
|
|
|
184
201
|
// 4.2.1 文件类型已保存,返回信息
|
|
185
202
|
if (params.backendSource.type === "file") {
|
|
186
|
-
backendSourceInfo =
|
|
203
|
+
backendSourceInfo = `**后端文档位置**:${buildOutputPath(params.featureName, "backend-doc.md", backendProjectRoot)}\n`;
|
|
187
204
|
} else if (params.backendSource.type === "url") {
|
|
188
205
|
backendSourceInfo = `**后端文档网页**:${params.backendSource.url || "后端文档网页 URL 未提供"}(请使用 Chrome DevTools MCP 读取并保存到 .specs/requirements/${params.featureName}/backend-doc.md)\n`;
|
|
189
206
|
}
|
|
190
207
|
} else {
|
|
191
208
|
// 4.3 使用已保存的后端文档
|
|
192
|
-
backendSourceInfo =
|
|
209
|
+
backendSourceInfo = `**后端文档位置**:${buildOutputPath(params.featureName, "backend-doc.md", projectRoot)}\n`;
|
|
193
210
|
}
|
|
194
211
|
}
|
|
195
212
|
|
|
196
213
|
// 5. 生成分析提示词
|
|
197
|
-
const outputPath =
|
|
198
|
-
const originDocPath =
|
|
199
|
-
debugLog(`生成输出路径`, { outputPath, originDocPath });
|
|
214
|
+
const outputPath = buildOutputPath(params.featureName, "requirements.md", projectRoot);
|
|
215
|
+
const originDocPath = buildOutputPath(params.featureName, "origin-requirement.md", projectRoot);
|
|
216
|
+
debugLog(`生成输出路径`, { outputPath, originDocPath, projectRoot });
|
|
200
217
|
|
|
201
218
|
let message = "📝 需求文档已准备完毕\n\n";
|
|
202
219
|
message += `**原始文档位置**:${originDocPath}\n`;
|
|
@@ -12,6 +12,35 @@ function debugLog(message: string, data?: any) {
|
|
|
12
12
|
console.error(logMessage);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* 从输入路径获取项目根目录
|
|
17
|
+
* 如果输入路径是绝对路径,返回该路径的项目根目录
|
|
18
|
+
* 否则使用当前工作目录
|
|
19
|
+
*/
|
|
20
|
+
export function getProjectRoot(inputPath: string): string {
|
|
21
|
+
if (path.isAbsolute(inputPath)) {
|
|
22
|
+
// 对于绝对路径,我们假设项目根目录是 .specs 的父目录
|
|
23
|
+
// 例如:/path/to/project/.specs/requirements/xxx
|
|
24
|
+
// 我们需要找到 /path/to/project
|
|
25
|
+
const parts = inputPath.split(path.sep);
|
|
26
|
+
const specsIndex = parts.indexOf('.specs');
|
|
27
|
+
if (specsIndex > 0) {
|
|
28
|
+
return parts.slice(0, specsIndex).join(path.sep);
|
|
29
|
+
}
|
|
30
|
+
// 如果没有找到 .specs,返回文件所在目录
|
|
31
|
+
return path.dirname(inputPath);
|
|
32
|
+
}
|
|
33
|
+
// 对于相对路径,使用当前工作目录
|
|
34
|
+
return process.cwd();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* 构建输出路径(使用绝对路径)
|
|
39
|
+
*/
|
|
40
|
+
export function buildOutputPath(featureName: string, fileName: string, projectRoot: string): string {
|
|
41
|
+
return path.join(projectRoot, '.specs', 'requirements', featureName, fileName);
|
|
42
|
+
}
|
|
43
|
+
|
|
15
44
|
interface RequirementSource {
|
|
16
45
|
type: "file" | "url";
|
|
17
46
|
path?: string;
|
|
@@ -83,7 +112,8 @@ export async function processRequirementDocument(
|
|
|
83
112
|
|
|
84
113
|
// 2.2.1 PDF 文件 - 返回读取指令
|
|
85
114
|
if (ext === "pdf") {
|
|
86
|
-
const
|
|
115
|
+
const projectRoot = getProjectRoot(filePath);
|
|
116
|
+
const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
|
|
87
117
|
return {
|
|
88
118
|
success: false,
|
|
89
119
|
message: `📄 检测到 PDF 文件
|
|
@@ -100,10 +130,13 @@ export async function processRequirementDocument(
|
|
|
100
130
|
|
|
101
131
|
// 2.2.2 Markdown 文件 - 保存到固定位置
|
|
102
132
|
if (ext === "md" || ext === "markdown") {
|
|
103
|
-
const
|
|
133
|
+
const projectRoot = getProjectRoot(filePath);
|
|
134
|
+
const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
|
|
135
|
+
|
|
104
136
|
debugLog(`准备保存 Markdown 文件`, {
|
|
105
137
|
inputPath: filePath,
|
|
106
138
|
outputPath: outputMdPath,
|
|
139
|
+
projectRoot,
|
|
107
140
|
isAbsolute: path.isAbsolute(filePath),
|
|
108
141
|
resolvedPath: path.resolve(filePath)
|
|
109
142
|
});
|
|
@@ -113,7 +146,7 @@ export async function processRequirementDocument(
|
|
|
113
146
|
debugLog(`成功读取文件内容`, { contentLength: content.length });
|
|
114
147
|
|
|
115
148
|
// 保存到固定位置
|
|
116
|
-
const outputDir =
|
|
149
|
+
const outputDir = path.dirname(outputMdPath);
|
|
117
150
|
debugLog(`准备创建目录`, { outputDir });
|
|
118
151
|
await fs.mkdir(outputDir, { recursive: true });
|
|
119
152
|
debugLog(`目录创建成功`, { outputDir });
|
|
@@ -140,7 +173,10 @@ export async function processRequirementDocument(
|
|
|
140
173
|
throw new McpError(-32602, "网页 URL 不能为空");
|
|
141
174
|
}
|
|
142
175
|
|
|
143
|
-
|
|
176
|
+
// 对于 URL,使用当前工作目录作为项目根目录
|
|
177
|
+
const projectRoot = process.cwd();
|
|
178
|
+
const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
|
|
179
|
+
debugLog(`处理网页 URL`, { url, projectRoot, outputMdPath });
|
|
144
180
|
return {
|
|
145
181
|
success: false,
|
|
146
182
|
message: `🌐 检测到网页 URL
|
|
@@ -163,9 +199,12 @@ export async function processRequirementDocument(
|
|
|
163
199
|
* 如果用户之前已经按照指令保存了文件,优先使用已保存的内容
|
|
164
200
|
*/
|
|
165
201
|
export async function tryReadSavedRequirement(
|
|
166
|
-
featureName: string
|
|
202
|
+
featureName: string,
|
|
203
|
+
projectRoot?: string
|
|
167
204
|
): Promise<string | null> {
|
|
168
|
-
const
|
|
205
|
+
const root = projectRoot || process.cwd();
|
|
206
|
+
const savedRequirementPath = buildOutputPath(featureName, "origin-requirement.md", root);
|
|
207
|
+
debugLog(`尝试读取已保存的需求文档`, { featureName, projectRoot: root, savedRequirementPath });
|
|
169
208
|
try {
|
|
170
209
|
const savedContent = await fs.readFile(savedRequirementPath, "utf-8");
|
|
171
210
|
if (savedContent) {
|
|
@@ -184,11 +223,13 @@ export async function tryReadSavedRequirement(
|
|
|
184
223
|
*/
|
|
185
224
|
export async function saveDesignDocument(
|
|
186
225
|
featureName: string,
|
|
187
|
-
designContent: string
|
|
226
|
+
designContent: string,
|
|
227
|
+
projectRoot?: string
|
|
188
228
|
): Promise<void> {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
const
|
|
229
|
+
const root = projectRoot || process.cwd();
|
|
230
|
+
debugLog(`saveDesignDocument 开始`, { featureName, projectRoot: root });
|
|
231
|
+
const designDocPath = buildOutputPath(featureName, "design-doc.md", root);
|
|
232
|
+
const outputDir = path.dirname(designDocPath);
|
|
192
233
|
debugLog(`设计稿准备创建目录`, { outputDir });
|
|
193
234
|
await fs.mkdir(outputDir, { recursive: true });
|
|
194
235
|
debugLog(`设计稿目录创建成功`);
|
|
@@ -201,9 +242,12 @@ export async function saveDesignDocument(
|
|
|
201
242
|
* 尝试读取已保存的设计稿文档
|
|
202
243
|
*/
|
|
203
244
|
export async function tryReadSavedDesign(
|
|
204
|
-
featureName: string
|
|
245
|
+
featureName: string,
|
|
246
|
+
projectRoot?: string
|
|
205
247
|
): Promise<string | null> {
|
|
206
|
-
const
|
|
248
|
+
const root = projectRoot || process.cwd();
|
|
249
|
+
const savedDesignPath = buildOutputPath(featureName, "design-doc.md", root);
|
|
250
|
+
debugLog(`尝试读取已保存的设计稿`, { featureName, projectRoot: root, savedDesignPath });
|
|
207
251
|
try {
|
|
208
252
|
const savedContent = await fs.readFile(savedDesignPath, "utf-8");
|
|
209
253
|
if (savedContent) {
|
|
@@ -222,11 +266,13 @@ export async function tryReadSavedDesign(
|
|
|
222
266
|
*/
|
|
223
267
|
export async function saveBackendDocument(
|
|
224
268
|
featureName: string,
|
|
225
|
-
backendContent: string
|
|
269
|
+
backendContent: string,
|
|
270
|
+
projectRoot?: string
|
|
226
271
|
): Promise<void> {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
const
|
|
272
|
+
const root = projectRoot || process.cwd();
|
|
273
|
+
debugLog(`saveBackendDocument 开始`, { featureName, projectRoot: root });
|
|
274
|
+
const backendDocPath = buildOutputPath(featureName, "backend-doc.md", root);
|
|
275
|
+
const outputDir = path.dirname(backendDocPath);
|
|
230
276
|
debugLog(`后端文档准备创建目录`, { outputDir });
|
|
231
277
|
await fs.mkdir(outputDir, { recursive: true });
|
|
232
278
|
debugLog(`后端文档目录创建成功`);
|
|
@@ -239,9 +285,12 @@ export async function saveBackendDocument(
|
|
|
239
285
|
* 尝试读取已保存的后端文档
|
|
240
286
|
*/
|
|
241
287
|
export async function tryReadSavedBackend(
|
|
242
|
-
featureName: string
|
|
288
|
+
featureName: string,
|
|
289
|
+
projectRoot?: string
|
|
243
290
|
): Promise<string | null> {
|
|
244
|
-
const
|
|
291
|
+
const root = projectRoot || process.cwd();
|
|
292
|
+
const savedBackendPath = buildOutputPath(featureName, "backend-doc.md", root);
|
|
293
|
+
debugLog(`尝试读取已保存的后端文档`, { featureName, projectRoot: root, savedBackendPath });
|
|
245
294
|
try {
|
|
246
295
|
const savedContent = await fs.readFile(savedBackendPath, "utf-8");
|
|
247
296
|
if (savedContent) {
|