mcp-probe-kit 3.6.2 → 3.6.5

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 (30) hide show
  1. package/README.md +2 -2
  2. package/build/lib/__tests__/gitnexus-bridge.unit.test.js +1 -1
  3. package/build/lib/__tests__/project-context-writer.unit.test.d.ts +1 -0
  4. package/build/lib/__tests__/project-context-writer.unit.test.js +28 -0
  5. package/build/lib/__tests__/workspace-root.unit.test.js +16 -0
  6. package/build/lib/feature-spec-writer.d.ts +12 -0
  7. package/build/lib/feature-spec-writer.js +14 -0
  8. package/build/lib/file-delivery.d.ts +17 -0
  9. package/build/lib/file-delivery.js +42 -0
  10. package/build/lib/graph-insights-writer.d.ts +10 -0
  11. package/build/lib/graph-insights-writer.js +65 -0
  12. package/build/lib/init-project-writer.d.ts +7 -0
  13. package/build/lib/init-project-writer.js +161 -0
  14. package/build/lib/project-context-writer.d.ts +41 -0
  15. package/build/lib/project-context-writer.js +120 -0
  16. package/build/lib/tool-annotations.js +2 -2
  17. package/build/lib/workspace-root.js +18 -3
  18. package/build/schemas/output/project-tools.d.ts +136 -0
  19. package/build/schemas/output/project-tools.js +65 -1
  20. package/build/tools/__tests__/add_feature.write.unit.test.d.ts +1 -0
  21. package/build/tools/__tests__/add_feature.write.unit.test.js +30 -0
  22. package/build/tools/__tests__/code_insight.unit.test.js +2 -4
  23. package/build/tools/__tests__/init_project.write.unit.test.d.ts +1 -0
  24. package/build/tools/__tests__/init_project.write.unit.test.js +22 -0
  25. package/build/tools/__tests__/init_project_context.unit.test.js +49 -45
  26. package/build/tools/add_feature.js +23 -6
  27. package/build/tools/code_insight.js +3 -3
  28. package/build/tools/init_project.js +25 -22
  29. package/build/tools/init_project_context.js +66 -44
  30. package/package.json +1 -1
@@ -70,6 +70,50 @@ export declare const ProjectInitSchema: {
70
70
  readonly items: {
71
71
  readonly type: "string";
72
72
  };
73
+ readonly description: "已废弃,请用 writtenFiles / plannedFiles";
74
+ };
75
+ readonly writtenFiles: {
76
+ readonly type: "array";
77
+ readonly items: {
78
+ readonly type: "string";
79
+ };
80
+ readonly description: "已写入磁盘的路径";
81
+ };
82
+ readonly plannedFiles: {
83
+ readonly type: "array";
84
+ readonly items: {
85
+ readonly type: "string";
86
+ };
87
+ readonly description: "规划中尚未创建的路径";
88
+ };
89
+ };
90
+ };
91
+ readonly writtenFiles: {
92
+ readonly type: "array";
93
+ readonly items: {
94
+ readonly type: "object";
95
+ readonly properties: {
96
+ readonly path: {
97
+ readonly type: "string";
98
+ };
99
+ readonly action: {
100
+ readonly type: "string";
101
+ readonly enum: readonly ["created", "updated", "skipped"];
102
+ };
103
+ };
104
+ };
105
+ };
106
+ readonly pendingFiles: {
107
+ readonly type: "array";
108
+ readonly items: {
109
+ readonly type: "object";
110
+ readonly properties: {
111
+ readonly path: {
112
+ readonly type: "string";
113
+ };
114
+ readonly reason: {
115
+ readonly type: "string";
116
+ };
73
117
  };
74
118
  };
75
119
  };
@@ -174,6 +218,36 @@ export declare const ProjectContextSchema: {
174
218
  };
175
219
  };
176
220
  };
221
+ readonly description: "文档索引(含已写入与待生成)";
222
+ };
223
+ readonly writtenFiles: {
224
+ readonly type: "array";
225
+ readonly items: {
226
+ readonly type: "object";
227
+ readonly properties: {
228
+ readonly path: {
229
+ readonly type: "string";
230
+ };
231
+ readonly action: {
232
+ readonly type: "string";
233
+ readonly enum: readonly ["created", "updated", "skipped"];
234
+ };
235
+ };
236
+ };
237
+ };
238
+ readonly pendingFiles: {
239
+ readonly type: "array";
240
+ readonly items: {
241
+ readonly type: "object";
242
+ readonly properties: {
243
+ readonly path: {
244
+ readonly type: "string";
245
+ };
246
+ readonly reason: {
247
+ readonly type: "string";
248
+ };
249
+ };
250
+ };
177
251
  };
