mcp-probe-kit 3.0.18 → 3.0.21

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 (62) hide show
  1. package/README.md +87 -55
  2. package/build/index.js +3 -1
  3. package/build/lib/__tests__/agents-md-template.unit.test.d.ts +1 -0
  4. package/build/lib/__tests__/agents-md-template.unit.test.js +27 -0
  5. package/build/lib/__tests__/memory-config.unit.test.js +9 -0
  6. package/build/lib/__tests__/memory-injection.unit.test.d.ts +1 -0
  7. package/build/lib/__tests__/memory-injection.unit.test.js +51 -0
  8. package/build/lib/__tests__/memory-orchestration.unit.test.d.ts +1 -0
  9. package/build/lib/__tests__/memory-orchestration.unit.test.js +84 -0
  10. package/build/lib/__tests__/memory-payload.unit.test.d.ts +1 -0
  11. package/build/lib/__tests__/memory-payload.unit.test.js +35 -0
  12. package/build/lib/__tests__/project-context-layout.unit.test.d.ts +1 -0
  13. package/build/lib/__tests__/project-context-layout.unit.test.js +80 -0
  14. package/build/lib/agents-md-template.d.ts +25 -0
  15. package/build/lib/agents-md-template.js +57 -0
  16. package/build/lib/memory-client.d.ts +8 -1
  17. package/build/lib/memory-client.js +53 -44
  18. package/build/lib/memory-config.d.ts +8 -0
  19. package/build/lib/memory-config.js +19 -0
  20. package/build/lib/memory-orchestration.d.ts +10 -3
  21. package/build/lib/memory-orchestration.js +146 -7
  22. package/build/lib/memory-payload.d.ts +21 -0
  23. package/build/lib/memory-payload.js +65 -0
  24. package/build/lib/merge-agents-md.d.ts +6 -0
  25. package/build/lib/merge-agents-md.js +51 -0
  26. package/build/lib/project-context-layout.d.ts +78 -0
  27. package/build/lib/project-context-layout.js +350 -0
  28. package/build/lib/workspace-root.js +6 -1
  29. package/build/resources/ui-ux-data/metadata.json +1 -1
  30. package/build/schemas/index.d.ts +62 -11
  31. package/build/schemas/memory-tools.d.ts +38 -9
  32. package/build/schemas/memory-tools.js +24 -9
  33. package/build/schemas/project-tools.d.ts +24 -2
  34. package/build/schemas/project-tools.js +24 -2
  35. package/build/tools/__tests__/code_insight.unit.test.js +3 -3
  36. package/build/tools/__tests__/init_project_context.unit.test.js +32 -21
  37. package/build/tools/__tests__/start_feature.unit.test.js +2 -1
  38. package/build/tools/code_insight.js +11 -9
  39. package/build/tools/index.d.ts +1 -0
  40. package/build/tools/index.js +1 -0
  41. package/build/tools/init_project_context.js +563 -506
  42. package/build/tools/memorize_asset.js +12 -0
  43. package/build/tools/scan_and_extract_patterns.js +7 -7
  44. package/build/tools/search_memory.d.ts +7 -0
  45. package/build/tools/search_memory.js +57 -0
  46. package/build/tools/start_bugfix.js +257 -251
  47. package/build/tools/start_feature.js +140 -134
  48. package/build/tools/start_ui.js +405 -405
  49. package/docs/.mcp-probe/layout.json +11 -0
  50. package/docs/data/tools.js +18 -0
  51. package/docs/i18n/all-tools/en.json +6 -1
  52. package/docs/i18n/all-tools/ja.json +2 -1
  53. package/docs/i18n/all-tools/ko.json +2 -1
  54. package/docs/i18n/all-tools/zh-CN.json +7 -2
  55. package/docs/i18n/en.json +38 -7
  56. package/docs/i18n/ja.json +9 -2
  57. package/docs/i18n/ko.json +9 -2
  58. package/docs/i18n/zh-CN.json +40 -9
  59. package/docs/memory-local-setup.md +314 -0
  60. package/docs/memory-local-setup.zh-CN.md +283 -0
  61. package/docs/pages/getting-started.html +252 -33
  62. package/package.json +2 -2
