@hupan56/wlkj 2.7.1 → 2.7.3
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/MAC-VERIFY.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# macOS 验证清单 (v2.7.1)
|
|
2
|
+
|
|
3
|
+
> 给 mac 同事跑这份清单,验证工作流在 macOS × Qoder 全系列上可用。
|
|
4
|
+
> 跑完把结果(每条 ✓/✗ + 截图或输出)反馈回来。
|
|
5
|
+
> 预计耗时:15-20 分钟(含装环境)。
|
|
6
|
+
|
|
7
|
+
## 已在 Windows 上模拟验证的项(mock sys.platform=darwin)
|
|
8
|
+
|
|
9
|
+
这些项已用 `mock sys.platform='darwin'` 在 Windows 上验证过逻辑正确,
|
|
10
|
+
mac 同事只需确认真实环境跑通(不需要深入查代码):
|
|
11
|
+
|
|
12
|
+
| 验证项 | 模拟结果 | 说明 |
|
|
13
|
+
|--------|---------|------|
|
|
14
|
+
| detectPyCmd(python3 探测) | ✓ PASS | mac 上 python 不存在时正确回退 python3 |
|
|
15
|
+
| .repo-root 锚点 | ✓ PASS | 用 PROJECT_ROOT,从任意 cwd 跑都指向仓库根 |
|
|
16
|
+
| venv 路径分支 | ✓ PASS | mac 下正确指向 `bin/python`(非 Scripts/python.exe) |
|
|
17
|
+
| find_repo_root 4 级回退 | ✓ PASS | 纯 os.path,跨平台无硬编码分隔符 |
|
|
18
|
+
| _find_python_with_deps | ✓ PASS | 用 shutil.which 探测,不硬编码 mac 路径 |
|
|
19
|
+
|
|
20
|
+
## 前置:你的 mac 环境是什么
|
|
21
|
+
|
|
22
|
+
先跑这条,把基础信息发回来:
|
|
23
|
+
```bash
|
|
24
|
+
sw_vers # macOS 版本
|
|
25
|
+
which python python3 node git brew 2>/dev/null # 已装的工具
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 阶段 1:环境安装(如果 python/node 没装)
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npx @hupan56/wlkj install-env --check
|
|
34
|
+
```
|
|
35
|
+
**预期**:列出 Node/Python/git 检测结果。缺哪个会标 `[缺失]`。
|
|
36
|
+
|
|
37
|
+
如果缺,去掉 `--check` 自动装(用 brew):
|
|
38
|
+
```bash
|
|
39
|
+
npx @hupan56/wlkj install-env
|
|
40
|
+
```
|
|
41
|
+
**预期**:`[OK] Node.js 已装` / `[OK] Python 已装` / pip 依赖装上(失败会切清华镜像)。
|
|
42
|
+
|
|
43
|
+
**关键验证点**(本轮修复):
|
|
44
|
+
- pip 装包如果默认源失败,应该自动切"清华"镜像重试
|
|
45
|
+
- 如果看到 `pip 安装失败 (尝试了所有镜像)` 才算异常
|
|
46
|
+
|
|
47
|
+
**mac 专属排查(brew 装完 PATH 未更新的常见坑)**:
|
|
48
|
+
- `brew install python@3.12` 装完后,**当前终端的 PATH 可能还没更新**,
|
|
49
|
+
导致 `python3: command not found`。
|
|
50
|
+
- 如果装完仍报缺失,**重开一个终端**再跑 `install-env --check`。
|
|
51
|
+
- 或手动验证:`which python3`(应指向 `/opt/homebrew/bin/python3` 或 `/usr/local/bin/python3`)
|
|
52
|
+
- 如果 `which python3` 找不到,跑:`brew link python@3.12` 或按 brew 提示加 PATH。
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 阶段 2:初始化工作流
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
cd ~/your-workspace # 你放工作流的目录
|
|
60
|
+
npx @hupan56/wlkj init 你的名字 你的角色
|
|
61
|
+
```
|
|
62
|
+
角色填:`pm` / `design` / `dev` / `test` / `admin`
|
|
63
|
+
|
|
64
|
+
**预期**:
|
|
65
|
+
- 环境检测:`Python: [OK] Python 3.x.x (python3)` ← **mac 上应该是 python3,不是 python**
|
|
66
|
+
- 角色选择菜单(如果没传角色参数):列出 5 个角色让你选
|
|
67
|
+
- 安装完成:`安装完成! (v2.7.0)`
|
|
68
|
+
|
|
69
|
+
**关键验证点**(本轮修复):
|
|
70
|
+
- macOS 上用 `python3` 不报错(旧版硬编码 `python` 会 `command not found`)
|
|
71
|
+
- 角色不是写死的 pm(旧版所有人都是 pm)
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## 阶段 3:状态检查
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
npx @hupan56/wlkj status
|
|
79
|
+
```
|
|
80
|
+
**预期**:
|
|
81
|
+
```
|
|
82
|
+
dev: 你的名字 (角色: dev) ← 显示你的角色,不是 pm
|
|
83
|
+
...
|
|
84
|
+
engine: 2.7.0 (最新: v2.7.0) [最新]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## 阶段 4:MCP 健康检查(核心!)
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
python3 .qoder/scripts/check_mcp.py
|
|
93
|
+
```
|
|
94
|
+
**预期**:7 项检查,每项 `[OK]` 或 `[WARN]`(WARN 是可选功能没装,正常):
|
|
95
|
+
```
|
|
96
|
+
--- 1. mcp.json 配置 ---
|
|
97
|
+
[OK] mcp.json 存在, 注册了 4 个 server
|
|
98
|
+
[OK] N 个 server 用 launcher 模式
|
|
99
|
+
--- 2. 仓库根定位 ---
|
|
100
|
+
[OK] .repo-root 锚点正确: /Users/你的名字/your-workspace
|
|
101
|
+
--- 3. MCP launcher ---
|
|
102
|
+
[OK] launcher 存在: ~/.qoderwork/mcp_launcher.py
|
|
103
|
+
--- 4. 知识图谱 MCP (kg) ---
|
|
104
|
+
[OK] kg 就绪 (python=..., 装了 duckdb)
|
|
105
|
+
--- 5. MySQL MCP ---
|
|
106
|
+
[OK/WARN] ...
|
|
107
|
+
--- 6. 蓝湖 MCP ---
|
|
108
|
+
[OK/WARN] ...
|
|
109
|
+
--- 7. Playwright MCP ---
|
|
110
|
+
[OK/WARN] ...
|
|
111
|
+
所有 MCP 就绪, Qoder 全系列可正常调用。
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**关键验证点**(本轮修复):
|
|
115
|
+
- `.repo-root 锚点正确` 指向你的工作流目录(旧版可能指向错误目录)
|
|
116
|
+
- 末尾 `所有 MCP 就绪` 或明确列出未就绪项
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 阶段 5:QoderWork 桌面端验证
|
|
121
|
+
|
|
122
|
+
1. 打开 QoderWork 桌面端
|
|
123
|
+
2. 新建对话,输入:`/wl-status`
|
|
124
|
+
3. **预期**:显示项目状态,含"当前角色: 你的角色名"
|
|
125
|
+
|
|
126
|
+
**关键验证点**:
|
|
127
|
+
- MCP 工具能调(说"查一下车辆代码",kg MCP 响应)
|
|
128
|
+
- 不出现"MCP 连接失败"黄标
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 阶段 6:性能感受(非必须,主观)
|
|
133
|
+
|
|
134
|
+
- `/wl-search 车辆`:应该 < 1 秒返回
|
|
135
|
+
- `/wl-prd-quick` 写个小需求:取上下文 + 出原型应该顺畅
|
|
136
|
+
|
|
137
|
+
如果某个命令明显卡(> 5 秒),记下是哪个命令 + 大概多久。
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 反馈格式
|
|
142
|
+
|
|
143
|
+
跑完把这份填回来:
|
|
144
|
+
```
|
|
145
|
+
阶段1 环境: ✓/✗ (备注)
|
|
146
|
+
阶段2 init: ✓/✗ (python3 是否正常 / 角色是否正确)
|
|
147
|
+
阶段3 status: ✓/✗ (角色显示对不对)
|
|
148
|
+
阶段4 check_mcp: ✓/✗ (几个 OK / 几个 WARN / 有无 BAD)
|
|
149
|
+
阶段5 QoderWork: ✓/✗ (MCP 是否绿 / 工具能否调)
|
|
150
|
+
阶段6 性能: (主观, 卡不卡)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
有 ✗ 的项,把完整命令输出贴回来,我来定位修复。
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## mac 专属注意事项(Windows 上测不到的坑)
|
|
158
|
+
|
|
159
|
+
1. **cron 全盘访问**:init 时会装周五 18:00 的定时更新(setup_weekly_cron.sh)。
|
|
160
|
+
macOS 默认 cron 没磁盘权限,任务会静默失败。
|
|
161
|
+
- 现象:`.qoder/logs/weekly-update.log` 不增长或报权限错
|
|
162
|
+
- 修复:系统设置 → 隐私与安全 → 完全磁盘访问 → 添加 `/usr/sbin/cron`
|
|
163
|
+
- 不影响日常使用,只影响每周自动更新(可手动跑 git_sync.py 替代)
|
|
164
|
+
|
|
165
|
+
2. **brew python 的 PATH**:见阶段 1 的排查提示。brew 装完要重开终端。
|
|
166
|
+
|
|
167
|
+
3. **lanhu venv 路径**:mac 上是 `.venv/bin/python`(非 Windows 的 `Scripts/python.exe`)。
|
|
168
|
+
check_mcp.py 已适配,但如果 setup_lanhu.py 没在 mac 上测过,留意这步。
|
|
169
|
+
|
|
170
|
+
4. **文件权限**:mac 上从 git 拉的 .sh 脚本可能没执行权限。
|
|
171
|
+
如果 `setup_weekly_cron.sh` 报 permission denied:`chmod +x .qoder/scripts/*.sh`
|
|
172
|
+
|
|
173
|
+
5. **大小写敏感文件系统**:mac 默认大小写不敏感(APFS),
|
|
174
|
+
如果代码里有 `Search.py` 和 `search.py` 会冲突。工作流脚本都是小写,一般无碍。
|
package/package.json
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hupan56/wlkj",
|
|
3
|
-
"version": "2.7.
|
|
3
|
+
"version": "2.7.3",
|
|
4
4
|
"description": "AI Product R&D Workflow - PRD/Prototype/Search/Task/Report",
|
|
5
5
|
"bin": {
|
|
6
6
|
"wlkj": "bin/cli.js"
|
|
7
7
|
},
|
|
8
8
|
"files": [
|
|
9
9
|
"bin/",
|
|
10
|
-
"templates/"
|
|
10
|
+
"templates/",
|
|
11
|
+
"MAC-VERIFY.md"
|
|
11
12
|
],
|
|
12
13
|
"keywords": [
|
|
13
14
|
"workflow",
|
|
@@ -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)
|
|
Binary file
|