@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.
- package/bin/cli.js +375 -78
- package/package.json +29 -29
- package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +23 -0
- package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +23 -0
- package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +1 -0
- package/templates/.qoder/learning/eval-history.jsonl +28 -0
- package/templates/data/index/wiki-index.json +8 -0
- package/templates/qoder/agents/insight-planning.md +1 -1
- package/templates/qoder/agents/insight-research.md +28 -15
- package/templates/qoder/commands/optional/wl-insight.md +159 -161
- package/templates/qoder/commands/optional/wl-report.md +4 -4
- package/templates/qoder/commands/optional/wl-status.md +2 -2
- package/templates/qoder/commands/wl-code.md +2 -2
- package/templates/qoder/commands/wl-design.md +2 -2
- package/templates/qoder/commands/wl-init.md +3 -3
- package/templates/qoder/commands/wl-prd.md +2 -2
- package/templates/qoder/commands/wl-req.md +43 -0
- package/templates/qoder/commands/wl-search.md +8 -8
- package/templates/qoder/commands/wl-task.md +17 -17
- package/templates/qoder/commands/wl-test.md +41 -15
- package/templates/qoder/config.yaml +17 -1
- package/templates/qoder/hooks/session-start.py +12 -22
- package/templates/qoder/nul +4 -0
- package/templates/qoder/rules/wl-pipeline.md +22 -48
- package/templates/qoder/scripts/README.md +139 -0
- package/templates/qoder/scripts/common/autotest_auth.py +109 -0
- package/templates/qoder/scripts/common/bootstrap.py +145 -0
- package/templates/qoder/scripts/common/check_publish.py +98 -0
- package/templates/qoder/scripts/common/cmd_registry.py +112 -0
- package/templates/qoder/scripts/common/config.py +187 -0
- package/templates/qoder/scripts/common/contract.py +317 -0
- package/templates/qoder/scripts/common/developer.py +2 -1
- package/templates/qoder/scripts/common/feishu.py +10 -9
- package/templates/qoder/scripts/common/guard.py +159 -0
- package/templates/qoder/scripts/common/identity.py +121 -2
- package/templates/qoder/scripts/common/kg_capabilities.py +182 -0
- package/templates/qoder/scripts/common/mcp_base.py +268 -0
- package/templates/qoder/scripts/common/paths.py +187 -1
- package/templates/qoder/scripts/common/result.py +223 -0
- package/templates/qoder/scripts/common/roles.py +60 -0
- package/templates/qoder/scripts/common/task_utils.py +21 -9
- package/templates/qoder/scripts/common/test_extract.py +115 -0
- package/templates/qoder/scripts/kg/__init__.py +11 -0
- package/templates/qoder/scripts/kg/build_entity_registry.py +196 -0
- package/templates/qoder/scripts/kg/build_relations.py +127 -0
- package/templates/qoder/scripts/{build_style_index.py → kg/build_style_index.py} +39 -10
- package/templates/qoder/scripts/kg/build_workflows.py +144 -0
- package/templates/qoder/scripts/{context_pack.py → kg/context_pack.py} +18 -11
- package/templates/qoder/scripts/{enrich_prompt.py → kg/enrich_prompt.py} +232 -226
- package/templates/qoder/scripts/{extract_api_params.py → kg/extract.py} +398 -246
- package/templates/qoder/scripts/{kg.py → kg/kg.py} +638 -708
- package/templates/qoder/scripts/{kg_build.py → kg/kg_build.py} +618 -612
- package/templates/qoder/scripts/{kg_build_db.py → kg/kg_build_db.py} +333 -327
- package/templates/qoder/scripts/{kg_duckdb.py → kg/kg_duckdb.py} +38 -37
- package/templates/qoder/scripts/{kg_incremental.py → kg/kg_incremental.py} +420 -393
- package/templates/qoder/scripts/{kg_link_db.py → kg/kg_link_db.py} +230 -224
- package/templates/qoder/scripts/{kg_semantic.py → kg/kg_semantic.py} +156 -150
- package/templates/qoder/scripts/kg/prefetch.py +359 -0
- package/templates/qoder/scripts/{search_index.py → kg/search_index.py} +70 -14
- package/templates/qoder/scripts/mcp/__init__.py +11 -0
- package/templates/qoder/scripts/{kg_mcp_server.py → mcp/kg_mcp_server.py} +77 -272
- package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → mcp/lanhu_stdio_wrapper.py} +125 -119
- package/templates/qoder/scripts/{check_mcp.py → mcp/mcp_doctor.py} +515 -298
- package/templates/qoder/scripts/{mcp_launcher.py → mcp/mcp_launcher.py} +442 -414
- package/templates/qoder/scripts/{mysql_mcp_server.py → mcp/mysql_mcp_server.py} +347 -396
- package/templates/qoder/scripts/{zentao_mcp_server.py → mcp/zentao_mcp_server.py} +384 -424
- package/templates/qoder/scripts/report/__init__.py +11 -0
- package/templates/qoder/scripts/{add_session.py → report/add_session.py} +250 -244
- package/templates/qoder/scripts/{archive_prd.py → report/archive_prd.py} +383 -377
- package/templates/qoder/scripts/{eval_prd.py → report/eval_prd.py} +73 -11
- package/templates/qoder/scripts/{export.py → report/export.py} +63 -0
- package/templates/qoder/scripts/{fill_prototype.py → report/fill_prototype.py} +6 -0
- package/templates/qoder/scripts/{gen_design_doc.py → report/gen_design_doc.py} +400 -394
- package/templates/qoder/scripts/{learn.py → report/learn.py} +152 -146
- package/templates/qoder/scripts/{learn_aggregate.py → report/learn_aggregate.py} +207 -201
- package/templates/qoder/scripts/{report.py → report/report.py} +287 -281
- package/templates/qoder/scripts/report/req.py +222 -0
- package/templates/qoder/scripts/report/role.py +33 -0
- package/templates/qoder/scripts/{status.py → report/status.py} +634 -628
- package/templates/qoder/scripts/setup/__init__.py +11 -0
- package/templates/qoder/scripts/setup/carriers.py +662 -0
- package/templates/qoder/scripts/{init_doctor.py → setup/init_doctor.py} +63 -26
- package/templates/qoder/scripts/{install_qoderwork.py → setup/install_qoderwork.py} +36 -26
- package/templates/qoder/scripts/{platform_doctor.py → setup/platform_doctor.py} +265 -259
- package/templates/qoder/scripts/{repo_root.py → setup/repo_root.py} +112 -106
- package/templates/qoder/scripts/{setup.py → setup/setup.py} +147 -0
- package/templates/qoder/scripts/{setup_lanhu.py → setup/setup_lanhu.py} +973 -963
- package/templates/qoder/scripts/task/__init__.py +11 -0
- package/templates/qoder/scripts/{git_sync.py → task/git_sync.py} +52 -31
- package/templates/qoder/scripts/{syncgate.py → task/syncgate.py} +6 -0
- package/templates/qoder/scripts/task/task.py +221 -0
- package/templates/qoder/scripts/task/task_lifecycle.py +596 -0
- package/templates/qoder/scripts/task/task_query.py +161 -0
- package/templates/qoder/scripts/task/task_relations.py +424 -0
- package/templates/qoder/scripts/{team_sync.py → task/team_sync.py} +93 -20
- package/templates/qoder/scripts/test/__init__.py +11 -0
- package/templates/qoder/scripts/{autotest.py → test/autotest.py} +1174 -1751
- package/templates/qoder/scripts/{autotest_batch.py → test/autotest_batch.py} +242 -224
- package/templates/qoder/scripts/test/autotest_data.py +675 -0
- package/templates/qoder/scripts/{autotest_run.py → test/autotest_run.py} +309 -297
- package/templates/qoder/scripts/{benchmark.py → test/benchmark.py} +6 -0
- package/templates/qoder/scripts/{kg_auto_login.py → test/kg_auto_login.py} +202 -196
- package/templates/qoder/scripts/{kg_test_runner.py → test/kg_test_runner.py} +7 -1
- package/templates/qoder/scripts/{page_probe.py → test/page_probe.py} +465 -459
- package/templates/qoder/scripts/wlkj.py +116 -0
- package/templates/qoder/settings.json +1 -10
- package/templates/qoder/skills/design-import/SKILL.md +226 -226
- package/templates/qoder/skills/design-review/SKILL.md +82 -82
- package/templates/qoder/skills/prd-generator/SKILL.md +26 -16
- package/templates/qoder/skills/prd-review/SKILL.md +5 -5
- package/templates/qoder/skills/prototype-generator/SKILL.md +256 -256
- package/templates/qoder/skills/spec-coder/SKILL.md +4 -4
- package/templates/qoder/skills/spec-generator/SKILL.md +4 -4
- package/templates/qoder/skills/test-generator/SKILL.md +5 -5
- package/templates/qoder/skills/wl-code/SKILL.md +4 -4
- package/templates/qoder/skills/wl-commit/SKILL.md +4 -4
- package/templates/qoder/skills/wl-design/SKILL.md +3 -3
- package/templates/qoder/skills/wl-init/SKILL.md +8 -8
- package/templates/qoder/skills/wl-insight/SKILL.md +5 -5
- package/templates/qoder/skills/wl-prd-full/SKILL.md +6 -6
- package/templates/qoder/skills/wl-prd-quick/SKILL.md +6 -6
- package/templates/qoder/skills/wl-prd-review/SKILL.md +4 -4
- package/templates/qoder/skills/wl-report/SKILL.md +7 -7
- package/templates/qoder/skills/wl-search/SKILL.md +13 -13
- package/templates/qoder/skills/wl-spec/SKILL.md +5 -5
- package/templates/qoder/skills/wl-status/SKILL.md +5 -5
- package/templates/qoder/skills/wl-task/SKILL.md +6 -6
- package/templates/qoder/skills/wl-test/SKILL.md +102 -39
- package/templates/root/AGENTS.md +39 -40
- package/templates/qoder/hooks/inject-workflow-state.py +0 -169
- package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/check_carriers.py +0 -238
- package/templates/qoder/scripts/check_mcp_launch.py +0 -183
- package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
- package/templates/qoder/scripts/collect_prds.py +0 -31
- package/templates/qoder/scripts/common/mentions.py +0 -134
- package/templates/qoder/scripts/common/utf8.py +0 -38
- package/templates/qoder/scripts/extract_routes.py +0 -54
- package/templates/qoder/scripts/extract_routes_tree.py +0 -78
- package/templates/qoder/scripts/handoff.py +0 -22
- package/templates/qoder/scripts/init_developer.py +0 -76
- package/templates/qoder/scripts/parse_prds.py +0 -33
- package/templates/qoder/scripts/role.py +0 -51
- package/templates/qoder/scripts/sync_carriers.py +0 -259
- package/templates/qoder/scripts/task.py +0 -1261
- package/templates/qoder/scripts/workspace_init.py +0 -102
- package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
- package/templates/qoder/skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp +0 -0
- /package/templates/qoder/scripts/{secure-ls.js → test/secure-ls.js} +0 -0
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
|
+
# v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
|
|
4
|
+
import os as _o, sys as _s
|
|
5
|
+
_cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
|
|
6
|
+
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
7
|
+
from bootstrap import setup; setup()
|
|
8
|
+
|
|
3
9
|
"""
|
|
4
10
|
QODER Init Doctor - 幂等的一站式环境体检 + 按需修复
|
|
5
11
|
|
|
@@ -44,7 +50,7 @@ except (AttributeError, TypeError, OSError, IOError):
|
|
|
44
50
|
except Exception:
|
|
45
51
|
pass
|
|
46
52
|
|
|
47
|
-
SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
53
|
+
SCRIPTS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 子包→scripts根
|
|
48
54
|
sys.path.insert(0, SCRIPTS_DIR)
|
|
49
55
|
|
|
50
56
|
from common.paths import get_repo_root, get_developer, get_developer_info
|
|
@@ -76,22 +82,37 @@ def problem(msg, hint=None):
|
|
|
76
82
|
|
|
77
83
|
|
|
78
84
|
def run_script(script, *args, timeout=1800):
|
|
79
|
-
"""
|
|
80
|
-
|
|
85
|
+
"""跑另一个脚本, 实时透传输出。
|
|
86
|
+
v3.0: 支持子目录化 — 先在 scripts/根找, 找不到扫各子包。"""
|
|
87
|
+
# 先试 scripts/根
|
|
88
|
+
cand = os.path.join(SCRIPTS_DIR, script)
|
|
89
|
+
if not os.path.isfile(cand):
|
|
90
|
+
# 扫各子包
|
|
91
|
+
for sub in ('io', 'setup', 'kg', 'build', 'test'):
|
|
92
|
+
c2 = os.path.join(SCRIPTS_DIR, sub, script)
|
|
93
|
+
if os.path.isfile(c2):
|
|
94
|
+
cand = c2
|
|
95
|
+
break
|
|
96
|
+
cmd = [sys.executable, cand] + list(args)
|
|
81
97
|
r = subprocess.run(cmd, cwd=BASE, timeout=timeout)
|
|
82
98
|
return r.returncode == 0
|
|
83
99
|
|
|
84
100
|
|
|
85
101
|
def load_config():
|
|
86
|
-
|
|
87
|
-
if not os.path.isfile(cfg):
|
|
88
|
-
return {}
|
|
102
|
+
"""v3.0: 转发到 Config 单例 (带 mtime 缓存)。"""
|
|
89
103
|
try:
|
|
90
|
-
import
|
|
91
|
-
|
|
92
|
-
return yaml.safe_load(f) or {}
|
|
104
|
+
from common.config import Config
|
|
105
|
+
return Config.load().raw
|
|
93
106
|
except Exception:
|
|
94
|
-
|
|
107
|
+
cfg = os.path.join(BASE, '.qoder', 'config.yaml')
|
|
108
|
+
if not os.path.isfile(cfg):
|
|
109
|
+
return {}
|
|
110
|
+
try:
|
|
111
|
+
import yaml
|
|
112
|
+
with open(cfg, encoding='utf-8') as f:
|
|
113
|
+
return yaml.safe_load(f) or {}
|
|
114
|
+
except Exception:
|
|
115
|
+
return {}
|
|
95
116
|
|
|
96
117
|
|
|
97
118
|
# ============================================================
|
|
@@ -100,7 +121,18 @@ def load_config():
|
|
|
100
121
|
|
|
101
122
|
def check_basics():
|
|
102
123
|
print('\n--- 1. 基础环境 ---')
|
|
103
|
-
|
|
124
|
+
# Python 版本下限检查 (v3.0+ 新增, 治"3.7 用户装 duckdb 难定位"隐患)
|
|
125
|
+
# duckdb>=1.1.0 / playwright>=1.40 / tree-sitter>=0.21 都要求 Python >=3.8
|
|
126
|
+
py_major, py_minor = sys.version_info[0], sys.version_info[1]
|
|
127
|
+
say(OK, 'Python {}.{} ({})'.format(py_major, py_minor, sys.platform))
|
|
128
|
+
if (py_major, py_minor) < (3, 8):
|
|
129
|
+
problem(
|
|
130
|
+
'Python {}.{} 低于最低要求 3.8 (duckdb/playwright/tree-sitter 需要)'.format(py_major, py_minor),
|
|
131
|
+
hint='升级 Python: 装 3.10+ (Windows python.org / Mac brew install python@3.10)'
|
|
132
|
+
)
|
|
133
|
+
elif (py_major, py_minor) < (3, 9):
|
|
134
|
+
say(WARN, 'Python {}.{} 可用但建议升级到 3.10+ (部分依赖未来可能提高要求)'.format(py_major, py_minor))
|
|
135
|
+
|
|
104
136
|
# git 可选 (无 git 时核心功能仍可用, 仅团队同步禁用)
|
|
105
137
|
try:
|
|
106
138
|
r = subprocess.run(['git', '--version'], capture_output=True, text=True,
|
|
@@ -225,9 +257,9 @@ def check_developer(fix, name=None, role=None):
|
|
|
225
257
|
if current:
|
|
226
258
|
info = get_developer_info() or {}
|
|
227
259
|
say(OK, '开发者: {} ({})'.format(current, info.get('role', '?')))
|
|
228
|
-
# 个人空间目录
|
|
260
|
+
# 个人空间目录 (v3.0 M3: drafts/outputs/journal/.private, 不再有inbox)
|
|
229
261
|
member = os.path.join(BASE, 'workspace', 'members', current)
|
|
230
|
-
missing = [s for s in ('drafts', '
|
|
262
|
+
missing = [s for s in ('drafts', 'outputs', 'journal')
|
|
231
263
|
if not os.path.isdir(os.path.join(member, s))]
|
|
232
264
|
if missing:
|
|
233
265
|
if fix:
|
|
@@ -377,17 +409,6 @@ def index_age_days():
|
|
|
377
409
|
return None
|
|
378
410
|
import time as _time
|
|
379
411
|
return int((_time.time() - os.path.getmtime(kg_path)) / 86400)
|
|
380
|
-
if os.path.isfile(meta_path):
|
|
381
|
-
try:
|
|
382
|
-
import json
|
|
383
|
-
with open(meta_path, encoding='utf-8') as f:
|
|
384
|
-
meta = json.load(f)
|
|
385
|
-
ts = datetime.strptime(meta.get('last_sync', ''), '%Y-%m-%d %H:%M')
|
|
386
|
-
except Exception:
|
|
387
|
-
ts = None
|
|
388
|
-
if ts is None:
|
|
389
|
-
ts = datetime.fromtimestamp(os.path.getmtime(ki_path))
|
|
390
|
-
return (datetime.now() - ts).total_seconds() / 86400
|
|
391
412
|
|
|
392
413
|
|
|
393
414
|
def _has_source_code():
|
|
@@ -544,11 +565,12 @@ def check_prd_templates():
|
|
|
544
565
|
problem('PRD 模板缺失: ' + md, '需要 AI 从团队章程 docx 重新蒸馏')
|
|
545
566
|
|
|
546
567
|
# Qoder 全系列载体: rules 在 IDE/Quest 生效, AGENTS.md 在 CLI 生效
|
|
568
|
+
# (Trellis 化: rules 是引擎的一部分, 由 wlkj init/update 生成, 不在团队 git 里)
|
|
547
569
|
rules_file = os.path.join(BASE, '.qoder', 'rules', 'wl-pipeline.md')
|
|
548
570
|
if os.path.isfile(rules_file):
|
|
549
|
-
say(OK, '.qoder/rules/wl-pipeline.md (Qoder IDE/Quest
|
|
571
|
+
say(OK, '.qoder/rules/wl-pipeline.md (Qoder IDE/Quest 规则载体, wlkj 生成)')
|
|
550
572
|
else:
|
|
551
|
-
problem('.qoder/rules/wl-pipeline.md 缺失', 'Quest 模式将不知道工作流规则,
|
|
573
|
+
problem('.qoder/rules/wl-pipeline.md 缺失', 'Quest 模式将不知道工作流规则, 跑 npx @hupan56/wlkj update 重新生成')
|
|
552
574
|
if os.path.isfile(os.path.join(BASE, 'AGENTS.md')):
|
|
553
575
|
say(OK, 'AGENTS.md (Qoder CLI / 其他 Agent 工具载体)')
|
|
554
576
|
else:
|
|
@@ -590,6 +612,21 @@ def check_weekly(fix):
|
|
|
590
612
|
def check_qoderwork():
|
|
591
613
|
"""检查 QoderWork 桌面端是否已安装本项目的技能(junction 到 ~/.qoderwork/skills/)。"""
|
|
592
614
|
print('\n--- 9. QoderWork 桌面端技能 (可选) ---')
|
|
615
|
+
|
|
616
|
+
# ★ v3.0 新增: launcher 文件就位检查 (全局, 缺失则所有 stdio MCP 黄灯)
|
|
617
|
+
# 场景: 换机器后没跑 install_qoderwork, mcp.json 引用的 launcher 不存在
|
|
618
|
+
home = os.environ.get('USERPROFILE') or os.environ.get('HOME') or os.path.expanduser('~')
|
|
619
|
+
launcher = os.path.join(home, '.qoderwork', 'mcp_launcher.py')
|
|
620
|
+
mcp_json = os.path.join(home, '.qoderwork', 'mcp.json')
|
|
621
|
+
if os.path.isfile(mcp_json):
|
|
622
|
+
# 装了 QoderWork 才检查 launcher (没装 mcp.json 的不算缺失)
|
|
623
|
+
if not os.path.isfile(launcher):
|
|
624
|
+
say(BAD, 'mcp_launcher.py 缺失: {} (所有 STDIO MCP 会黄灯)'.format(launcher))
|
|
625
|
+
print(' -> 跑: python .qoder/scripts/install_qoderwork.py')
|
|
626
|
+
issues.append('mcp_launcher.py 缺失')
|
|
627
|
+
else:
|
|
628
|
+
say(OK, 'mcp_launcher.py 就位 (STDIO MCP 启动器)')
|
|
629
|
+
|
|
593
630
|
src_skills = os.path.join(BASE, '.qoder', 'skills')
|
|
594
631
|
if not os.path.isdir(src_skills):
|
|
595
632
|
say(WARN, '.qoder/skills/ 不存在, 跳过 QoderWork 检查')
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
# v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
|
|
3
|
+
import os as _o, sys as _s
|
|
4
|
+
_cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
|
|
5
|
+
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
6
|
+
from bootstrap import setup; setup()
|
|
7
|
+
|
|
2
8
|
"""
|
|
3
9
|
install_qoderwork.py - 把 .qoder/skills/ 安装到 QoderWork 桌面端可识别的位置
|
|
4
10
|
|
|
@@ -38,9 +44,9 @@ if sys.platform == "win32":
|
|
|
38
44
|
except (AttributeError, IOError):
|
|
39
45
|
pass
|
|
40
46
|
|
|
41
|
-
# 路径自检:项目根 =
|
|
47
|
+
# 路径自检:项目根 = 本文件上四级 (v3.0: setup/ -> scripts/ -> .qoder/ -> repo)
|
|
42
48
|
SCRIPT_DIR = Path(__file__).resolve().parent
|
|
43
|
-
PROJECT_ROOT = SCRIPT_DIR.parent.parent
|
|
49
|
+
PROJECT_ROOT = SCRIPT_DIR.parent.parent.parent # v3.0: setup子包多一层
|
|
44
50
|
SOURCE_SKILLS_DIR = PROJECT_ROOT / ".qoder" / "skills"
|
|
45
51
|
SOURCE_COMMANDS_DIR = PROJECT_ROOT / ".qoder" / "commands"
|
|
46
52
|
|
|
@@ -405,13 +411,14 @@ def rewrite_mcp_json_for_launcher():
|
|
|
405
411
|
return
|
|
406
412
|
|
|
407
413
|
# 选 Python 写进 mcp.json:
|
|
408
|
-
#
|
|
409
|
-
#
|
|
410
|
-
#
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
414
|
+
# v3.0 修复: 用装了核心依赖的 Python 绝对路径 (不用命令名)!
|
|
415
|
+
# 原因: QoderWork 桌面应用不继承 shell PATH, 命令名(python/py -3)找不到 → 黄灯。
|
|
416
|
+
# 绝对路径每次 install 时探测, 换机器重跑 update 自动刷新。
|
|
417
|
+
# 依赖查找: 先找装了 duckdb 的 python (find_python_with_core_deps),
|
|
418
|
+
# 找不到回退 detect_python_command。
|
|
419
|
+
try:
|
|
420
|
+
py_cmd = find_python_with_core_deps()
|
|
421
|
+
except Exception:
|
|
415
422
|
py_cmd = detect_python_command() or "python"
|
|
416
423
|
launcher = str(_HOME / ".qoderwork" / "mcp_launcher.py")
|
|
417
424
|
# MCP 名 → launcher 子命令
|
|
@@ -426,7 +433,7 @@ def rewrite_mcp_json_for_launcher():
|
|
|
426
433
|
entry = servers.get(srv)
|
|
427
434
|
# 全新机器: kg/mysql/lanhu 条目可能不存在 → 创建它 (launcher 模式)
|
|
428
435
|
if not entry:
|
|
429
|
-
servers[srv] = {"command": py_cmd, "args": [launcher, sub]}
|
|
436
|
+
servers[srv] = {"command": py_cmd, "args": [launcher, sub], "enabled": True}
|
|
430
437
|
changed = True
|
|
431
438
|
continue
|
|
432
439
|
# 已是 launcher 模式? 检查 command 是否需要更新 (Python 路径可能变了)
|
|
@@ -435,7 +442,11 @@ def rewrite_mcp_json_for_launcher():
|
|
|
435
442
|
# launcher 模式, 但 command 可能指向旧的/错的 Python → 更新
|
|
436
443
|
old_cmd = entry.get("command", "") if isinstance(entry, dict) else ""
|
|
437
444
|
if old_cmd != py_cmd:
|
|
438
|
-
servers[srv] = {"command": py_cmd, "args": [launcher, sub]}
|
|
445
|
+
servers[srv] = {"command": py_cmd, "args": [launcher, sub], "enabled": True}
|
|
446
|
+
changed = True
|
|
447
|
+
# 补 enabled (旧版可能没写, 导致黄灯)
|
|
448
|
+
if isinstance(entry, dict) and not entry.get("enabled"):
|
|
449
|
+
entry["enabled"] = True
|
|
439
450
|
changed = True
|
|
440
451
|
continue
|
|
441
452
|
# mysql env 抽离到独立文件
|
|
@@ -447,7 +458,7 @@ def rewrite_mcp_json_for_launcher():
|
|
|
447
458
|
except OSError:
|
|
448
459
|
pass
|
|
449
460
|
# 改成 launcher 模式
|
|
450
|
-
servers[srv] = {"command": py_cmd, "args": [launcher, sub]}
|
|
461
|
+
servers[srv] = {"command": py_cmd, "args": [launcher, sub], "enabled": True}
|
|
451
462
|
changed = True
|
|
452
463
|
|
|
453
464
|
if changed:
|
|
@@ -456,12 +467,9 @@ def rewrite_mcp_json_for_launcher():
|
|
|
456
467
|
QODERWORK_MCP_FILE.write_text(
|
|
457
468
|
json.dumps(cfg, indent=2, ensure_ascii=False) + "\n", encoding="utf-8")
|
|
458
469
|
print(f"\n--- mcp.json 重写为 launcher 模式 ---")
|
|
459
|
-
|
|
460
|
-
print(f" [UPD] kg/mysql/zentao/lanhu → command={py_cmd} (装了依赖的Python)")
|
|
461
|
-
else:
|
|
462
|
-
print(f" [UPD] kg/mysql/zentao/lanhu → command={py_cmd}")
|
|
470
|
+
print(f" [UPD] kg/mysql/zentao/lanhu → command={py_cmd} (命令名, 跨机器通用)")
|
|
463
471
|
print(f" args=[mcp_launcher.py, <名>] (launcher 内部找装依赖的 Python)")
|
|
464
|
-
print(f"
|
|
472
|
+
print(f" 不再写死绝对路径, 换机器/重装Python不会失效")
|
|
465
473
|
except OSError as e:
|
|
466
474
|
print(f" [ERR] mcp.json 重写失败: {e}")
|
|
467
475
|
|
|
@@ -488,7 +496,7 @@ def main():
|
|
|
488
496
|
print("MCP 配置刷新 (--mcp-only)")
|
|
489
497
|
print("=" * 56)
|
|
490
498
|
# 1. 复制 launcher
|
|
491
|
-
launcher_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "mcp_launcher.py"
|
|
499
|
+
launcher_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "mcp" / "mcp_launcher.py" # v3.0: mcp子包
|
|
492
500
|
launcher_dst = _HOME / ".qoderwork" / "mcp_launcher.py"
|
|
493
501
|
try:
|
|
494
502
|
launcher_dst.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -508,15 +516,17 @@ def main():
|
|
|
508
516
|
except Exception:
|
|
509
517
|
pass
|
|
510
518
|
# 4. 写 .repo-root 锚点 (launcher 定位仓库根用)
|
|
511
|
-
#
|
|
512
|
-
#
|
|
513
|
-
|
|
514
|
-
# PROJECT_ROOT 由本文件位置推出 (scripts/ -> .qoder/ -> repo), 与 cwd 无关。
|
|
519
|
+
# 防御: 二次验证 PROJECT_ROOT 是"真仓库" (有 workspace/data/.git),
|
|
520
|
+
# 防止测试在临时目录跑 install 污染全局 .repo-root。
|
|
521
|
+
is_real_repo = any((PROJECT_ROOT / m).exists() for m in ('workspace', 'data', '.git'))
|
|
515
522
|
anchor = _HOME / ".qoderwork" / ".repo-root"
|
|
516
523
|
try:
|
|
517
524
|
anchor.parent.mkdir(parents=True, exist_ok=True)
|
|
518
|
-
|
|
519
|
-
|
|
525
|
+
if is_real_repo:
|
|
526
|
+
anchor.write_text(str(PROJECT_ROOT), encoding="utf-8")
|
|
527
|
+
print(f" [OK] .repo-root 锚点: {anchor} -> {PROJECT_ROOT}")
|
|
528
|
+
else:
|
|
529
|
+
print(f" [SKIP] .repo-root 未更新 ({PROJECT_ROOT} 非真仓库, 缺 workspace/data/.git)")
|
|
520
530
|
except OSError:
|
|
521
531
|
pass
|
|
522
532
|
return
|
|
@@ -659,7 +669,7 @@ def main():
|
|
|
659
669
|
# QoderWork 桌面端工作目录是临时会话目录, 不是仓库根, 相对路径失效。
|
|
660
670
|
# repo_root.py 从 mcp.json 反推仓库根, 命令文件靠它定位脚本/模板。
|
|
661
671
|
if action in ("install", "check"):
|
|
662
|
-
repo_root_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "repo_root.py"
|
|
672
|
+
repo_root_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "setup" / "repo_root.py" # v3.0: setup子包
|
|
663
673
|
repo_root_dst = _HOME / ".qoderwork" / "repo_root.py"
|
|
664
674
|
if repo_root_src.is_file():
|
|
665
675
|
if action == "check":
|
|
@@ -684,7 +694,7 @@ def main():
|
|
|
684
694
|
# .repo-root 锚点文件让 launcher 能定位仓库根 (不依赖 mcp.json 里的路径)。
|
|
685
695
|
if action in ("install", "check"):
|
|
686
696
|
print(f"\n--- mcp_launcher.py (统一 MCP 启动器) ---")
|
|
687
|
-
launcher_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "mcp_launcher.py"
|
|
697
|
+
launcher_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "mcp" / "mcp_launcher.py" # v3.0: mcp子包
|
|
688
698
|
launcher_dst = _HOME / ".qoderwork" / "mcp_launcher.py"
|
|
689
699
|
anchor_dst = _HOME / ".qoderwork" / ".repo-root"
|
|
690
700
|
if action == "check":
|