mcp-probe-kit 3.0.18 → 3.0.19

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 (37) hide show
  1. package/README.md +75 -50
  2. package/build/lib/__tests__/agents-md-template.unit.test.d.ts +1 -0
  3. package/build/lib/__tests__/agents-md-template.unit.test.js +25 -0
  4. package/build/lib/__tests__/project-context-layout.unit.test.d.ts +1 -0
  5. package/build/lib/__tests__/project-context-layout.unit.test.js +80 -0
  6. package/build/lib/agents-md-template.d.ts +25 -0
  7. package/build/lib/agents-md-template.js +55 -0
  8. package/build/lib/memory-orchestration.d.ts +3 -1
  9. package/build/lib/memory-orchestration.js +71 -5
  10. package/build/lib/merge-agents-md.d.ts +6 -0
  11. package/build/lib/merge-agents-md.js +51 -0
  12. package/build/lib/project-context-layout.d.ts +78 -0
  13. package/build/lib/project-context-layout.js +350 -0
  14. package/build/lib/workspace-root.js +6 -1
  15. package/build/resources/ui-ux-data/metadata.json +1 -1
  16. package/build/schemas/index.d.ts +25 -3
  17. package/build/schemas/memory-tools.d.ts +1 -1
  18. package/build/schemas/memory-tools.js +1 -1
  19. package/build/schemas/project-tools.d.ts +24 -2
  20. package/build/schemas/project-tools.js +24 -2
  21. package/build/tools/__tests__/code_insight.unit.test.js +3 -3
  22. package/build/tools/__tests__/init_project_context.unit.test.js +32 -21
  23. package/build/tools/__tests__/start_feature.unit.test.js +2 -1
  24. package/build/tools/code_insight.js +11 -9
  25. package/build/tools/init_project_context.js +563 -506
  26. package/build/tools/start_bugfix.js +254 -248
  27. package/build/tools/start_feature.js +137 -131
  28. package/build/tools/start_ui.js +402 -402
  29. package/docs/.mcp-probe/layout.json +11 -0
  30. package/docs/i18n/en.json +36 -5
  31. package/docs/i18n/ja.json +9 -2
  32. package/docs/i18n/ko.json +9 -2
  33. package/docs/i18n/zh-CN.json +36 -5
  34. package/docs/memory-local-setup.md +314 -0
  35. package/docs/memory-local-setup.zh-CN.md +280 -0
  36. package/docs/pages/getting-started.html +249 -31
  37. package/package.json +1 -1
@@ -4,10 +4,11 @@ import path from 'node:path';
4
4
  import { describe, expect, test } from 'vitest';
5
5
  import { initProjectContext } from '../init_project_context.js';
