@hupan56/wlkj 2.7.11 → 3.0.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 (152) hide show
  1. package/bin/cli.js +375 -78
  2. package/package.json +29 -29
  3. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +23 -0
  4. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +23 -0
  5. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +1 -0
  6. package/templates/.qoder/learning/eval-history.jsonl +28 -0
  7. package/templates/data/index/wiki-index.json +8 -0
  8. package/templates/qoder/agents/insight-planning.md +1 -1
  9. package/templates/qoder/agents/insight-research.md +28 -15
  10. package/templates/qoder/commands/optional/wl-insight.md +159 -161
  11. package/templates/qoder/commands/optional/wl-report.md +4 -4
  12. package/templates/qoder/commands/optional/wl-status.md +2 -2
  13. package/templates/qoder/commands/wl-code.md +2 -2
  14. package/templates/qoder/commands/wl-design.md +2 -2
  15. package/templates/qoder/commands/wl-init.md +3 -3
  16. package/templates/qoder/commands/wl-prd.md +2 -2
  17. package/templates/qoder/commands/wl-req.md +43 -0
  18. package/templates/qoder/commands/wl-search.md +8 -8
  19. package/templates/qoder/commands/wl-task.md +17 -17
  20. package/templates/qoder/commands/wl-test.md +41 -15
  21. package/templates/qoder/config.yaml +17 -1
  22. package/templates/qoder/hooks/session-start.py +12 -22
  23. package/templates/qoder/nul +4 -0
  24. package/templates/qoder/rules/wl-pipeline.md +22 -48
  25. package/templates/qoder/scripts/README.md +139 -0
  26. package/templates/qoder/scripts/common/autotest_auth.py +109 -0
  27. package/templates/qoder/scripts/common/bootstrap.py +145 -0
  28. package/templates/qoder/scripts/common/check_publish.py +98 -0
  29. package/templates/qoder/scripts/common/cmd_registry.py +112 -0
  30. package/templates/qoder/scripts/common/config.py +187 -0
  31. package/templates/qoder/scripts/common/contract.py +317 -0
  32. package/templates/qoder/scripts/common/developer.py +2 -1
  33. package/templates/qoder/scripts/common/feishu.py +10 -9
  34. package/templates/qoder/scripts/common/guard.py +159 -0
  35. package/templates/qoder/scripts/common/identity.py +121 -2
  36. package/templates/qoder/scripts/common/kg_capabilities.py +182 -0
  37. package/templates/qoder/scripts/common/mcp_base.py +268 -0
  38. package/templates/qoder/scripts/common/paths.py +187 -1
  39. package/templates/qoder/scripts/common/result.py +223 -0
  40. package/templates/qoder/scripts/common/roles.py +60 -0
  41. package/templates/qoder/scripts/common/task_utils.py +21 -9
  42. package/templates/qoder/scripts/common/test_extract.py +115 -0
  43. package/templates/qoder/scripts/kg/__init__.py +11 -0
  44. package/templates/qoder/scripts/kg/build_entity_registry.py +196 -0
  45. package/templates/qoder/scripts/kg/build_relations.py +127 -0
  46. package/templates/qoder/scripts/{build_style_index.py → kg/build_style_index.py} +39 -10
  47. package/templates/qoder/scripts/kg/build_workflows.py +144 -0
  48. package/templates/qoder/scripts/{context_pack.py → kg/context_pack.py} +18 -11
  49. package/templates/qoder/scripts/{enrich_prompt.py → kg/enrich_prompt.py} +232 -226
  50. package/templates/qoder/scripts/{extract_api_params.py → kg/extract.py} +398 -246
  51. package/templates/qoder/scripts/{kg.py → kg/kg.py} +638 -708
  52. package/templates/qoder/scripts/{kg_build.py → kg/kg_build.py} +618 -612
  53. package/templates/qoder/scripts/{kg_build_db.py → kg/kg_build_db.py} +333 -327
  54. package/templates/qoder/scripts/{kg_duckdb.py → kg/kg_duckdb.py} +38 -37
  55. package/templates/qoder/scripts/{kg_incremental.py → kg/kg_incremental.py} +420 -393
  56. package/templates/qoder/scripts/{kg_link_db.py → kg/kg_link_db.py} +230 -224
  57. package/templates/qoder/scripts/{kg_semantic.py → kg/kg_semantic.py} +156 -150
  58. package/templates/qoder/scripts/kg/prefetch.py +359 -0
  59. package/templates/qoder/scripts/{search_index.py → kg/search_index.py} +70 -14
  60. package/templates/qoder/scripts/mcp/__init__.py +11 -0
  61. package/templates/qoder/scripts/{kg_mcp_server.py → mcp/kg_mcp_server.py} +77 -272
  62. package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → mcp/lanhu_stdio_wrapper.py} +125 -119
  63. package/templates/qoder/scripts/{check_mcp.py → mcp/mcp_doctor.py} +515 -298
  64. package/templates/qoder/scripts/{mcp_launcher.py → mcp/mcp_launcher.py} +442 -414
  65. package/templates/qoder/scripts/{mysql_mcp_server.py → mcp/mysql_mcp_server.py} +347 -396
  66. package/templates/qoder/scripts/{zentao_mcp_server.py → mcp/zentao_mcp_server.py} +384 -424
  67. package/templates/qoder/scripts/report/__init__.py +11 -0
  68. package/templates/qoder/scripts/{add_session.py → report/add_session.py} +250 -244
  69. package/templates/qoder/scripts/{archive_prd.py → report/archive_prd.py} +383 -377
  70. package/templates/qoder/scripts/{eval_prd.py → report/eval_prd.py} +73 -11
  71. package/templates/qoder/scripts/{export.py → report/export.py} +63 -0
  72. package/templates/qoder/scripts/{fill_prototype.py → report/fill_prototype.py} +6 -0
  73. package/templates/qoder/scripts/{gen_design_doc.py → report/gen_design_doc.py} +400 -394
  74. package/templates/qoder/scripts/{learn.py → report/learn.py} +152 -146
  75. package/templates/qoder/scripts/{learn_aggregate.py → report/learn_aggregate.py} +207 -201
  76. package/templates/qoder/scripts/{report.py → report/report.py} +287 -281
  77. package/templates/qoder/scripts/report/req.py +222 -0
  78. package/templates/qoder/scripts/report/role.py +33 -0
  79. package/templates/qoder/scripts/{status.py → report/status.py} +634 -628
  80. package/templates/qoder/scripts/setup/__init__.py +11 -0
  81. package/templates/qoder/scripts/setup/carriers.py +662 -0
  82. package/templates/qoder/scripts/{init_doctor.py → setup/init_doctor.py} +63 -26
  83. package/templates/qoder/scripts/{install_qoderwork.py → setup/install_qoderwork.py} +36 -26
  84. package/templates/qoder/scripts/{platform_doctor.py → setup/platform_doctor.py} +265 -259
  85. package/templates/qoder/scripts/{repo_root.py → setup/repo_root.py} +112 -106
  86. package/templates/qoder/scripts/{setup.py → setup/setup.py} +147 -0
  87. package/templates/qoder/scripts/{setup_lanhu.py → setup/setup_lanhu.py} +973 -963
  88. package/templates/qoder/scripts/task/__init__.py +11 -0
  89. package/templates/qoder/scripts/{git_sync.py → task/git_sync.py} +52 -31
  90. package/templates/qoder/scripts/{syncgate.py → task/syncgate.py} +6 -0
  91. package/templates/qoder/scripts/task/task.py +221 -0
  92. package/templates/qoder/scripts/task/task_lifecycle.py +596 -0
  93. package/templates/qoder/scripts/task/task_query.py +161 -0
  94. package/templates/qoder/scripts/task/task_relations.py +424 -0
  95. package/templates/qoder/scripts/{team_sync.py → task/team_sync.py} +93 -20
  96. package/templates/qoder/scripts/test/__init__.py +11 -0
  97. package/templates/qoder/scripts/{autotest.py → test/autotest.py} +1174 -1751
  98. package/templates/qoder/scripts/{autotest_batch.py → test/autotest_batch.py} +242 -224
  99. package/templates/qoder/scripts/test/autotest_data.py +675 -0
  100. package/templates/qoder/scripts/{autotest_run.py → test/autotest_run.py} +309 -297
  101. package/templates/qoder/scripts/{benchmark.py → test/benchmark.py} +6 -0
  102. package/templates/qoder/scripts/{kg_auto_login.py → test/kg_auto_login.py} +202 -196
  103. package/templates/qoder/scripts/{kg_test_runner.py → test/kg_test_runner.py} +7 -1
  104. package/templates/qoder/scripts/{page_probe.py → test/page_probe.py} +465 -459
  105. package/templates/qoder/scripts/wlkj.py +116 -0
  106. package/templates/qoder/settings.json +1 -10
  107. package/templates/qoder/skills/design-import/SKILL.md +226 -226
  108. package/templates/qoder/skills/design-review/SKILL.md +82 -82
  109. package/templates/qoder/skills/prd-generator/SKILL.md +26 -16
  110. package/templates/qoder/skills/prd-review/SKILL.md +5 -5
  111. package/templates/qoder/skills/prototype-generator/SKILL.md +256 -256
  112. package/templates/qoder/skills/spec-coder/SKILL.md +4 -4
  113. package/templates/qoder/skills/spec-generator/SKILL.md +4 -4
  114. package/templates/qoder/skills/test-generator/SKILL.md +5 -5
  115. package/templates/qoder/skills/wl-code/SKILL.md +4 -4
  116. package/templates/qoder/skills/wl-commit/SKILL.md +4 -4
  117. package/templates/qoder/skills/wl-design/SKILL.md +3 -3
  118. package/templates/qoder/skills/wl-init/SKILL.md +8 -8
  119. package/templates/qoder/skills/wl-insight/SKILL.md +5 -5
  120. package/templates/qoder/skills/wl-prd-full/SKILL.md +6 -6
  121. package/templates/qoder/skills/wl-prd-quick/SKILL.md +6 -6
  122. package/templates/qoder/skills/wl-prd-review/SKILL.md +4 -4
  123. package/templates/qoder/skills/wl-report/SKILL.md +7 -7
  124. package/templates/qoder/skills/wl-search/SKILL.md +13 -13
  125. package/templates/qoder/skills/wl-spec/SKILL.md +5 -5
  126. package/templates/qoder/skills/wl-status/SKILL.md +5 -5
  127. package/templates/qoder/skills/wl-task/SKILL.md +6 -6
  128. package/templates/qoder/skills/wl-test/SKILL.md +102 -39
  129. package/templates/root/AGENTS.md +39 -40
  130. package/templates/qoder/hooks/inject-workflow-state.py +0 -169
  131. package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
  132. package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
  133. package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
  134. package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
  135. package/templates/qoder/scripts/check_carriers.py +0 -238
  136. package/templates/qoder/scripts/check_mcp_launch.py +0 -183
  137. package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
  138. package/templates/qoder/scripts/collect_prds.py +0 -31
  139. package/templates/qoder/scripts/common/mentions.py +0 -134
  140. package/templates/qoder/scripts/common/utf8.py +0 -38
  141. package/templates/qoder/scripts/extract_routes.py +0 -54
  142. package/templates/qoder/scripts/extract_routes_tree.py +0 -78
  143. package/templates/qoder/scripts/handoff.py +0 -22
  144. package/templates/qoder/scripts/init_developer.py +0 -76
  145. package/templates/qoder/scripts/parse_prds.py +0 -33
  146. package/templates/qoder/scripts/role.py +0 -51
  147. package/templates/qoder/scripts/sync_carriers.py +0 -259
  148. package/templates/qoder/scripts/task.py +0 -1261
  149. package/templates/qoder/scripts/workspace_init.py +0 -102
  150. package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
  151. package/templates/qoder/skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp +0 -0
  152. /package/templates/qoder/scripts/{secure-ls.js → test/secure-ls.js} +0 -0
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ wlkj.py - 工作流顶层调度器 (统一入口, 兼容旧调用)
5
+
6
+ v3.0 引入: 把分散的脚本调用收敛到一个入口, 提供"逻辑分组"体验,
7
+ 而不需要物理分子目录 (避免 170+ 处路径改写 + 40 处 sys.path 风险)。
8
+
9
+ 用法 (与旧 python .qoder/scripts/xxx.py 等价):
10
+ python .qoder/scripts/wlkj.py kg search 保险 --platform web
11
+ python .qoder/scripts/wlkj.py task list
12
+ python .qoder/scripts/wlkj.py doctor --fix
13
+ python .qoder/scripts/wlkj.py search 考勤
14
+ python .qoder/scripts/wlkj.py status
15
+
16
+ 分组 (逻辑导航, 非物理目录):
17
+ kg/* 知识图谱 (kg.py 的子命令直接透传)
18
+ task 任务系统
19
+ search 代码搜索
20
+ doctor 环境体检
21
+ status 项目状态
22
+ sync 团队同步
23
+ ...
24
+
25
+ 设计:
26
+ - 透明转发: 不改变任何子脚本的行为, 只是把 argv 转过去
27
+ - 兼容: 旧的 `python .qoder/scripts/kg.py` 仍可用 (脚本都还在原位)
28
+ - 零维护: 加新命令只需在 DISPATCH 表加一行
29
+ """
30
+
31
+ import os
32
+ import subprocess
33
+ import sys
34
+
35
+ # 命令 → 脚本 映射 (加新命令只需在此加一行)
36
+ # v3.0: 脚本已分子目录, 路径更新为 子包/脚本
37
+ DISPATCH = {
38
+ 'kg': 'kg/kg.py',
39
+ 'task': 'task/task.py',
40
+ 'sync': 'task/team_sync.py',
41
+ 'team-sync': 'task/team_sync.py',
42
+ 'git-sync': 'task/git_sync.py',
43
+ 'search': 'kg/search_index.py',
44
+ 'context': 'kg/context_pack.py',
45
+ 'prefetch': 'kg/prefetch.py',
46
+ 'status': 'report/status.py',
47
+ 'report': 'report/report.py',
48
+ 'doctor': 'setup/init_doctor.py',
49
+ 'init': 'setup/setup.py',
50
+ 'test': 'test/autotest.py',
51
+ 'autotest': 'test/autotest.py',
52
+ 'eval': 'report/eval_prd.py',
53
+ 'eva': 'report/eval_prd.py',
54
+ 'export': 'report/export.py',
55
+ 'style': 'kg/build_style_index.py',
56
+ 'role': 'report/role.py',
57
+ }
58
+
59
+
60
+ def _usage():
61
+ lines = [
62
+ 'wlkj.py — 工作流顶层调度器',
63
+ '',
64
+ '用法: python .qoder/scripts/wlkj.py <命令> [参数...]',
65
+ '',
66
+ '命令分组 (转发到对应脚本):',
67
+ ' 知识图谱: kg <子命令> (kg.py, 13+ 能力)',
68
+ ' 任务: task <子命令> (task.py, create/list/start/finish)',
69
+ ' 同步: sync pull|push (team_sync.py)',
70
+ ' 搜索: search <词> (search_index.py)',
71
+ ' 上下文: context <词> (context_pack.py)',
72
+ ' 体检: doctor [--fix] (init_doctor.py)',
73
+ ' 状态: status (status.py)',
74
+ ' 报告: report daily|weekly (report.py)',
75
+ ' 测试: test <子命令> (autotest.py)',
76
+ ' 评估: eval <prd.md> (eval_prd.py)',
77
+ ' 导出: export <格式> (export.py)',
78
+ '',
79
+ '示例:',
80
+ ' wlkj.py kg search 保险 --platform web',
81
+ ' wlkj.py task create "登录优化"',
82
+ ' wlkj.py doctor --fix',
83
+ '',
84
+ '注: 旧的 python .qoder/scripts/kg.py 形式仍可用 (脚本在原位)。',
85
+ ]
86
+ return '\n'.join(lines)
87
+
88
+
89
+ def main():
90
+ argv = sys.argv[1:]
91
+ if not argv or argv[0] in ('-h', '--help', 'help'):
92
+ print(_usage())
93
+ return 0
94
+
95
+ cmd = argv[0]
96
+ rest = argv[1:]
97
+
98
+ script = DISPATCH.get(cmd)
99
+ if not script:
100
+ # 未知命令: 提示 + 退出
101
+ sys.stderr.write('未知命令: %s\n' % cmd)
102
+ sys.stderr.write('可用命令: %s\n' % ', '.join(sorted(DISPATCH.keys())))
103
+ return 1
104
+
105
+ script_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), script)
106
+ if not os.path.isfile(script_path):
107
+ sys.stderr.write('脚本不存在: %s\n' % script_path)
108
+ return 1
109
+
110
+ # 透明转发: 用当前 python 跑目标脚本, 透传所有参数和 exit code
111
+ r = subprocess.run([sys.executable, script_path] + rest)
112
+ return r.returncode
113
+
114
+
115
+ if __name__ == '__main__':
116
+ sys.exit(main())
@@ -39,15 +39,6 @@
39
39
  }
40
40
  ]
41
41
  }
42
- ],
43
- "UserPromptSubmit": [
44
- {
45
- "hooks": [
46
- {
47
- "command": "python .qoder/hooks/inject-workflow-state.py || python3 .qoder/hooks/inject-workflow-state.py"
48
- }
49
- ]
50
- }
51
42
  ]
52
43
  }
53
- }
44
+ }
@@ -1,226 +1,226 @@
1
- ---
2
- name: design-import
3
- description: "把设计师的 Figma/Axure 设计稿录入工作流,生成设计规范 spec.json 并存入知识图谱。Import designer's Figma/Axure design into the pipeline as a style spec. 用户说'录入设计稿''Figma稿录入''把这个设计录入'时触发。"
4
- trigger: "user says '录入设计稿', 'Figma 稿录入', '把这个设计录入', or wants to feed their design into the AI workflow"
5
- ---
6
-
7
-
8
- ## 🔧 仓库根定位(QoderWork 桌面端 vs Qoder IDE/CLI)
9
-
10
- **后续脚本里的 `$R` 代表仓库根**,先确定它(QoderWork 桌面端工作目录不是仓库根,相对路径会失效):
11
- ```bash
12
- R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
13
- ```
14
- > `repo_root.py` 从 `~/.qoderwork/mcp.json` 反推仓库根;失败回退 `.`(IDE/CLI 工作目录即仓库根)。找不到时先跑 `python .qoder/scripts/install_qoderwork.py`。
15
-
16
- # Design Import Skill(设计师专用)
17
-
18
- > 🚫 **边界铁律:蓝湖工具(`mcp__lanhu__*`)只能在本 skill(即 `/wl-design-spec 录入`)内部调用。**
19
- > 用户直接说"查蓝湖""读一下这个蓝湖链接"而没走录入命令时,**不要裸调蓝湖**——先确认意图,
20
- > 引导到 `/wl-design-spec 录入 <蓝湖链接>`。工作流是非侵入式的,所有能力必须经命令/工序站触发,
21
- > 不能脱离流程裸调工具(否则不可控、不可审计)。
22
-
23
- 把设计师在 Figma/Axure 里出的设计稿,转成工作流能消化的**设计规范 spec.json**,
24
- 存到 `data/style/`,进入知识图谱。从此同需求的 AI 原型优先锚定这份 spec,
25
- 不再跟设计师的稿打架。
26
-
27
- ## ⚙️ 自取上下文(QoderWork 无 hook 注入,必须自读)
28
-
29
- - `.qoder/.developer` — 当前设计师名(产出归属)
30
- - `.qoder/.current-task` — 若存在,spec 命名带上任务关键词
31
- - 平台必须明确(Web/APP/Both);如未指定,先问
32
-
33
- **已录入清单**(设计师问"我录过哪些"时):
34
- ```bash
35
- ls "$R/data/style/"*-design-spec.json 2>/dev/null # 列所有 spec
36
- ```
37
- 对每个文件读 `requirement`/`platform`/`source` 字段汇总给设计师,让他知道哪些录过、哪端录了。
38
-
39
- ## Step 0: 确认平台
40
-
41
- 跟 /wl-prd-full 一样,先问:Web 管理端 / APP 移动端 / 两端都要?
42
- **问了就停,等设计师回答。**
43
-
44
- ## Step 1: 收集设计信息
45
-
46
- 设计师用以下任一方式提供设计信息(按精度从高到低排):
47
-
48
- **方式 A(最推荐):蓝湖链接直读**
49
-
50
- 设计师发蓝湖链接(`https://lanhuapp.com/web/#/item/...`),AI 用蓝湖 MCP 精确提取颜色/尺寸/字体/切图,比截图口述精确 10 倍。**走以下 4 步,每步失败就降级到方式 B(绝不报错、绝不阻塞):**
51
-
52
- **A-1. 探测蓝湖可用性(失败就静默降级)**
53
- ```
54
- 调 mcp__lanhu__get_designs(url=<链接>)
55
- ```
56
- - 返回设计图列表 → 继续 A-2
57
- - 报"连接失败"/工具不存在/418(cookie 失效)→ **立刻降级**:告诉用户"蓝湖没起/cookie 失效,改用截图口述",然后走方式 B,**不许卡住**
58
-
59
- > 蓝湖是增强不是必需。没有蓝湖,工作流照样完整跑(方式 B/C/D 都不依赖蓝湖)。
60
-
61
- **A-2. 选设计图(图多时帮用户缩小范围)**
62
- ```
63
- 调 mcp__lanhu__get_designs(url=<链接>) → 返回 {designs:[{name, width, height, ...}], sectors:[...], total_designs}
64
- ```
65
- - **图少(≤15 张)**:直接列全部图名,问"录入哪张?"(**问了就停**)
66
- - **图多(>15 张)**:别一次倒几百张,先帮缩小:
67
- 1. 若有 `sectors`(分组):先列分组名+图数,问"哪个分组?",再列该组图
68
- 2. 没分组:问设计师"你要录的功能叫什么?",按图名关键词过滤后列
69
- 3. 过滤掉明显占位名(如重复的"命名"),只列有意义的
70
- - 选定后记下图名,进 A-3。**可一次选多张**(`design_names` 支持数组)。
71
-
72
- **A-3. 读标注 + 切图**
73
- ```
74
- 调 mcp__lanhu__get_ai_analyze_design_result(url=<链接>, design_names=[<选中的图名>])
75
- → 返回: HTML/CSS 标注 (rgba 值、width、padding、font...) + 还原指引
76
- 调 mcp__lanhu__get_design_slices(url=<链接>, design_name=<图名>, include_metadata=true)
77
- → 返回: {slices:[{name, size, download_url, svg_url, scale_urls:{1x,2x,3x}}]}
78
- ```
79
- - CSS 标注 → 填 `design_tokens`/`layout`/`components`
80
- - **切图**:每个 slice 的 `svg_url` 是设计师切的**真实图标矢量**。挑出图标类(size 小、name 含"图标/icon/箭头"等),
81
- 填进 spec.json 的 `icons` 字段(见 Step 2)。这是原型图标的最佳真源(优于 ref-icon.json 通用图标)。
82
- 返回的 CSS 标注是**设计稿的权威真值**,优先级高于代码风格、高于 PDF 规范。
83
-
84
- **A-4. AI 语义映射进 spec.json(关键:落到实处)**
85
- 蓝湖返回的是一堆 CSS 属性,AI 读懂后**语义判断**填进 spec.json 各字段:
86
-
87
- | 蓝湖返回 | 填进 spec.json 哪里 | 怎么判断 |
88
- |---------|-------------------|---------|
89
- | 出现最多的背景色/按钮色 (如 `rgba(255,115,10,1)`) | `design_tokens["--primary-color"]` | 统计频率,按钮/导航反复用的色 = 主色 |
90
- | 容器 width (如 `200px`) | `design_tokens["--sidebar-width"]` | web 端左侧固定宽容器 = 侧边栏 |
91
- | 行高 padding font-size | `design_tokens["--table-row-height"]` 等 | 表格行的 height |
92
- | 布局结构 | `layout.description` / `layout.sidebar` | 看是左+右(web) 还是单列(app) |
93
- | 卡片/表格/表单/按钮组 | `components[]` | 按视觉块列 |
94
-
95
- **铁律:CSS 值原样填,禁止改格式。** `rgba(255,115,10,1)` 不要写成 `#FF730A`,`200px` 不要四舍五入。蓝湖给什么就填什么(这是设计稿的真值,AI 改了就不准了)。
96
-
97
- > 蓝湖 MCP 是 STDIO 模式:开 QoderWork 自动起、关自动停,**无需手动 start**。
98
- > cookie 按角色隔离在 `workspace/members/{当前用户}/.secrets/lanhu.env`(不进 git)——
99
- > wrapper(lanhu_stdio_wrapper.py)读当前 `.developer` 角色的 cookie 拉起服务,UI 角色有改稿权限、PM/开发只读。
100
- > 没配的话跑 `python "$R/.qoder/scripts/setup_lanhu.py"`;换角色改 `.developer` + 配新角色 cookie 后重启 QoderWork。
101
-
102
- **方式 B:截图 + 口述**
103
- 设计师发一张 Figma/Axure 截图,口述关键设计决策:
104
- - "主色用 #1677ff,背景用 #f5f5f5"
105
- - "侧边栏宽 200px,一级菜单点击展开二级"
106
- - "表格行高 48px,斑马纹"
107
-
108
- **方式 C:导出标注**
109
- 设计师从 Figma 导出 CSS / 标注 PDF / tokens JSON,AI 直接读。
110
-
111
- **方式 D:参照现有系统页面改**
112
- 设计师说"类似 XX 页面,但侧边栏改成手风琴式"——AI 读那个页面代码,提取基础 spec,再叠加设计师的改动。
113
-
114
- ## Step 2: 生成 spec.json
115
-
116
- 把设计信息结构化成 spec.json,格式对齐 `data/index/vben-style-reference.json`:
117
-
118
- ```json
119
- {
120
- "source": "Figma (设计师: {designer})",
121
- "imported_at": "2026-06-16",
122
- "platform": "web",
123
- "requirement": "{需求名}",
124
- "design_tokens": {
125
- "--primary-color": "#1677ff",
126
- "--bg-color": "#f5f5f5",
127
- "--sidebar-width": "200px",
128
- "--table-row-height": "48px"
129
- },
130
- "layout": {
131
- "description": "左侧侧边栏 + 右侧内容区;一级菜单点击展开二级手风琴",
132
- "sidebar": "width: 200px, collapsible, accordion mode",
133
- "content": "padding: 16px, background: #f5f5f5"
134
- },
135
- "components": [
136
- {"name": "侧边栏菜单", "spec": "三级折叠,一级固定,二级手风琴展开"},
137
- {"name": "数据表格", "spec": "VxeGrid 风格,行高 48px,斑马纹"}
138
- ],
139
- "notes": "设计师强调:侧边栏必须有图标,不能用纯文字",
140
- "icons": [
141
- {"name": "返回箭头", "svg_url": "https://lanhu-oss-.../xxx.svg", "size": "7x14", "usage": "顶部返回按钮"},
142
- {"name": "提交图标", "svg_url": "https://lanhu-oss-.../yyy.svg", "size": "20x20", "usage": "提交按钮"}
143
- ],
144
- "lanhu_source": {
145
- "url": "https://lanhuapp.com/web/#/item/project/stage?pid=...",
146
- "image_names": ["问题反馈-详情"],
147
- "slice_count": 12,
148
- "imported_at": "2026-06-18"
149
- }
150
- }
151
- ```
152
-
153
- > ⚠️ **`requirement` 字段是落地关键**:fill_prototype.py 靠它匹配关键词
154
- > (`load_design_spec` 扫描 `data/style/*-design-spec.json`,`requirement` 包含查询词就命中)。
155
- > 所以 `requirement` 必须跟未来 `/wl-design-draw` 的关键词一致(如"问题反馈""营业外合同")。
156
- > 蓝湖来源时填 `source: "蓝湖直读 (设计师: XX)"`,截图口述填 `source: "Figma (设计师: XX)"`,
157
- > 下游 fill_prototype 不管来源只认值。
158
- > **`lanhu_source` 可选**:仅蓝湖来源时填,记录链接/图名/切图数,可追溯设计稿出处。
159
-
160
- ## Step 3: 存储到知识图谱
161
-
162
- - 存到 `data/style/{需求名}-{平台}-design-spec.json`(平台 = web/app,避免同功能多端冲突)
163
- - 例:`待办-web-design-spec.json`、`待办-app-design-spec.json`
164
- - 同需求同平台重新录入 → 覆盖(更新);不同平台 → 各自独立文件
165
- - **优先级声明**:这份 spec 的优先级 > 代码风格 > PDF 规范
166
- (因为它是最新、最明确的设计决策)
167
- - **`requirement` 字段填法**(解决"设计师不知道 PM 搜什么词"):
168
- 用**功能名 + 同义词**,别只填图名。如图名"设置-我的待办",requirement 填 `"待办 我的待办 设置待办"`
169
- (空格分隔多个可能的关键词),这样 PM 搜"待办"或"我的待办"都能命中。
170
-
171
- > 🎯 **落地链路(已验证通)**:spec.json 落盘后,下次 `/wl-design-draw <同关键词>` 时,
172
- > `fill_prototype.py` 的 `load_design_spec()` 会自动命中这份 spec(靠 `requirement` 字段匹配),
173
- > 把 `design_tokens` **原样注入**原型 HTML 的 `:root` CSS(最高优先级,覆盖模板默认色)。
174
- > 即:蓝湖读到的 `rgba(255,115,10,1)` 会真实出现在原型里,不是 AI 看一眼就忘。
175
- > 验证方法:看输出原型 `:root` 里有没有 `/* design-import spec tokens (优先级最高) */` 注释及下面的值。
176
-
177
- ## Step 3.5: 录入埋点
178
-
179
- spec.json 落盘后埋点,供 /wl-status 统计设计录入活跃度:
180
- ```bash
181
- python "$R/.qoder/scripts/learn.py" record design_import "{\"requirement\": \"<需求名>\", \"platform\": \"<web|app>\", \"source\": \"<蓝湖|截图|导出>\"}"
182
- ```
183
- > 失败静默忽略。
184
-
185
- ## Step 4: 确认与通知
186
- 输出给设计师:
187
- ```
188
- ✅ 设计规范已录入: data/style/{需求名}-design-spec.json
189
- - 平台: Web 管理端
190
- - 来源: 蓝湖直读 (设计师: XX) ← 或 截图口述
191
- - 主色: rgba(255,115,10,1)
192
- - 布局: 左侧边栏 200px + 手风琴二级菜单
193
- - 组件: 侧边栏菜单、数据表格
194
-
195
- ✅ 已自动接入原型链路:下次 PM/任何人用同一关键词出原型时,
196
- fill_prototype.py 会自动发现并优先用这份 spec(优先级高于代码风格),
197
- 主色/侧边栏宽度/布局全部按你的设计来(design_tokens 注入原型 :root)。
198
-
199
-
200
- 设计师可以随时说"录入设计稿"更新它。
201
- ```
202
-
203
- ## 铁律
204
-
205
- - **有蓝湖 MCP 时优先用它直读**:设计师发蓝湖链接,AI 调 `mcp__lanhu__*` 提取精确参数,
206
- 不要让设计师截图口述(截图口述是蓝湖不可用时的降级方案)
207
- - **绝不编造 token**:设计师没说的值,留空或标"待确认",不要自己猜
208
- - **图标必须来自真源**:即使设计师用了 emoji 示意,录入时也要替换成系统真源
209
- (Web: data/index/ref-icon.json 的 Ant Design SVG)
210
- - **spec 一旦录入,同需求 prototype 必须锚定它**:AI 出原型前先查 data/style/ 有没有 spec
211
-
212
- ## 🆕 录入前可参考知识图谱新数据
213
-
214
- 设计师录入 spec 前,可以先问 AI 系统现状,让 spec 更贴合系统:
215
-
216
- - **"这个功能模块现在有哪些页面?"** → AI 调 `mcp__qoder-knowledge-graph__feature_overview(feature='资产管理')`
217
- 返回该模块所有页面 + API + 按钮,设计师知道改哪些、加哪些
218
- - **"这个模块的业务流程是什么?"** → AI 调 `mcp__qoder-knowledge-graph__get_workflow(module='资产')`
219
- 返回操作链(查询→新增→审批→...),spec 里的交互流程跟系统一致
220
- - **"系统里这个模块的按钮都叫什么?"** → 看 DESIGN.md 的 "Real Button Texts" 段
221
- 或 entity-registry.json,spec 里的按钮文案跟系统统一
222
- - **"这个模块用的是什么布局模式?"** → 看 DESIGN.md 的 layout_fingerprint
223
- spec 里的侧边栏宽度/布局模式跟系统一致(如 160px / mixed-nav)
224
-
225
- > 这些数据让设计师的 spec 不是"凭空设计",而是"基于系统现状的增量改进"——
226
- > 录入的 spec 天然就跟系统风格一致,AI 出原型时不会打架。
1
+ ---
2
+ name: design-import
3
+ description: "把设计师的 Figma/Axure 设计稿录入工作流,生成设计规范 spec.json 并存入知识图谱。Import designer's Figma/Axure design into the pipeline as a style spec. "
4
+ trigger: "user invokes /wl-* command explicitly"
5
+ ---
6
+
7
+
8
+ ## 🔧 仓库根定位(QoderWork 桌面端 vs Qoder IDE/CLI)
9
+
10
+ **后续脚本里的 `$R` 代表仓库根**,先确定它(QoderWork 桌面端工作目录不是仓库根,相对路径会失效):
11
+ ```bash
12
+ R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
13
+ ```
14
+ > `repo_root.py` 从 `~/.qoderwork/mcp.json` 反推仓库根;失败回退 `.`(IDE/CLI 工作目录即仓库根)。找不到时先跑 `python .qoder/scripts/setup/install_qoderwork.py`。
15
+
16
+ # Design Import Skill(设计师专用)
17
+
18
+ > 🚫 **边界铁律:蓝湖工具(`mcp__lanhu__*`)只能在本 skill(即 `/wl-design 预览`)内部调用。**
19
+ > 用户直接说"查蓝湖""读一下这个蓝湖链接"而没走录入命令时,**不要裸调蓝湖**——先确认意图,
20
+ > 引导到 `/wl-design 预览 <蓝湖链接>`。工作流是非侵入式的,所有能力必须经命令/工序站触发,
21
+ > 不能脱离流程裸调工具(否则不可控、不可审计)。
22
+
23
+ 把设计师在 Figma/Axure 里出的设计稿,转成工作流能消化的**设计规范 spec.json**,
24
+ 存到 `data/style/`,进入知识图谱。从此同需求的 AI 原型优先锚定这份 spec,
25
+ 不再跟设计师的稿打架。
26
+
27
+ ## ⚙️ 自取上下文(QoderWork 无 hook 注入,必须自读)
28
+
29
+ - `.qoder/.developer` — 当前设计师名(产出归属)
30
+ - `.qoder/.current-task` — 若存在,spec 命名带上任务关键词
31
+ - 平台必须明确(Web/APP/Both);如未指定,先问
32
+
33
+ **已录入清单**(设计师问"我录过哪些"时):
34
+ ```bash
35
+ ls "$R/data/style/"*-design-spec.json 2>/dev/null # 列所有 spec
36
+ ```
37
+ 对每个文件读 `requirement`/`platform`/`source` 字段汇总给设计师,让他知道哪些录过、哪端录了。
38
+
39
+ ## Step 0: 确认平台
40
+
41
+ 跟 /wl-prd-full 一样,先问:Web 管理端 / APP 移动端 / 两端都要?
42
+ **问了就停,等设计师回答。**
43
+
44
+ ## Step 1: 收集设计信息
45
+
46
+ 设计师用以下任一方式提供设计信息(按精度从高到低排):
47
+
48
+ **方式 A(最推荐):蓝湖链接直读**
49
+
50
+ 设计师发蓝湖链接(`https://lanhuapp.com/web/#/item/...`),AI 用蓝湖 MCP 精确提取颜色/尺寸/字体/切图,比截图口述精确 10 倍。**走以下 4 步,每步失败就降级到方式 B(绝不报错、绝不阻塞):**
51
+
52
+ **A-1. 探测蓝湖可用性(失败就静默降级)**
53
+ ```
54
+ 调 mcp__lanhu__get_designs(url=<链接>)
55
+ ```
56
+ - 返回设计图列表 → 继续 A-2
57
+ - 报"连接失败"/工具不存在/418(cookie 失效)→ **立刻降级**:告诉用户"蓝湖没起/cookie 失效,改用截图口述",然后走方式 B,**不许卡住**
58
+
59
+ > 蓝湖是增强不是必需。没有蓝湖,工作流照样完整跑(方式 B/C/D 都不依赖蓝湖)。
60
+
61
+ **A-2. 选设计图(图多时帮用户缩小范围)**
62
+ ```
63
+ 调 mcp__lanhu__get_designs(url=<链接>) → 返回 {designs:[{name, width, height, ...}], sectors:[...], total_designs}
64
+ ```
65
+ - **图少(≤15 张)**:直接列全部图名,问"录入哪张?"(**问了就停**)
66
+ - **图多(>15 张)**:别一次倒几百张,先帮缩小:
67
+ 1. 若有 `sectors`(分组):先列分组名+图数,问"哪个分组?",再列该组图
68
+ 2. 没分组:问设计师"你要录的功能叫什么?",按图名关键词过滤后列
69
+ 3. 过滤掉明显占位名(如重复的"命名"),只列有意义的
70
+ - 选定后记下图名,进 A-3。**可一次选多张**(`design_names` 支持数组)。
71
+
72
+ **A-3. 读标注 + 切图**
73
+ ```
74
+ 调 mcp__lanhu__get_ai_analyze_design_result(url=<链接>, design_names=[<选中的图名>])
75
+ → 返回: HTML/CSS 标注 (rgba 值、width、padding、font...) + 还原指引
76
+ 调 mcp__lanhu__get_design_slices(url=<链接>, design_name=<图名>, include_metadata=true)
77
+ → 返回: {slices:[{name, size, download_url, svg_url, scale_urls:{1x,2x,3x}}]}
78
+ ```
79
+ - CSS 标注 → 填 `design_tokens`/`layout`/`components`
80
+ - **切图**:每个 slice 的 `svg_url` 是设计师切的**真实图标矢量**。挑出图标类(size 小、name 含"图标/icon/箭头"等),
81
+ 填进 spec.json 的 `icons` 字段(见 Step 2)。这是原型图标的最佳真源(优于 ref-icon.json 通用图标)。
82
+ 返回的 CSS 标注是**设计稿的权威真值**,优先级高于代码风格、高于 PDF 规范。
83
+
84
+ **A-4. AI 语义映射进 spec.json(关键:落到实处)**
85
+ 蓝湖返回的是一堆 CSS 属性,AI 读懂后**语义判断**填进 spec.json 各字段:
86
+
87
+ | 蓝湖返回 | 填进 spec.json 哪里 | 怎么判断 |
88
+ |---------|-------------------|---------|
89
+ | 出现最多的背景色/按钮色 (如 `rgba(255,115,10,1)`) | `design_tokens["--primary-color"]` | 统计频率,按钮/导航反复用的色 = 主色 |
90
+ | 容器 width (如 `200px`) | `design_tokens["--sidebar-width"]` | web 端左侧固定宽容器 = 侧边栏 |
91
+ | 行高 padding font-size | `design_tokens["--table-row-height"]` 等 | 表格行的 height |
92
+ | 布局结构 | `layout.description` / `layout.sidebar` | 看是左+右(web) 还是单列(app) |
93
+ | 卡片/表格/表单/按钮组 | `components[]` | 按视觉块列 |
94
+
95
+ **铁律:CSS 值原样填,禁止改格式。** `rgba(255,115,10,1)` 不要写成 `#FF730A`,`200px` 不要四舍五入。蓝湖给什么就填什么(这是设计稿的真值,AI 改了就不准了)。
96
+
97
+ > 蓝湖 MCP 是 STDIO 模式:开 QoderWork 自动起、关自动停,**无需手动 start**。
98
+ > cookie 按角色隔离在 `workspace/members/{当前用户}/.secrets/lanhu.env`(不进 git)——
99
+ > wrapper(lanhu_stdio_wrapper.py)读当前 `.developer` 角色的 cookie 拉起服务,UI 角色有改稿权限、PM/开发只读。
100
+ > 没配的话跑 `python "$R/.qoder/scripts/setup/setup_lanhu.py"`;换角色改 `.developer` + 配新角色 cookie 后重启 QoderWork。
101
+
102
+ **方式 B:截图 + 口述**
103
+ 设计师发一张 Figma/Axure 截图,口述关键设计决策:
104
+ - "主色用 #1677ff,背景用 #f5f5f5"
105
+ - "侧边栏宽 200px,一级菜单点击展开二级"
106
+ - "表格行高 48px,斑马纹"
107
+
108
+ **方式 C:导出标注**
109
+ 设计师从 Figma 导出 CSS / 标注 PDF / tokens JSON,AI 直接读。
110
+
111
+ **方式 D:参照现有系统页面改**
112
+ 设计师说"类似 XX 页面,但侧边栏改成手风琴式"——AI 读那个页面代码,提取基础 spec,再叠加设计师的改动。
113
+
114
+ ## Step 2: 生成 spec.json
115
+
116
+ 把设计信息结构化成 spec.json,格式对齐 `data/index/vben-style-reference.json`:
117
+
118
+ ```json
119
+ {
120
+ "source": "Figma (设计师: {designer})",
121
+ "imported_at": "2026-06-16",
122
+ "platform": "web",
123
+ "requirement": "{需求名}",
124
+ "design_tokens": {
125
+ "--primary-color": "#1677ff",
126
+ "--bg-color": "#f5f5f5",
127
+ "--sidebar-width": "200px",
128
+ "--table-row-height": "48px"
129
+ },
130
+ "layout": {
131
+ "description": "左侧侧边栏 + 右侧内容区;一级菜单点击展开二级手风琴",
132
+ "sidebar": "width: 200px, collapsible, accordion mode",
133
+ "content": "padding: 16px, background: #f5f5f5"
134
+ },
135
+ "components": [
136
+ {"name": "侧边栏菜单", "spec": "三级折叠,一级固定,二级手风琴展开"},
137
+ {"name": "数据表格", "spec": "VxeGrid 风格,行高 48px,斑马纹"}
138
+ ],
139
+ "notes": "设计师强调:侧边栏必须有图标,不能用纯文字",
140
+ "icons": [
141
+ {"name": "返回箭头", "svg_url": "https://lanhu-oss-.../xxx.svg", "size": "7x14", "usage": "顶部返回按钮"},
142
+ {"name": "提交图标", "svg_url": "https://lanhu-oss-.../yyy.svg", "size": "20x20", "usage": "提交按钮"}
143
+ ],
144
+ "lanhu_source": {
145
+ "url": "https://lanhuapp.com/web/#/item/project/stage?pid=...",
146
+ "image_names": ["问题反馈-详情"],
147
+ "slice_count": 12,
148
+ "imported_at": "2026-06-18"
149
+ }
150
+ }
151
+ ```
152
+
153
+ > ⚠️ **`requirement` 字段是落地关键**:fill_prototype.py 靠它匹配关键词
154
+ > (`load_design_spec` 扫描 `data/style/*-design-spec.json`,`requirement` 包含查询词就命中)。
155
+ > 所以 `requirement` 必须跟未来 `/wl-design 预览` 的关键词一致(如"问题反馈""营业外合同")。
156
+ > 蓝湖来源时填 `source: "蓝湖直读 (设计师: XX)"`,截图口述填 `source: "Figma (设计师: XX)"`,
157
+ > 下游 fill_prototype 不管来源只认值。
158
+ > **`lanhu_source` 可选**:仅蓝湖来源时填,记录链接/图名/切图数,可追溯设计稿出处。
159
+
160
+ ## Step 3: 存储到知识图谱
161
+
162
+ - 存到 `data/style/{需求名}-{平台}-design-spec.json`(平台 = web/app,避免同功能多端冲突)
163
+ - 例:`待办-web-design-spec.json`、`待办-app-design-spec.json`
164
+ - 同需求同平台重新录入 → 覆盖(更新);不同平台 → 各自独立文件
165
+ - **优先级声明**:这份 spec 的优先级 > 代码风格 > PDF 规范
166
+ (因为它是最新、最明确的设计决策)
167
+ - **`requirement` 字段填法**(解决"设计师不知道 PM 搜什么词"):
168
+ 用**功能名 + 同义词**,别只填图名。如图名"设置-我的待办",requirement 填 `"待办 我的待办 设置待办"`
169
+ (空格分隔多个可能的关键词),这样 PM 搜"待办"或"我的待办"都能命中。
170
+
171
+ > 🎯 **落地链路(已验证通)**:spec.json 落盘后,下次 `/wl-design 预览 <同关键词>` 时,
172
+ > `fill_prototype.py` 的 `load_design_spec()` 会自动命中这份 spec(靠 `requirement` 字段匹配),
173
+ > 把 `design_tokens` **原样注入**原型 HTML 的 `:root` CSS(最高优先级,覆盖模板默认色)。
174
+ > 即:蓝湖读到的 `rgba(255,115,10,1)` 会真实出现在原型里,不是 AI 看一眼就忘。
175
+ > 验证方法:看输出原型 `:root` 里有没有 `/* design-import spec tokens (优先级最高) */` 注释及下面的值。
176
+
177
+ ## Step 3.5: 录入埋点
178
+
179
+ spec.json 落盘后埋点,供 /wl-status 统计设计录入活跃度:
180
+ ```bash
181
+ python "$R/.qoder/scripts/report/learn.py" record design_import "{\"requirement\": \"<需求名>\", \"platform\": \"<web|app>\", \"source\": \"<蓝湖|截图|导出>\"}"
182
+ ```
183
+ > 失败静默忽略。
184
+
185
+ ## Step 4: 确认与通知
186
+ 输出给设计师:
187
+ ```
188
+ ✅ 设计规范已录入: data/style/{需求名}-design-spec.json
189
+ - 平台: Web 管理端
190
+ - 来源: 蓝湖直读 (设计师: XX) ← 或 截图口述
191
+ - 主色: rgba(255,115,10,1)
192
+ - 布局: 左侧边栏 200px + 手风琴二级菜单
193
+ - 组件: 侧边栏菜单、数据表格
194
+
195
+ ✅ 已自动接入原型链路:下次 PM/任何人用同一关键词出原型时,
196
+ fill_prototype.py 会自动发现并优先用这份 spec(优先级高于代码风格),
197
+ 主色/侧边栏宽度/布局全部按你的设计来(design_tokens 注入原型 :root)。
198
+
199
+
200
+ 设计师可以随时说"录入设计稿"更新它。
201
+ ```
202
+
203
+ ## 铁律
204
+
205
+ - **有蓝湖 MCP 时优先用它直读**:设计师发蓝湖链接,AI 调 `mcp__lanhu__*` 提取精确参数,
206
+ 不要让设计师截图口述(截图口述是蓝湖不可用时的降级方案)
207
+ - **绝不编造 token**:设计师没说的值,留空或标"待确认",不要自己猜
208
+ - **图标必须来自真源**:即使设计师用了 emoji 示意,录入时也要替换成系统真源
209
+ (Web: data/index/ref-icon.json 的 Ant Design SVG)
210
+ - **spec 一旦录入,同需求 prototype 必须锚定它**:AI 出原型前先查 data/style/ 有没有 spec
211
+
212
+ ## 🆕 录入前可参考知识图谱新数据
213
+
214
+ 设计师录入 spec 前,可以先问 AI 系统现状,让 spec 更贴合系统:
215
+
216
+ - **"这个功能模块现在有哪些页面?"** → AI 调 `mcp__qoder-knowledge-graph__feature_overview(feature='资产管理')`
217
+ 返回该模块所有页面 + API + 按钮,设计师知道改哪些、加哪些
218
+ - **"这个模块的业务流程是什么?"** → AI 调 `mcp__qoder-knowledge-graph__get_workflow(module='资产')`
219
+ 返回操作链(查询→新增→审批→...),spec 里的交互流程跟系统一致
220
+ - **"系统里这个模块的按钮都叫什么?"** → 看 DESIGN.md 的 "Real Button Texts" 段
221
+ 或 entity-registry.json,spec 里的按钮文案跟系统统一
222
+ - **"这个模块用的是什么布局模式?"** → 看 DESIGN.md 的 layout_fingerprint
223
+ spec 里的侧边栏宽度/布局模式跟系统一致(如 160px / mixed-nav)
224
+
225
+ > 这些数据让设计师的 spec 不是"凭空设计",而是"基于系统现状的增量改进"——
226
+ > 录入的 spec 天然就跟系统风格一致,AI 出原型时不会打架。