mcp-probe-kit 3.0.16 → 3.0.17

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 (74) hide show
  1. package/README.md +601 -399
  2. package/build/index.js +13 -1
  3. package/build/lib/__tests__/memory-client.unit.test.d.ts +1 -0
  4. package/build/lib/__tests__/memory-client.unit.test.js +83 -0
  5. package/build/lib/__tests__/memory-config.unit.test.d.ts +1 -0
  6. package/build/lib/__tests__/memory-config.unit.test.js +33 -0
  7. package/build/lib/cursor-history-client.d.ts +54 -0
  8. package/build/lib/cursor-history-client.js +240 -0
  9. package/build/lib/gitnexus-bridge.js +6 -8
  10. package/build/lib/memory-client.d.ts +61 -0
  11. package/build/lib/memory-client.js +293 -0
  12. package/build/lib/memory-config.d.ts +14 -0
  13. package/build/lib/memory-config.js +31 -0
  14. package/build/lib/memory-orchestration.d.ts +26 -0
  15. package/build/lib/memory-orchestration.js +65 -0
  16. package/build/lib/project-detector.js +6 -4
  17. package/build/lib/workspace-root.d.ts +12 -0
  18. package/build/lib/workspace-root.js +153 -0
  19. package/build/resources/ui-ux-data/metadata.json +1 -1
  20. package/build/schemas/code-analysis-tools.d.ts +1 -1
  21. package/build/schemas/code-analysis-tools.js +1 -1
  22. package/build/schemas/index.d.ts +198 -4
  23. package/build/schemas/index.js +2 -0
  24. package/build/schemas/memory-tools.d.ts +191 -0
  25. package/build/schemas/memory-tools.js +106 -0
  26. package/build/schemas/orchestration-tools.d.ts +3 -3
  27. package/build/schemas/orchestration-tools.js +3 -3
  28. package/build/schemas/ui-ux-schemas.d.ts +8 -0
  29. package/build/schemas/ui-ux-schemas.js +4 -0
  30. package/build/tools/__tests__/cursor-history.unit.test.d.ts +1 -0
  31. package/build/tools/__tests__/cursor-history.unit.test.js +87 -0
  32. package/build/tools/__tests__/memorize_asset.unit.test.d.ts +1 -0
  33. package/build/tools/__tests__/memorize_asset.unit.test.js +68 -0
  34. package/build/tools/code_insight.d.ts +20 -0
  35. package/build/tools/code_insight.js +15 -0
  36. package/build/tools/cursor_list_conversations.d.ts +7 -0
  37. package/build/tools/cursor_list_conversations.js +35 -0
  38. package/build/tools/cursor_read_conversation.d.ts +7 -0
  39. package/build/tools/cursor_read_conversation.js +36 -0
  40. package/build/tools/cursor_search_conversations.d.ts +7 -0
  41. package/build/tools/cursor_search_conversations.js +36 -0
  42. package/build/tools/index.d.ts +6 -0
  43. package/build/tools/index.js +7 -0
  44. package/build/tools/init_project_context.d.ts +20 -1
  45. package/build/tools/init_project_context.js +114 -99
  46. package/build/tools/memorize_asset.d.ts +7 -0
  47. package/build/tools/memorize_asset.js +66 -0
  48. package/build/tools/read_memory_asset.d.ts +7 -0
  49. package/build/tools/read_memory_asset.js +26 -0
  50. package/build/tools/scan_and_extract_patterns.d.ts +27 -0
  51. package/build/tools/scan_and_extract_patterns.js +346 -0
  52. package/build/tools/start_bugfix.d.ts +20 -0
  53. package/build/tools/start_bugfix.js +97 -69
  54. package/build/tools/start_feature.d.ts +20 -0
  55. package/build/tools/start_feature.js +61 -31
  56. package/build/tools/start_onboard.d.ts +20 -0
  57. package/build/tools/start_onboard.js +15 -0
  58. package/build/tools/start_ui.d.ts +20 -0
  59. package/build/tools/start_ui.js +66 -32
  60. package/docs/data/tools.js +472 -373
  61. package/docs/i18n/all-tools/en.json +38 -5
  62. package/docs/i18n/all-tools/ja.json +14 -4
  63. package/docs/i18n/all-tools/ko.json +13 -3
  64. package/docs/i18n/all-tools/zh-CN.json +38 -5
  65. package/docs/i18n/en.json +48 -10
  66. package/docs/i18n/ja.json +47 -9
  67. package/docs/i18n/ko.json +47 -9
  68. package/docs/i18n/zh-CN.json +48 -10
  69. package/docs/pages/all-tools.html +515 -515
  70. package/docs/pages/examples.html +661 -661
  71. package/docs/pages/getting-started.html +673 -582
  72. package/docs/pages/migration.html +291 -291
  73. package/package.json +83 -82
  74. package/docs/debug-i18n.html +0 -163
