bmall-mcp 1.8.1 → 1.8.3

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 CHANGED
@@ -204,6 +204,19 @@ src/
204
204
 
205
205
  ## Changelog
206
206
 
207
+ ### v1.8.3 (2026-03-16)
208
+ - ✅ 优化 PDF 读取策略:采用**分两步读取**策略(text + OCR)
209
+ - ✅ 新增 PDF 语言自动检测:根据文件名自动识别中文/英文文档
210
+ - ✅ 完善 PDF 读取提示:建议先读文本层,再用 OCR 提取图片表格
211
+ - ✅ 避免内容遗漏:结合两种方式确保内容完整准确
212
+
213
+ ### v1.8.2 (2026-03-16)
214
+ - ✅ 修复工作目录问题:MCP 在根目录 `/` 运行时无法创建 `.specs` 目录
215
+ - ✅ 新增项目根目录自动识别:从输入文件的绝对路径智能提取项目根目录
216
+ - ✅ 优化路径处理:所有输出路径使用绝对路径,避免相对路径的依赖问题
217
+ - ✅ 完善 getProjectRoot 函数:支持从 `.specs` 路径自动识别项目根目录
218
+ - ✅ 更新所有文件操作函数:使用 buildOutputPath 生成绝对路径
219
+
207
220
  ### v1.8.1 (2026-03-16)
208
221
  - ✅ 新增 generate_requirements 工具详细调试日志
209
222
  - ✅ 添加环境信息输出(工作目录、平台、主目录)
@@ -1 +1 @@
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
+ {"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 = `**设计稿位置**:.specs/requirements/${params.featureName}/design-doc.md\n`;
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 = `**设计稿位置**:.specs/requirements/${params.featureName}/design-doc.md\n`;
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 = `**后端文档位置**:.specs/requirements/${params.featureName}/backend-doc.md\n`;
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 = `**后端文档位置**:.specs/requirements/${params.featureName}/backend-doc.md\n`;
130
+ backendSourceInfo = `**后端文档位置**:${buildOutputPath(params.featureName, "backend-doc.md", projectRoot)}\n`;
119
131
  }
120
132
  }
121
133
  // 5. 生成分析提示词