@@ -1,4 +1,33 @@
1
1
  export declare const memoryToolSchemas: readonly [{
2
+ readonly name: "search_memory";
3
+ readonly description: "按语义检索共享记忆库。适合在 start_* 之外主动查找历史 Bug 修复或可复用模式;命中后用 read_memory_asset 读取全文。";
4
+ readonly inputSchema: {
5
+ readonly type: "object";
6
+ readonly properties: {
7
+ readonly query: {
8
+ readonly type: "string";
9
+ readonly description: "检索 query(现象、报错、关键词、功能描述等)";
10
+ };
11
+ readonly type: {
12
+ readonly type: "string";
13
+ readonly description: "优先匹配的资产类型,如 bugfix、pattern、component";
14
+ };
15
+ readonly tags: {
16
+ readonly type: "array";
17
+ readonly items: {
18
+ readonly type: "string";
19
+ };
20
+ readonly description: "优先匹配的标签";
21
+ };
22
+ readonly limit: {
23
+ readonly type: "number";
24
+ readonly description: "返回条数,默认 MEMORY_SEARCH_LIMIT";
25
+ };
26
+ };
27
+ readonly required: readonly ["query"];
28
+ readonly additionalProperties: true;
29
+ };
30
+ }, {
2
31
  readonly name: "read_memory_asset";
3
32
  readonly description: "当编排阶段已检索到记忆摘要,且 AI 需要查看完整沉淀代码或详细规范时使用。根据 asset_id 读取记忆资产详情。";
4
33
  readonly inputSchema: {
@@ -14,7 +43,7 @@ export declare const memoryToolSchemas: readonly [{
14
43
  };
15
44
  }, {
16
45
  readonly name: "memorize_asset";
17
- readonly description: " AI 完成开发并确认存在可复用代码、模式或规范时使用。将高价值资产沉淀到记忆系统。";
46
+ readonly description: "沉淀可检索资产到共享记忆库。Bug 修复后必须 type=bugfix,content 含【现象】【根因】【修复】【验证】。跨仓库共享时勿填 source_project/source_path,路径写入 content 即可。";
18
47
  readonly inputSchema: {
19
48
  readonly type: "object";
20
49
  readonly properties: {
@@ -24,7 +53,7 @@ export declare const memoryToolSchemas: readonly [{
24
53
  };
25
54
  readonly type: {
26
55
  readonly type: "string";
27
- readonly description: "资产类型,如 code/component/pattern/spec";
56
+ readonly description: "资产类型:bugfix / pattern / component / code 等";
28
57
  };
29
58
  readonly description: {
30
59
  readonly type: "string";
@@ -32,11 +61,11 @@ export declare const memoryToolSchemas: readonly [{
32
61
  };
33
62
  readonly summary: {
34
63
  readonly type: "string";
35
- readonly description: "用于检索的凝练摘要";
64
+ readonly description: "检索用一句话摘要(关键词 + 根因/要点)";
36
65
  };
37
66
  readonly content: {
38
67
  readonly type: "string";
39
- readonly description: "完整内容";
68
+ readonly description: "完整内容(bugfix 建议结构化四段)";
40
69
  };
41
70
  readonly code_snippet: {
42
71
  readonly type: "string";
@@ -44,15 +73,15 @@ export declare const memoryToolSchemas: readonly [{
44
73
  };
45
74
  readonly file_path: {
46
75
  readonly type: "string";
47
- readonly description: "来源文件路径";
76
+ readonly description: "已废弃:勿用于跨仓库沉淀,路径写入 content";
48
77
  };
49
78
  readonly source_project: {
50
79
  readonly type: "string";
51
- readonly description: "来源项目";
80
+ readonly description: "已废弃:仅同仓库追溯时可选";
52
81
  };
53
82
  readonly source_path: {
54
83
  readonly type: "string";
55
- readonly description: "来源路径";
84
+ readonly description: "已废弃:仅同仓库追溯时可选";
56
85
  };
57
86
  readonly usage: {
58
87
  readonly type: "string";
@@ -67,7 +96,7 @@ export declare const memoryToolSchemas: readonly [{
67
96
  readonly items: {
68
97
  readonly type: "string";
69
98
  };
70
- readonly description: "标签列表";
99
+ readonly description: "标签列表,如 bugfix, root-cause";
71
100
  };
72
101
  };
73
102
  readonly required: readonly ["name", "description", "summary"];
@@ -89,7 +118,7 @@ export declare const memoryToolSchemas: readonly [{
89
118
  };
90
119
  readonly project_name: {
91
120
  readonly type: "string";
92
- readonly description: "来源项目名";
121
+ readonly description: "已废弃,扫描结果不再写入 source_project";
93
122
  };
94
123
  readonly directory_path: {
95
124
  readonly type: "string";
@@ -1,4 +1,19 @@
1
1
  export const memoryToolSchemas = [
2
+ {
3
+ name: 'search_memory',
4
+ description: '按语义检索共享记忆库。适合在 start_* 之外主动查找历史 Bug 修复或可复用模式;命中后用 read_memory_asset 读取全文。',
5
+ inputSchema: {
6
+ type: 'object',
7
+ properties: {
8
+ query: { type: 'string', description: '检索 query(现象、报错、关键词、功能描述等)' },
9
+ type: { type: 'string', description: '优先匹配的资产类型,如 bugfix、pattern、component' },
10
+ tags: { type: 'array', items: { type: 'string' }, description: '优先匹配的标签' },
11
+ limit: { type: 'number', description: '返回条数,默认 MEMORY_SEARCH_LIMIT' },
12
+ },
13
+ required: ['query'],
14
+ additionalProperties: true,
15
+ },
16
+ },
2
17
  {
3
18
  name: 'read_memory_asset',
4
19
  description: '当编排阶段已检索到记忆摘要,且 AI 需要查看完整沉淀代码或详细规范时使用。根据 asset_id 读取记忆资产详情。',
@@ -16,22 +31,22 @@ export const memoryToolSchemas = [
16
31
  },
17
32
  {
18
33
  name: 'memorize_asset',
19
- description: ' AI 完成开发并确认存在可复用代码、模式或规范时使用。将高价值资产沉淀到记忆系统。',
34
+ description: '沉淀可检索资产到共享记忆库。Bug 修复后必须 type=bugfix,content 含【现象】【根因】【修复】【验证】。跨仓库共享时勿填 source_project/source_path,路径写入 content 即可。',
20
35
  inputSchema: {
21
36
  type: 'object',
22
37
  properties: {
23
38
  name: { type: 'string', description: '资产名称' },
24
- type: { type: 'string', description: '资产类型,如 code/component/pattern/spec' },
39
+ type: { type: 'string', description: '资产类型:bugfix / pattern / component / code 等' },
25
40
  description: { type: 'string', description: '资产描述' },
26
- summary: { type: 'string', description: '用于检索的凝练摘要' },
27
- content: { type: 'string', description: '完整内容' },
41
+ summary: { type: 'string', description: '检索用一句话摘要(关键词 + 根因/要点)' },
42
+ content: { type: 'string', description: '完整内容(bugfix 建议结构化四段)' },
28
43
  code_snippet: { type: 'string', description: '代码片段,content 的别名' },
29
- file_path: { type: 'string', description: '来源文件路径' },
30
- source_project: { type: 'string', description: '来源项目' },
31
- source_path: { type: 'string', description: '来源路径' },
44
+ file_path: { type: 'string', description: '已废弃:勿用于跨仓库沉淀,路径写入 content' },
45
+ source_project: { type: 'string', description: '已废弃:仅同仓库追溯时可选' },
46
+ source_path: { type: 'string', description: '已废弃:仅同仓库追溯时可选' },
32
47
  usage: { type: 'string', description: '适用场景/使用方式' },
33
48
  confidence: { type: 'number', description: '置信度,0-1' },
34
- tags: { type: 'array', items: { type: 'string' }, description: '标签列表' },
49
+ tags: { type: 'array', items: { type: 'string' }, description: '标签列表,如 bugfix, root-cause' },
35
50
  },
36
51
  required: ['name', 'description', 'summary'],
37
52
  additionalProperties: true,
@@ -45,7 +60,7 @@ export const memoryToolSchemas = [
45
60
  properties: {
46
61
  content: { type: 'string', description: '待分析的代码或文本内容。传入该字段时走单段分析模式' },
47
62
  file_path: { type: 'string', description: '来源文件路径。单段分析时作为来源路径使用' },
48
- project_name: { type: 'string', description: '来源项目名' },
63
+ project_name: { type: 'string', description: '已废弃,扫描结果不再写入 source_project' },
49
64
  directory_path: { type: 'string', description: '要扫描的目录路径。最佳实践是传相对 `project_root` 的路径,例如 `app/utils`;如果拿不到 `project_root`,才传目录绝对路径。不要传带项目名的半相对路径,例如 `font-miniapp-api/app/utils`。' },
50
65
  project_root: { type: 'string', description: '项目根目录绝对路径。目录扫描时建议始终传入;传入后,`directory_path` 应写成相对项目根的路径。' },
51
66
  max_files: { type: 'number', description: '最多扫描多少个文件,默认 30,最大 200' },
@@ -3,13 +3,35 @@
3
3
  */
4
4
  export declare const projectToolSchemas: readonly [{
5
5
  readonly name: "init_project_context";
6
- readonly description: "当用户需要生成项目上下文文档、帮助团队快速上手时使用。生成项目上下文文档(技术栈/架构/编码规范),供后续开发参考";
6
+ readonly description: "生成/更新项目上下文:默认写入 AGENTS.md(含 MCP 与 GitNexus 触发规则)及 docs/project-context/。新功能请先 start_feature,修 bug 请先 start_bugfix。完成后 Agent 应阅读 AGENTS.md。";
7
7
  readonly inputSchema: {
8
8
  readonly type: "object";
9
9
  readonly properties: {
10
10
  readonly docs_dir: {
11
11
  readonly type: "string";
12
- readonly description: "文档目录。可选,默认 docs";
12
+ readonly description: "附属文档根目录(project-context、graph-insights)。默认 docs";
13
+ };
14
+ readonly index_style: {
15
+ readonly type: "string";
16
+ readonly enum: readonly ["auto", "agents", "legacy"];
17
+ readonly description: "索引风格:auto(默认 AGENTS.md)、agents、legacy(docs/project-context.md)";
18
+ };
19
+ readonly output: {
20
+ readonly type: "string";
21
+ readonly description: "高级:索引文件相对路径,如 AGENTS.md";
22
+ };
23
+ readonly output_dir: {
24
+ readonly type: "string";
25
+ readonly description: "高级:索引所在目录,如 .claude/rules";
26
+ };
27
+ readonly filename: {
28
+ readonly type: "string";
29
+ readonly description: "高级:与 output_dir 合用,默认 project-context.md";
30
+ };
31
+ readonly locale: {
32
+ readonly type: "string";
33
+ readonly enum: readonly ["en", "zh-CN"];
34
+ readonly description: "AGENTS.md 语言;默认根据 README 探测";
13
35
  };
14
36
  };
15
37
  readonly required: readonly [];
@@ -4,13 +4,35 @@
4
4
  export const projectToolSchemas = [
5
5
  {
6
6
  name: "init_project_context",
7
- description: "当用户需要生成项目上下文文档、帮助团队快速上手时使用。生成项目上下文文档(技术栈/架构/编码规范),供后续开发参考",
7
+ description: "生成/更新项目上下文:默认写入 AGENTS.md(含 MCP 与 GitNexus 触发规则)及 docs/project-context/。新功能请先 start_feature,修 bug 请先 start_bugfix。完成后 Agent 应阅读 AGENTS.md。",
8
8
  inputSchema: {
9
9
  type: "object",
10
10
  properties: {
11
11
  docs_dir: {
12
12
  type: "string",
13
- description: "文档目录。可选,默认 docs",
13
+ description: "附属文档根目录(project-context、graph-insights)。默认 docs",
14
+ },
15
+ index_style: {
16
+ type: "string",
17
+ enum: ["auto", "agents", "legacy"],
18
+ description: "索引风格:auto(默认 AGENTS.md)、agents、legacy(docs/project-context.md)",
19
+ },
20
+ output: {
21
+ type: "string",
22
+ description: "高级:索引文件相对路径,如 AGENTS.md",
23
+ },
24
+ output_dir: {
25
+ type: "string",
26
+ description: "高级:索引所在目录,如 .claude/rules",
27
+ },
28
+ filename: {
29
+ type: "string",
30
+ description: "高级:与 output_dir 合用,默认 project-context.md",
31
+ },
32
+ locale: {
33
+ type: "string",
34
+ enum: ["en", "zh-CN"],
35
+ description: "AGENTS.md 语言;默认根据 README 探测",
14
36
  },
15
37
  },
16
38
  required: [],
@@ -144,15 +144,15 @@ describe("code_insight 单元测试", () => {
144
144
  expect(text).toMatch(/不要只口头总结而不写文件/);
145
145
  expect(text).toMatch(/docs\/graph-insights\/latest\.md/);
146
146
  expect(text).toMatch(/使用场景指南/);
147
- expect(structured.projectDocs.latestMarkdownFilePath).toContain("/docs/graph-insights/latest.md");
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).toContain("/docs/project-context.md");
149
+ expect(structured.projectDocs.projectContextFilePath).toMatch(/\/(AGENTS\.md|docs\/project-context\.md)$/);
150
150
  expect(structured.projectDocs.navigationSnippet).toMatch(/代码图谱洞察/);
151
151
  expect(structured.plan.mode).toBe("delegated");
152
152
  expect(structured.plan.steps).toHaveLength(2);
153
153
  expect(structured.plan.steps[0].id).toBe("consume-result");
154
154
  expect(structured.plan.steps[1].id).toBe("optional-save");
155
- expect(structured.plan.steps[1].outputs[0]).toContain("/docs/graph-insights/latest.md");
155
+ expect(structured.plan.steps[1].outputs[0]).toMatch(/docs\/graph-insights\/latest\.md$/);
156
156
  expect(fs.existsSync(path.join(projectRoot, "docs", "graph-insights", "latest.md"))).toBe(false);
157
157
  }
158
158
  finally {
@@ -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;
@@ -16,6 +16,7 @@ export { interview } from "./interview.js";
16
16
  export { askUser } from "./ask_user.js";
17
17
  export { uiDesignSystem, uiSearch, syncUiData } from "./ui-ux-tools.js";
18
18
  export { startUi } from "./start_ui.js";
19
+ export { searchMemory } from "./search_memory.js";
19
20
  export { readMemoryAsset } from "./read_memory_asset.js";
20
21
  export { memorizeAsset } from "./memorize_asset.js";
21
22
  export { scanAndExtractPatterns } from "./scan_and_extract_patterns.js";
@@ -20,6 +20,7 @@ export { askUser } from "./ask_user.js";
20
20
  export { uiDesignSystem, uiSearch, syncUiData } from "./ui-ux-tools.js";
21
21
  export { startUi } from "./start_ui.js";
22
22
  // 记忆工具
23
+ export { searchMemory } from "./search_memory.js";
23
24
  export { readMemoryAsset } from "./read_memory_asset.js";
24
25
  export { memorizeAsset } from "./memorize_asset.js";
25
26
  export { scanAndExtractPatterns } from "./scan_and_extract_patterns.js";