mcp-probe-kit 3.1.0 → 3.3.0

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 (119) hide show
  1. package/README.md +15 -5
  2. package/build/index.js +5 -2
  3. package/build/lib/__tests__/memory-orchestration.unit.test.js +88 -0
  4. package/build/lib/__tests__/memory-payload.unit.test.js +35 -0
  5. package/build/lib/__tests__/quality-constraints.unit.test.d.ts +1 -0
  6. package/build/lib/__tests__/quality-constraints.unit.test.js +54 -0
  7. package/build/lib/__tests__/spec-validator.unit.test.d.ts +1 -0
  8. package/build/lib/__tests__/spec-validator.unit.test.js +147 -0
  9. package/build/lib/agents-md-template.js +32 -32
  10. package/build/lib/cursor-history-client.d.ts +54 -0
  11. package/build/lib/cursor-history-client.js +240 -0
  12. package/build/lib/memory-orchestration.js +29 -8
  13. package/build/lib/quality-constraints.d.ts +54 -0
  14. package/build/lib/quality-constraints.js +155 -0
  15. package/build/lib/skill-bridge.js +12 -12
  16. package/build/lib/spec-validator.d.ts +36 -0
  17. package/build/lib/spec-validator.js +116 -0
  18. package/build/lib/template-loader.js +223 -61
  19. package/build/lib/tool-annotations.d.ts +30 -0
  20. package/build/lib/tool-annotations.js +55 -0
  21. package/build/lib/toolset-manager.js +2 -0
  22. package/build/resources/ui-ux-data/guidelines/vercel-web-interface.json +1632 -1632
  23. package/build/resources/ui-ux-data/metadata.json +30 -30
  24. package/build/resources/ui-ux-data/shadcn/blocks.json +2541 -2541
  25. package/build/resources/ui-ux-data/shadcn/components.json +997 -997
  26. package/build/resources/ui-ux-data/themes/presets.json +483 -483
  27. package/build/schemas/index.d.ts +22 -0
  28. package/build/schemas/project-tools.d.ts +22 -0
  29. package/build/schemas/project-tools.js +23 -0
  30. package/build/tools/__tests__/cursor-history.unit.test.d.ts +1 -0
  31. package/build/tools/__tests__/cursor-history.unit.test.js +38 -0
  32. package/build/tools/check_spec.d.ts +7 -0
  33. package/build/tools/check_spec.js +81 -0
  34. package/build/tools/code_insight.js +41 -41
  35. package/build/tools/code_review.js +11 -4
  36. package/build/tools/cursor_read_conversation.d.ts +7 -0
  37. package/build/tools/cursor_read_conversation.js +36 -0
  38. package/build/tools/fix_bug.js +161 -161
  39. package/build/tools/gencommit.js +60 -60
  40. package/build/tools/index.d.ts +1 -0
  41. package/build/tools/index.js +1 -0
  42. package/build/tools/init_project_context.js +432 -432
  43. package/build/tools/start_bugfix.js +21 -10
  44. package/build/tools/start_feature.js +46 -11
  45. package/build/tools/start_product.js +1 -1
  46. package/build/tools/start_ui.js +44 -13
  47. package/build/tools/ui-ux-tools.d.ts +3 -0
  48. package/build/tools/ui-ux-tools.js +302 -290
  49. package/build/utils/__tests__/vercel-guidelines-sync.unit.test.js +12 -12
  50. package/build/utils/design-reasoning-engine.d.ts +2 -0
  51. package/build/utils/design-reasoning-engine.js +3 -0
  52. package/build/utils/themes-sync.js +8 -8
  53. package/package.json +4 -3
  54. package/build/resources/index.d.ts +0 -4
  55. package/build/resources/index.js +0 -4
  56. package/build/resources/tool-params-guide.d.ts +0 -571
  57. package/build/resources/tool-params-guide.js +0 -488
  58. package/build/tools/analyze_project.d.ts +0 -1
  59. package/build/tools/analyze_project.js +0 -527
  60. package/build/tools/check_deps.d.ts +0 -13
  61. package/build/tools/check_deps.js +0 -204
  62. package/build/tools/convert.d.ts +0 -13
  63. package/build/tools/convert.js +0 -599
  64. package/build/tools/css_order.d.ts +0 -13
  65. package/build/tools/css_order.js +0 -81
  66. package/build/tools/debug.d.ts +0 -13
  67. package/build/tools/debug.js +0 -131
  68. package/build/tools/design2code.d.ts +0 -20
  69. package/build/tools/design2code.js +0 -426
  70. package/build/tools/detect_shell.d.ts +0 -6
  71. package/build/tools/detect_shell.js +0 -151
  72. package/build/tools/explain.d.ts +0 -13
  73. package/build/tools/explain.js +0 -390
  74. package/build/tools/fix.d.ts +0 -13
  75. package/build/tools/fix.js +0 -303
  76. package/build/tools/gen_mock.d.ts +0 -22
  77. package/build/tools/gen_mock.js +0 -269
  78. package/build/tools/gen_skill.d.ts +0 -13
  79. package/build/tools/gen_skill.js +0 -560
  80. package/build/tools/genapi.d.ts +0 -13
  81. package/build/tools/genapi.js +0 -174
  82. package/build/tools/genchangelog.d.ts +0 -13
  83. package/build/tools/genchangelog.js +0 -250
  84. package/build/tools/gendoc.d.ts +0 -13
  85. package/build/tools/gendoc.js +0 -232
  86. package/build/tools/genpr.d.ts +0 -13
  87. package/build/tools/genpr.js +0 -194
  88. package/build/tools/genreadme.d.ts +0 -13
  89. package/build/tools/genreadme.js +0 -626
  90. package/build/tools/gensql.d.ts +0 -13
  91. package/build/tools/gensql.js +0 -320
  92. package/build/tools/genui.d.ts +0 -13
  93. package/build/tools/genui.js +0 -803
  94. package/build/tools/init_component_catalog.d.ts +0 -22
  95. package/build/tools/init_component_catalog.js +0 -809
  96. package/build/tools/init_setting.d.ts +0 -13
  97. package/build/tools/init_setting.js +0 -47
  98. package/build/tools/perf.d.ts +0 -13
  99. package/build/tools/perf.js +0 -409
  100. package/build/tools/render_ui.d.ts +0 -22
  101. package/build/tools/render_ui.js +0 -384
  102. package/build/tools/resolve_conflict.d.ts +0 -13
  103. package/build/tools/resolve_conflict.js +0 -349
  104. package/build/tools/security_scan.d.ts +0 -22
  105. package/build/tools/security_scan.js +0 -323
  106. package/build/tools/split.d.ts +0 -13
  107. package/build/tools/split.js +0 -599
  108. package/build/tools/start_api.d.ts +0 -13
  109. package/build/tools/start_api.js +0 -193
  110. package/build/tools/start_doc.d.ts +0 -13
  111. package/build/tools/start_doc.js +0 -207
  112. package/build/tools/start_refactor.d.ts +0 -13
  113. package/build/tools/start_refactor.js +0 -188
  114. package/build/tools/start_release.d.ts +0 -13
  115. package/build/tools/start_release.js +0 -167
  116. package/build/tools/start_review.d.ts +0 -13
  117. package/build/tools/start_review.js +0 -175
  118. /package/build/{utils/design-docs-generator.d.ts → lib/__tests__/memory-orchestration.unit.test.d.ts} +0 -0
  119. /package/build/{utils/design-docs-generator.js → lib/__tests__/memory-payload.unit.test.d.ts} +0 -0