122
- const outputPath = `.specs/requirements/${params.featureName}/requirements.md`;
123
- const originDocPath = `.specs/requirements/${params.featureName}/origin-requirement.md`;
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":"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"}
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,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
+ {"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,CAiJxB;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,26 +79,51 @@ export async function processRequirementDocument(requirementSource, featureName,
52
79
  debugLog(`文件扩展名`, { ext });
53
80
  // 2.2.1 PDF 文件 - 返回读取指令
54
81
  if (ext === "pdf") {
55
- const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
82
+ const projectRoot = getProjectRoot(filePath);
83
+ const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
84
+ // 检测语言(简单的启发式规则)
85
+ const fileName = filePath.split('/').pop() || '';
86
+ const isChinese = /[\u4e00-\u9fa5]/.test(fileName);
87
+ const language = isChinese ? 'chi_sim' : 'eng';
56
88
  return {
57
89
  success: false,
58
90
  message: `📄 检测到 PDF 文件
59
91
 
60
- 请使用 PDF Reader MCP 读取 PDF 内容
61
- 保存到:${outputMdPath}
92
+ ⚠️ **重要提示**:为确保完整提取 PDF 内容,建议**分两步读取**:
93
+
94
+ **步骤 1:使用 \`read_pdf_text\` 提取文本层**
95
+ - 优势:快速、准确、保留原始格式
96
+ - 保存到:\`${outputMdPath.replace('.md', '-text.md')}\`
97
+
98
+ **步骤 2:使用 \`read_by_ocr\` 提取图片和表格**
99
+ - 优势:可提取图片、表格、扫描件等非文本内容
100
+ - 语言:\`${language}\`(中文文档使用 \`chi_sim\`,英文使用 \`eng\`)
101
+ - DPI:\`300\`(默认值)
102
+ - 保存到:\`${outputMdPath.replace('.md', '-ocr.md')}\`
103
+
104
+ **步骤 3:合并两个文件**
105
+ - 将 \`-text.md\` 和 \`-ocr.md\` 的内容合并
106
+ - 保存到:\`${outputMdPath}\`
107
+
62
108
  完成后重新调用本工具`,
63
109
  needsAction: {
64
110
  type: "read_pdf",
65
- instruction: `使用 PDF Reader MCP 读取 ${filePath},保存到 ${outputMdPath}`,
111
+ instruction: `使用 PDF Reader MCP 分两步读取 ${filePath}
112
+ 1. 先用 read_pdf_text 提取文本层,保存到 ${outputMdPath.replace('.md', '-text.md')}
113
+ 2. 再用 read_by_ocr 提取图片表格(language="${language}",dpi=300),保存到 ${outputMdPath.replace('.md', '-ocr.md')}
114
+ 3. 合并两个文件内容到 ${outputMdPath}
115
+ 这样可以确保内容完整,既保留文本的准确性,又提取了图片表格等视觉内容。`,
66
116
  },
67
117
  };
68
118
  }
69
119
  // 2.2.2 Markdown 文件 - 保存到固定位置
70
120
  if (ext === "md" || ext === "markdown") {
71
- const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
121
+ const projectRoot = getProjectRoot(filePath);
122
+ const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
72
123
  debugLog(`准备保存 Markdown 文件`, {
73
124
  inputPath: filePath,
74
125
  outputPath: outputMdPath,
126
+ projectRoot,
75
127
  isAbsolute: path.isAbsolute(filePath),
76
128
  resolvedPath: path.resolve(filePath)
77
129
  });
@@ -79,7 +131,7 @@ export async function processRequirementDocument(requirementSource, featureName,
79
131
  const content = await fs.readFile(filePath, "utf-8");
80
132
  debugLog(`成功读取文件内容`, { contentLength: content.length });
81
133
  // 保存到固定位置
82
- const outputDir = outputMdPath.substring(0, outputMdPath.lastIndexOf("/"));
134
+ const outputDir = path.dirname(outputMdPath);
83
135
  debugLog(`准备创建目录`, { outputDir });
84
136
  await fs.mkdir(outputDir, { recursive: true });
85
137
  debugLog(`目录创建成功`, { outputDir });
@@ -101,7 +153,10 @@ export async function processRequirementDocument(requirementSource, featureName,
101
153
  if (!url) {
102
154
  throw new McpError(-32602, "网页 URL 不能为空");
103
155
  }
104
- const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
156
+ // 对于 URL,使用当前工作目录作为项目根目录
157
+ const projectRoot = process.cwd();
158
+ const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
159
+ debugLog(`处理网页 URL`, { url, projectRoot, outputMdPath });
105
160
  return {
106
161
  success: false,
107
162
  message: `🌐 检测到网页 URL
@@ -121,8 +176,10 @@ export async function processRequirementDocument(requirementSource, featureName,
121
176
  * 尝试读取已保存的需求文档
122
177
  * 如果用户之前已经按照指令保存了文件,优先使用已保存的内容
123
178
  */
124
- export async function tryReadSavedRequirement(featureName) {
125
- const savedRequirementPath = `.specs/requirements/${featureName}/origin-requirement.md`;
179
+ export async function tryReadSavedRequirement(featureName, projectRoot) {
180
+ const root = projectRoot || process.cwd();
181
+ const savedRequirementPath = buildOutputPath(featureName, "origin-requirement.md", root);
182
+ debugLog(`尝试读取已保存的需求文档`, { featureName, projectRoot: root, savedRequirementPath });
126
183
  try {
127
184
  const savedContent = await fs.readFile(savedRequirementPath, "utf-8");
128
185
  if (savedContent) {
@@ -139,10 +196,11 @@ export async function tryReadSavedRequirement(featureName) {
139
196
  * 保存设计稿内容到文件
140
197
  * 用于保存从 Figma MCP 读取的设计稿内容
141
198
  */
142
- export async function saveDesignDocument(featureName, designContent) {
143
- debugLog(`saveDesignDocument 开始`, { featureName });
144
- const designDocPath = `.specs/requirements/${featureName}/design-doc.md`;
145
- const outputDir = designDocPath.substring(0, designDocPath.lastIndexOf("/"));
199
+ export async function saveDesignDocument(featureName, designContent, projectRoot) {
200
+ const root = projectRoot || process.cwd();
201
+ debugLog(`saveDesignDocument 开始`, { featureName, projectRoot: root });
202
+ const designDocPath = buildOutputPath(featureName, "design-doc.md", root);
203
+ const outputDir = path.dirname(designDocPath);
146
204
  debugLog(`设计稿准备创建目录`, { outputDir });
147
205
  await fs.mkdir(outputDir, { recursive: true });
148
206
  debugLog(`设计稿目录创建成功`);
@@ -153,8 +211,10 @@ export async function saveDesignDocument(featureName, designContent) {
153
211
  /**
154
212
  * 尝试读取已保存的设计稿文档
155
213
  */
156
- export async function tryReadSavedDesign(featureName) {
157
- const savedDesignPath = `.specs/requirements/${featureName}/design-doc.md`;
214
+ export async function tryReadSavedDesign(featureName, projectRoot) {
215
+ const root = projectRoot || process.cwd();
216
+ const savedDesignPath = buildOutputPath(featureName, "design-doc.md", root);
217
+ debugLog(`尝试读取已保存的设计稿`, { featureName, projectRoot: root, savedDesignPath });
158
218
  try {
159
219
  const savedContent = await fs.readFile(savedDesignPath, "utf-8");
160
220
  if (savedContent) {
@@ -171,10 +231,11 @@ export async function tryReadSavedDesign(featureName) {
171
231
  * 保存后端文档内容到文件
172
232
  * 用于保存从 PDF/网页读取的后端文档内容
173
233
  */
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("/"));
234
+ export async function saveBackendDocument(featureName, backendContent, projectRoot) {
235
+ const root = projectRoot || process.cwd();
236
+ debugLog(`saveBackendDocument 开始`, { featureName, projectRoot: root });
237
+ const backendDocPath = buildOutputPath(featureName, "backend-doc.md", root);
238
+ const outputDir = path.dirname(backendDocPath);
178
239
  debugLog(`后端文档准备创建目录`, { outputDir });
179
240
  await fs.mkdir(outputDir, { recursive: true });
180
241
  debugLog(`后端文档目录创建成功`);
@@ -185,8 +246,10 @@ export async function saveBackendDocument(featureName, backendContent) {
185
246
  /**
186
247
  * 尝试读取已保存的后端文档
187
248
  */
188
- export async function tryReadSavedBackend(featureName) {
189
- const savedBackendPath = `.specs/requirements/${featureName}/backend-doc.md`;
249
+ export async function tryReadSavedBackend(featureName, projectRoot) {
250
+ const root = projectRoot || process.cwd();
251
+ const savedBackendPath = buildOutputPath(featureName, "backend-doc.md", root);
252
+ debugLog(`尝试读取已保存的后端文档`, { featureName, projectRoot: root, savedBackendPath });
190
253
  try {
191
254
  const savedContent = await fs.readFile(savedBackendPath, "utf-8");
192
255
  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,uBAAuB,WAAW,IAAI,cAAc,EAAE,CAAC;YAC5E,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE;;;MAGX,YAAY;WACP;gBACH,WAAW,EAAE;oBACX,IAAI,EAAE,UAAU;oBAChB,WAAW,EAAE,wBAAwB,QAAQ,QAAQ,YAAY,EAAE;iBACpE;aACF,CAAC;QACJ,CAAC;QAED,8BAA8B;QAC9B,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YACvC,MAAM,YAAY,GAAG,uBAAuB,WAAW,IAAI,cAAc,EAAE,CAAC;YAC5E,QAAQ,CAAC,kBAAkB,EAAE;gBAC3B,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAE,YAAY;gBACxB,UAAU,EAAE,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;gBACrC,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;aACrC,CAAC,CAAC;YAEH,iBAAiB;YACjB,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;YACrD,QAAQ,CAAC,UAAU,EAAE,EAAE,aAAa,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;YAExD,UAAU;YACV,MAAM,SAAS,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3E,QAAQ,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;YAClC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,QAAQ,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;YAElC,QAAQ,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAC;YACjD,MAAM,EAAE,CAAC,SAAS,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YACnD,QAAQ,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC,CAAC;YAEjD,OAAO;gBACL,OAAO,EAAE,IAAI;gBACb,OAAO;gBACP,OAAO,EAAE,cAAc,YAAY,EAAE;aACtC,CAAC;QACJ,CAAC;QAED,eAAe;QACf,MAAM,IAAI,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,GAAG,iBAAiB,CAAC,CAAC;IAChE,CAAC;IAED,eAAe;IACf,IAAI,iBAAiB,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,iBAAiB,CAAC,GAAG,CAAC;QAClC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,QAAQ,CAAC,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,YAAY,GAAG,uBAAuB,WAAW,IAAI,cAAc,EAAE,CAAC;QAC5E,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO,EAAE;;;MAGT,YAAY;WACP;YACL,WAAW,EAAE;gBACX,IAAI,EAAE,UAAU;gBAChB,WAAW,EAAE,6BAA6B,GAAG,QAAQ,YAAY,EAAE;aACpE;SACF,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,QAAQ,CAAC,CAAC,KAAK,EAAE,2CAA2C,CAAC,CAAC;AAC1E,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,WAAmB;IAEnB,MAAM,oBAAoB,GAAG,uBAAuB,WAAW,wBAAwB,CAAC;IACxF,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;QACtE,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,iBAAiB,oBAAoB,EAAE,CAAC,CAAC;YACrD,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ;IACV,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB,EACnB,aAAqB;IAErB,QAAQ,CAAC,uBAAuB,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,uBAAuB,WAAW,gBAAgB,CAAC;IACzE,MAAM,SAAS,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,QAAQ,CAAC,WAAW,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACrC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,QAAQ,CAAC,WAAW,CAAC,CAAC;IACtB,MAAM,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,aAAa,EAAE,OAAO,CAAC,CAAC;IAC1D,OAAO,CAAC,GAAG,CAAC,cAAc,aAAa,EAAE,CAAC,CAAC;IAC3C,QAAQ,CAAC,WAAW,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,WAAmB;IAEnB,MAAM,eAAe,GAAG,uBAAuB,WAAW,gBAAgB,CAAC;IAC3E,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QACjE,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,gBAAgB,eAAe,EAAE,CAAC,CAAC;YAC/C,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ;IACV,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB,EACnB,cAAsB;IAEtB,QAAQ,CAAC,wBAAwB,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IACpD,MAAM,cAAc,GAAG,uBAAuB,WAAW,iBAAiB,CAAC;IAC3E,MAAM,SAAS,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC,EAAE,cAAc,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/E,QAAQ,CAAC,YAAY,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;IACtC,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,QAAQ,CAAC,YAAY,CAAC,CAAC;IACvB,MAAM,EAAE,CAAC,SAAS,CAAC,cAAc,EAAE,cAAc,EAAE,OAAO,CAAC,CAAC;IAC5D,OAAO,CAAC,GAAG,CAAC,eAAe,cAAc,EAAE,CAAC,CAAC;IAC7C,QAAQ,CAAC,YAAY,EAAE,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC;AACzD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,WAAmB;IAEnB,MAAM,gBAAgB,GAAG,uBAAuB,WAAW,iBAAiB,CAAC;IAC7E,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QAClE,IAAI,YAAY,EAAE,CAAC;YACjB,OAAO,CAAC,GAAG,CAAC,iBAAiB,gBAAgB,EAAE,CAAC,CAAC;YACjD,OAAO,YAAY,CAAC;QACtB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ;IACV,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bmall-mcp",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "MCP Server for bmall development rules and tools",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -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 = `**设计稿位置**:.specs/requirements/${params.featureName}/design-doc.md\n`;
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 = `**设计稿位置**:.specs/requirements/${params.featureName}/design-doc.md\n`;
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 = `**后端文档位置**:.specs/requirements/${params.featureName}/backend-doc.md\n`;
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 = `**后端文档位置**:.specs/requirements/${params.featureName}/backend-doc.md\n`;
209
+ backendSourceInfo = `**后端文档位置**:${buildOutputPath(params.featureName, "backend-doc.md", projectRoot)}\n`;
193
210
  }
194
211
  }
195
212
 
196
213
  // 5. 生成分析提示词
197
- const outputPath = `.specs/requirements/${params.featureName}/requirements.md`;
198
- const originDocPath = `.specs/requirements/${params.featureName}/origin-requirement.md`;
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,27 +112,55 @@ export async function processRequirementDocument(
83
112
 
84
113
  // 2.2.1 PDF 文件 - 返回读取指令
85
114
  if (ext === "pdf") {
86
- const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
115
+ const projectRoot = getProjectRoot(filePath);
116
+ const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
117
+
118
+ // 检测语言(简单的启发式规则)
119
+ const fileName = filePath.split('/').pop() || '';
120
+ const isChinese = /[\u4e00-\u9fa5]/.test(fileName);
121
+ const language = isChinese ? 'chi_sim' : 'eng';
122
+
87
123
  return {
88
124
  success: false,
89
125
  message: `📄 检测到 PDF 文件
90
126
 
91
- 请使用 PDF Reader MCP 读取 PDF 内容
92
- 保存到:${outputMdPath}
127
+ ⚠️ **重要提示**:为确保完整提取 PDF 内容,建议**分两步读取**:
128
+
129
+ **步骤 1:使用 \`read_pdf_text\` 提取文本层**
130
+ - 优势:快速、准确、保留原始格式
131
+ - 保存到:\`${outputMdPath.replace('.md', '-text.md')}\`
132
+
133
+ **步骤 2:使用 \`read_by_ocr\` 提取图片和表格**
134
+ - 优势:可提取图片、表格、扫描件等非文本内容
135
+ - 语言:\`${language}\`(中文文档使用 \`chi_sim\`,英文使用 \`eng\`)
136
+ - DPI:\`300\`(默认值)
137
+ - 保存到:\`${outputMdPath.replace('.md', '-ocr.md')}\`
138
+
139
+ **步骤 3:合并两个文件**
140
+ - 将 \`-text.md\` 和 \`-ocr.md\` 的内容合并
141
+ - 保存到:\`${outputMdPath}\`
142
+
93
143
  完成后重新调用本工具`,
94
144
  needsAction: {
95
145
  type: "read_pdf",
96
- instruction: `使用 PDF Reader MCP 读取 ${filePath},保存到 ${outputMdPath}`,
146
+ instruction: `使用 PDF Reader MCP 分两步读取 ${filePath}
147
+ 1. 先用 read_pdf_text 提取文本层,保存到 ${outputMdPath.replace('.md', '-text.md')}
148
+ 2. 再用 read_by_ocr 提取图片表格(language="${language}",dpi=300),保存到 ${outputMdPath.replace('.md', '-ocr.md')}
149
+ 3. 合并两个文件内容到 ${outputMdPath}
150
+ 这样可以确保内容完整,既保留文本的准确性,又提取了图片表格等视觉内容。`,
97
151
  },
98
152
  };
99
153
  }
100
154
 
101
155
  // 2.2.2 Markdown 文件 - 保存到固定位置
102
156
  if (ext === "md" || ext === "markdown") {
103
- const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
157
+ const projectRoot = getProjectRoot(filePath);
158
+ const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
159
+
104
160
  debugLog(`准备保存 Markdown 文件`, {
105
161
  inputPath: filePath,
106
162
  outputPath: outputMdPath,
163
+ projectRoot,
107
164
  isAbsolute: path.isAbsolute(filePath),
108
165
  resolvedPath: path.resolve(filePath)
109
166
  });
@@ -113,7 +170,7 @@ export async function processRequirementDocument(
113
170
  debugLog(`成功读取文件内容`, { contentLength: content.length });
114
171
 
115
172
  // 保存到固定位置
116
- const outputDir = outputMdPath.substring(0, outputMdPath.lastIndexOf("/"));
173
+ const outputDir = path.dirname(outputMdPath);
117
174
  debugLog(`准备创建目录`, { outputDir });
118
175
  await fs.mkdir(outputDir, { recursive: true });
119
176
  debugLog(`目录创建成功`, { outputDir });
@@ -140,7 +197,10 @@ export async function processRequirementDocument(
140
197
  throw new McpError(-32602, "网页 URL 不能为空");
141
198
  }
142
199
 
143
- const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
200
+ // 对于 URL,使用当前工作目录作为项目根目录
201
+ const projectRoot = process.cwd();
202
+ const outputMdPath = buildOutputPath(featureName, outputFileName, projectRoot);
203
+ debugLog(`处理网页 URL`, { url, projectRoot, outputMdPath });
144
204
  return {
145
205
  success: false,
146
206
  message: `🌐 检测到网页 URL
@@ -163,9 +223,12 @@ export async function processRequirementDocument(
163
223
  * 如果用户之前已经按照指令保存了文件,优先使用已保存的内容
164
224
  */
165
225
  export async function tryReadSavedRequirement(
166
- featureName: string
226
+ featureName: string,
227
+ projectRoot?: string
167
228
  ): Promise<string | null> {
168
- const savedRequirementPath = `.specs/requirements/${featureName}/origin-requirement.md`;
229
+ const root = projectRoot || process.cwd();
230
+ const savedRequirementPath = buildOutputPath(featureName, "origin-requirement.md", root);
231
+ debugLog(`尝试读取已保存的需求文档`, { featureName, projectRoot: root, savedRequirementPath });
169
232
  try {
170
233
  const savedContent = await fs.readFile(savedRequirementPath, "utf-8");
171
234
  if (savedContent) {
@@ -184,11 +247,13 @@ export async function tryReadSavedRequirement(
184
247
  */
185
248
  export async function saveDesignDocument(
186
249
  featureName: string,
187
- designContent: string
250
+ designContent: string,
251
+ projectRoot?: string
188
252
  ): Promise<void> {
189
- debugLog(`saveDesignDocument 开始`, { featureName });
190
- const designDocPath = `.specs/requirements/${featureName}/design-doc.md`;
191
- const outputDir = designDocPath.substring(0, designDocPath.lastIndexOf("/"));
253
+ const root = projectRoot || process.cwd();
254
+ debugLog(`saveDesignDocument 开始`, { featureName, projectRoot: root });
255
+ const designDocPath = buildOutputPath(featureName, "design-doc.md", root);
256
+ const outputDir = path.dirname(designDocPath);
192
257
  debugLog(`设计稿准备创建目录`, { outputDir });
193
258
  await fs.mkdir(outputDir, { recursive: true });
194
259
  debugLog(`设计稿目录创建成功`);
@@ -201,9 +266,12 @@ export async function saveDesignDocument(
201
266
  * 尝试读取已保存的设计稿文档
202
267
  */
203
268
  export async function tryReadSavedDesign(
204
- featureName: string
269
+ featureName: string,
270
+ projectRoot?: string
205
271
  ): Promise<string | null> {
206
- const savedDesignPath = `.specs/requirements/${featureName}/design-doc.md`;
272
+ const root = projectRoot || process.cwd();
273
+ const savedDesignPath = buildOutputPath(featureName, "design-doc.md", root);
274
+ debugLog(`尝试读取已保存的设计稿`, { featureName, projectRoot: root, savedDesignPath });
207
275
  try {
208
276
  const savedContent = await fs.readFile(savedDesignPath, "utf-8");
209
277
  if (savedContent) {
@@ -222,11 +290,13 @@ export async function tryReadSavedDesign(
222
290
  */
223
291
  export async function saveBackendDocument(
224
292
  featureName: string,
225
- backendContent: string
293
+ backendContent: string,
294
+ projectRoot?: string
226
295
  ): Promise<void> {
227
- debugLog(`saveBackendDocument 开始`, { featureName });
228
- const backendDocPath = `.specs/requirements/${featureName}/backend-doc.md`;
229
- const outputDir = backendDocPath.substring(0, backendDocPath.lastIndexOf("/"));
296
+ const root = projectRoot || process.cwd();
297
+ debugLog(`saveBackendDocument 开始`, { featureName, projectRoot: root });
298
+ const backendDocPath = buildOutputPath(featureName, "backend-doc.md", root);
299
+ const outputDir = path.dirname(backendDocPath);
230
300
  debugLog(`后端文档准备创建目录`, { outputDir });
231
301
  await fs.mkdir(outputDir, { recursive: true });
232
302
  debugLog(`后端文档目录创建成功`);
@@ -239,9 +309,12 @@ export async function saveBackendDocument(
239
309
  * 尝试读取已保存的后端文档
240
310
  */
241
311
  export async function tryReadSavedBackend(
242
- featureName: string
312
+ featureName: string,
313
+ projectRoot?: string
243
314
  ): Promise<string | null> {
244
- const savedBackendPath = `.specs/requirements/${featureName}/backend-doc.md`;
315
+ const root = projectRoot || process.cwd();
316
+ const savedBackendPath = buildOutputPath(featureName, "backend-doc.md", root);
317
+ debugLog(`尝试读取已保存的后端文档`, { featureName, projectRoot: root, savedBackendPath });
245
318
  try {
246
319
  const savedContent = await fs.readFile(savedBackendPath, "utf-8");
247
320
  if (savedContent) {