6
6
  describe('init_project_context 单元测试', () => {
7
- test('返回 delegated plan,并预置 code_insight 图谱初始化步骤', async () => {
7
+ test('返回 delegated plan,含 finalize-agents-md 与 AGENTS.md 模板', async () => {
8
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-probe-kit-init-'));
8
9
  const result = await initProjectContext({
9
10
  docs_dir: 'docs',
10
- project_root: 'E:/workspace/github/mcp-probe-kit',
11
+ project_root: projectRoot,
11
12
  });
12
13
  expect(result.isError).toBeFalsy();
13
14
  expect('structuredContent' in result).toBe(true);
@@ -15,49 +16,59 @@ describe('init_project_context 单元测试', () => {
15
16
  throw new Error('structuredContent 缺失');
16
17
  }
17
18
  const structured = result.structuredContent;
19
+ expect(structured.documentation.some((item) => item.path === 'AGENTS.md')).toBe(true);
18
20
  expect(structured.documentation.some((item) => item.path === 'docs/graph-insights/latest.md')).toBe(true);
19
- expect(structured.documentation.some((item) => item.path === 'docs/graph-insights/latest.json')).toBe(true);
20
- expect(structured.metadata?.graphDocs?.latestMarkdownFilePath).toContain('/docs/graph-insights/latest.md');
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);
21
25
  const plan = structured.metadata?.plan;
22
26
  expect(plan?.mode).toBe('delegated');
23
27
  expect(plan.steps.map((step) => step.id)).toEqual([
24
- 'write-project-context',
28
+ 'write-modular-docs',
25
29
  'bootstrap-code-insight',
26
30
  'persist-graph-docs',
31
+ 'finalize-agents-md',
27
32
  ]);
28
- expect(plan.steps[1].action).toMatch(/code_insight/);
33
+ expect(plan.steps[0].outputs).toContain('docs/project-context.md');
34
+ expect(plan.steps[3].id).toBe('finalize-agents-md');
29
35
  });
30
- test('输出文本包含 graph-insights 入口和 delegated plan', async () => {
36
+ test('输出文本包含 AGENTS.md MCP 触发规则', async () => {
37
+ const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-probe-kit-init-'));
31
38
  const result = await initProjectContext({
32
- docs_dir: 'docs',
33
- project_root: 'E:/workspace/github/mcp-probe-kit',
39
+ project_root: projectRoot,
34
40
  });
35
41
  const text = result.content[0].text;
36
- expect(text).toMatch(/graph-insights\/latest\.md/);
37
- expect(text).toMatch(/delegated plan/);
38
- expect(text).toMatch(/code_insight/);
42
+ expect(text).toMatch(/AGENTS\.md/);
43
+ expect(text).toMatch(/start_feature/);
44
+ expect(text).toMatch(/finalize-agents-md/);
39
45
  });
40
- test('已存在 project-context.md 时不再规划重写上下文文档', async () => {
46
+ test('已存在 project-context 分类文档时跳过重写 modular', async () => {
41
47
  const projectRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'mcp-probe-kit-context-'));
42
- fs.mkdirSync(path.join(projectRoot, 'docs'), { recursive: true });
48
+ fs.mkdirSync(path.join(projectRoot, 'docs', 'project-context'), { recursive: true });
43
49
  fs.writeFileSync(path.join(projectRoot, 'docs', 'project-context.md'), '# existing context\n', 'utf8');
44
50
  const result = await initProjectContext({
45
51
  docs_dir: 'docs',
46
52
  project_root: projectRoot,
47
53
  });
48
54
  expect(result.isError).toBeFalsy();
49
- expect('structuredContent' in result).toBe(true);
50
- if (!('structuredContent' in result)) {
51
- throw new Error('structuredContent 缺失');
52
- }
53
55
  const structured = result.structuredContent;
54
- expect(structured.metadata?.projectContextExists).toBe(true);
56
+ expect(structured.metadata?.legacyProjectContextExists).toBe(true);
55
57
  expect(structured.metadata?.plan?.steps.map((step) => step.id)).toEqual([
56
58
  'bootstrap-code-insight',
57
59
  'persist-graph-docs',
60
+ 'finalize-agents-md',
58
61
  ]);
59
62
  const text = result.content[0].text;
60
- expect(text).toMatch(/已存在(将保留,不覆盖)/);
61
- expect(text).toMatch(/不要重写/);
63
+ expect(text).toMatch(/保留/);
64
+ });
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');
62
73
  });
63
74
  });
@@ -25,12 +25,13 @@ describe('start_feature 单元测试', () => {
25
25
  expect(plan).toBeTruthy();
26
26
  expect(plan.mode).toBe('delegated');
27
27
  expect(Array.isArray(plan.steps)).toBe(true);
28
- expect(plan.steps.length).toBe(3);
28
+ expect(plan.steps.length).toBeGreaterThanOrEqual(3);
29
29
  const tools = plan.steps.map((step) => step.tool);
30
30
  expect(tools).toContain('init_project_context');
31
31
  expect(tools).toContain('add_feature');
32
32
  expect(tools).toContain('estimate');
33
33
  const contextStep = plan.steps.find((step) => step.tool === 'init_project_context');
34
+ expect(contextStep.outputs).toContain('AGENTS.md');
34
35
  expect(contextStep.outputs).toContain('docs/graph-insights/latest.md');
35
36
  expect(contextStep.outputs).toContain('docs/graph-insights/latest.json');
36
37
  expect(contextStep.when).toMatch(/graph-insights\/latest\.md/);
@@ -5,7 +5,8 @@ import { okStructured } from "../lib/response.js";
5
5
  import { renderOrchestrationHeader } from "../lib/orchestration-guidance.js";
6
6
  import { runCodeInsightBridge, } from "../lib/gitnexus-bridge.js";
7
7
  import { throwIfAborted, } from "../lib/tool-execution-context.js";
8
- import { isLikelyProjectNamedRelativePath, buildProjectRootRetryHint } from "../lib/workspace-root.js";
8
+ import { isLikelyProjectNamedRelativePath, buildProjectRootRetryHint, resolveWorkspaceRoot } from "../lib/workspace-root.js";
9
+ import { layoutAbsPath, parseLayoutArgsFromRecord, resolveProjectContextLayout, } from "../lib/project-context-layout.js";
9
10
  const ALLOWED_MODES = new Set(["auto", "query", "context", "impact"]);
10
11
  const ALLOWED_DIRECTIONS = new Set(["upstream", "downstream"]);
11
12
  const DEFAULT_AUTO_QUERY = "项目整体架构 核心流程 关键模块 依赖关系 入口点";
@@ -25,7 +26,7 @@ function buildProjectDocsOutputs(input) {
25
26
  if (!projectRoot) {
26
27
  return null;
27
28
  }
28
- const docsRoot = path.join(path.resolve(projectRoot), input.docsDirName || "docs", "graph-insights");
29
+ const docsRoot = path.join(path.resolve(projectRoot), input.graphDir || "docs/graph-insights");
29
30
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
30
31
  const suffix = makeSafeSegment(input.structured.summary || input.mode);
31
32
  const baseName = `${timestamp}-${input.mode}-${suffix}`;
@@ -126,13 +127,13 @@ function formatAmbiguities(ambiguities) {
126
127
  })
127
128
  .join("\n");
128
129
  }
129
- function createProjectDocsPlan(projectRoot, docsDirName, docsSnapshot) {
130
- const docsDir = path.dirname(docsSnapshot.markdownFilePath);
130
+ function createProjectDocsPlan(layout, docsSnapshot) {
131
+ const docsDir = layout.contextRoot;
131
132
  return {
132
133
  docsDir,
133
- projectContextFilePath: toPosixPath(path.join(path.resolve(projectRoot), docsDirName, "project-context.md")),
134
- latestMarkdownFilePath: toPosixPath(path.join(docsDir, "latest.md")),
135
- latestJsonFilePath: toPosixPath(path.join(docsDir, "latest.json")),
134
+ projectContextFilePath: toPosixPath(layoutAbsPath(layout, layout.indexPath)),
135
+ latestMarkdownFilePath: layout.latestMarkdownPath,
136
+ latestJsonFilePath: layout.latestJsonPath,
136
137
  archiveMarkdownFilePath: docsSnapshot.markdownFilePath,
137
138
  archiveJsonFilePath: docsSnapshot.jsonFilePath,
138
139
  navigationSnippet: `### [代码图谱洞察](./graph-insights/latest.md)
@@ -264,6 +265,7 @@ export async function codeInsight(args, context) {
264
265
  };
265
266
  }
266
267
  const docsDirName = getString(parsedArgs.docs_dir) || "docs";
268
+ const layout = resolveProjectContextLayout(projectRoot ? resolveWorkspaceRoot(projectRoot) : resolveWorkspaceRoot(), parseLayoutArgsFromRecord({ docs_dir: docsDirName }));
267
269
  const goal = getString(parsedArgs.goal);
268
270
  const taskContext = getString(parsedArgs.task_context);
269
271
  const direction = normalizeDirection(getString(parsedArgs.direction));
@@ -344,12 +346,12 @@ ${result.warnings.length > 0 ? `警告: ${result.warnings.join(", ")}` : ""}`.tr
344
346
  const docsProjectRoot = saveToDocs ? (projectRoot || result.sourceRoot) : "";
345
347
  const docsSnapshot = buildProjectDocsOutputs({
346
348
  projectRoot: docsProjectRoot,
347
- docsDirName,
349
+ graphDir: layout.graphDir,
348
350
  mode,
349
351
  structured,
350
352
  });
351
353
  const projectDocs = docsSnapshot
352
- ? createProjectDocsPlan(docsProjectRoot, docsDirName, docsSnapshot)
354
+ ? createProjectDocsPlan(layout, docsSnapshot)
353
355
  : undefined;
354
356
  if (projectDocs) {
355
357
  structured.projectDocs = projectDocs;