@@ -0,0 +1,87 @@
1
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
2
+ const listConversationsMock = vi.fn();
3
+ const searchHistoryMock = vi.fn();
4
+ const readConversationMock = vi.fn();
5
+ vi.mock('../../lib/cursor-history-client.js', () => ({
6
+ createCursorHistoryClient: () => ({
7
+ listConversations: listConversationsMock,
8
+ searchHistory: searchHistoryMock,
9
+ readConversation: readConversationMock,
10
+ }),
11
+ }));
12
+ import { cursorListConversations } from '../cursor_list_conversations.js';
13
+ import { cursorSearchConversations } from '../cursor_search_conversations.js';
14
+ import { cursorReadConversation } from '../cursor_read_conversation.js';
15
+ beforeEach(() => {
16
+ listConversationsMock.mockReset();
17
+ searchHistoryMock.mockReset();
18
+ readConversationMock.mockReset();
19
+ });
20
+ afterEach(() => {
21
+ vi.clearAllMocks();
22
+ });
23
+ describe('cursor history tools', () => {
24
+ test('cursor_list_conversations 返回摘要列表', async () => {
25
+ listConversationsMock.mockResolvedValue([
26
+ { composerId: 'c1', name: '新需求', source: 'composerHeaders' },
27
+ ]);
28
+ const result = await cursorListConversations({ title_query: '新需求', limit: 10 });
29
+ expect(result.isError).toBe(false);
30
+ expect('structuredContent' in result).toBe(true);
31
+ if (!('structuredContent' in result)) {
32
+ throw new Error('structuredContent 缺失');
33
+ }
34
+ expect(result.content[0].text).toContain('已获取 1 条 Cursor 会话摘要');
35
+ expect(result.structuredContent.count).toBe(1);
36
+ expect(listConversationsMock).toHaveBeenCalledWith({
37
+ titleQuery: '新需求',
38
+ workspaceQuery: '',
39
+ includeArchived: false,
40
+ limit: 10,
41
+ });
42
+ });
43
+ test('cursor_search_conversations 缺少 query 时返回错误', async () => {
44
+ const result = await cursorSearchConversations({});
45
+ expect(result.isError).toBe(true);
46
+ expect(result.content[0].text).toContain('缺少必填参数: query');
47
+ });
48
+ test('cursor_search_conversations 返回命中结果', async () => {
49
+ searchHistoryMock.mockResolvedValue([
50
+ { composerId: 'c1', conversationName: '新需求', bubbleId: 'b1', type: 1, text: '我们先聊需求' },
51
+ ]);
52
+ const result = await cursorSearchConversations({ query: '需求', composer_id: 'c1', limit: 5 });
53
+ expect(result.isError).toBe(false);
54
+ expect('structuredContent' in result).toBe(true);
55
+ if (!('structuredContent' in result)) {
56
+ throw new Error('structuredContent 缺失');
57
+ }
58
+ expect(result.structuredContent.count).toBe(1);
59
+ expect(searchHistoryMock).toHaveBeenCalledWith({
60
+ query: '需求',
61
+ composerId: 'c1',
62
+ limit: 5,
63
+ });
64
+ });
65
+ test('cursor_read_conversation 返回消息时间线', async () => {
66
+ readConversationMock.mockResolvedValue({
67
+ composerId: 'c1',
68
+ messages: [
69
+ { bubbleId: 'b1', type: 1, text: '我们先聊需求' },
70
+ { bubbleId: 'b2', type: 2, text: '听懂了' },
71
+ ],
72
+ });
73
+ const result = await cursorReadConversation({ composer_id: 'c1', limit: 50, include_empty: true });
74
+ expect(result.isError).toBe(false);
75
+ expect('structuredContent' in result).toBe(true);
76
+ if (!('structuredContent' in result)) {
77
+ throw new Error('structuredContent 缺失');
78
+ }
79
+ expect(result.content[0].text).toContain('共 2 条消息');
80
+ expect(result.structuredContent.messageCount).toBe(2);
81
+ expect(readConversationMock).toHaveBeenCalledWith({
82
+ composerId: 'c1',
83
+ limit: 50,
84
+ includeEmpty: true,
85
+ });
86
+ });
87
+ });
@@ -0,0 +1,68 @@
1
+ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest';
2
+ const upsertAssetMock = vi.fn();
3
+ const isEnabledMock = vi.fn();
4
+ vi.mock('../../lib/memory-client.js', () => ({
5
+ createMemoryClient: () => ({
6
+ isEnabled: isEnabledMock,
7
+ upsertAsset: upsertAssetMock,
8
+ }),
9
+ }));
10
+ import { memorizeAsset } from '../memorize_asset.js';
11
+ beforeEach(() => {
12
+ isEnabledMock.mockReset();
13
+ upsertAssetMock.mockReset();
14
+ });
15
+ afterEach(() => {
16
+ vi.clearAllMocks();
17
+ });
18
+ describe('memorize_asset 单元测试', () => {
19
+ const validArgs = {
20
+ name: 'AppError',
21
+ description: '统一错误封装',
22
+ summary: '用于标准化应用错误处理',
23
+ content: 'export class AppError extends Error {}',
24
+ };
25
+ test('记忆服务未开启时返回跳过结果而不是报错', async () => {
26
+ isEnabledMock.mockReturnValue(false);
27
+ const result = await memorizeAsset(validArgs);
28
+ expect(result.isError).toBe(false);
29
+ expect('structuredContent' in result).toBe(true);
30
+ if (!('structuredContent' in result)) {
31
+ throw new Error('structuredContent 缺失');
32
+ }
33
+ expect(result.content[0].text).toContain('记忆服务未开启');
34
+ expect(result.structuredContent).toEqual({ enabled: false, stored: false });
35
+ expect(upsertAssetMock).not.toHaveBeenCalled();
36
+ });
37
+ test('记忆服务开启时写入资产', async () => {
38
+ isEnabledMock.mockReturnValue(true);
39
+ upsertAssetMock.mockResolvedValue({
40
+ id: 'asset-1',
41
+ name: 'AppError',
42
+ type: 'code',
43
+ description: '统一错误封装',
44
+ summary: '用于标准化应用错误处理',
45
+ content: 'export class AppError extends Error {}',
46
+ tags: [],
47
+ confidence: 0.7,
48
+ createdAt: '2026-01-01T00:00:00.000Z',
49
+ updatedAt: '2026-01-01T00:00:00.000Z',
50
+ });
51
+ const result = await memorizeAsset(validArgs);
52
+ expect(result.isError).toBe(false);
53
+ expect('structuredContent' in result).toBe(true);
54
+ if (!('structuredContent' in result)) {
55
+ throw new Error('structuredContent 缺失');
56
+ }
57
+ expect(result.content[0].text).toContain('已沉淀记忆资产: AppError');
58
+ expect(result.structuredContent.enabled).toBe(true);
59
+ expect(result.structuredContent.stored).toBe(true);
60
+ expect(upsertAssetMock).toHaveBeenCalledTimes(1);
61
+ expect(upsertAssetMock).toHaveBeenCalledWith(expect.objectContaining({
62
+ name: 'AppError',
63
+ description: '统一错误封装',
64
+ summary: '用于标准化应用错误处理',
65
+ content: 'export class AppError extends Error {}',
66
+ }));
67
+ });
68
+ });
@@ -44,5 +44,25 @@ export declare function codeInsight(args: any, context?: ToolExecutionContext):
44
44
  text: string;
