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 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":"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":"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,EACnB,cAAc,EACd,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAEpC;;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;AAuBD;;GAEG;AACH,SAAS,sBAAsB,CAC7B,MAAkC;IAYlC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,KAAK,EAAE;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,yLAAyL;gBAClM,WAAW,EAAE;oBACX,IAAI,EAAE,iBAAiB;oBACvB,WAAW,EAAE,4EAA4E;iBAC1F;aACF;SACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAkC;IASlC,QAAQ,CAAC,yBAAyB,EAAE;QAClC,MAAM;QACN,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;QAClB,QAAQ,EAAE,EAAE,CAAC,QAAQ,EAAE;QACvB,OAAO,EAAE,EAAE,CAAC,OAAO,EAAE;KACtB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,YAAY;QACZ,MAAM,UAAU,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACtB,OAAO,UAAU,CAAC,KAAM,CAAC;QAC3B,CAAC;QAED,cAAc;QAEd,uBAAuB;QACvB,IAAI,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,MAAM,CAAC,iBAAiB,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC;YAC9E,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;QAC9D,CAAC;QACD,QAAQ,CAAC,SAAS,EAAE,EAAE,WAAW,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAEzD,6CAA6C;QAC7C,QAAQ,CAAC,cAAc,EAAE,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC;QAC3E,MAAM,YAAY,GAAG,MAAM,uBAAuB,CAAC,MAAM,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC;QACpF,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,QAAQ,CAAC,gBAAgB,CAAC,CAAC;YAC3B,oBAAoB;YACpB,MAAM,iBAAiB,GAAG,MAAM,0BAA0B,CACxD,MAAM,CAAC,iBAAiB,EACxB,MAAM,CAAC,WAAW,CACnB,CAAC;YAEF,iCAAiC;YACjC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,CAAC;gBAC/B,QAAQ,CAAC,UAAU,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC;gBAC5C,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,OAAO,EAAE,iBAAiB,CAAC,OAAQ;oBACnC,WAAW,EAAE,iBAAiB,CAAC,WAAW;iBAC3C,CAAC;YACJ,CAAC;YAED,gCAAgC;QAClC,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,WAAW;QACX,IAAI,gBAAgB,GAAG,EAAE,CAAC;QAC1B,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YACxB,oBAAoB;YACpB,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAEjE,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,iBAAiB;gBACjB,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBACxC,kBAAkB;oBAClB,MAAM,iBAAiB,GAAG,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,IAAK,CAAC,CAAC;oBACpE,QAAQ,CAAC,UAAU,EAAE,EAAE,iBAAiB,EAAE,CAAC,CAAC;oBAE5C,MAAM,YAAY,GAAG,MAAM,0BAA0B,CACnD,MAAM,CAAC,YAAmB,EAC1B,MAAM,CAAC,WAAW,EAClB,eAAe,CAChB,CAAC;oBAEF,IAAI,CAAC,YAAY,CAAC,OAAO,EAAE,CAAC;wBAC1B,OAAO;4BACL,OAAO,EAAE,KAAK;4BACd,OAAO,EAAE,YAAY,CAAC,OAAQ;4BAC9B,WAAW,EAAE,YAAY,CAAC,WAAW;yBACtC,CAAC;oBACJ,CAAC;oBAED,gBAAgB,GAAG,aAAa,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,eAAe,EAAE,iBAAiB,CAAC,IAAI,CAAC;gBAC9G,CAAC;qBAAM,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;oBAChD,gBAAgB,GAAG,aAAa,MAAM,CAAC,YAAY,CAAC,GAAG,IAAI,aAAa,6CAA6C,MAAM,CAAC,WAAW,mBAAmB,CAAC;gBAC7J,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,gBAAgB;gBAChB,gBAAgB,GAAG,aAAa,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,eAAe,EAAE,WAAW,CAAC,IAAI,CAAC;YACxG,CAAC;QACH,CAAC;QAED,YAAY;QACZ,IAAI,iBAAiB,GAAG,EAAE,CAAC;QAC3B,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;YACzB,qBAAqB;YACrB,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YAEnE,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,kBAAkB;gBAClB,mBAAmB;gBACnB,MAAM,kBAAkB,GAAG,cAAc,CAAC,MAAM,CAAC,aAAa,CAAC,IAAK,CAAC,CAAC;gBACtE,QAAQ,CAAC,WAAW,EAAE,EAAE,kBAAkB,EAAE,CAAC,CAAC;gBAE9C,MAAM,aAAa,GAAG,MAAM,0BAA0B,CACpD,MAAM,CAAC,aAAa,EACpB,MAAM,CAAC,WAAW,EAClB,gBAAgB,CACjB,CAAC;gBAEF,IAAI,CAAC,aAAa,CAAC,OAAO,EAAE,CAAC;oBAC3B,OAAO;wBACL,OAAO,EAAE,KAAK;wBACd,OAAO,EAAE,aAAa,CAAC,OAAQ;wBAC/B,WAAW,EAAE,aAAa,CAAC,WAAW;qBACvC,CAAC;gBACJ,CAAC;gBAED,qBAAqB;gBACrB,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBACzC,iBAAiB,GAAG,cAAc,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,CAAC,IAAI,CAAC;gBAClH,CAAC;qBAAM,IAAI,MAAM,CAAC,aAAa,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;oBAC/C,iBAAiB,GAAG,cAAc,MAAM,CAAC,aAAa,CAAC,GAAG,IAAI,gBAAgB,uDAAuD,MAAM,CAAC,WAAW,oBAAoB,CAAC;gBAC9K,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,iBAAiB;gBACjB,iBAAiB,GAAG,cAAc,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,gBAAgB,EAAE,WAAW,CAAC,IAAI,CAAC;YAC3G,CAAC;QACH,CAAC;QAED,aAAa;QACb,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,iBAAiB,EAAE,WAAW,CAAC,CAAC;QACvF,MAAM,aAAa,GAAG,eAAe,CAAC,MAAM,CAAC,WAAW,EAAE,uBAAuB,EAAE,WAAW,CAAC,CAAC;QAChG,QAAQ,CAAC,QAAQ,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,CAAC;QAE/D,IAAI,OAAO,GAAG,kBAAkB,CAAC;QACjC,OAAO,IAAI,cAAc,aAAa,IAAI,CAAC;QAC3C,IAAI,gBAAgB,EAAE,CAAC;YACrB,OAAO,IAAI,gBAAgB,CAAC;QAC9B,CAAC;QACD,IAAI,iBAAiB,EAAE,CAAC;YACtB,OAAO,IAAI,iBAAiB,CAAC;QAC/B,CAAC;QACD,OAAO,IAAI,cAAc,UAAU,MAAM,CAAC;QAC1C,OAAO,IAAI,mBAAmB,CAAC,aAAa,EAAE,UAAU,EAAE,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;QAErG,QAAQ,CAAC,SAAS,CAAC,CAAC;QACpB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,OAAO;YACP,WAAW,EAAE;gBACX,IAAI,EAAE,iBAAiB;gBACvB,WAAW,EAAE,MAAM,aAAa,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,OAAO,UAAU,EAAE;aAClJ;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,QAAQ,CAAC,MAAM,EAAE;YACf,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC;gBAC9B,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,KAAK,EAAE,KAAK,CAAC,KAAK;gBAClB,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAClB,CAAC,CAAC;QACH,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;YAC9B,MAAM,KAAK,CAAC;QACd,CAAC;QACD,MAAM,IAAI,QAAQ,CAChB,CAAC,KAAK,EACN,aAAa,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACtE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAC1B,aAAqB,EACrB,UAAkB,EAClB,YAAsE,EACtE,aAAqE;IAErE,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7C,IAAI,MAAM,GAAG;;;;;;;;aAQF,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;;;;qBAIjD,aAAa;aACrB,YAAY,CAAC,CAAC,CAAC,4BAA4B,WAAW,iBAAiB,YAAY,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,+BAAgC;cACnK,aAAa,CAAC,CAAC,CAAC,4BAA4B,WAAW,iDAAiD,CAAC,CAAC,CAAC,0BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBAkIjI,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,uBAAuB,UAAU;;;CAG7E,CAAC;IAEA,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -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,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 outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
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 outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
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 = outputMdPath.substring(0, outputMdPath.lastIndexOf("/"));
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
- const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
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 savedRequirementPath = `.specs/requirements/${featureName}/origin-requirement.md`;
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
- debugLog(`saveDesignDocument 开始`, { featureName });
144
- const designDocPath = `.specs/requirements/${featureName}/design-doc.md`;
145
- const outputDir = designDocPath.substring(0, designDocPath.lastIndexOf("/"));
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 savedDesignPath = `.specs/requirements/${featureName}/design-doc.md`;
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
- debugLog(`saveBackendDocument 开始`, { featureName });
176
- const backendDocPath = `.specs/requirements/${featureName}/backend-doc.md`;
177
- const outputDir = backendDocPath.substring(0, backendDocPath.lastIndexOf("/"));
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 savedBackendPath = `.specs/requirements/${featureName}/backend-doc.md`;
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":"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"}
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.2",
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,7 +112,8 @@ 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);
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 outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
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 = outputMdPath.substring(0, outputMdPath.lastIndexOf("/"));
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
- const outputMdPath = `.specs/requirements/${featureName}/${outputFileName}`;
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 savedRequirementPath = `.specs/requirements/${featureName}/origin-requirement.md`;
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
- debugLog(`saveDesignDocument 开始`, { featureName });
190
- const designDocPath = `.specs/requirements/${featureName}/design-doc.md`;
191
- const outputDir = designDocPath.substring(0, designDocPath.lastIndexOf("/"));
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 savedDesignPath = `.specs/requirements/${featureName}/design-doc.md`;
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
- debugLog(`saveBackendDocument 开始`, { featureName });
228
- const backendDocPath = `.specs/requirements/${featureName}/backend-doc.md`;
229
- const outputDir = backendDocPath.substring(0, backendDocPath.lastIndexOf("/"));
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 savedBackendPath = `.specs/requirements/${featureName}/backend-doc.md`;
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) {