mcp-probe-kit 3.6.3 → 3.6.8

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.
Files changed (55) hide show
  1. package/README.md +3 -1
  2. package/build/index.js +1 -0
  3. package/build/lib/__tests__/agents-md-template.unit.test.js +2 -0
  4. package/build/lib/__tests__/agents-skill-ref.unit.test.d.ts +1 -0
  5. package/build/lib/__tests__/agents-skill-ref.unit.test.js +32 -0
  6. package/build/lib/__tests__/harness-adapters.unit.test.d.ts +1 -0
  7. package/build/lib/__tests__/harness-adapters.unit.test.js +68 -0
  8. package/build/lib/__tests__/harness-skill-targets.unit.test.d.ts +1 -0
  9. package/build/lib/__tests__/harness-skill-targets.unit.test.js +59 -0
  10. package/build/lib/__tests__/project-context-writer.unit.test.d.ts +1 -0
  11. package/build/lib/__tests__/project-context-writer.unit.test.js +28 -0
  12. package/build/lib/__tests__/project-mcp-resources.unit.test.js +1 -1
  13. package/build/lib/__tests__/workflow-skill-frontmatter.unit.test.d.ts +1 -0
  14. package/build/lib/__tests__/workflow-skill-frontmatter.unit.test.js +31 -0
  15. package/build/lib/__tests__/workflow-skill-installer.unit.test.js +21 -6
  16. package/build/lib/agents-md-template.d.ts +1 -0
  17. package/build/lib/agents-md-template.js +21 -6
  18. package/build/lib/agents-skill-ref.d.ts +6 -0
  19. package/build/lib/agents-skill-ref.js +45 -0
  20. package/build/lib/feature-spec-writer.d.ts +12 -0
  21. package/build/lib/feature-spec-writer.js +14 -0
  22. package/build/lib/file-delivery.d.ts +17 -0
  23. package/build/lib/file-delivery.js +42 -0
  24. package/build/lib/graph-insights-writer.d.ts +10 -0
  25. package/build/lib/graph-insights-writer.js +65 -0
  26. package/build/lib/harness-adapters.d.ts +19 -0
  27. package/build/lib/harness-adapters.js +166 -0
  28. package/build/lib/harness-skill-targets.d.ts +38 -0
  29. package/build/lib/harness-skill-targets.js +95 -0
  30. package/build/lib/init-project-writer.d.ts +7 -0
  31. package/build/lib/init-project-writer.js +161 -0
  32. package/build/lib/project-context-layout.d.ts +15 -2
  33. package/build/lib/project-context-layout.js +27 -3
  34. package/build/lib/project-context-writer.d.ts +41 -0
  35. package/build/lib/project-context-writer.js +120 -0
  36. package/build/lib/tool-annotations.js +2 -2
  37. package/build/lib/workflow-skill-installer.d.ts +2 -0
  38. package/build/lib/workflow-skill-installer.js +19 -5
  39. package/build/lib/workflow-skill-template.d.ts +3 -0
  40. package/build/lib/workflow-skill-template.js +12 -5
  41. package/build/lib/workflow-skill-version.d.ts +7 -1
  42. package/build/lib/workflow-skill-version.js +45 -2
  43. package/build/schemas/output/project-tools.d.ts +136 -0
  44. package/build/schemas/output/project-tools.js +65 -1
  45. package/build/tools/__tests__/add_feature.write.unit.test.d.ts +1 -0
  46. package/build/tools/__tests__/add_feature.write.unit.test.js +30 -0
  47. package/build/tools/__tests__/code_insight.unit.test.js +2 -4
  48. package/build/tools/__tests__/init_project.write.unit.test.d.ts +1 -0
  49. package/build/tools/__tests__/init_project.write.unit.test.js +22 -0
  50. package/build/tools/__tests__/init_project_context.unit.test.js +49 -45
  51. package/build/tools/add_feature.js +23 -6
  52. package/build/tools/code_insight.js +3 -3
  53. package/build/tools/init_project.js +25 -22
  54. package/build/tools/init_project_context.js +83 -46
  55. package/package.json +84 -84
