@hupan56/wlkj 3.3.5 → 3.3.6
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/package.json
CHANGED
|
@@ -51,9 +51,21 @@ from foundation.integrations.zentao_client import ZentaoClient
|
|
|
51
51
|
# ============================================================
|
|
52
52
|
|
|
53
53
|
def _zentao_creds():
|
|
54
|
-
"""
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
"""构建禅道客户端。返回 (client, preset_account)。
|
|
55
|
+
|
|
56
|
+
凭据源优先级:
|
|
57
|
+
① 云平台 per-user 凭据(Option A:get_zentao_creds)—— account 已知(preset)
|
|
58
|
+
② 本地 .qoder/config.yaml + secrets/zentao.env —— account 走 member.json
|
|
59
|
+
云凭据优先:demo 机器在内网可达禅道,平台凭据比本地文件更可能是最新配的。
|
|
60
|
+
凭据全无 → (None, '')。
|
|
61
|
+
"""
|
|
62
|
+
c = _cloud_zentao_creds()
|
|
63
|
+
if c and c.get('ok') and c.get('url') and c.get('account') and c.get('password'):
|
|
64
|
+
try:
|
|
65
|
+
return ZentaoClient(c['url'], c['account'], c['password']), c['account']
|
|
66
|
+
except Exception:
|
|
67
|
+
pass
|
|
68
|
+
return ZentaoClient.from_config(), ''
|
|
57
69
|
|
|
58
70
|
|
|
59
71
|
def _cloud_my_panel():
|
|
@@ -107,6 +119,52 @@ def _cloud_my_panel():
|
|
|
107
119
|
return data # {ok:True/False, ...}
|
|
108
120
|
|
|
109
121
|
|
|
122
|
+
def _cloud_zentao_creds():
|
|
123
|
+
"""Option A:从平台取禅道凭据(url/account/password 解密)。
|
|
124
|
+
|
|
125
|
+
用途:云到禅道被防火墙挡(my-panel 登录失败)时,本机(demo 机器,内网可达)
|
|
126
|
+
用平台凭据直连禅道拉真实数据。凭据随绑定 token 取本人配置(同信任级)。
|
|
127
|
+
Returns: {ok:True, url, account, password} 或 None(云不可达/未配置)。
|
|
128
|
+
"""
|
|
129
|
+
import json as _json
|
|
130
|
+
import urllib.request as _u
|
|
131
|
+
cfg_candidates = []
|
|
132
|
+
try:
|
|
133
|
+
from foundation.core.paths import get_repo_root
|
|
134
|
+
cfg_candidates.append(os.path.join(str(get_repo_root()), '.qoder', 'mcp_config.json'))
|
|
135
|
+
except Exception:
|
|
136
|
+
pass
|
|
137
|
+
cfg_candidates.append(os.path.join(_SCRIPTS, '..', 'mcp_config.json'))
|
|
138
|
+
token, url = '', ''
|
|
139
|
+
for cp in cfg_candidates:
|
|
140
|
+
try:
|
|
141
|
+
with open(cp, encoding='utf-8') as f:
|
|
142
|
+
cfg = _json.load(f)
|
|
143
|
+
srv = (cfg.get('mcpServers') or {}).get('wlinkj-knowledge') or {}
|
|
144
|
+
token = srv.get('token', '')
|
|
145
|
+
url = (srv.get('url') or '').rstrip('/')
|
|
146
|
+
if token and url:
|
|
147
|
+
break
|
|
148
|
+
except Exception:
|
|
149
|
+
continue
|
|
150
|
+
if not token or not url:
|
|
151
|
+
return None
|
|
152
|
+
endpoint = url if url.endswith('/mcp') else url + '/mcp'
|
|
153
|
+
body = _json.dumps({"jsonrpc": "2.0", "id": 1, "method": "tools/call",
|
|
154
|
+
"params": {"name": "get_zentao_creds", "arguments": {}}}).encode('utf-8')
|
|
155
|
+
req = _u.Request(endpoint, data=body, method='POST')
|
|
156
|
+
req.add_header('Content-Type', 'application/json')
|
|
157
|
+
req.add_header('X-MCP-Token', token)
|
|
158
|
+
try:
|
|
159
|
+
with _u.urlopen(req, timeout=15) as resp:
|
|
160
|
+
r = _json.loads(resp.read().decode('utf-8', errors='replace'))
|
|
161
|
+
text = r.get('result', {}).get('content', [{}])[0].get('text', '')
|
|
162
|
+
data = _json.loads(text) if text else {}
|
|
163
|
+
return data if data.get('ok') else None
|
|
164
|
+
except Exception:
|
|
165
|
+
return None
|
|
166
|
+
|
|
167
|
+
|
|
110
168
|
def _resolve_my_account(developer):
|
|
111
169
|
"""解析当前 developer → 禅道 account。返回 (account, 错误原因)。"""
|
|
112
170
|
mem = get_member(developer)
|
|
@@ -451,28 +509,31 @@ def fetch_workbench(include_closed=False, kind=None):
|
|
|
451
509
|
else:
|
|
452
510
|
cloud_error = None # 云不可达(switch_project 没跑/平台宕机)→ 静默回退本地
|
|
453
511
|
|
|
454
|
-
# ①
|
|
455
|
-
client = _zentao_creds()
|
|
512
|
+
# ① 凭据(云平台优先 Option A,回退本地文件)
|
|
513
|
+
client, preset_account = _zentao_creds()
|
|
456
514
|
if client is None:
|
|
457
|
-
base_msg = ('禅道凭据未配置。推荐在【平台设置 → 禅道】配置(panel
|
|
515
|
+
base_msg = ('禅道凭据未配置。推荐在【平台设置 → 禅道】配置(panel 自动走云取凭据);'
|
|
458
516
|
'或本地 .qoder/config.yaml 的 zentao.url + secrets/zentao.env 账号密码。')
|
|
459
517
|
if cloud_error:
|
|
460
|
-
base_msg += '
|
|
518
|
+
base_msg += '(云 my-panel 失败:%s)' % cloud_error
|
|
461
519
|
return {'ok': False, 'error': base_msg}, 3
|
|
462
520
|
|
|
463
521
|
ok, msg = client.credentials_ok()
|
|
464
522
|
if not ok:
|
|
465
523
|
return {'ok': False, 'error': '禅道凭据不完整: %s' % msg}, 3
|
|
466
524
|
|
|
467
|
-
# ②
|
|
525
|
+
# ② 内网连通(本机能否直连禅道——demo 机器在内网可达)
|
|
468
526
|
ok, msg = client.check_intranet()
|
|
469
527
|
if not ok:
|
|
470
|
-
return {'ok': False, 'error': '
|
|
528
|
+
return {'ok': False, 'error': '本机连不上禅道内网: %s' % msg}, 5
|
|
471
529
|
|
|
472
|
-
# ③
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
530
|
+
# ③ 归属(云凭据带的 account 优先;否则走 member.json)
|
|
531
|
+
if preset_account:
|
|
532
|
+
my_account = preset_account
|
|
533
|
+
else:
|
|
534
|
+
my_account, err = _resolve_my_account(developer) if developer else (None, '未识别当前开发者身份。')
|
|
535
|
+
if not my_account:
|
|
536
|
+
return {'ok': False, 'error': err}, 3
|
|
476
537
|
|
|
477
538
|
# ④ 收集 (三域并行, 按 kind 决定取哪几域)
|
|
478
539
|
from concurrent.futures import ThreadPoolExecutor
|