package/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  > 🚀 AI-Powered Complete Development Toolkit - Covering the Entire Development Lifecycle
28
28
 
29
- A powerful MCP (Model Context Protocol) server providing **26 tools** covering the complete workflow from product analysis to final release (Requirements → Design → Development → Quality → Release), all tools support **structured output**.
29
+ A powerful MCP (Model Context Protocol) server providing **27 tools** covering the complete workflow from product analysis to final release (Requirements → Design → Development → Quality → Release), all tools support **structured output**.
30
30
 
31
31
  **🎉 v3.0 Major Update**: Streamlined tool count, focus on core competencies, eliminate choice paralysis, let AI do more native work
32
32
 
@@ -42,7 +42,7 @@ A powerful MCP (Model Context Protocol) server providing **26 tools** covering t
42
42
 
43
43
  - [Quick Start](https://mcp-probe-kit.bytezonex.com/pages/getting-started.html) - Setup in 5 minutes
44
44
  - [Local Memory Stack (Qdrant + Nomic Embed)](docs/memory-local-setup.md) - Docker Compose, ports `50008` / `50012`, MCP env
45
- - [All Tools](https://mcp-probe-kit.bytezonex.com/pages/all-tools.html) - Complete list of 26 tools
45
+ - [All Tools](https://mcp-probe-kit.bytezonex.com/pages/all-tools.html) - Complete list of 27 tools
46
46
  - [Best Practices](https://mcp-probe-kit.bytezonex.com/pages/examples.html) - Full development workflow guide
47
47
  - [v3.0 Migration Guide](https://mcp-probe-kit.bytezonex.com/pages/migration.html) - Upgrade from v2.x to v3.0
48
48
 
@@ -50,7 +50,7 @@ A powerful MCP (Model Context Protocol) server providing **26 tools** covering t
50
50
 
51
51
  ## ✨ Core Features
52
52
 
53
- ### 📦 26 Tools
53
+ ### 📦 27 Tools
54
54
 
55
55
  - **🔄 Workflow Orchestration** (6 tools) - One-click complex development workflows
56
56
  - `start_feature`, `start_bugfix`, `start_onboard`, `start_ui`, `start_product`, `start_ralph`
@@ -60,13 +60,23 @@ A powerful MCP (Model Context Protocol) server providing **26 tools** covering t
60
60
  - `gencommit`, `git_work_report`
61
61
  - **⚡ Code Generation** (1 tool) - Test generation
62
62
  - `gentest`
63
- - **📦 Project Management** (6 tools) - Project initialization and requirements management
64
- - `init_project`, `init_project_context`, `add_feature`, `estimate`, `interview`, `ask_user`
63
+ - **📦 Project Management** (7 tools) - Project initialization, requirements, and spec validation
64
+ - `init_project`, `init_project_context`, `add_feature`, `check_spec`, `estimate`, `interview`, `ask_user`
65
65
  - **🎨 UI/UX Utilities** (3 tools) - Design systems and UI data synchronization
66
66
  - `ui_design_system`, `ui_search`, `sync_ui_data`
67
67
  - **🧠 Memory** (4 tools) - Reusable asset memory
68
68
  - `search_memory`, `read_memory_asset`, `memorize_asset`, `scan_and_extract_patterns`
69
69
 
70
+ ### 🛡️ Quality Constraints (single source of truth)
71
+
72
+ All hard quality rules live in one module (`src/lib/quality-constraints.ts`) and are injected into `code_review`, the `add_feature` task templates, and the UI tools. Change once, apply everywhere — inspired by [taste-skill](https://github.com/Leonxlnx/taste-skill) and [impeccable](https://github.com/pbakaus/impeccable).
73
+
74
+ - **Code limits**: single file ≤ 500 lines (split into modules/components when exceeded), function ≤ 50 lines, nesting ≤ 4, parameters ≤ 3.
75
+ - **Completeness blacklist**: `code_review` flags placeholder/elision patterns (`// ...`, `// TODO`, `// rest of code`, bare `...`) as CRITICAL — "a partial output is a broken output".
76
+ - **Anti-laziness task templates**: `add_feature` tasks now carry a Scope-lock deliverable count, a mandatory evidence block (read code before writing), a per-file line budget, and a binary zero-tolerance rule for placeholders. `check_spec` validates these (missing Scope-lock = error, thin task without evidence = warning).
77
+ - **UI hard red lines**: numeric, machine-checkable rules — 4pt spacing scale, WCAG contrast (4.5/3/3), type scale ≥ 1.25, hero font ≤ 6rem, OKLCH, eight interaction states, cognitive load ≤ 4, motion 150-300ms.
78
+ - **UI banned list + Pre-Flight checklist**: match-and-refuse blacklist for AI slop (default Inter/Roboto, AI purple-blue gradients, gradient text, cookie-cutter card grids, em-dash, cream/beige body backgrounds, nested cards) plus a delivery-gate self-check matrix.
79
+
70
80
  ### 🧠 Code Graph Bridge (GitNexus)
71
81
 
72
82
  - `code_insight` bridges GitNexus by default for query/context/impact analysis
package/build/index.js CHANGED
@@ -5,10 +5,11 @@ import { InMemoryTaskMessageQueue, InMemoryTaskStore, } from "@modelcontextproto
5
5
  import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ProgressNotificationSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
6
6
  import * as fs from "node:fs";
7
7
  import * as path from "node:path";
8
- import { initProject, gencommit, codeReview, codeInsight, gentest, refactor, initProjectContext, addFeature, fixBug, estimate, startFeature, startBugfix, startOnboard, startRalph, interview, askUser, uiDesignSystem, uiSearch, syncUiData, startUi, startProduct, gitWorkReport, searchMemory, readMemoryAsset, memorizeAsset, scanAndExtractPatterns } from "./tools/index.js";
8
+ import { initProject, gencommit, codeReview, codeInsight, gentest, refactor, initProjectContext, addFeature, fixBug, estimate, checkSpec, startFeature, startBugfix, startOnboard, startRalph, interview, askUser, uiDesignSystem, uiSearch, syncUiData, startUi, startProduct, gitWorkReport, searchMemory, readMemoryAsset, memorizeAsset, scanAndExtractPatterns } from "./tools/index.js";
9
9
  import { VERSION, NAME } from "./version.js";
10
10
  import { allToolSchemas } from "./schemas/index.js";
11
11
  import { filterTools, getToolsetFromEnv } from "./lib/toolset-manager.js";
12
+ import { withToolAnnotations } from "./lib/tool-annotations.js";
12
13
  import { isAbortError, } from "./lib/tool-execution-context.js";
13
14
  const EXTENSIONS_CAPABILITY_KEY = "io.github.mybolide/extensions";
14
15
  const MAX_UI_APP_RESOURCES = 30;
@@ -410,7 +411,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
410
411
  const filteredTools = filterTools(allToolSchemas, toolset);
411
412
  console.error(`[MCP Probe Kit] 当前工具集: ${toolset} (${filteredTools.length}/${allToolSchemas.length} 个工具)`);
412
413
  return {
413
- tools: filteredTools,
414
+ tools: filteredTools.map(withToolAnnotations),
414
415
  };
415
416
  });
416
417
  async function executeTool(name, args, context) {
@@ -431,6 +432,8 @@ async function executeTool(name, args, context) {
431
432
  return await initProjectContext(args);
432
433
  case "add_feature":
433
434
  return await addFeature(args);
435
+ case "check_spec":
436
+ return await checkSpec(args);
434
437
  case "fix_bug":
435
438
  return await fixBug(args);
436
439
  case "estimate":
@@ -0,0 +1,88 @@
1
+ import { afterEach, describe, expect, test, vi } from 'vitest';
2
+ import { renderMemoryGuideSection, shouldShowSourceInSearch, } from '../memory-orchestration.js';
3
+ afterEach(() => {
4
+ vi.unstubAllEnvs();
5
+ });
6
+ describe('memory-orchestration', () => {
7
+ test('does not show source path by default', () => {
8
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', '');
9
+ vi.stubEnv('MEMORY_REPO_ID', '');
10
+ const section = renderMemoryGuideSection({
11
+ enabled: true,
12
+ available: true,
13
+ degraded: false,
14
+ query: '404 submit',
15
+ results: [
16
+ {
17
+ id: '1',
18
+ score: 0.91,
19
+ name: 'purchase-create-submit-404',
20
+ type: 'bugfix',
21
+ description: 'desc',
22
+ summary: 'summary',
23
+ content: '',
24
+ tags: ['bugfix'],
25
+ sourceProject: 'zhixing/gongyingshang',
26
+ sourcePath: 'admin-api/app.js',
27
+ },
28
+ ],
29
+ assetsById: {},
30
+ });
31
+ expect(section).toContain('purchase-create-submit-404');
32
+ expect(section).not.toContain('admin-api/app.js');
33
+ expect(section).not.toContain('来源:');
34
+ });
35
+ test('shows source path when MEMORY_REPO_ID matches', () => {
36
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', '');
37
+ vi.stubEnv('MEMORY_REPO_ID', 'zhixing/gongyingshang');
38
+ expect(shouldShowSourceInSearch({
39
+ id: '1',
40
+ score: 0.9,
41
+ name: 'x',
42
+ type: 'bugfix',
43
+ description: '',
44
+ summary: '',
45
+ content: '',
46
+ tags: [],
47
+ sourceProject: 'zhixing/gongyingshang',
48
+ sourcePath: 'admin-api/app.js',
49
+ })).toBe(true);
50
+ expect(shouldShowSourceInSearch({
51
+ id: '2',
52
+ score: 0.9,
53
+ name: 'y',
54
+ type: 'bugfix',
55
+ description: '',
56
+ summary: '',
57
+ content: '',
58
+ tags: [],
59
+ sourceProject: 'other/repo',
60
+ sourcePath: 'src/index.ts',
61
+ })).toBe(false);
62
+ });
63
+ test('MEMORY_SEARCH_SHOW_SOURCE=true always shows source', () => {
64
+ vi.stubEnv('MEMORY_SEARCH_SHOW_SOURCE', 'true');
65
+ vi.stubEnv('MEMORY_REPO_ID', '');
66
+ const section = renderMemoryGuideSection({
67
+ enabled: true,
68
+ available: true,
69
+ degraded: false,
70
+ query: 'q',
71
+ results: [
72
+ {
73
+ id: '1',
74
+ score: 0.8,
75
+ name: 'n',
76
+ type: 'bugfix',
77
+ description: '',
78
+ summary: 's',
79
+ content: '',
80
+ tags: [],
81
+ sourcePath: 'admin-api/app.js',
82
+ },
83
+ ],
84
+ assetsById: {},
85
+ });
86
+ expect(section).toContain('来源: admin-api/app.js');
87
+ });
88
+ });
@@ -0,0 +1,35 @@
1
+ import { describe, expect, test } from 'vitest';
2
+ import { normalizeMemoryPayload, payloadToMemoryFields } from '../memory-payload.js';
3
+ describe('memory-payload', () => {
4
+ test('maps legacy kind/title/source fields to current schema', () => {
5
+ const normalized = normalizeMemoryPayload({
6
+ kind: 'extracted_pattern',
7
+ title: 'Feishu submit success but sync_failed',
8
+ source: 'scan_and_extract_patterns-fallback',
9
+ content: 'Pattern: proxy mismatch',
10
+ tags: ['feishu', 'pattern'],
11
+ created_at: '2026-05-25T11:20:06.705Z',
12
+ });
13
+ expect(normalized.name).toBe('Feishu submit success but sync_failed');
14
+ expect(normalized.type).toBe('pattern');
15
+ expect(normalized.summary).toContain('Pattern');
16
+ expect(normalized.createdAt).toBe('2026-05-25T11:20:06.705Z');
17
+ });
18
+ test('payloadToMemoryFields preserves standard asset fields', () => {
19
+ const fields = payloadToMemoryFields({
20
+ id: 'asset-1',
21
+ name: 'purchase-create-submit-404',
22
+ type: 'bugfix',
23
+ description: '送审 404',
24
+ summary: 'res.data.purchase.id',
25
+ content: '【现象】404',
26
+ tags: ['bugfix'],
27
+ confidence: 0.95,
28
+ createdAt: '2026-05-27T04:28:04.684Z',
29
+ updatedAt: '2026-05-27T04:28:04.684Z',
30
+ });
31
+ expect(fields.name).toBe('purchase-create-submit-404');
32
+ expect(fields.type).toBe('bugfix');
33
+ expect(fields.tags).toEqual(['bugfix']);
34
+ });
35
+ });
@@ -0,0 +1,54 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { CODE_LIMITS, BANNED_CODE_PATTERNS, UI_HARD_RULES, UI_BANNED_LIST, renderCodeLimits, renderBannedPatterns, renderUiHardRules, renderUiBannedList, renderPreFlightChecklist, } from '../quality-constraints.js';
3
+ describe('quality-constraints(质量约束单一真相源)', () => {
4
+ test('CODE_LIMITS 数值符合预期(单文件 500 / 函数 50)', () => {
5
+ expect(CODE_LIMITS.maxFileLines).toBe(500);
6
+ expect(CODE_LIMITS.maxFunctionLines).toBe(50);
7
+ expect(CODE_LIMITS.maxNestingDepth).toBe(4);
8
+ expect(CODE_LIMITS.maxParameters).toBe(3);
9
+ });
10
+ test('黑名单与硬约束清单非空', () => {
11
+ expect(BANNED_CODE_PATTERNS.length).toBeGreaterThan(0);
12
+ expect(UI_HARD_RULES.length).toBeGreaterThan(0);
13
+ expect(UI_BANNED_LIST.length).toBeGreaterThan(0);
14
+ });
15
+ test('代码完整性黑名单含关键占位模式', () => {
16
+ expect(BANNED_CODE_PATTERNS).toContain('// TODO');
17
+ expect(BANNED_CODE_PATTERNS).toContain('// ...');
18
+ });
19
+ test('UI 黑名单含 em-dash 零容忍与 AI 紫蓝渐变', () => {
20
+ expect(UI_BANNED_LIST.some((b) => b.includes('em-dash'))).toBe(true);
21
+ expect(UI_BANNED_LIST.some((b) => b.includes('紫蓝渐变'))).toBe(true);
22
+ });
23
+ test('renderCodeLimits 输出含 500 行红线', () => {
24
+ const out = renderCodeLimits();
25
+ expect(out).toContain('500');
26
+ expect(out).toContain('HIGH');
27
+ });
28
+ test('renderBannedPatterns 输出含 CRITICAL 与二元规则', () => {
29
+ const out = renderBannedPatterns();
30
+ expect(out).toContain('CRITICAL');
31
+ expect(out).toContain('二元');
32
+ });
33
+ test('renderUiHardRules 含 4pt 间距阶梯与对比度阈值', () => {
34
+ const out = renderUiHardRules();
35
+ expect(out).toContain('4, 8, 12, 16, 24, 32, 48, 64, 96');
36
+ expect(out).toContain('4.5:1');
37
+ });
38
+ test('renderUiBannedList 输出每条以 ❌ 标记', () => {
39
+ const out = renderUiBannedList();
40
+ expect(out).toContain('❌');
41
+ });
42
+ test('renderPreFlightChecklist 含 Scope-lock 与完整性勾选项', () => {
43
+ const out = renderPreFlightChecklist();
44
+ expect(out).toContain('Pre-Flight');
45
+ expect(out).toContain('Scope-lock');
46
+ expect(out).toContain('占位符');
47
+ });
48
+ // 防回归:注入下游 prompt 的渲染输出自身不得含 em-dash,否则与「em-dash 零容忍」自相矛盾
49
+ test('代码类渲染输出不含 em-dash(避免规则自相矛盾)', () => {
50
+ expect(renderCodeLimits()).not.toContain('—');
51
+ expect(renderBannedPatterns()).not.toContain('—');
52
+ expect(renderPreFlightChecklist()).not.toContain('—');
53
+ });
54
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,147 @@
1
+ import { describe, test, expect } from 'vitest';
2
+ import { validateSpecDocuments, extractFrIds } from '../spec-validator.js';
3
+ const goodReq = `# 需求文档:demo
4
+
5
+ ## 功能概述
6
+ 做一个登录功能。
7
+
8
+ ## 历史经验与坑(来自记忆库)
9
+ - 可复用经验: 无
10
+ - 必须规避的坑: 无
11
+
12
+ ## 范围边界
13
+ In Scope: 登录
14
+ Out of Scope: 注册
15
+
16
+ ## 需求列表
17
+ ### FR-1: 登录
18
+ **优先级:** Must
19
+ **用户故事:** 作为用户,我想登录,以便访问系统。
20
+ #### 验收标准(EARS)
21
+ 1. WHEN 提交正确凭证 THEN 系统 SHALL 登录成功
22
+
23
+ ## 非功能需求
24
+ - NFR-1: 登录响应 < 1s
25
+
26
+ ## 依赖关系
27
+ - 无
28
+ `;
29
+ const goodDesign = `# 设计文档:demo
30
+
31
+ ## 概述
32
+ 登录设计。
33
+ **对应需求:** FR-1
34
+
35
+ ## 技术方案
36
+ ### 技术选型
37
+ 使用 JWT。
38
+
39
+ ## 数据模型
40
+ 不涉及。
41
+
42
+ ## API 设计
43
+ POST /api/login
44
+
45
+ ## 文件结构
46
+ src/login.ts
47
+
48
+ ## 设计决策
49
+ 决策 1:用 JWT。
50
+
51
+ ## 风险评估
52
+ 无。
53
+ `;
54
+ const goodTasks = `# 任务清单:demo
55
+
56
+ ## 概述
57
+ 任务分解。
58
+
59
+ ## 交付物清单(Scope-lock)
60
+ - 预计新建文件数: 1 个
61
+ - 预计修改文件数: 0 个
62
+
63
+ ## 任务列表
64
+ ### 阶段 2: 核心实现
65
+ - [ ] 2.1 实现登录接口 POST /api/login,校验邮箱并返回 JWT
66
+ - 证据块: 先读 src/router.ts:1,确认路由注册方式
67
+ - _需求: FR-1_ | _设计: API 设计_
68
+
69
+ ## 检查点
70
+ - [ ] 阶段 2 完成后:登录可用
71
+
72
+ ## 需求覆盖矩阵
73
+ | 需求 ID | 设计章节 | 任务编号 | 状态 |
74
+ | FR-1 | API 设计 | 2.1 | 未开始 |
75
+
76
+ ## 文件变更清单
77
+ | 文件 | 操作 | 说明 |
78
+ | src/login.ts | 新建 | 登录接口 |
79
+ `;
80
+ describe('spec-validator(P1 填写后校验)', () => {
81
+ test('完整规格通过校验', () => {
82
+ const r = validateSpecDocuments({ requirements: goodReq, design: goodDesign, tasks: goodTasks });
83
+ expect(r.passed).toBe(true);
84
+ expect(r.errorCount).toBe(0);
85
+ expect(r.frIds).toContain('FR-1');
86
+ });
87
+ test('残留 [填写:] 占位 → 未通过', () => {
88
+ const r = validateSpecDocuments({ requirements: goodReq + '\n- [填写:补充]', design: goodDesign, tasks: goodTasks });
89
+ expect(r.passed).toBe(false);
90
+ expect(r.issues.some((i) => i.file === 'requirements' && i.code === 'placeholder')).toBe(true);
91
+ });
92
+ test('缺少 design 文件 → 未通过', () => {
93
+ const r = validateSpecDocuments({ requirements: goodReq, design: null, tasks: goodTasks });
94
+ expect(r.passed).toBe(false);
95
+ expect(r.issues.some((i) => i.file === 'design' && i.code === 'missing_file')).toBe(true);
96
+ });
97
+ test('无 EARS 验收标准 → 未通过', () => {
98
+ const r = validateSpecDocuments({
99
+ requirements: goodReq.replace('1. WHEN 提交正确凭证 THEN 系统 SHALL 登录成功', '1. 能登录'),
100
+ design: goodDesign,
101
+ tasks: goodTasks,
102
+ });
103
+ expect(r.passed).toBe(false);
104
+ expect(r.issues.some((i) => i.code === 'no_acceptance')).toBe(true);
105
+ });
106
+ test('FR 未进 tasks 覆盖矩阵 → 跨文档未覆盖', () => {
107
+ const reqTwoFr = goodReq.replace('## 非功能需求', `### FR-2: 登出
108
+ **优先级:** Should
109
+ **用户故事:** 作为用户,我想登出。
110
+ #### 验收标准(EARS)
111
+ 1. WHEN 点击登出 THEN 系统 SHALL 退出登录
112
+
113
+ ## 非功能需求`);
114
+ const r = validateSpecDocuments({ requirements: reqTwoFr, design: goodDesign, tasks: goodTasks });
115
+ expect(r.passed).toBe(false);
116
+ expect(r.issues.some((i) => i.code === 'uncovered_fr')).toBe(true);
117
+ });
118
+ test('extractFrIds 去重并保序', () => {
119
+ expect(extractFrIds('FR-1 写了 FR-1 又写 FR-2')).toEqual(['FR-1', 'FR-2']);
120
+ });
121
+ test('tasks 缺少「交付物清单」章节 → 未通过', () => {
122
+ const tasksNoScope = goodTasks.replace(/## 交付物清单(Scope-lock)[\s\S]*?\n\n/, '');
123
+ // 防 fixture 漂移导致替换失效造成假通过
124
+ expect(tasksNoScope).not.toContain('交付物清单');
125
+ const r = validateSpecDocuments({ requirements: goodReq, design: goodDesign, tasks: tasksNoScope });
126
+ expect(r.passed).toBe(false);
127
+ expect(r.issues.some((i) => i.file === 'tasks' && i.code === 'missing_section')).toBe(true);
128
+ });
129
+ test('任务无「证据块」→ thin_task 提醒(warning,不阻断)', () => {
130
+ const tasksThin = goodTasks.replace(' - 证据块: 先读 src/router.ts:1,确认路由注册方式\n', '');
131
+ expect(tasksThin).not.toBe(goodTasks);
132
+ const r = validateSpecDocuments({ requirements: goodReq, design: goodDesign, tasks: tasksThin });
133
+ expect(r.issues.some((i) => i.code === 'thin_task')).toBe(true);
134
+ expect(r.warningCount).toBeGreaterThan(0);
135
+ // 核心语义:thin_task 是 warning,不应阻断 passed
136
+ expect(r.passed).toBe(true);
137
+ });
138
+ test('裸 [填写] 占位(无冒号)也应被检出', () => {
139
+ const r = validateSpecDocuments({
140
+ requirements: goodReq + '\n- 备注: [填写]',
141
+ design: goodDesign,
142
+ tasks: goodTasks,
143
+ });
144
+ expect(r.passed).toBe(false);
145
+ expect(r.issues.some((i) => i.file === 'requirements' && i.code === 'placeholder')).toBe(true);
146
+ });
147
+ });
@@ -4,18 +4,18 @@ function link(layout, targetRel) {
4
4
  }
5
5
  function memorySection(locale) {
6
6
  if (locale === "zh-CN") {
7
- return `
8
- 记忆(需 MEMORY_QDRANT_URL 等已配置):
9
- - 检索:\`start_*\` 命中后**自动注入**历史经验全文;中途补查可用 \`search_memory\`;单条精读仍可用 \`read_memory_asset\`
10
- - 沉淀:跨仓库共享**勿填** source_project/source_path;路径写进 content;summary 写检索关键词
11
- - Bug 修完验证通过 → **必须** \`memorize_asset\` type=\`bugfix\` tags=\`bugfix,root-cause\`(content 含【现象】【根因】【修复】【验证】)
7
+ return `
8
+ 记忆(需 MEMORY_QDRANT_URL 等已配置):
9
+ - 检索:\`start_*\` 命中后**自动注入**历史经验全文;中途补查可用 \`search_memory\`;单条精读仍可用 \`read_memory_asset\`
10
+ - 沉淀:跨仓库共享**勿填** source_project/source_path;路径写进 content;summary 写检索关键词
11
+ - Bug 修完验证通过 → **必须** \`memorize_asset\` type=\`bugfix\` tags=\`bugfix,root-cause\`(content 含【现象】【根因】【修复】【验证】)
12
12
  - 功能/UI 可复用产出 → \`memorize_asset\` type=\`pattern\`/\`component\``;
13
13
  }
14
- return `
15
- Memory (requires MEMORY_* env):
16
- - Search: \`start_*\` auto-injects full memory hits; use \`search_memory\` mid-task; \`read_memory_asset\` for a specific id
17
- - Store: do NOT use source_project/source_path for cross-repo pools; put paths in content; write keyword-rich summary
18
- - After verified bugfix → MUST \`memorize_asset\` type=\`bugfix\` (sections: symptom, root cause, fix, verification)
14
+ return `
15
+ Memory (requires MEMORY_* env):
16
+ - Search: \`start_*\` auto-injects full memory hits; use \`search_memory\` mid-task; \`read_memory_asset\` for a specific id
17
+ - Store: do NOT use source_project/source_path for cross-repo pools; put paths in content; write keyword-rich summary
18
+ - After verified bugfix → MUST \`memorize_asset\` type=\`bugfix\` (sections: symptom, root cause, fix, verification)
19
19
  - Reusable feature/UI → \`memorize_asset\` type=\`pattern\`/\`component\``;
20
20
  }
21
21
  /**
@@ -26,30 +26,30 @@ export function generateAgentsMdInner(input) {
26
26
  const graph = link(layout, layout.latestMarkdownPath);
27
27
  const ctxIndex = link(layout, layout.legacyIndexPath);
28
28
  if (locale === "zh-CN") {
29
- return `## MCP(必须先调)
30
- 需已配置 mcp-probe-kit。\`start_*\` 若返回 delegated plan,逐步执行完再结束。
31
-
32
- - 新功能 → \`start_feature\`(会先搜记忆)
33
- - Bug → \`start_bugfix\`(会先搜记忆)
34
- - UI → \`start_ui\`(会先搜记忆)
35
- - 不熟代码 / 影响面 → \`code_insight\`(context / impact / auto)
36
- - 缺上下文 → \`init_project_context\`
37
- - 提交 → \`gencommit\`
38
-
39
- 上下文:写代码前先读 [project-context](${ctxIndex})(链到 \`${layout.modularDir}/\` 各文档)
29
+ return `## MCP(必须先调)
30
+ 需已配置 mcp-probe-kit。\`start_*\` 若返回 delegated plan,逐步执行完再结束。
31
+
32
+ - 新功能 → \`start_feature\`(会先搜记忆)
33
+ - Bug → \`start_bugfix\`(会先搜记忆)
34
+ - UI → \`start_ui\`(会先搜记忆)
35
+ - 不熟代码 / 影响面 → \`code_insight\`(context / impact / auto)
36
+ - 缺上下文 → \`init_project_context\`
37
+ - 提交 → \`gencommit\`
38
+
39
+ 上下文:写代码前先读 [project-context](${ctxIndex})(链到 \`${layout.modularDir}/\` 各文档)
40
40
  图谱:大改前读 [latest](${graph});过期 \`code_insight\` mode=auto save_to_docs=true${memorySection(locale)}`;
41
41
  }
42
- return `## MCP (call first)
43
- Requires mcp-probe-kit. Complete every \`start_*\` delegated plan step before done.
44
-
45
- - Feature → \`start_feature\` (searches memory first)
46
- - Bug → \`start_bugfix\` (searches memory first)
47
- - UI → \`start_ui\` (searches memory first)
48
- - Unfamiliar code / impact → \`code_insight\` (context / impact / auto)
49
- - Missing context → \`init_project_context\`
50
- - Commit → \`gencommit\`
51
-
52
- Context: before coding read [project-context](${ctxIndex}) (links to \`${layout.modularDir}/\`)
42
+ return `## MCP (call first)
43
+ Requires mcp-probe-kit. Complete every \`start_*\` delegated plan step before done.
44
+
45
+ - Feature → \`start_feature\` (searches memory first)
46
+ - Bug → \`start_bugfix\` (searches memory first)
47
+ - UI → \`start_ui\` (searches memory first)
48
+ - Unfamiliar code / impact → \`code_insight\` (context / impact / auto)
49
+ - Missing context → \`init_project_context\`
50
+ - Commit → \`gencommit\`
51
+
52
+ Context: before coding read [project-context](${ctxIndex}) (links to \`${layout.modularDir}/\`)
53
53
  Graph: read [latest](${graph}) before large changes; refresh \`code_insight\` mode=auto save_to_docs=true${memorySection(locale)}`;
54
54
  }
55
55
  export function generateAgentsMdTemplate(input) {
@@ -0,0 +1,54 @@
1
+ export interface CursorConversationSummary {
2
+ composerId: string;
3
+ name: string;
4
+ createdAt?: number;
5
+ lastUpdatedAt?: number;
6
+ workspaceId?: string;
7
+ workspacePath?: string;
8
+ mode?: string;
9
+ contextUsagePercent?: number;
10
+ subtitle?: string;
11
+ isArchived?: boolean;
12
+ source: 'composerHeaders';
13
+ }
14
+ export interface CursorConversationMessage {
15
+ bubbleId: string;
16
+ type: number;
17
+ text: string;
18
+ createdAt?: string;
19
+ requestId?: string;
20
+ }
21
+ export interface CursorConversationDetail {
22
+ composerId: string;
23
+ messages: CursorConversationMessage[];
24
+ }
25
+ export interface CursorHistorySearchResult {
26
+ composerId: string;
27
+ conversationName: string;
28
+ bubbleId: string;
29
+ type: number;
30
+ text: string;
31
+ createdAt?: string;
32
+ requestId?: string;
33
+ }
34
+ export declare class CursorHistoryClient {
35
+ private withDatabase;
36
+ private loadConversationIndex;
37
+ listConversations(params?: {
38
+ titleQuery?: string;
39
+ workspaceQuery?: string;
40
+ includeArchived?: boolean;
41
+ limit?: number;
42
+ }): Promise<CursorConversationSummary[]>;
43
+ searchHistory(params: {
44
+ query: string;
45
+ composerId?: string;
46
+ limit?: number;
47
+ }): Promise<CursorHistorySearchResult[]>;
48
+ readConversation(params: {
49
+ composerId: string;
50
+ limit?: number;
51
+ includeEmpty?: boolean;
52
+ }): Promise<CursorConversationDetail>;
53
+ }
54
+ export declare function createCursorHistoryClient(): CursorHistoryClient;