@hupan56/wlkj 2.7.2 → 2.7.4
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.
- package/bin/cli.js +162 -32
- package/package.json +1 -1
- package/templates/qoder/commands/wl-design.md +113 -20
- package/templates/qoder/commands/wl-prd.md +89 -17
- package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/git_sync.py +5 -1
- package/templates/qoder/scripts/platform_doctor.py +259 -0
- package/templates/qoder/commands/wl-design-draw.md +0 -78
- package/templates/qoder/commands/wl-design-scan.md +0 -108
- package/templates/qoder/commands/wl-design-spec.md +0 -154
- package/templates/qoder/commands/wl-prd-full.md +0 -226
- package/templates/qoder/commands/wl-prd-quick.md +0 -134
- package/templates/qoder/commands/wl-prd-review.md +0 -104
- package/templates/qoder/scripts/__pycache__/search_index.cpython-39.pyc +0 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
platform_doctor.py - 跨平台环境自诊断 (任何 OS 跑, 输出环境真相)
|
|
5
|
+
|
|
6
|
+
为什么需要它:
|
|
7
|
+
MAC-VERIFY.md 是人工清单, mac 同事跑完如果失败, 反馈信息往往不够定位。
|
|
8
|
+
本脚本自动收集所有跨平台关键信息, 一次跑完输出结构化报告,
|
|
9
|
+
同事直接把输出贴回来即可 —— 无需懂代码。
|
|
10
|
+
|
|
11
|
+
它在任何 OS (Windows/macOS/Linux) 上行为一致, 显式报告:
|
|
12
|
+
- 平台 + 架构
|
|
13
|
+
- python/python3/node/git 是否可用 + 真实路径
|
|
14
|
+
- 工作流引擎是否完整 (关键脚本在不在)
|
|
15
|
+
- MCP 各组件就绪状态
|
|
16
|
+
- 角色配置
|
|
17
|
+
- 发现的问题 + 修复建议
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
python3 .qoder/scripts/platform_doctor.py
|
|
21
|
+
# 或 mac 上: python3 platform_doctor.py (从包目录跑也行)
|
|
22
|
+
Exit: 0 = 健康, 1 = 有问题
|
|
23
|
+
"""
|
|
24
|
+
import json
|
|
25
|
+
import os
|
|
26
|
+
import platform
|
|
27
|
+
import shutil
|
|
28
|
+
import subprocess
|
|
29
|
+
import sys
|
|
30
|
+
from pathlib import Path
|
|
31
|
+
|
|
32
|
+
if sys.platform == 'win32':
|
|
33
|
+
try:
|
|
34
|
+
sys.stdout.reconfigure(encoding='utf-8')
|
|
35
|
+
except (AttributeError, IOError):
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
# 定位仓库根 (和 mcp_launcher 同样的多级回退)
|
|
39
|
+
HERE = Path(__file__).resolve().parent
|
|
40
|
+
BASE = None
|
|
41
|
+
for candidate in [HERE.parent.parent, HERE.parent, HERE]:
|
|
42
|
+
if (candidate / '.qoder' / 'scripts').is_dir():
|
|
43
|
+
BASE = candidate
|
|
44
|
+
break
|
|
45
|
+
if BASE is None:
|
|
46
|
+
BASE = HERE.parent.parent # 最佳猜测
|
|
47
|
+
|
|
48
|
+
report = {'platform': {}, 'tools': {}, 'engine': {}, 'mcp': {},
|
|
49
|
+
'role': {}, 'issues': [], 'verdict': 'UNKNOWN'}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def add_issue(level, msg, fix=None):
|
|
53
|
+
report['issues'].append({'level': level, 'msg': msg, 'fix': fix or ''})
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def which(cmd):
|
|
57
|
+
"""找命令路径, 返回字符串或 None。"""
|
|
58
|
+
return shutil.which(cmd)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def run(cmd, timeout=8):
|
|
62
|
+
"""跑命令, 返回 (rc, output)。"""
|
|
63
|
+
try:
|
|
64
|
+
r = subprocess.run(cmd, capture_output=True, text=True,
|
|
65
|
+
encoding='utf-8', errors='replace', timeout=timeout)
|
|
66
|
+
return r.returncode, (r.stdout or '').strip()
|
|
67
|
+
except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
|
|
68
|
+
return 1, ''
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# ============================================================
|
|
72
|
+
# 1. 平台信息
|
|
73
|
+
# ============================================================
|
|
74
|
+
report['platform'] = {
|
|
75
|
+
'sys_platform': sys.platform,
|
|
76
|
+
'platform_system': platform.system(),
|
|
77
|
+
'machine': platform.machine(),
|
|
78
|
+
'python_version': sys.version.split()[0],
|
|
79
|
+
'python_executable': sys.executable,
|
|
80
|
+
}
|
|
81
|
+
plat_name = platform.system()
|
|
82
|
+
is_mac = sys.platform == 'darwin'
|
|
83
|
+
is_win = sys.platform == 'win32'
|
|
84
|
+
print('【平台】 %s %s (sys.platform=%s)' % (
|
|
85
|
+
plat_name, platform.machine(), sys.platform))
|
|
86
|
+
print(' Python: %s @ %s' % (sys.version.split()[0], sys.executable))
|
|
87
|
+
|
|
88
|
+
# ============================================================
|
|
89
|
+
# 2. 工具探测 (python/python3/node/git/brew)
|
|
90
|
+
# ============================================================
|
|
91
|
+
print('\n【工具探测】')
|
|
92
|
+
for tool in ['python', 'python3', 'node', 'npm', 'npx', 'git']:
|
|
93
|
+
if is_mac and tool == 'python':
|
|
94
|
+
# mac 上 python 通常不存在, 这是正常的
|
|
95
|
+
pass
|
|
96
|
+
p = which(tool)
|
|
97
|
+
ver = ''
|
|
98
|
+
if p:
|
|
99
|
+
if tool in ('python', 'python3'):
|
|
100
|
+
rc, v = run([tool, '--version'])
|
|
101
|
+
ver = v or '(版本未知)'
|
|
102
|
+
elif tool in ('node',):
|
|
103
|
+
rc, v = run([tool, '--version'])
|
|
104
|
+
ver = v
|
|
105
|
+
elif tool == 'git':
|
|
106
|
+
rc, v = run([tool, '--version'])
|
|
107
|
+
ver = v
|
|
108
|
+
report['tools'][tool] = {'path': p, 'version': ver}
|
|
109
|
+
status = '✓ %s' % ver if p else '✗ 未找到'
|
|
110
|
+
print(' %-8s %s' % (tool, status))
|
|
111
|
+
|
|
112
|
+
# 关键: python/python3 关系 (mac 验证核心)
|
|
113
|
+
py = which('python')
|
|
114
|
+
py3 = which('python3')
|
|
115
|
+
if is_mac and not py and py3:
|
|
116
|
+
print(' [mac 正常] python 不存在, python3 可用 (cli.js detectPyCmd 会选 python3)')
|
|
117
|
+
elif not py and not py3:
|
|
118
|
+
add_issue('CRITICAL', 'python 和 python3 都没找到',
|
|
119
|
+
'mac: brew install python@3.12; win: 装 Python 勾 Add to PATH')
|
|
120
|
+
elif not py3 and py:
|
|
121
|
+
add_issue('WARN', '只有 python 没有 python3 (罕见, 一般不影响)')
|
|
122
|
+
|
|
123
|
+
if is_mac:
|
|
124
|
+
brew = which('brew')
|
|
125
|
+
print(' brew: %s' % (brew or '✗ (装包用: https://brew.sh)'))
|
|
126
|
+
|
|
127
|
+
# ============================================================
|
|
128
|
+
# 3. 引擎完整性
|
|
129
|
+
# ============================================================
|
|
130
|
+
print('\n【工作流引擎】')
|
|
131
|
+
scripts_dir = BASE / '.qoder' / 'scripts'
|
|
132
|
+
key_scripts = [
|
|
133
|
+
'setup.py', 'kg.py', 'context_pack.py', 'search_index.py',
|
|
134
|
+
'mcp_launcher.py', 'install_qoderwork.py', 'role.py',
|
|
135
|
+
'common/pip_install.py', 'common/events.py', 'common/platform_guard.py',
|
|
136
|
+
'check_mcp.py', 'check_carriers.py',
|
|
137
|
+
]
|
|
138
|
+
missing_scripts = []
|
|
139
|
+
for s in key_scripts:
|
|
140
|
+
exists = (scripts_dir / s).is_file()
|
|
141
|
+
if not exists:
|
|
142
|
+
missing_scripts.append(s)
|
|
143
|
+
report['engine'][s] = exists
|
|
144
|
+
|
|
145
|
+
if missing_scripts:
|
|
146
|
+
add_issue('CRITICAL', '引擎脚本缺失: %s' % ', '.join(missing_scripts),
|
|
147
|
+
'跑: npx @hupan56/wlkj update')
|
|
148
|
+
print(' ✗ 缺失: %s' % ', '.join(missing_scripts))
|
|
149
|
+
else:
|
|
150
|
+
print(' ✓ %d 个关键脚本齐全' % len(key_scripts))
|
|
151
|
+
|
|
152
|
+
# 引擎版本
|
|
153
|
+
ver_file = BASE / '.qoder' / '.engine-version'
|
|
154
|
+
if ver_file.is_file():
|
|
155
|
+
ver = ver_file.read_text(encoding='utf-8').strip()
|
|
156
|
+
report['engine']['version'] = ver
|
|
157
|
+
print(' 引擎版本: %s' % ver)
|
|
158
|
+
|
|
159
|
+
# ============================================================
|
|
160
|
+
# 4. MCP 组件
|
|
161
|
+
# ============================================================
|
|
162
|
+
print('\n【MCP 组件】')
|
|
163
|
+
# 4.1 mcp.json
|
|
164
|
+
HOME = Path(os.environ.get('USERPROFILE') or os.path.expanduser('~'))
|
|
165
|
+
mcp_file = HOME / '.qoderwork' / 'mcp.json'
|
|
166
|
+
if mcp_file.is_file():
|
|
167
|
+
try:
|
|
168
|
+
cfg = json.loads(mcp_file.read_text(encoding='utf-8'))
|
|
169
|
+
servers = list(cfg.get('mcpServers', {}).keys())
|
|
170
|
+
report['mcp']['servers'] = servers
|
|
171
|
+
print(' mcp.json: %d 个 server (%s)' % (len(servers), ', '.join(servers)))
|
|
172
|
+
except (ValueError, OSError):
|
|
173
|
+
add_issue('WARN', 'mcp.json 解析失败', '重跑 install_qoderwork.py --mcp-only')
|
|
174
|
+
print(' mcp.json: 解析失败')
|
|
175
|
+
else:
|
|
176
|
+
add_issue('WARN', 'mcp.json 不存在 (QoderWork 未配 MCP)',
|
|
177
|
+
'跑: python .qoder/scripts/install_qoderwork.py --mcp-only')
|
|
178
|
+
print(' mcp.json: 不存在')
|
|
179
|
+
|
|
180
|
+
# 4.2 .repo-root 锚点
|
|
181
|
+
anchor = HOME / '.qoderwork' / '.repo-root'
|
|
182
|
+
if anchor.is_file():
|
|
183
|
+
root_val = anchor.read_text(encoding='utf-8').strip()
|
|
184
|
+
is_correct = (Path(root_val) / '.qoder' / 'scripts').is_dir()
|
|
185
|
+
report['mcp']['repo_root'] = root_val
|
|
186
|
+
if is_correct:
|
|
187
|
+
print(' .repo-root: ✓ 指向 %s' % root_val)
|
|
188
|
+
else:
|
|
189
|
+
add_issue('CRITICAL', '.repo-root 指向错误目录: %s' % root_val,
|
|
190
|
+
'跑: python install_qoderwork.py --mcp-only (会用 PROJECT_ROOT 修复)')
|
|
191
|
+
print(' .repo-root: ✗ 指向错误 %s' % root_val)
|
|
192
|
+
else:
|
|
193
|
+
add_issue('WARN', '.repo-root 锚点不存在',
|
|
194
|
+
'跑: install_qoderwork.py --mcp-only')
|
|
195
|
+
print(' .repo-root: 不存在')
|
|
196
|
+
|
|
197
|
+
# 4.3 duckdb (kg MCP 依赖)
|
|
198
|
+
try:
|
|
199
|
+
import duckdb
|
|
200
|
+
print(' duckdb: ✓ 已装 (kg MCP 可用)')
|
|
201
|
+
report['mcp']['duckdb'] = True
|
|
202
|
+
except ImportError:
|
|
203
|
+
add_issue('CRITICAL', 'duckdb 未装 (kg MCP 会崩)',
|
|
204
|
+
'pip install duckdb 或 npx wlkj install-env')
|
|
205
|
+
print(' duckdb: ✗ 未装')
|
|
206
|
+
|
|
207
|
+
# ============================================================
|
|
208
|
+
# 5. 角色配置
|
|
209
|
+
# ============================================================
|
|
210
|
+
print('\n【角色配置】')
|
|
211
|
+
dev_file = BASE / '.qoder' / '.developer'
|
|
212
|
+
if dev_file.is_file():
|
|
213
|
+
lines = dev_file.read_text(encoding='utf-8').split('\n')
|
|
214
|
+
name_l = next((l for l in lines if l.startswith('name=')), '')
|
|
215
|
+
role_l = next((l for l in lines if l.startswith('role=')), '')
|
|
216
|
+
name = name_l.split('=', 1)[1].strip() if name_l else '?'
|
|
217
|
+
role = role_l.split('=', 1)[1].strip() if role_l else 'pm(默认)'
|
|
218
|
+
report['role'] = {'name': name, 'role': role}
|
|
219
|
+
print(' 开发者: %s' % name)
|
|
220
|
+
print(' 角色: %s' % role)
|
|
221
|
+
if not role_l:
|
|
222
|
+
add_issue('INFO', '角色未显式设置 (默认 pm)',
|
|
223
|
+
'重跑 init 选角色: npx wlkj init %s <pm|design|dev|test|admin>' % name)
|
|
224
|
+
else:
|
|
225
|
+
add_issue('CRITICAL', '.developer 不存在 (未初始化)',
|
|
226
|
+
'跑: npx @hupan56/wlkj init <名字> <角色>')
|
|
227
|
+
print(' 未初始化!')
|
|
228
|
+
|
|
229
|
+
# ============================================================
|
|
230
|
+
# 6. 总结
|
|
231
|
+
# ============================================================
|
|
232
|
+
criticals = [i for i in report['issues'] if i['level'] == 'CRITICAL']
|
|
233
|
+
warns = [i for i in report['issues'] if i['level'] == 'WARN']
|
|
234
|
+
|
|
235
|
+
print('\n' + '=' * 56)
|
|
236
|
+
if criticals:
|
|
237
|
+
print('发现 %d 个严重问题:' % len(criticals))
|
|
238
|
+
for i in criticals:
|
|
239
|
+
print(' 🔴 %s' % i['msg'])
|
|
240
|
+
if i['fix']:
|
|
241
|
+
print(' 修复: %s' % i['fix'])
|
|
242
|
+
report['verdict'] = 'BROKEN'
|
|
243
|
+
elif warns:
|
|
244
|
+
print('发现 %d 个警告 (非阻塞, 但建议处理):' % len(warns))
|
|
245
|
+
for i in warns:
|
|
246
|
+
print(' 🟡 %s' % i['msg'])
|
|
247
|
+
if i['fix']:
|
|
248
|
+
print(' 建议: %s' % i['fix'])
|
|
249
|
+
report['verdict'] = 'OK_WITH_WARNINGS'
|
|
250
|
+
else:
|
|
251
|
+
print('✓ 环境健康, 工作流可用。')
|
|
252
|
+
report['verdict'] = 'HEALTHY'
|
|
253
|
+
print('=' * 56)
|
|
254
|
+
|
|
255
|
+
# 机器可读报告 (便于同事贴回来)
|
|
256
|
+
print('\n--- 可粘贴报告 (JSON) ---')
|
|
257
|
+
print(json.dumps(report, ensure_ascii=False, indent=2))
|
|
258
|
+
|
|
259
|
+
sys.exit(1 if criticals else 0)
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: wl-design-draw
|
|
3
|
-
description: "画界面/原型。说你要什么,AI 画出来。新页面、改页面、参考竞品都行。"
|
|
4
|
-
argument-hint: "<你要画什么>"
|
|
5
|
-
auto-approve: true
|
|
6
|
-
allowed-tools: [Read, Glob, Grep, Bash, Write, Edit, mcp__qoder-knowledge-graph, mcp__lanhu]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# /wl-design-draw - 画界面
|
|
10
|
-
|
|
11
|
-
User input: $ARGUMENTS
|
|
12
|
-
|
|
13
|
-
> 用户说"画什么",AI 画出来。就这么简单。
|
|
14
|
-
|
|
15
|
-
## 🔧 环境自检(QoderWork 桌面端 vs Qoder IDE/CLI)
|
|
16
|
-
|
|
17
|
-
**先确定仓库根 R**(QoderWork 桌面端工作目录不是仓库根,相对路径会失效):
|
|
18
|
-
```bash
|
|
19
|
-
R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
|
|
20
|
-
```
|
|
21
|
-
> 后续脚本统一用 `python "$R/.qoder/scripts/xxx.py"`。
|
|
22
|
-
|
|
23
|
-
## Step 1: 平台(问了就停)
|
|
24
|
-
|
|
25
|
-
```
|
|
26
|
-
这个界面是针对哪个平台?
|
|
27
|
-
1. Web 管理端 (fywl-ui)
|
|
28
|
-
2. APP 移动端 (Carmg-H5)
|
|
29
|
-
3. 两端都要
|
|
30
|
-
请选择 (1/2/3):
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Step 2: 如果输入是大板块,先缩小到具体页面
|
|
34
|
-
|
|
35
|
-
"资产"有 38 个页面,不能直接画。调 `mcp__qoder-knowledge-graph__feature_overview(feature='资产')`,
|
|
36
|
-
列出页面问用户选哪个(**问了就停**)。
|
|
37
|
-
|
|
38
|
-
具体功能(如"营业外合同筛选")跳过这步。
|
|
39
|
-
|
|
40
|
-
## Step 3: 画
|
|
41
|
-
|
|
42
|
-
**先拿设计约束 + 真实数据(不许跳过,不许手写 HTML):**
|
|
43
|
-
|
|
44
|
-
```
|
|
45
|
-
mcp__qoder-knowledge-graph__get_design_system(platform='web') → 颜色/布局/按钮/组件
|
|
46
|
-
mcp__qoder-knowledge-graph__fill_prototype(keyword='营业外合同', platform='web') → 80% 草稿
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
FALLBACK(无 MCP 时):
|
|
50
|
-
```bash
|
|
51
|
-
python "$R/.qoder/scripts/gen_design_doc.py"
|
|
52
|
-
python "$R/.qoder/scripts/fill_prototype.py" 营业外合同 --platform web
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
**拿到草稿后微调:**
|
|
56
|
-
- 按钮用真实文案(数据清单里的,不是编的"新增/编辑")
|
|
57
|
-
- 补交互细节(弹窗/Tab/折叠)
|
|
58
|
-
- 画完整状态(有数据 + 空状态 + 加载中)
|
|
59
|
-
- **颜色/宽度/间距不许改**(来自真实系统,AI 猜的一定不对)
|
|
60
|
-
|
|
61
|
-
## 铁律
|
|
62
|
-
|
|
63
|
-
1. **必须先调 get_design_system + fill_prototype**,不许跳过直接手写
|
|
64
|
-
2. **若设计师录入了蓝湖 spec,fill_prototype 会自动注入**——先确认 `data/style/{关键词}-design-spec.json` 是否存在。若有,fill_prototype 会把蓝湖的真实 `design_tokens`(如 `rgba(255,115,10,1)`)原样注入原型 `:root`,**这一步全自动,不用手动调蓝湖**。验证:看输出原型 `:root` 里有没有 `/* design-import spec tokens (优先级最高) */`
|
|
65
|
-
3. **颜色只用真源**(蓝湖 spec 注入值 > get_design_system 的 HSL,不是 #1890ff)
|
|
66
|
-
4. **按钮用真实文案**(entity-registry 的,不是编的)
|
|
67
|
-
5. **布局参数不猜**(蓝湖 spec 的 width 或 layout_fingerprint 的 160px)
|
|
68
|
-
6. **图标禁 emoji**(Web 用 Ant Design SVG,APP 用 Vant 字体图标)
|
|
69
|
-
7. **画完整状态**(不只画"有数据",还要画空状态/加载中/错误)
|
|
70
|
-
|
|
71
|
-
> 蓝湖与画图的关系:**蓝湖在录入环节(/wl-design-spec)发力**,读出的 CSS 值存进 spec.json;
|
|
72
|
-
> 画图时 fill_prototype 自动消费 spec.json,不需要 draw 再调蓝湖。蓝湖没起/没录入?不影响 draw,
|
|
73
|
-
> fill_prototype 降级用 layout_fingerprint + 代码风格,照样出原型(只是不如蓝湖精确)。
|
|
74
|
-
|
|
75
|
-
## 存储与 Figma
|
|
76
|
-
|
|
77
|
-
存到 `workspace/members/{developer}/drafts/prototype-{feature}.html`。
|
|
78
|
-
设计师可在 Figma 用 html.to.design 插件导入精修。
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: wl-design-scan
|
|
3
|
-
description: "扫描/审视系统现状。看功能模块有哪些页面/按钮/流程/风格/测试覆盖。画原型前必做。"
|
|
4
|
-
argument-hint: "<功能模块名或关键词>"
|
|
5
|
-
auto-approve: true
|
|
6
|
-
allowed-tools: [Read, Glob, Grep, Bash, mcp__qoder-knowledge-graph]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# /wl-design-scan - 审视系统现状
|
|
10
|
-
|
|
11
|
-
User input: $ARGUMENTS
|
|
12
|
-
|
|
13
|
-
> 画之前先看。设计师/PM 需要理解"系统现在长什么样"才能动手。
|
|
14
|
-
> 这是业界 Discover 阶段的工具——understand before you design。
|
|
15
|
-
|
|
16
|
-
## 🔧 环境自检(QoderWork 桌面端 vs Qoder IDE/CLI)
|
|
17
|
-
|
|
18
|
-
**先确定仓库根 R**(QoderWork 桌面端工作目录不是仓库根,相对路径会失效):
|
|
19
|
-
```bash
|
|
20
|
-
R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
|
|
21
|
-
```
|
|
22
|
-
> 后续脚本统一用 `python "$R/.qoder/scripts/xxx.py"`。
|
|
23
|
-
|
|
24
|
-
## 第一步:判断用户想看什么
|
|
25
|
-
|
|
26
|
-
| 用户说什么 | 调什么 | 返回什么 |
|
|
27
|
-
|-----------|--------|---------|
|
|
28
|
-
| "XX 有哪些页面""XX 功能模块" | `feature_overview(feature='XX')` | 页面列表 + 端点数 + 按钮数 + 测试数 |
|
|
29
|
-
| "XX 的操作流程""XX 业务流程" | `get_workflow(module='XX')` | 操作链(查询→新增→审批→...) |
|
|
30
|
-
| "XX 用什么风格""系统主色" | `get_design_system(platform='web')` | token + 布局指纹 + 组件表 + 真实按钮 |
|
|
31
|
-
| "XX 有没有测试""XX 测试覆盖" | `coverage_matrix()` | 17 个功能的测试覆盖红黄绿 |
|
|
32
|
-
| "改 XX 影响什么" | `get_impact(endpoint='XX')` | 影响页面数 + 操作数 + 可回归测试 |
|
|
33
|
-
| "XX 按钮 调什么接口" | `context_360(symbol='handleXX')` | 按钮关联的 API + Controller + 调用链 |
|
|
34
|
-
| 模糊 | 先问 | "你想看功能模块、操作流程、设计风格、测试覆盖、还是影响分析?" |
|
|
35
|
-
|
|
36
|
-
## 第二步:执行查询
|
|
37
|
-
|
|
38
|
-
**PREFERRED: MCP 工具**(QoderWork 有 MCP 时直接调)
|
|
39
|
-
```
|
|
40
|
-
mcp__qoder-knowledge-graph__feature_overview(feature='资产管理')
|
|
41
|
-
mcp__qoder-knowledge-graph__get_workflow(module='资产')
|
|
42
|
-
mcp__qoder-knowledge-graph__get_design_system(platform='web')
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
**FALLBACK: Python 脚本**
|
|
46
|
-
```bash
|
|
47
|
-
python "$R/.qoder/scripts/search_index.py" 资产 --platform web
|
|
48
|
-
python "$R/.qoder/scripts/search_index.py" --style table --platform web
|
|
49
|
-
python "$R/.qoder/scripts/search_index.py" --field assetName
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
## 第三步:结构化输出
|
|
53
|
-
|
|
54
|
-
不是简单返回数据,而是**帮用户理解**:
|
|
55
|
-
|
|
56
|
-
### 功能模块视图(用户说"XX 有哪些页面"时)
|
|
57
|
-
```
|
|
58
|
-
📊 资产管理 (assets) 模块全景
|
|
59
|
-
页面: 38 个
|
|
60
|
-
API: 12 个端点
|
|
61
|
-
按钮: 108 个操作
|
|
62
|
-
测试: 3 个测试用例 (覆盖率偏低 ⚠️)
|
|
63
|
-
|
|
64
|
-
主要页面类型:
|
|
65
|
-
- table-page: 20 个 (异常申请/记录/分析...)
|
|
66
|
-
- form-page: 12 个 (新增/编辑/审批...)
|
|
67
|
-
- dashboard: 3 个 (资产看板)
|
|
68
|
-
- detail-page: 3 个
|
|
69
|
-
|
|
70
|
-
标杆页面 (最适合做参考的):
|
|
71
|
-
1. assets/abnormal/apply/index.vue (异常申请, 19个字段)
|
|
72
|
-
2. assets/abnormalManage/abnormalAnalysis/index.vue (分析看板)
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
### 操作流程视图(用户说"XX 流程"时)
|
|
76
|
-
```
|
|
77
|
-
🔄 资产管理操作链 (7 步)
|
|
78
|
-
查询 → 新增 → 提交 → 审批 → 归档 → 导出 → 删除
|
|
79
|
-
|
|
80
|
-
⚠️ 步骤较多 (7步), 考虑优化:
|
|
81
|
-
- 第3步"提交"和第4步"审批"可能合并
|
|
82
|
-
- 第6步"导出"可放到工具栏, 不算独立步骤
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### 设计风格视图(用户说"XX 风格"时)
|
|
86
|
-
```
|
|
87
|
-
🎨 fywl-ui 设计指纹
|
|
88
|
-
主色: hsl(214.58, 86.34%, 59.8%) (Vben 蓝)
|
|
89
|
-
侧边栏: 160px, 浅色, mixed-nav 布局
|
|
90
|
-
顶栏: 深色, 含 logo + 通知 + 头像
|
|
91
|
-
圆角: 0.25rem
|
|
92
|
-
字体: -apple-system, BlinkMacSystemFont, ...
|
|
93
|
-
|
|
94
|
-
真实按钮文案示例: 添加反馈资产, 导出Excel, 批量导入, ...
|
|
95
|
-
常用组件: Modal(273次), Input(135次), FormItem(95次), ...
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
## 使用示例
|
|
99
|
-
|
|
100
|
-
```
|
|
101
|
-
/wl-design-scan 资产管理 → 功能模块全景
|
|
102
|
-
/wl-design-scan 资产的操作流程 → 操作链分析
|
|
103
|
-
/wl-design-scan 系统设计风格 → 设计 token + 布局指纹
|
|
104
|
-
/wl-design-scan 哪些功能没测试 → 覆盖矩阵
|
|
105
|
-
/wl-design-scan 改 /asset 影响 → 影响分析
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
> scan 不产出文件,只返回结构化分析。帮设计师/PM"看清楚"再动手。
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: wl-design-spec
|
|
3
|
-
description: "设计交付。录入设计稿→spec.json + 评审原型合规性。设计师和系统对接的唯一入口。"
|
|
4
|
-
argument-hint: "<录入|评审> <描述>"
|
|
5
|
-
auto-approve: true
|
|
6
|
-
allowed-tools: [Read, Glob, Grep, Bash, Write, Edit, mcp__qoder-knowledge-graph, mcp__lanhu]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# /wl-design-spec - 设计交付
|
|
10
|
-
|
|
11
|
-
User input: $ARGUMENTS
|
|
12
|
-
|
|
13
|
-
> 设计的终点:把设计意图"规格化"让前端能实现,并评审原型是否合规。
|
|
14
|
-
> 包含两个动作:**录入**(设计师→系统)和**评审**(系统→设计师)。
|
|
15
|
-
|
|
16
|
-
## 🔧 环境自检(QoderWork 桌面端 vs Qoder IDE/CLI)
|
|
17
|
-
|
|
18
|
-
**先确定仓库根 R**(QoderWork 桌面端工作目录不是仓库根,相对路径会失效):
|
|
19
|
-
```bash
|
|
20
|
-
R=$(python ~/.qoderwork/repo_root.py 2>/dev/null) || R=.
|
|
21
|
-
```
|
|
22
|
-
> 后续脚本统一用 `python "$R/.qoder/scripts/xxx.py"`。
|
|
23
|
-
|
|
24
|
-
## 第一步:判断用户要做哪个动作
|
|
25
|
-
|
|
26
|
-
| 用户说什么 | 动作 | 跳到 |
|
|
27
|
-
|-----------|------|------|
|
|
28
|
-
| "录入""这是 Figma 稿""把这个设计录进去""设计稿录入" | **录入** | 录入段 |
|
|
29
|
-
| "评审""检查""看看这个原型""合规吗" | **评审** | 评审段 |
|
|
30
|
-
| 模糊 | 先问 | "你是要录入设计稿,还是评审现有原型?" |
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## 录入(设计师把 Figma 稿变成 spec.json)
|
|
35
|
-
|
|
36
|
-
**铁律:平台必须先问。** 问完就停。
|
|
37
|
-
|
|
38
|
-
### 流程
|
|
39
|
-
|
|
40
|
-
完整执行见 `.qoder/skills/design-import/SKILL.md`:
|
|
41
|
-
|
|
42
|
-
1. **录入前先看现状**(让 spec 不是凭空设计,是基于系统增量改进):
|
|
43
|
-
```
|
|
44
|
-
mcp__qoder-knowledge-graph__feature_overview(feature='资产') → 这个模块现有页面/按钮
|
|
45
|
-
mcp__qoder-knowledge-graph__get_workflow(module='资产') → 现有操作流程
|
|
46
|
-
mcp__qoder-knowledge-graph__get_design_system(platform='web') → 现有 token/布局/组件
|
|
47
|
-
```
|
|
48
|
-
设计师据此知道"系统现在有什么、我的设计改了什么"。
|
|
49
|
-
|
|
50
|
-
2. **收集设计信息**(按精度从高到低):
|
|
51
|
-
- **蓝湖链接(最推荐)**:设计师发 `https://lanhuapp.com/web/#/item/...`,走 4 步直读
|
|
52
|
-
(详见 design-import/SKILL.md 方式 A):
|
|
53
|
-
① `mcp__lanhu__get_designs(url)` 探测+列图(失败就降级截图口述,不报错)
|
|
54
|
-
② 让设计师选哪张图(**问了就停**)
|
|
55
|
-
③ `mcp__lanhu__get_ai_analyze_design_result(url, design_names)` 读 CSS 标注+切图
|
|
56
|
-
④ AI 语义映射进 spec.json(出现最多的色→主色,width→侧边栏...)
|
|
57
|
-
- **铁律:蓝湖 CSS 值原样填**。`rgba(255,115,10,1)` 不写成 `#FF730A`,`200px` 不四舍五入
|
|
58
|
-
- STDIO 自动开关(开 QoderWork 自动起/关自动停,无需手动 start);cookie 按角色在 `workspace/members/{当前用户}/.secrets/lanhu.env`
|
|
59
|
-
- **截图 + 口述**(蓝湖不可用时降级):设计师发一张 Figma 截图,口述关键决策
|
|
60
|
-
- **导出标注**(CSS / JSON / PDF)
|
|
61
|
-
- **参照现有页面改**("类似 XX 页面,但侧边栏改成手风琴")
|
|
62
|
-
|
|
63
|
-
3. **生成 spec.json**,结构包含:
|
|
64
|
-
```json
|
|
65
|
-
{
|
|
66
|
-
"platform": "web",
|
|
67
|
-
"requirement": "异常资产申请页改版",
|
|
68
|
-
"design_tokens": { "--primary-color": "rgba(255,115,10,1)", "--sidebar-width": "160px" },
|
|
69
|
-
"layout": { "description": "...", "sidebar": "...", "content": "..." },
|
|
70
|
-
"components": [{ "name": "...", "spec": "..." }],
|
|
71
|
-
"behaviors": { "sidebar_collapse": "click", "form_mode": "wizard" },
|
|
72
|
-
"source": "蓝湖直读 (设计师: XXX)",
|
|
73
|
-
"lanhu_source": { "url": "...", "image_names": ["..."] }
|
|
74
|
-
}
|
|
75
|
-
```
|
|
76
|
-
> ⚠️ `requirement` 必须跟未来 `/wl-design-draw` 关键词一致(fill_prototype 靠它匹配)。
|
|
77
|
-
> 蓝湖来源填 `"source": "蓝湖直读 (...)"` + `lanhu_source`;截图口述只填 `source`。
|
|
78
|
-
|
|
79
|
-
4. **存储到** `data/style/{需求名}-{平台}-design-spec.json`(平台=web/app,避免同功能多端冲突;同需求同平台重录=覆盖更新)
|
|
80
|
-
> `requirement` 用"功能名+同义词"(如 `待办 我的待办 设置待办`),让 PM 搜各种词都能命中。
|
|
81
|
-
|
|
82
|
-
5. **优先级声明**:spec.json > 代码风格 > PDF 规范
|
|
83
|
-
一旦录入,同需求的 `/wl-design-draw` 必须锚定它。
|
|
84
|
-
|
|
85
|
-
### 铁律
|
|
86
|
-
|
|
87
|
-
- **绝不编造 token**:设计师没说的值,留空或标"待确认"
|
|
88
|
-
- **图标必须来自真源**:即使设计师用 emoji 示意,录入时替换成系统真源
|
|
89
|
-
(Web: `data/index/ref-icon.json` Ant Design SVG;APP: Vant 字体图标)
|
|
90
|
-
- **录入后同需求原型必须锚定它**
|
|
91
|
-
|
|
92
|
-
### 完成提示
|
|
93
|
-
|
|
94
|
-
```
|
|
95
|
-
✅ 设计规范已录入: data/style/{需求名}-design-spec.json
|
|
96
|
-
下次 /wl-design-draw 同关键词时,会自动优先用这份 spec。
|
|
97
|
-
设计师可随时 /wl-design-spec 录入 更新它。
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### Figma 协作流程
|
|
101
|
-
|
|
102
|
-
设计师在 Figma 精修完设计稿后,导出/截图,用 `/wl-design-spec 录入` 录入。
|
|
103
|
-
完整 Figma 协作指南见 `.qoder/skills/design-import/figma-workflow.md`。
|
|
104
|
-
|
|
105
|
-
---
|
|
106
|
-
|
|
107
|
-
## 评审(检查原型是否合规)
|
|
108
|
-
|
|
109
|
-
完整执行见 `.qoder/skills/design-review/SKILL.md`。
|
|
110
|
-
|
|
111
|
-
读最新的 `workspace/members/{dev}/drafts/prototype-*.html`,按 checklist 评审:
|
|
112
|
-
|
|
113
|
-
### 评审 checklist
|
|
114
|
-
|
|
115
|
-
**视觉合规:**
|
|
116
|
-
- [ ] 颜色来自真源(get_design_system 的 HSL token,不是 #1890ff)
|
|
117
|
-
- [ ] 图标来自真源(ref-icon.json 的 SVG,无 emoji)
|
|
118
|
-
- [ ] 侧边栏宽度 = layout_fingerprint 值(fywl-ui 是 160px)
|
|
119
|
-
- [ ] 字体/圆角/间距跟系统一致
|
|
120
|
-
|
|
121
|
-
**内容合规:**
|
|
122
|
-
- [ ] 按钮文案用了系统真实文案(entity-registry,非编的"新增/编辑")
|
|
123
|
-
- [ ] 表格列/表单字段来自真实代码(fill_prototype 数据清单)
|
|
124
|
-
- [ ] 若设计师 spec 存在:原型匹配 spec 的布局/配色/组件
|
|
125
|
-
|
|
126
|
-
**交互合规:**
|
|
127
|
-
- [ ] 交互流程闭环(对照 get_workflow 的操作链,原型覆盖了全部步骤)
|
|
128
|
-
- [ ] 包含完整状态(有数据/空状态/加载中/错误)
|
|
129
|
-
- [ ] 布局跟同功能模块标杆页面一致(对照 feature_overview)
|
|
130
|
-
|
|
131
|
-
**测试影响:**
|
|
132
|
-
- [ ] 若改动页面有测试覆盖(coverage_matrix),提醒"改动后需回归测试"
|
|
133
|
-
|
|
134
|
-
### 评审时可调 MCP 工具
|
|
135
|
-
|
|
136
|
-
- `mcp__qoder-knowledge-graph__feature_overview(feature='XX')` → 功能画像,对比原型是否遗漏
|
|
137
|
-
- `mcp__qoder-knowledge-graph__get_workflow(module='XX')` → 操作链,检查原型是否覆盖完整流程
|
|
138
|
-
- `mcp__coverage_matrix()` → 测试覆盖,判断改动是否需回归
|
|
139
|
-
- `mcp__qoder-knowledge-graph__get_design_system(platform='web')` → 真实 token/按钮做对照
|
|
140
|
-
|
|
141
|
-
### 输出
|
|
142
|
-
|
|
143
|
-
报告:PASS 或 🔴/🟡 问题清单(不产文件,只出报告)。
|
|
144
|
-
若不通过,附上修复建议和参考文件路径。
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
|
-
## 使用示例
|
|
149
|
-
|
|
150
|
-
```
|
|
151
|
-
/wl-design-spec 录入 这个 Figma 稿 → 录入设计稿
|
|
152
|
-
/wl-design-spec 评审 最新原型 → 评审原型
|
|
153
|
-
/wl-design-spec 这个按钮文案对不对 → 评审(按钮文案检查)
|
|
154
|
-
```
|