178
252
  readonly nextSteps: {
179
253
  readonly type: "array";
@@ -268,6 +342,41 @@ export declare const FeatureSpecSchema: {
268
342
  };
269
343
  };
270
344
  };
345
+ readonly writtenFiles: {
346
+ readonly type: "array";
347
+ readonly items: {
348
+ readonly type: "object";
349
+ readonly properties: {
350
+ readonly path: {
351
+ readonly type: "string";
352
+ };
353
+ readonly action: {
354
+ readonly type: "string";
355
+ readonly enum: readonly ["created", "updated", "skipped"];
356
+ };
357
+ };
358
+ };
359
+ };
360
+ readonly pendingFiles: {
361
+ readonly type: "array";
362
+ readonly items: {
363
+ readonly type: "object";
364
+ readonly properties: {
365
+ readonly path: {
366
+ readonly type: "string";
367
+ };
368
+ readonly reason: {
369
+ readonly type: "string";
370
+ };
371
+ };
372
+ };
373
+ };
374
+ readonly specPaths: {
375
+ readonly type: "array";
376
+ readonly items: {
377
+ readonly type: "string";
378
+ };
379
+ };
271
380
  };
272
381
  readonly required: readonly ["summary", "featureName", "requirements", "tasks"];
273
382
  };
@@ -459,7 +568,17 @@ export interface ProjectInit {
459
568
  structure: {
460
569
  directories?: string[];
461
570
  files?: string[];
571
+ writtenFiles?: string[];
572
+ plannedFiles?: string[];
462
573
  };
574
+ writtenFiles?: Array<{
575
+ path: string;
576
+ action: 'created' | 'updated' | 'skipped';
577
+ }>;
578
+ pendingFiles?: Array<{
579
+ path: string;
580
+ reason: string;
581
+ }>;
463
582
  techStack?: string[];
464
583
  dependencies?: Record<string, string>;
465
584
  scripts?: Record<string, string>;
@@ -486,6 +605,14 @@ export interface ProjectContext {
486
605
  }>;
487
606
  nextSteps?: string[];
488
607
  metadata?: Record<string, any>;
608
+ writtenFiles?: Array<{
609
+ path: string;
610
+ action: 'created' | 'updated' | 'skipped';
611
+ }>;
612
+ pendingFiles?: Array<{
613
+ path: string;
614
+ reason: string;
615
+ }>;
489
616
  }
490
617
  export interface FeatureSpec {
491
618
  summary: string;
@@ -509,6 +636,15 @@ export interface FeatureSpec {
509
636
  normal?: string;
510
637
  pessimistic?: string;
511
638
  };
639
+ writtenFiles?: Array<{
640
+ path: string;
641
+ action: 'created' | 'updated' | 'skipped';
642
+ }>;
643
+ pendingFiles?: Array<{
644
+ path: string;
645
+ reason: string;
646
+ }>;
647
+ specPaths?: string[];
512
648
  }
513
649
  export interface Estimate {
514
650
  summary: string;
@@ -32,7 +32,29 @@ export const ProjectInitSchema = {
32
32
  description: '项目结构',
33
33
  properties: {
34
34
  directories: { type: 'array', items: { type: 'string' } },
35
- files: { type: 'array', items: { type: 'string' } },
35
+ files: { type: 'array', items: { type: 'string' }, description: '已废弃,请用 writtenFiles / plannedFiles' },
36
+ writtenFiles: { type: 'array', items: { type: 'string' }, description: '已写入磁盘的路径' },
37
+ plannedFiles: { type: 'array', items: { type: 'string' }, description: '规划中尚未创建的路径' },
38
+ },
39
+ },
40
+ writtenFiles: {
41
+ type: 'array',
42
+ items: {
43
+ type: 'object',
44
+ properties: {
45
+ path: { type: 'string' },
46
+ action: { type: 'string', enum: ['created', 'updated', 'skipped'] },
47
+ },
48
+ },
49
+ },
50
+ pendingFiles: {
51
+ type: 'array',
52
+ items: {
53
+ type: 'object',
54
+ properties: {
55
+ path: { type: 'string' },
56
+ reason: { type: 'string' },
57
+ },
36
58
  },
37
59
  },
38
60
  techStack: {
@@ -100,6 +122,27 @@ export const ProjectContextSchema = {
100
122
  purpose: { type: 'string' },
101
123
  },
102
124
  },
125
+ description: '文档索引(含已写入与待生成)',
126
+ },
127
+ writtenFiles: {
128
+ type: 'array',
129
+ items: {
130
+ type: 'object',
131
+ properties: {
132
+ path: { type: 'string' },
133
+ action: { type: 'string', enum: ['created', 'updated', 'skipped'] },
134
+ },
135
+ },
136
+ },
137
+ pendingFiles: {
138
+ type: 'array',
139
+ items: {
140
+ type: 'object',
141
+ properties: {
142
+ path: { type: 'string' },
143
+ reason: { type: 'string' },
144
+ },
145
+ },
103
146
  },
