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.
- package/README.md +3 -1
- package/build/index.js +1 -0
- package/build/lib/__tests__/agents-md-template.unit.test.js +2 -0
- package/build/lib/__tests__/agents-skill-ref.unit.test.d.ts +1 -0
- package/build/lib/__tests__/agents-skill-ref.unit.test.js +32 -0
- package/build/lib/__tests__/harness-adapters.unit.test.d.ts +1 -0
- package/build/lib/__tests__/harness-adapters.unit.test.js +68 -0
- package/build/lib/__tests__/harness-skill-targets.unit.test.d.ts +1 -0
- package/build/lib/__tests__/harness-skill-targets.unit.test.js +59 -0
- package/build/lib/__tests__/project-context-writer.unit.test.d.ts +1 -0
- package/build/lib/__tests__/project-context-writer.unit.test.js +28 -0
- package/build/lib/__tests__/project-mcp-resources.unit.test.js +1 -1
- package/build/lib/__tests__/workflow-skill-frontmatter.unit.test.d.ts +1 -0
- package/build/lib/__tests__/workflow-skill-frontmatter.unit.test.js +31 -0
- package/build/lib/__tests__/workflow-skill-installer.unit.test.js +21 -6
- package/build/lib/agents-md-template.d.ts +1 -0
- package/build/lib/agents-md-template.js +21 -6
- package/build/lib/agents-skill-ref.d.ts +6 -0
- package/build/lib/agents-skill-ref.js +45 -0
- package/build/lib/feature-spec-writer.d.ts +12 -0
- package/build/lib/feature-spec-writer.js +14 -0
- package/build/lib/file-delivery.d.ts +17 -0
- package/build/lib/file-delivery.js +42 -0
- package/build/lib/graph-insights-writer.d.ts +10 -0
- package/build/lib/graph-insights-writer.js +65 -0
- package/build/lib/harness-adapters.d.ts +19 -0
- package/build/lib/harness-adapters.js +166 -0
- package/build/lib/harness-skill-targets.d.ts +38 -0
- package/build/lib/harness-skill-targets.js +95 -0
- package/build/lib/init-project-writer.d.ts +7 -0
- package/build/lib/init-project-writer.js +161 -0
- package/build/lib/project-context-layout.d.ts +15 -2
- package/build/lib/project-context-layout.js +27 -3
- package/build/lib/project-context-writer.d.ts +41 -0
- package/build/lib/project-context-writer.js +120 -0
- package/build/lib/tool-annotations.js +2 -2
- package/build/lib/workflow-skill-installer.d.ts +2 -0
- package/build/lib/workflow-skill-installer.js +19 -5
- package/build/lib/workflow-skill-template.d.ts +3 -0
- package/build/lib/workflow-skill-template.js +12 -5
- package/build/lib/workflow-skill-version.d.ts +7 -1
- package/build/lib/workflow-skill-version.js +45 -2
- package/build/schemas/output/project-tools.d.ts +136 -0
- package/build/schemas/output/project-tools.js +65 -1
- package/build/tools/__tests__/add_feature.write.unit.test.d.ts +1 -0
- package/build/tools/__tests__/add_feature.write.unit.test.js +30 -0
- package/build/tools/__tests__/code_insight.unit.test.js +2 -4
- package/build/tools/__tests__/init_project.write.unit.test.d.ts +1 -0
- package/build/tools/__tests__/init_project.write.unit.test.js +22 -0
- package/build/tools/__tests__/init_project_context.unit.test.js +49 -45
- package/build/tools/add_feature.js +23 -6
- package/build/tools/code_insight.js +3 -3
- package/build/tools/init_project.js +25 -22
- package/build/tools/init_project_context.js +83 -46
- package/package.json +84 -84
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -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
|
|
2
|
-
import os from
|
|
3
|
-
import path from
|
|
4
|
-
import { describe, expect, test } from
|
|
5
|
-
import { initProjectContext } from
|
|
6
|
-
describe(
|
|
7
|
-
test(
|
|
8
|
-
const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
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:
|
|
10
|
+
docs_dir: "docs",
|
|
11
11
|
project_root: projectRoot,
|
|
12
12
|
});
|
|
13
13
|
expect(result.isError).toBeFalsy();
|
|
14
|
-
expect(
|
|
15
|
-
if (!(
|
|
16
|
-
throw new Error(
|
|
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.
|
|
20
|
-
expect(structured.
|
|
21
|
-
expect(structured.
|
|
22
|
-
expect(
|
|
23
|
-
expect(
|
|
24
|
-
expect(fs.existsSync(path.join(projectRoot,
|
|
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(
|
|
27
|
+
expect(plan?.mode).toBe("delegated");
|
|
27
28
|
expect(plan.steps.map((step) => step.id)).toEqual([
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
'finalize-agents-md',
|
|
29
|
+
"write-modular-docs",
|
|
30
|
+
"bootstrap-code-insight",
|
|
31
|
+
"persist-graph-docs",
|
|
32
32
|
]);
|
|
33
|
-
|
|
34
|
-
expect(
|
|
33
|
+
const text = result.content[0].text;
|
|
34
|
+
expect(text).toMatch(/文件落盘状态/);
|
|
35
|
+
expect(text).toMatch(/尚未创建/);
|
|
35
36
|
});
|
|
36
|
-
test(
|
|
37
|
-
const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
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(
|
|
44
|
-
expect(text).toMatch(/finalize-agents-md/);
|
|
44
|
+
expect(text).toMatch(/文件落盘状态/);
|
|
45
45
|
});
|
|
46
|
-
test(
|
|
47
|
-
const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
48
|
-
fs.mkdirSync(path.join(projectRoot,
|
|
49
|
-
fs.writeFileSync(path.join(projectRoot,
|
|
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:
|
|
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
|
-
|
|
59
|
-
|
|
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(
|
|
66
|
-
const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(),
|
|
67
|
-
fs.writeFileSync(path.join(projectRoot,
|
|
68
|
-
const result = await initProjectContext({
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
expect(
|
|
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 {
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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: "
|
|
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
|
-
: "
|
|
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
|
-
|
|
238
|
-
|
|
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
|
-
'确认
|
|
252
|
-
'
|
|
253
|
-
'
|
|
254
|
-
'
|
|
255
|
-
'
|
|
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
|
|
10
|
-
import
|
|
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:
|
|
183
|
+
graphReady: fs.existsSync(layoutAbsPath(layout, layout.latestMarkdownPath)),
|
|
184
|
+
contextReady: modularExists,
|
|
180
185
|
});
|
|
181
186
|
const mergedAgents = mergeAgentsMdBlock(existingAgentsRaw, agentsInner);
|
|
182
|
-
const
|
|
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
|
|
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:
|
|
216
|
-
outputs: [
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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
|
|
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
|
-
? "
|
|
247
|
-
: "
|
|
278
|
+
? "补齐图谱(保留现有分类文档;AGENTS.md 已由 MCP 写入)"
|
|
279
|
+
: "写入 AGENTS.md 与 layout,由 Agent 生成 project-context 与图谱",
|
|
248
280
|
tasks: modularExists
|
|
249
|
-
? ["保留现有分类文档", "code_insight
|
|
250
|
-
: ["
|
|
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
|
-
: [
|
|
293
|
-
"调用 code_insight",
|
|
294
|
-
|
|
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}
|
|
310
|
-
|
|
311
|
-
## AGENTS.md 终稿(finalize-agents-md 使用 fsWrite 写入 \`${layout.indexPath}\`)
|
|
342
|
+
return okStructured(`${header}
|
|
343
|
+
${deliverySection}
|
|
312
344
|
|
|
313
|
-
|
|
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
|
|
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 ? '**如果该文件已存在,跳过此步骤,不要覆盖**' : '
|
|
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 及分类文档,不做覆盖' :
|
|
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
|
-
|
|
810
|
+
**由 Agent 使用 fsWrite 创建此文件**`;
|
|
774
811
|
}
|
|
775
812
|
/**
|
|
776
813
|
* init_project_context 工具实现
|