@@ -0,0 +1,22 @@
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { describe, expect, test } from "vitest";
5
+ import { initProject } from "../init_project.js";
6
+ describe("init_project 落盘边界", () => {
7
+ test("仅写入 Skill 与 AGENTS.md,docs 由 Agent 创建", async () => {
8
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-probe-init-project-"));
9
+ const result = await initProject({
10
+ project_name: "Demo App",
11
+ project_root: projectRoot,
12
+ input: "一个简单的演示应用",
13
+ });
14
+ expect(result.isError).toBeFalsy();
15
+ const structured = result.structuredContent;
16
+ expect(structured.writtenFiles.length).toBe(2);
17
+ expect(structured.pendingFiles.length).toBeGreaterThan(0);
18
+ expect(fs.existsSync(path.join(projectRoot, "AGENTS.md"))).toBe(true);
19
+ expect(fs.existsSync(path.join(projectRoot, "docs", "project-context.md"))).toBe(false);
20
+ expect(fs.existsSync(path.join(projectRoot, "docs", "specs", "demo-app", "requirements.md"))).toBe(false);
21
+ });
22
+ });
@@ -1,74 +1,78 @@
1
- import fs from 'node:fs';
2
- import os from 'node:os';
3
- import path from 'node:path';
4
- import { describe, expect, test } from 'vitest';
5
- import { initProjectContext } from '../init_project_context.js';
6
- describe('init_project_context 单元测试', () => {
7
- test('返回 delegated plan,含 finalize-agents-md 与 AGENTS.md 模板', async () => {
8
- const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-probe-kit-init-'));
1
+ import fs from "node:fs";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ import { describe, expect, test } from "vitest";
5
+ import { initProjectContext } from "../init_project_context.js";
6
+ describe("init_project_context 单元测试", () => {
7
+ test("MCP 仅写入 AGENTS.md 与 layout.json", async () => {
8
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-probe-kit-init-"));
9
9
  const result = await initProjectContext({
10
- docs_dir: 'docs',
10
+ docs_dir: "docs",
11
11
  project_root: projectRoot,
12
12
  });
13
13
  expect(result.isError).toBeFalsy();
14
- expect('structuredContent' in result).toBe(true);
15
- if (!('structuredContent' in result)) {
16
- throw new Error('structuredContent 缺失');
14
+ expect("structuredContent" in result).toBe(true);
15
+ if (!("structuredContent" in result)) {
16
+ throw new Error("structuredContent 缺失");
17
17
  }
18
18
  const structured = result.structuredContent;
19
- expect(structured.documentation.some((item) => item.path === 'AGENTS.md')).toBe(true);
20
- expect(structured.documentation.some((item) => item.path === 'docs/graph-insights/latest.md')).toBe(true);
21
- expect(structured.metadata?.layout?.indexPath).toBe('AGENTS.md');
22
- expect(structured.metadata?.agentsMdTemplate).toMatch(/mcp-probe:context begin/);
23
- expect(structured.metadata?.manifestWritten).toBe('docs/.mcp-probe/layout.json');
24
- expect(fs.existsSync(path.join(projectRoot, 'docs', '.mcp-probe', 'layout.json'))).toBe(true);
19
+ expect(structured.writtenFiles.some((f) => f.path === "AGENTS.md")).toBe(true);
20
+ expect(structured.writtenFiles.some((f) => f.path === "docs/.mcp-probe/layout.json")).toBe(true);
21
+ expect(structured.pendingFiles.some((f) => f.path === "docs/project-context.md")).toBe(true);
22
+ expect(fs.existsSync(path.join(projectRoot, "docs", ".mcp-probe", "layout.json"))).toBe(true);
23
+ expect(fs.existsSync(path.join(projectRoot, "AGENTS.md"))).toBe(true);
24
+ expect(fs.existsSync(path.join(projectRoot, "docs", "project-context.md"))).toBe(false);
25
+ expect(fs.existsSync(path.join(projectRoot, "docs", "project-context", "tech-stack.md"))).toBe(false);
25
26
  const plan = structured.metadata?.plan;
26
- expect(plan?.mode).toBe('delegated');
27
+ expect(plan?.mode).toBe("delegated");
27
28
  expect(plan.steps.map((step) => step.id)).toEqual([
28
- 'write-modular-docs',
29
- 'bootstrap-code-insight',
30
- 'persist-graph-docs',
31
- 'finalize-agents-md',
29
+ "write-modular-docs",
30
+ "bootstrap-code-insight",
31
+ "persist-graph-docs",
32
32
  ]);
33
- expect(plan.steps[0].outputs).toContain('docs/project-context.md');
34
- expect(plan.steps[3].id).toBe('finalize-agents-md');
33
+ const text = result.content[0].text;
34
+ expect(text).toMatch(/文件落盘状态/);
35
+ expect(text).toMatch(/尚未创建/);
35
36
  });
36
- test('输出文本包含 AGENTS.md 与 MCP 触发规则', async () => {
37
- const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-probe-kit-init-'));
37
+ test("输出文本包含 AGENTS.md 与 MCP 触发规则", async () => {
38
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-probe-kit-init-"));
38
39
  const result = await initProjectContext({
39
40
  project_root: projectRoot,
40
41
  });
41
42
  const text = result.content[0].text;
42
43
  expect(text).toMatch(/AGENTS\.md/);
43
- expect(text).toMatch(/start_feature/);
44
- expect(text).toMatch(/finalize-agents-md/);
44
+ expect(text).toMatch(/文件落盘状态/);
45
45
  });
46
- test('已存在 project-context 分类文档时跳过重写 modular', async () => {
47
- const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-probe-kit-context-'));
48
- fs.mkdirSync(path.join(projectRoot, 'docs', 'project-context'), { recursive: true });
49
- fs.writeFileSync(path.join(projectRoot, 'docs', 'project-context.md'), '# existing context\n', 'utf8');
46
+ test("已存在 project-context 分类文档时跳过重写 modular", async () => {
47
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-probe-kit-context-"));
48
+ fs.mkdirSync(path.join(projectRoot, "docs", "project-context"), { recursive: true });
49
+ fs.writeFileSync(path.join(projectRoot, "docs", "project-context.md"), "# existing context\n", "utf8");
50
50
  const result = await initProjectContext({
51
- docs_dir: 'docs',
51
+ docs_dir: "docs",
52
52
  project_root: projectRoot,
53
53
  });
54
54
  expect(result.isError).toBeFalsy();
55
55
  const structured = result.structuredContent;
56
56
  expect(structured.metadata?.legacyProjectContextExists).toBe(true);
57
57
  expect(structured.metadata?.plan?.steps.map((step) => step.id)).toEqual([
58
- 'bootstrap-code-insight',
59
- 'persist-graph-docs',
60
- 'finalize-agents-md',
58
+ "bootstrap-code-insight",
59
+ "persist-graph-docs",
61
60
  ]);
61
+ expect(structured.pendingFiles.every((f) => !f.path.startsWith("docs/project-context"))).toBe(true);
62
+ expect(fs.readFileSync(path.join(projectRoot, "docs", "project-context.md"), "utf8")).toBe("# existing context\n");
63
+ expect(fs.existsSync(path.join(projectRoot, "AGENTS.md"))).toBe(true);
62
64
  const text = result.content[0].text;
63
65
  expect(text).toMatch(/保留/);
64
66
  });
65
- test('已有 AGENTS.md 用户内容时 prepend merge', async () => {
66
- const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-probe-kit-agents-'));
67
- fs.writeFileSync(path.join(projectRoot, 'AGENTS.md'), '# Custom rules\n', 'utf8');
68
- const result = await initProjectContext({ project_root: projectRoot });
69
- const structured = result.structuredContent;
70
- expect(structured.metadata?.agentsMdMergeMode).toBe('prepended');
71
- expect(structured.metadata?.agentsMdTemplate).toMatch(/<!-- mcp-probe:context begin/);
72
- expect(structured.metadata?.agentsMdTemplate).toContain('# Custom rules');
67
+ test("已有 AGENTS.md merge 而非覆盖", async () => {
68
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-probe-kit-agents-"));
69
+ fs.writeFileSync(path.join(projectRoot, "AGENTS.md"), "# Custom rules\n", "utf8");
70
+ const result = await initProjectContext({
71
+ project_root: projectRoot,
72
+ });
73
+ const agents = fs.readFileSync(path.join(projectRoot, "AGENTS.md"), "utf8");
74
+ expect(agents).toContain("# Custom rules");
75
+ expect(agents).toMatch(/mcp-probe:context/);
76
+ expect(result.structuredContent.metadata?.agentsMdMergeMode).not.toBe("replaced");
73
77
  });
74
78
  });
@@ -1,12 +1,12 @@
1
1
  import { parseArgs, getString } from "../utils/parseArgs.js";
2
- import { okText } from "../lib/response.js";
2
+ import { okStructured } from "../lib/response.js";
3
3
  import { loadTemplate, normalizeTemplateProfile } from "../lib/template-loader.js";
4
4
  import { handleToolError } from "../utils/error-handler.js";
5
5
  /**
6
6
  * add_feature 工具
7
7
  *
8
8
  * 功能:为已有项目添加新功能的规格文档
9
- * 模式:指令生成器模式 - 返回详细的生成指南,由 AI 执行实际操作
9
+ * 模式:指令生成器 MCP 返回模板与要求,由调用方 Agent 按模板落盘
10
10
  *
11
11
  * 输出文件:
12
12
  * - docs/specs/{feature_name}/requirements.md - 需求文档
@@ -236,9 +236,9 @@ ${combinedValidation.warnings.length > 0 ? `- 其他警告: ${combinedValidation
236
236
 
237
237
  ---
238
238
 
239
- ## 📝 创建文档
239
+ ## 📝 创建文档(由 Agent 落盘)
240
240
 
241
- 请在 \`${docsDir}/specs/${featureName}/\` 目录下创建以下三个文件:
241
+ MCP **不会**写入磁盘。请根据下方模板,在 \`${docsDir}/specs/${featureName}/\` 创建三个文件并替换占位符。
242
242
 
243
243
  ### 文件 1: requirements.md
244
244
 
@@ -286,9 +286,26 @@ ${fenceClose}
286
286
  *指南版本: 1.1.0*
287
287
  *工具: MCP Probe Kit - add_feature*
288
288
  `;
289
- return okText(guide, {
289
+ const specPaths = [
290
+ `${docsDir}/specs/${featureName}/requirements.md`,
291
+ `${docsDir}/specs/${featureName}/design.md`,
292
+ `${docsDir}/specs/${featureName}/tasks.md`,
293
+ ];
294
+ const pendingFiles = specPaths.map((specPath) => ({
295
+ path: specPath,
296
+ reason: "由 Agent 根据本工具返回的模板写入",
297
+ }));
298
+ const structuredData = {
299
+ summary: `功能规格:${featureName}`,
300
+ featureName,
301
+ requirements: ["见 requirements.md 模板"],
302
+ tasks: [{ id: "1", title: "按模板创建 specs 文档", description: "将下方模板落盘并补充真实内容" }],
303
+ pendingFiles,
304
+ specPaths,
305
+ };
306
+ return okStructured(guide, structuredData, {
290
307
  schema: (await import("../schemas/output/project-tools.js")).FeatureSpecSchema,
291
- note: "本工具返回功能规格生成指南,AI 应根据指南创建需求、设计和任务文档",
308
+ note: "本工具返回模板与要求,不代写文件;Agent 须按指南创建 specs",
292
309
  template: {
293
310
  profile: templateProfile,
294
311
  requested: profileDecision.requested,
@@ -197,7 +197,7 @@ function renderUsageGuide() {
197
197
  ## 下一步建议
198
198
  - 查询不精确: 增加 \`goal\`(例如“理解登录认证流程”)
199
199
  - 出现歧义: 传入 \`uid\` 或 \`file_path\` 重新执行
200
- - 需要落盘: 传 \`save_to_docs: true\`,再按 delegated plan 写入 docs/graph-insights`;
200
+ - 需要落盘: 传 \`save_to_docs: true\`,再按 delegated plan 由 Agent 写入 docs/graph-insights`;
201
201
  }
202
202
  export function resolveCodeInsightQuery(input) {
203
203
  const finalTarget = input.target || ((input.mode === "context" || input.mode === "impact") ? input.input : "");
@@ -369,7 +369,7 @@ ${result.warnings.length > 0 ? `警告: ${result.warnings.join(", ")}` : ""}`.tr
369
369
  structured.nextAction = delegatedPlan?.kind === "ambiguity"
370
370
  ? "请先选择 uid 或 file_path 重新调用 code_insight 完成消歧"
371
371
  : projectDocs
372
- ? `请按 delegated plan 落盘图谱文档,并更新 ${projectDocs.projectContextFilePath} 的索引入口`
372
+ ? `请按 delegated plan 由 Agent 落盘图谱文档,并更新 ${projectDocs.projectContextFilePath} 的索引入口`
373
373
  : null;
374
374
  const structuredWithHandles = attachHandles(structured, {
375
375
  graph_resource: DEFAULT_GRAPH_RESOURCE_URI,
@@ -379,7 +379,7 @@ ${result.warnings.length > 0 ? `警告: ${result.warnings.join(", ")}` : ""}`.tr
379
379
  tool: "code_insight",
380
380
  goal: delegatedPlan.kind === "ambiguity"
381
381
  ? "先完成符号消歧,再继续图谱分析"
382
- : "完成图谱分析后,将结果按 delegated plan 落盘到 docs/graph-insights",
382
+ : "完成图谱分析后,由 Agent 按 delegated plan 落盘到 docs/graph-insights",
383
383
  tasks: delegatedPlan.kind === "ambiguity"
384
384
  ? [
385
385
  "先阅读本次 code_insight 返回的 candidates",
@@ -37,6 +37,21 @@ export async function initProject(args) {
37
37
  : "";
38
38
  const featureSlug = projectName.toLowerCase().replace(/\s+/g, '-');
39
39
  const agentsRel = toPosixPath(bootstrap.agentsMd.path);
40
+ const bootstrapWritten = [
41
+ { path: MCP_PROBE_SKILL_REL_PATH, action: bootstrap.skill.created ? "created" : bootstrap.skill.updated ? "updated" : "skipped" },
42
+ { path: agentsRel, action: bootstrap.agentsMd.created ? "created" : bootstrap.agentsMd.updated ? "updated" : "skipped" },
43
+ ];
44
+ const pendingFiles = [
45
+ { path: "docs/project-context.md", reason: "由 Agent 按指南创建" },
46
+ { path: "docs/constitution.md", reason: "由 Agent 按指南创建" },
47
+ { path: `docs/specs/${featureSlug}/requirements.md`, reason: "由 Agent 按指南创建" },
48
+ { path: `docs/specs/${featureSlug}/design.md`, reason: "由 Agent 按指南创建" },
49
+ { path: `docs/specs/${featureSlug}/tasks.md`, reason: "由 Agent 按指南创建" },
50
+ { path: `docs/specs/${featureSlug}/research.md`, reason: "由 Agent 按指南创建" },
51
+ { path: "scripts/check-prerequisites.sh", reason: "由 Agent 按指南创建" },
52
+ { path: "scripts/setup.sh", reason: "由 Agent 按指南创建" },
53
+ { path: "src/", reason: "由 Agent 按项目类型创建源代码目录" },
54
+ ];
40
55
  const message = `你需要按照 Spec-Driven Development(规范驱动开发)的方式初始化项目,参考 https://github.com/github/spec-kit 的工作流程。
41
56
 
42
57
  📋 **项目需求**:
@@ -208,7 +223,7 @@ ${warningBlock}
208
223
  7. 识别可以并行执行的任务以优化开发效率
209
224
 
210
225
  🚀 **开始执行**:
211
- 现在请按照上述步骤创建项目结构和所有必需的文档。`;
226
+ MCP 已写入 Skill 与 AGENTS.md。请按上述步骤由 Agent 创建 docs、scripts、src 及 specs 文档。`;
212
227
  // 创建结构化数据对象
213
228
  const structuredData = {
214
229
  summary: `初始化项目:${projectName}`,
@@ -234,29 +249,17 @@ ${warningBlock}
234
249
  'scripts/',
235
250
  'src/'
236
251
  ],
237
- files: [
238
- MCP_PROBE_SKILL_REL_PATH,
239
- agentsRel,
240
- 'docs/project-context.md',
241
- 'docs/constitution.md',
242
- `docs/specs/${featureSlug}/requirements.md`,
243
- `docs/specs/${featureSlug}/design.md`,
244
- `docs/specs/${featureSlug}/tasks.md`,
245
- `docs/specs/${featureSlug}/research.md`,
246
- 'scripts/check-prerequisites.sh',
247
- 'scripts/setup.sh'
248
- ]
252
+ writtenFiles: bootstrapWritten.map((file) => file.path),
253
+ plannedFiles: pendingFiles.map((file) => file.path),
249
254
  },
255
+ writtenFiles: bootstrapWritten,
256
+ pendingFiles,
250
257
  nextSteps: [
251
- '确认 .agents/skills/mcp-probe-kit/SKILL.md 与 AGENTS.md 已落盘',
252
- '创建项目目录结构',
253
- '生成 project-context.md',
254
- '生成 constitution.md',
255
- '生成需求文档 requirements.md',
256
- '生成设计文档 design.md',
257
- '生成任务清单 tasks.md',
258
- '生成技术调研 research.md',
259
- '创建辅助脚本'
258
+ '确认 Skill 与 AGENTS.md 已落盘',
259
+ '按指南创建 docs/ 文档与 specs',
260
+ '创建 scripts/ 辅助脚本',
261
+ '创建 src/ 源代码目录',
262
+ '运行 init_project_context 生成完整上下文与图谱',
260
263
  ]
261
264
  };
262
265
  return okStructured(message, structuredData, {
@@ -6,8 +6,12 @@ import { resolveWorkspaceRoot, isLikelyProjectNamedRelativePath, buildProjectRoo
6
6
  import { detectDocumentLocale, layoutAbsPath, legacyProjectContextExists, parseLayoutArgsFromRecord, resolveProjectContextLayout, toPosixPath, writeLayoutManifest, } from "../lib/project-context-layout.js";
7
7
  import { mergeAgentsMdBlock } from "../lib/merge-agents-md.js";
8
8
  import { generateAgentsMdInner } from "../lib/agents-md-template.js";
9
- import * as fs from 'fs';
10
- import * as path from 'path';
9
+ import { ensureHarnessAdapters } from "../lib/harness-adapters.js";
10
+ import { generateWorkflowSkillContent, MCP_PROBE_SKILL_REL_PATH } from "../lib/workflow-skill-template.js";
11
+ import { getMcpProbeSkillVersion } from "../lib/workflow-skill-version.js";
12
+ import { formatFileDeliverySection, writeProjectFile, } from "../lib/file-delivery.js";
13
+ import * as fs from "fs";
14
+ import * as path from "path";
11
15
  /**
12
16
  * init_project_context 工具
13
17
  *
@@ -176,16 +180,55 @@ async function generateProjectContext(layout, projectRoot) {
176
180
  category: detection.category,
177
181
  docs,
178
182
  projectRootPosix: layout.projectRootPosix,
179
- graphReady: false,
183
+ graphReady: fs.existsSync(layoutAbsPath(layout, layout.latestMarkdownPath)),
184
+ contextReady: modularExists,
180
185
  });
181
186
  const mergedAgents = mergeAgentsMdBlock(existingAgentsRaw, agentsInner);
182
- const manifestWritten = writeLayoutManifest(projectRootAbs, layout);
187
+ const skillPath = layoutAbsPath(layout, MCP_PROBE_SKILL_REL_PATH);
188
+ const skillContent = fs.existsSync(skillPath)
189
+ ? fs.readFileSync(skillPath, "utf8")
190
+ : generateWorkflowSkillContent(getMcpProbeSkillVersion());
191
+ const harnessResult = ensureHarnessAdapters(projectRootAbs, skillContent, layout.indexPath);
192
+ const manifestWritten = writeLayoutManifest(projectRootAbs, layout, harnessResult.layoutHarness);
193
+ const agentsMdWritten = writeProjectFile(projectRootAbs, layout.indexPath, mergedAgents.content, "always");
194
+ const writtenFiles = [
195
+ agentsMdWritten,
196
+ { path: manifestWritten, action: "updated" },
197
+ ...harnessResult.adapters
198
+ .filter((a) => a.created || a.updated)
199
+ .map((a) => ({
200
+ path: a.path,
201
+ action: (a.created ? "created" : "updated"),
202
+ })),
203
+ ];
204
+ const pendingFiles = [
205
+ ...(modularExists
206
+ ? []
207
+ : [
208
+ {
209
+ path: layout.legacyIndexPath,
210
+ reason: "由 Agent 按本工具返回的模板写入",
211
+ },
212
+ ...docs.map((doc) => ({
213
+ path: `${layout.modularDir}/${doc.file}`,
214
+ reason: "由 Agent 按模板写入",
215
+ })),
216
+ ]),
217
+ {
218
+ path: graphDocs.latestMarkdownFilePath,
219
+ reason: "由 Agent 按 code_insight 分析结果写入",
220
+ },
221
+ {
222
+ path: graphDocs.latestJsonFilePath,
223
+ reason: "由 Agent 按 code_insight 结构化结果写入",
224
+ },
225
+ ];
226
+ const deliverySection = formatFileDeliverySection({ writtenFiles, pendingFiles });
183
227
  const codeInsightArgs = JSON.stringify({
184
228
  mode: "auto",
185
229
  project_root: layout.projectRootPosix,
186
230
  docs_dir: docsDir,
187
231
  });
188
- const modularOutputs = docs.map((doc) => `${layout.modularDir}/${doc.file}`);
189
232
  const plan = {
190
233
  mode: "delegated",
191
234
  steps: modularExists
@@ -194,60 +237,49 @@ async function generateProjectContext(layout, projectRoot) {
194
237
  id: "bootstrap-code-insight",
195
238
  action: `检测到现有 ${layout.legacyIndexPath},跳过重写分类文档,调用 code_insight 补齐图谱`,
196
239
  outputs: [graphDocs.latestMarkdownFilePath, graphDocs.latestJsonFilePath],
197
- note: `调用参数: ${codeInsightArgs}`,
240
+ note: `调用参数: ${codeInsightArgs};${layout.indexPath} 与 layout 已由 MCP 写入`,
198
241
  },
199
242
  {
200
243
  id: "persist-graph-docs",
201
- action: `执行 code_insight 的 delegated plan,写入 ${layout.graphDir}/`,
244
+ action: `执行 code_insight 的 delegated plan,由 Agent 写入 ${layout.graphDir}/`,
202
245
  outputs: [graphDocs.latestMarkdownFilePath, graphDocs.latestJsonFilePath],
203
246
  note: "保留现有 project-context 分类文档",
204
247
  },
205
- {
206
- id: "finalize-agents-md",
207
- action: `将下方 agentsMdTemplate 写入 ${layout.indexPath}(mcp-probe 块置顶,保留用户原有内容)`,
208
- outputs: [layout.indexPath],
209
- note: `mergeMode: ${mergedAgents.mergeMode};layout manifest 已由服务端写入 ${manifestWritten}`,
210
- },
211
248
  ]
212
249
  : [
213
250
  {
214
251
  id: "write-modular-docs",
215
- action: `先创建 ${layout.legacyIndexPath}(文档索引),再创建 ${layout.modularDir}/ 分类文档`,
216
- outputs: [layout.legacyIndexPath, ...modularOutputs],
217
- note: modularExists
218
- ? "跳过:索引与分类文档已存在"
219
- : "project-context.md 是细节入口;AGENTS.md 仅含 MCP 规则",
252
+ action: `由 Agent 创建 ${layout.legacyIndexPath} ${layout.modularDir}/ 分类文档(见下方模板)`,
253
+ outputs: [
254
+ layout.legacyIndexPath,
255
+ ...docs.map((doc) => `${layout.modularDir}/${doc.file}`),
256
+ ],
220
257
  },
221
258
  {
222
259
  id: "bootstrap-code-insight",
223
260
  action: "调用 code_insight 做整体图谱分析",
224
261
  outputs: [graphDocs.latestMarkdownFilePath, graphDocs.latestJsonFilePath],
225
- note: `调用参数: ${codeInsightArgs}`,
262
+ note: `调用参数: ${codeInsightArgs};${layout.indexPath} 已由 MCP 写入`,
226
263
  },
227
264
  {
228
265
  id: "persist-graph-docs",
229
- action: `执行 code_insight 的 delegated plan,写入 ${layout.graphDir}/`,
266
+ action: `执行 code_insight 的 delegated plan,由 Agent 写入 ${layout.graphDir}/`,
230
267
  outputs: [graphDocs.latestMarkdownFilePath, graphDocs.latestJsonFilePath],
231
268
  },
232
- {
233
- id: "finalize-agents-md",
234
- action: `将下方 agentsMdTemplate 写入 ${layout.indexPath}(mcp-probe 块置顶)`,
235
- outputs: [layout.indexPath],
236
- note: `mergeMode: ${mergedAgents.mergeMode};manifest 已写入 ${manifestWritten}`,
237
- },
238
269
  ],
239
270
  };
240
271
  const guide = generateGuideText(detection, projectInfo, docs, layout, resolvedRoot, {
241
272
  modularExists,
273
+ agentsMdWritten: true,
242
274
  });
243
275
  const header = renderOrchestrationHeader({
244
276
  tool: "init_project_context",
245
277
  goal: modularExists
246
- ? "补齐图谱与 AGENTS.md 入口(保留现有分类文档)"
247
- : "生成项目上下文、图谱入口与 AGENTS.md 操作规则",
278
+ ? "补齐图谱(保留现有分类文档;AGENTS.md 已由 MCP 写入)"
279
+ : "写入 AGENTS.md 与 layout,由 Agent 生成 project-context 与图谱",
248
280
  tasks: modularExists
249
- ? ["保留现有分类文档", "code_insight 生成图谱", `写入 ${layout.indexPath}`]
250
- : ["写分类文档", "code_insight", `写入 ${layout.indexPath}`],
281
+ ? ["保留现有分类文档", "code_insight + Agent 落盘图谱"]
282
+ : ["MCP 已写 AGENTS.md 与 layout", "Agent 写分类文档", "code_insight + Agent 落盘图谱"],
251
283
  notes: [
252
284
  `项目根目录: ${toPosixPath(resolvedRoot)}`,
253
285
  `上下文目录: ${docsDir}`,
@@ -289,16 +321,17 @@ async function generateProjectContext(layout, projectRoot) {
289
321
  nextSteps: [
290
322
  ...(modularExists
291
323
  ? [`保留 ${layout.legacyIndexPath} 与分类文档`]
292
- : [`生成 ${layout.modularDir}/ 分类文档`]),
293
- "调用 code_insight",
294
- `将 agentsMdTemplate 写入 ${layout.indexPath}`,
324
+ : [`由 Agent 按模板创建 ${layout.modularDir}/ 分类文档`]),
325
+ "调用 code_insight,由 Agent 落盘图谱",
326
+ `${layout.indexPath} ${manifestWritten} 已由 MCP 写入(mergeMode: ${mergedAgents.mergeMode})`,
295
327
  ],
328
+ writtenFiles,
329
+ pendingFiles,
296
330
  metadata: {
297
331
  plan,
298
332
  graphDocs,
299
333
  layout,
300
334
  locale,
301
- agentsMdTemplate: mergedAgents.content,
302
335
  agentsMdMergeMode: mergedAgents.mergeMode,
303
336
  manifestWritten,
304
337
  projectContextFilePath: agentsPath,
@@ -306,15 +339,12 @@ async function generateProjectContext(layout, projectRoot) {
306
339
  projectContextExists: modularExists,
307
340
  },
308
341
  };
309
- return okStructured(`${header}${guide}
310
-
311
- ## AGENTS.md 终稿(finalize-agents-md 使用 fsWrite 写入 \`${layout.indexPath}\`)
342
+ return okStructured(`${header}
343
+ ${deliverySection}
312
344
 
313
- \`\`\`markdown
314
- ${mergedAgents.content}
315
- \`\`\`
345
+ ${guide}
316
346
 
317
- ## delegated plan
347
+ ## 后续 delegated plan(分类文档与图谱由 Agent 落盘)
318
348
  ${renderPlanSteps(plan.steps)}
319
349
  `, structuredData, {
320
350
  schema: (await import("../schemas/output/project-tools.js")).ProjectContextSchema,
@@ -332,7 +362,14 @@ function generateGuideText(detection, projectInfo, docs, layout, projectRoot, op
332
362
  const timestamp = new Date().toISOString();
333
363
  const docsDir = layout.contextRoot;
334
364
  const projectContextExists = options?.modularExists === true;
365
+ const agentsMdWritten = options?.agentsMdWritten === true;
335
366
  return `# 项目上下文文档生成指导
367
+ ${agentsMdWritten ? `
368
+ ## ⚠️ 文件落盘说明
369
+
370
+ **MCP 已写入** \`${layout.indexPath}\` 与 \`${layout.manifestPath}\`。
371
+ **分类文档与图谱**须由 Agent 按下方模板与 \`code_insight\` 结果自行落盘(见 pendingFiles)。
372
+ ` : ""}
336
373
 
337
374
  ## 📊 项目信息
338
375
 
@@ -345,8 +382,8 @@ function generateGuideText(detection, projectInfo, docs, layout, projectRoot, op
345
382
 
346
383
  ## 🔎 当前状态
347
384
 
348
- - **${layout.indexPath}**: Agent 入口(finalize-agents-md 写入,mcp-probe 块置顶)
349
- - **${layout.legacyIndexPath}**: ${projectContextExists ? '已存在(将保留分类文档)' : '将随分类文档一并生成'}
385
+ - **${layout.indexPath}**: Agent 入口(${agentsMdWritten ? "已由 MCP 写入" : "待 MCP 写入"},mcp-probe 块置顶)
386
+ - **${layout.legacyIndexPath}**: ${projectContextExists ? "已存在(将保留分类文档)" : "由 Agent 按模板创建"}
350
387
  - **图谱文档**: 需要确保 ${layout.latestMarkdownPath} 与 ${layout.latestJsonPath} 可用
351
388
 
352
389
  ## 📋 需要生成的文档
@@ -431,7 +468,7 @@ ${generateDevGuide(docs)}
431
468
  *生成工具: MCP Probe Kit - init_project_context v2.1*
432
469
  \`\`\`
433
470
 
434
- ${projectContextExists ? '**如果该文件已存在,跳过此步骤,不要覆盖**' : '**使用 fsWrite 创建此文件**'}
471
+ ${projectContextExists ? '**如果该文件已存在,跳过此步骤,不要覆盖**' : '**由 Agent 使用 fsWrite 创建此文件**'}
435
472
 
436
473
  ---
437
474
 
@@ -445,7 +482,7 @@ ${docs.map((doc, index) => generateDocTemplate(doc, index + 2, projectInfo, dete
445
482
 
446
483
  请确认:
447
484
 
448
- - [ ] ${projectContextExists ? '保留现有 project-context 及分类文档,不做覆盖' : `已使用 fsWrite 创建 **${docs.length + 1}** 个文件`}
485
+ - [ ] ${projectContextExists ? '保留现有 project-context 及分类文档,不做覆盖' : `由 Agent 创建 **${docs.length + 1}** 个分类文档`}
449
486
  - [ ] 索引文件 \`project-context.md\` ${projectContextExists ? '已存在并保留' : '已创建(最重要!)'}
450
487
  - [ ] 索引文件已包含 \`graph-insights/latest.md\` 的入口
451
488
  - [ ] 所有文档都包含**真实的文件路径**(不是 [xxx] 占位符)
@@ -770,7 +807,7 @@ function generateDocTemplate(doc, step, projectInfo, detection, docsDir) {
770
807
 
771
808
  ${template}
772
809
 
773
- **使用 fsWrite 创建此文件**`;
810
+ **由 Agent 使用 fsWrite 创建此文件**`;
774
811
  }
775
812
  /**
776
813
  * init_project_context 工具实现