45
45
  }[];
46
46
  isError: boolean;
47
+ structuredContent: {
48
+ error_code: string;
49
+ rejected_project_root: string;
50
+ retry_hint: {
51
+ preferred: {
52
+ project_root: string;
53
+ path: string;
54
+ };
55
+ fallback: {
56
+ project_root: string;
57
+ };
58
+ };
59
+ };
60
+ } | {
61
+ content: {
62
+ type: string;
63
+ text: string;
64
+ }[];
65
+ isError: boolean;
66
+ structuredContent?: undefined;
47
67
  }>;
48
68
  export {};
@@ -5,6 +5,7 @@ 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
9
  const ALLOWED_MODES = new Set(["auto", "query", "context", "impact"]);
9
10
  const ALLOWED_DIRECTIONS = new Set(["upstream", "downstream"]);
10
11
  const DEFAULT_AUTO_QUERY = "项目整体架构 核心流程 关键模块 依赖关系 入口点";
@@ -248,6 +249,20 @@ export async function codeInsight(args, context) {
248
249
  const filePath = getString(parsedArgs.file_path);
249
250
  const repo = getString(parsedArgs.repo);
250
251
  const projectRoot = getString(parsedArgs.project_root);
252
+ if (isLikelyProjectNamedRelativePath(projectRoot)) {
253
+ return {
254
+ content: [{
255
+ type: "text",
256
+ text: `拒绝执行 code_insight:project_root 不能传带项目名的半相对路径,例如 ${projectRoot}。请改为传项目根目录绝对路径。`,
257
+ }],
258
+ isError: true,
259
+ structuredContent: {
260
+ error_code: "INVALID_PROJECT_ROOT",
261
+ rejected_project_root: projectRoot,
262
+ retry_hint: buildProjectRootRetryHint(projectRoot),
263
+ },
264
+ };
265
+ }
251
266
  const docsDirName = getString(parsedArgs.docs_dir) || "docs";
252
267
  const goal = getString(parsedArgs.goal);
253
268
  const taskContext = getString(parsedArgs.task_context);
@@ -0,0 +1,7 @@
1
+ export declare function cursorListConversations(args: any): Promise<import("../lib/response.js").ToolResponse | {
2
+ content: Array<{
3
+ type: string;
4
+ text: string;
5
+ }>;
6
+ isError: true;
7
+ }>;
@@ -0,0 +1,35 @@
1
+ import { parseArgs, getString, getNumber, getBoolean } from '../utils/parseArgs.js';
2
+ import { okStructured } from '../lib/response.js';
3
+ import { handleToolError } from '../utils/error-handler.js';
4
+ import { createCursorHistoryClient } from '../lib/cursor-history-client.js';
5
+ export async function cursorListConversations(args) {
6
+ try {
7
+ const parsed = parseArgs(args, {
8
+ defaultValues: {
9
+ title_query: '',
10
+ workspace_query: '',
11
+ include_archived: false,
12
+ limit: 20,
13
+ },
14
+ fieldAliases: {
15
+ title_query: ['title', 'name_query', 'query'],
16
+ workspace_query: ['workspace', 'workspace_path'],
17
+ include_archived: ['archived'],
18
+ },
19
+ });
20
+ const client = createCursorHistoryClient();
21
+ const conversations = await client.listConversations({
22
+ titleQuery: getString(parsed.title_query),
23
+ workspaceQuery: getString(parsed.workspace_query),
24
+ includeArchived: getBoolean(parsed.include_archived, false),
25
+ limit: getNumber(parsed.limit, 20),
26
+ });
27
+ return okStructured(`已获取 ${conversations.length} 条 Cursor 会话摘要。`, {
28
+ count: conversations.length,
29
+ conversations,
30
+ });
31
+ }
32
+ catch (error) {
33
+ return handleToolError(error, 'cursor_list_conversations');
34
+ }
35
+ }
@@ -0,0 +1,7 @@
1
+ export declare function cursorReadConversation(args: any): Promise<import("../lib/response.js").ToolResponse | {
2
+ content: Array<{
3
+ type: string;
4
+ text: string;
5
+ }>;
6
+ isError: true;
7
+ }>;
@@ -0,0 +1,36 @@
1
+ import { parseArgs, getString, getNumber, getBoolean } from '../utils/parseArgs.js';
2
+ import { okStructured } from '../lib/response.js';
3
+ import { handleToolError } from '../utils/error-handler.js';
4
+ import { createCursorHistoryClient } from '../lib/cursor-history-client.js';
5
+ export async function cursorReadConversation(args) {
6
+ try {
7
+ const parsed = parseArgs(args, {
8
+ defaultValues: {
9
+ composer_id: '',
10
+ limit: 200,
11
+ include_empty: false,
12
+ },
13
+ fieldAliases: {
14
+ composer_id: ['conversation_id', 'chat_id'],
15
+ },
16
+ });
17
+ const composerId = getString(parsed.composer_id).trim();
18
+ if (!composerId) {
19
+ throw new Error('缺少必填参数: composer_id');
20
+ }
21
+ const client = createCursorHistoryClient();
22
+ const conversation = await client.readConversation({
23
+ composerId,
24
+ limit: getNumber(parsed.limit, 200),
25
+ includeEmpty: getBoolean(parsed.include_empty, false),
26
+ });
27
+ return okStructured(`已读取 Cursor 会话 ${composerId},共 ${conversation.messages.length} 条消息。`, {
28
+ composerId,
29
+ messageCount: conversation.messages.length,
30
+ conversation,
31
+ });
32
+ }
33
+ catch (error) {
34
+ return handleToolError(error, 'cursor_read_conversation');
35
+ }
36
+ }
@@ -0,0 +1,7 @@
1
+ export declare function cursorSearchConversations(args: any): Promise<import("../lib/response.js").ToolResponse | {
2
+ content: Array<{
3
+ type: string;
4
+ text: string;
5
+ }>;
6
+ isError: true;
7
+ }>;
@@ -0,0 +1,36 @@
1
+ import { parseArgs, getString, getNumber } from '../utils/parseArgs.js';
2
+ import { okStructured } from '../lib/response.js';
3
+ import { handleToolError } from '../utils/error-handler.js';
4
+ import { createCursorHistoryClient } from '../lib/cursor-history-client.js';
5
+ export async function cursorSearchConversations(args) {
6
+ try {
7
+ const parsed = parseArgs(args, {
8
+ defaultValues: {
9
+ query: '',
10
+ composer_id: '',
11
+ limit: 20,
12
+ },
13
+ primaryField: 'query',
14
+ fieldAliases: {
15
+ composer_id: ['conversation_id', 'chat_id'],
16
+ },
17
+ });
18
+ const query = getString(parsed.query).trim();
19
+ if (!query) {
20
+ throw new Error('缺少必填参数: query');
21
+ }
22
+ const client = createCursorHistoryClient();
23
+ const matches = await client.searchHistory({
24
+ query,
25
+ composerId: getString(parsed.composer_id),
26
+ limit: getNumber(parsed.limit, 20),
27
+ });
28
+ return okStructured(`已找到 ${matches.length} 条 Cursor 历史命中。`, {
29
+ count: matches.length,
30
+ matches,
31
+ });
32
+ }
33
+ catch (error) {
34
+ return handleToolError(error, 'cursor_search_conversations');
35
+ }
36
+ }
@@ -16,5 +16,11 @@ 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 { readMemoryAsset } from "./read_memory_asset.js";
20
+ export { memorizeAsset } from "./memorize_asset.js";
21
+ export { scanAndExtractPatterns } from "./scan_and_extract_patterns.js";
22
+ export { cursorListConversations } from "./cursor_list_conversations.js";
23
+ export { cursorSearchConversations } from "./cursor_search_conversations.js";
24
+ export { cursorReadConversation } from "./cursor_read_conversation.js";
19
25
  export { startProduct } from "./start_product.js";
20
26
  export { gitWorkReport } from "./git_work_report.js";
@@ -19,6 +19,13 @@ export { askUser } from "./ask_user.js";
19
19
  // UI/UX Pro Max 工具
20
20
  export { uiDesignSystem, uiSearch, syncUiData } from "./ui-ux-tools.js";
21
21
  export { startUi } from "./start_ui.js";
22
+ // 记忆工具
23
+ export { readMemoryAsset } from "./read_memory_asset.js";
24
+ export { memorizeAsset } from "./memorize_asset.js";
25
+ export { scanAndExtractPatterns } from "./scan_and_extract_patterns.js";
26
+ export { cursorListConversations } from "./cursor_list_conversations.js";
27
+ export { cursorSearchConversations } from "./cursor_search_conversations.js";
28
+ export { cursorReadConversation } from "./cursor_read_conversation.js";
22
29
  // 产品设计工作流
23
30
  export { startProduct } from "./start_product.js";
24
31
  // Git 工具
@@ -6,4 +6,23 @@
6
6
  * @param args.project_root - 项目根目录,默认当前目录
7
7
  * @returns MCP 响应,包含文档生成指导
8
8
  */
9
- export declare function initProjectContext(args: any): Promise<import("../lib/response.js").ToolResponse>;
9
+ export declare function initProjectContext(args: any): Promise<import("../lib/response.js").ToolResponse | {
10
+ content: {
11
+ type: string;
12
+ text: string;
13
+ }[];
14
+ isError: boolean;
15
+ structuredContent: {
16
+ error_code: string;
17
+ rejected_project_root: string;
18
+ retry_hint: {
19
+ preferred: {
20
+ project_root: string;
21
+ path: string;
22
+ };
23
+ fallback: {
24
+ project_root: string;
25
+ };
26
+ };
27
+ };
28
+ }>;