104
147
  nextSteps: {
105
148
  type: 'array',
@@ -156,6 +199,27 @@ export const FeatureSpecSchema = {
156
199
  pessimistic: { type: 'string' },
157
200
  },
158
201
  },
202
+ writtenFiles: {
203
+ type: 'array',
204
+ items: {
205
+ type: 'object',
206
+ properties: {
207
+ path: { type: 'string' },
208
+ action: { type: 'string', enum: ['created', 'updated', 'skipped'] },
209
+ },
210
+ },
211
+ },
212
+ pendingFiles: {
213
+ type: 'array',
214
+ items: {
215
+ type: 'object',
216
+ properties: {
217
+ path: { type: 'string' },
218
+ reason: { type: 'string' },
219
+ },
220
+ },
221
+ },
222
+ specPaths: { type: 'array', items: { type: 'string' } },
159
223
  },
160
224
  required: ['summary', 'featureName', 'requirements', 'tasks'],
161
225
  };
@@ -0,0 +1,30 @@
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 { addFeature } from "../add_feature.js";
6
+ describe("add_feature 不落盘", () => {
7
+ test("仅返回模板与 pendingFiles,不写 specs 文件", async () => {
8
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "mcp-probe-add-feature-"));
9
+ const cwd = process.cwd();
10
+ process.chdir(projectRoot);
11
+ try {
12
+ const result = await addFeature({
13
+ feature_name: "user-auth",
14
+ description: "用户登录与注册",
15
+ });
16
+ expect(result.isError).toBeFalsy();
17
+ const structured = result.structuredContent;
18
+ expect(structured.pendingFiles).toHaveLength(3);
19
+ expect(structured.writtenFiles).toBeUndefined();
20
+ expect(fs.existsSync(path.join(projectRoot, "docs", "specs", "user-auth", "requirements.md"))).toBe(false);
21
+ const text = String(result.content[0].text);
22
+ expect(text).toMatch(/由 Agent 落盘/);
23
+ expect(text).toMatch(/MCP \*\*不会\*\*写入磁盘/);
24
+ }
25
+ finally {
26
+ process.chdir(cwd);
27
+ fs.rmSync(projectRoot, { recursive: true, force: true });
28
+ }
29
+ });
30
+ });
@@ -128,7 +128,7 @@ describe("code_insight 单元测试", () => {
128
128
  }
129
129
  }
130
130
  });
131
- test("返回 docs 保存指引而不直接代写文件", async () => {
131
+ test("save_to_docs 时返回 delegated plan,由 Agent 落盘图谱文件", async () => {
132
132
  const prev = process.env.MCP_ENABLE_GITNEXUS_BRIDGE;
133
133
  process.env.MCP_ENABLE_GITNEXUS_BRIDGE = "0";
134
134
  const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), "code-insight-docs-"));
@@ -146,13 +146,11 @@ describe("code_insight 单元测试", () => {
146
146
  expect(text).toMatch(/使用场景指南/);
147
147
  expect(structured.projectDocs.latestMarkdownFilePath).toMatch(/docs\/graph-insights\/latest\.md$/);
148
148
  expect(structured.projectDocs.archiveMarkdownFilePath).toContain("/docs/graph-insights/");
149
- expect(structured.projectDocs.projectContextFilePath).toMatch(/\/(AGENTS\.md|docs\/project-context\.md)$/);
150
- expect(structured.projectDocs.navigationSnippet).toMatch(/代码图谱洞察/);
151
149
  expect(structured.plan.mode).toBe("delegated");
152
150
  expect(structured.plan.steps).toHaveLength(2);
153
151
  expect(structured.plan.steps[0].id).toBe("consume-result");
154
152
  expect(structured.plan.steps[1].id).toBe("optional-save");
155
- expect(structured.plan.steps[1].outputs[0]).toMatch(/docs\/graph-insights\/latest\.md$/);
153
+ expect(structured.writtenFiles).toBeUndefined();
156
154
  expect(fs.existsSync(path.join(projectRoot, "docs", "graph-insights", "latest.md"))).toBe(false);
157
155
  }
158
156
  finally {
@@ -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, {