@hupan56/wlkj 3.3.13 → 3.3.14
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 +1 -23
- package/package.json +29 -29
- package/templates/qoder/agents/design-agent.md +20 -0
- package/templates/qoder/agents/spec-generator.md +21 -0
- package/templates/qoder/commands/optional/wl-spec.md +2 -12
- package/templates/qoder/commands/optional/wl-status.md +0 -8
- package/templates/qoder/commands/wl-code.md +0 -8
- package/templates/qoder/commands/wl-commit.md +1 -11
- package/templates/qoder/commands/wl-init.md +129 -129
- package/templates/qoder/commands/wl-prd.md +0 -24
- package/templates/qoder/commands/wl-search.md +11 -26
- package/templates/qoder/commands/wl-task.md +1 -11
- package/templates/qoder/commands/wl-test.md +0 -8
- package/templates/qoder/config.yaml +8 -3
- package/templates/qoder/hooks/session-start.py +365 -384
- package/templates/qoder/hooks/stop-eval.py +254 -383
- package/templates/qoder/scripts/capability/adapters/mcp.py +314 -322
- package/templates/qoder/scripts/capability/registry.py +248 -245
- package/templates/qoder/scripts/capability/registry_mcp.py +4 -10
- package/templates/qoder/scripts/capability/smoke_test_report.json.new +94 -0
- package/templates/qoder/scripts/deployment/setup/init_doctor.py +2 -6
- package/templates/qoder/scripts/deployment/setup/install_qoderwork.py +14 -0
- package/templates/qoder/scripts/deployment/setup/setup.py +2 -16
- package/templates/qoder/scripts/domain/integration/return_to_platform.py +2 -4
- package/templates/qoder/scripts/domain/integration/spec_upload.py +4 -4
- package/templates/qoder/scripts/domain/kg/build/build_entity_registry.py +12 -12
- package/templates/qoder/scripts/domain/kg/build/build_relations.py +12 -12
- package/templates/qoder/scripts/domain/kg/extract/asset/__init__.py +10 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/asset_tree.py +57 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/discussion_importer.py +62 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/prd_importer.py +146 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/prototype_importer.py +64 -0
- package/templates/qoder/scripts/domain/kg/extract/asset/returns_importer.py +52 -0
- package/templates/qoder/scripts/domain/kg/extract/build_goal3.py +104 -0
- package/templates/qoder/scripts/domain/kg/extract/build_goal4.py +55 -0
- package/templates/qoder/scripts/domain/kg/extract/build_goal5.py +95 -0
- package/templates/qoder/scripts/domain/kg/extract/db/__init__.py +8 -0
- package/templates/qoder/scripts/domain/kg/extract/db/data_profile.py +22 -0
- package/templates/qoder/scripts/domain/kg/extract/db/fk_extractor.py +55 -0
- package/templates/qoder/scripts/domain/kg/extract/db/schema_extractor.py +90 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/__init__.py +9 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/community_summarizer.py +206 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/embed_builder.py +132 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/naming_matcher.py +80 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/promote.py +59 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/recompute.py +93 -0
- package/templates/qoder/scripts/domain/kg/extract/inference/weak_link.py +421 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/__init__.py +9 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/all.py +79 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/mapper_parser.py +99 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/relation_builder.py +69 -0
- package/templates/qoder/scripts/domain/kg/extract/mybatis/sql_extractor.py +78 -0
- package/templates/qoder/scripts/domain/kg/extract/prd/__init__.py +8 -0
- package/templates/qoder/scripts/domain/kg/extract/prd/prd_chunk_embed.py +105 -0
- package/templates/qoder/scripts/domain/kg/extract/prd/prd_llm_extract.py +153 -0
- package/templates/qoder/scripts/domain/kg/extract/prd/req_anchor.py +120 -0
- package/templates/qoder/scripts/domain/kg/graph/kg_link_db.py +235 -0
- package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +5 -41
- package/templates/qoder/scripts/domain/kg/kg.py +0 -14
- package/templates/qoder/scripts/domain/kg/search/enrich_prompt.py +238 -0
- package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
- package/templates/qoder/scripts/domain/kg/switch_project.py +2 -2
- package/templates/qoder/scripts/domain/kg/sync_repowiki.py +109 -0
- package/templates/qoder/scripts/domain/task/wlkj_panel.py +1348 -1503
- package/templates/qoder/scripts/engine/poller.py +219 -0
- package/templates/qoder/scripts/foundation/bootstrap.py +145 -156
- package/templates/qoder/scripts/orchestration/wlkj.py +189 -306
- package/templates/qoder/settings.json +0 -8
- package/templates/qoder/skills/wl-spec/SKILL.md +1 -1
- package/templates/qoder/commands/wl-data.md +0 -46
- package/templates/qoder/commands/wl-fix.md +0 -47
- package/templates/qoder/commands/wl-knowledge.md +0 -41
- package/templates/qoder/commands/wl-review.md +0 -49
- package/templates/qoder/contracts/insight.md +0 -55
- package/templates/qoder/hooks/pre-tool-use-commit.py +0 -124
- package/templates/qoder/scripts/foundation/io/context_cache.py +0 -94
- package/templates/qoder/scripts/tool_guide.md +0 -70
- package/templates/qoder/scripts/validation/eval/alignment_matrix.py +0 -176
- package/templates/qoder/scripts/validation/eval/bf2_content_fidelity.py +0 -110
- package/templates/qoder/scripts/validation/eval/bf2_llmjudge.py +0 -104
- package/templates/qoder/scripts/validation/eval/bf_score.py +0 -218
- package/templates/qoder/scripts/validation/eval/code_flywheel.py +0 -150
- package/templates/qoder/scripts/validation/eval/dispatcher_ab.py +0 -156
- package/templates/qoder/scripts/validation/eval/dispatcher_ab_2026-07-21.json +0 -23
- package/templates/qoder/scripts/validation/eval/feature_fidelity_flywheel.py +0 -143
- package/templates/qoder/scripts/validation/eval/gradient_matrix.py +0 -261
- package/templates/qoder/scripts/validation/eval/gradient_matrix_baseline_2026-07-21.json +0 -33
- package/templates/qoder/scripts/validation/eval/metrics_dashboard.py +0 -105
- package/templates/qoder/scripts/validation/eval/multi_turn_flywheel.py +0 -118
- package/templates/qoder/scripts/validation/eval/prd_fidelity_flywheel.py +0 -128
- package/templates/qoder/scripts/validation/eval/prd_flywheel.py +0 -148
- package/templates/qoder/scripts/validation/eval/prototype_fidelity_flywheel.py +0 -166
- package/templates/qoder/scripts/validation/eval/recall_flywheel.py +0 -148
- package/templates/qoder/scripts/validation/eval/robustness_flywheel.py +0 -139
- package/templates/qoder/scripts/validation/eval/speed_accuracy_flywheel.py +0 -188
- package/templates/qoder/scripts/validation/eval/task_flywheel.py +0 -124
- package/templates/qoder/scripts/validation/eval/token_flywheel.py +0 -88
- package/templates/qoder/scripts/validation/metrics/eval_code_ac.py +0 -177
- package/templates/qoder/scripts/validation/metrics/lint_cases.py +0 -170
- package/templates/qoder/scripts/validation/test/test_context_cache.py +0 -78
- package/templates/qoder/scripts/validation/test/test_lint_cases.py +0 -60
- package/templates/qoder/scripts/validation/test/test_pre_tool_use_commit.py +0 -70
- package/templates/workspace/specs/REQ-TEST-CTX/.context-cache.json +0 -1
|
@@ -1,245 +1,248 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""
|
|
3
|
-
capability.registry —— 宿主发现 + Nexus Facade。
|
|
4
|
-
|
|
5
|
-
设计模式:
|
|
6
|
-
- Registry(HOST_TABLE 单一事实源,泛化 common.active_task._ENV_SESSION_KEYS)
|
|
7
|
-
- Facade(resolve() 一行入口)
|
|
8
|
-
- Bridge(Cap 抽象 × 宿主实现 正交)
|
|
9
|
-
|
|
10
|
-
主轴: 工作流面向能力编程,不面向宿主。
|
|
11
|
-
cap = resolve()
|
|
12
|
-
cap.memory.recall(...) # 不管在 QoderWork 还是 CLI,同一行代码
|
|
13
|
-
"""
|
|
14
|
-
from __future__ import annotations
|
|
15
|
-
|
|
16
|
-
import os
|
|
17
|
-
from typing import Any
|
|
18
|
-
|
|
19
|
-
from .caps import (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
"
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
"
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
"
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
#
|
|
94
|
-
"
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
self.
|
|
132
|
-
self.
|
|
133
|
-
self.
|
|
134
|
-
self.
|
|
135
|
-
self.
|
|
136
|
-
self.
|
|
137
|
-
self.
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"
|
|
151
|
-
"
|
|
152
|
-
"
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
#
|
|
165
|
-
#
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
mcp_servers
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
capability.registry —— 宿主发现 + Nexus Facade。
|
|
4
|
+
|
|
5
|
+
设计模式:
|
|
6
|
+
- Registry(HOST_TABLE 单一事实源,泛化 common.active_task._ENV_SESSION_KEYS)
|
|
7
|
+
- Facade(resolve() 一行入口)
|
|
8
|
+
- Bridge(Cap 抽象 × 宿主实现 正交)
|
|
9
|
+
|
|
10
|
+
主轴: 工作流面向能力编程,不面向宿主。
|
|
11
|
+
cap = resolve()
|
|
12
|
+
cap.memory.recall(...) # 不管在 QoderWork 还是 CLI,同一行代码
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
from .caps import (
|
|
20
|
+
NoOpCronCap,
|
|
21
|
+
NoOpNotifyCap,
|
|
22
|
+
NoOpPresentCap,
|
|
23
|
+
NoOpSandboxCap,
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# =============================================================================
|
|
28
|
+
# HOST_TABLE —— 宿主注册表
|
|
29
|
+
# -----------------------------------------------------------------------------
|
|
30
|
+
# 泛化 common/active_task.py:_ENV_SESSION_KEYS 的 7 宿主表:
|
|
31
|
+
# 从"只探测身份"扩展为"身份 + 能力清单"。
|
|
32
|
+
#
|
|
33
|
+
# 现在最小形态: Python dict。
|
|
34
|
+
# 未来完整形态: manifests/*.yaml 声明式文件(每宿主一份)。
|
|
35
|
+
# 迁移路径: dict → yaml,resolve() 接口不变,工作流零改动。
|
|
36
|
+
# =============================================================================
|
|
37
|
+
|
|
38
|
+
HOST_TABLE: dict[str, dict] = {
|
|
39
|
+
# ── Qoder 系列(第一宿主系列,2026-07 对齐最新产品线)─────────────
|
|
40
|
+
# 主开发宿主 + 办公产品。(Qoder CLI / Cloud Agents 后续按需再加;QoderWake 架构性不接。)
|
|
41
|
+
# features = 引擎已接(非 NoOp adapter);native = 产品原生能力(仅建模,不算实现)。
|
|
42
|
+
"qoder-desktop": {
|
|
43
|
+
# Qoder 1.0 "Autonomous Development Desktop"(原 qoder-ide;Quest Window/Agent Mode 是其模式,故原 qoder-quest 合并于此)
|
|
44
|
+
"detect": ("QODER_DESKTOP", "QODER_IDE"),
|
|
45
|
+
"features": ("mcp", "memory", "cron", "present"),
|
|
46
|
+
"native": ("agent-mode", "context-engine", "vm-sandbox", "hooks", "skills", "mcp-sse"),
|
|
47
|
+
"mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
|
|
48
|
+
"note": "Qoder Desktop/IDE 1.0(主开发宿主;Quest 是其模式,非独立宿主)",
|
|
49
|
+
},
|
|
50
|
+
"qoder-work": {
|
|
51
|
+
# QoderWork:办公产品(非开发者,文档/报告/PPT/M365)。~/.qoderwork/ 投影 + qoder_show_widget 是其接入点。
|
|
52
|
+
"detect": ("QODER_SESSION_ID",),
|
|
53
|
+
"features": ("mcp", "memory", "cron", "present"),
|
|
54
|
+
"native": ("office-agent", "m365", "human-in-loop", "hooks", "show-widget"),
|
|
55
|
+
"mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
|
|
56
|
+
"note": "QoderWork 桌面办公 Agent(非开发者;文档/PPT/M365);~/.qoderwork/ 投影入口",
|
|
57
|
+
},
|
|
58
|
+
# ── 其他宿主(通用 AI 工具)────────────────────────────────
|
|
59
|
+
"codex": {
|
|
60
|
+
"detect": ("CODEX_SESSION_ID", "CODEX_THREAD_ID"),
|
|
61
|
+
"features": ("repo", "identity"),
|
|
62
|
+
"mcp_servers": [],
|
|
63
|
+
"note": "OpenAI Codex CLI",
|
|
64
|
+
},
|
|
65
|
+
"claude": {
|
|
66
|
+
"detect": ("CLAUDE_SESSION_ID", "CLAUDE_CODE_SESSION_ID"),
|
|
67
|
+
"features": ("repo", "identity"),
|
|
68
|
+
"mcp_servers": [],
|
|
69
|
+
"note": "Claude Code",
|
|
70
|
+
},
|
|
71
|
+
"cursor": {
|
|
72
|
+
"detect": ("CURSOR_SESSION_ID",),
|
|
73
|
+
"features": ("repo", "identity"),
|
|
74
|
+
"mcp_servers": [],
|
|
75
|
+
},
|
|
76
|
+
"opencode": {
|
|
77
|
+
"detect": ("OPENCODE_SESSION_ID", "OPENCODE_RUN_ID"),
|
|
78
|
+
"features": ("repo", "identity"),
|
|
79
|
+
"mcp_servers": [],
|
|
80
|
+
},
|
|
81
|
+
"gemini": {
|
|
82
|
+
"detect": ("GEMINI_SESSION_ID",),
|
|
83
|
+
"features": ("repo", "identity"),
|
|
84
|
+
"mcp_servers": [],
|
|
85
|
+
},
|
|
86
|
+
"copilot": {
|
|
87
|
+
"detect": ("COPILOT_SESSION_ID",),
|
|
88
|
+
"features": ("repo", "identity"),
|
|
89
|
+
"mcp_servers": [],
|
|
90
|
+
},
|
|
91
|
+
# ── 兜底 ──────────────────────────────────────────────────
|
|
92
|
+
"cli": {
|
|
93
|
+
"detect": (), # 兜底:无 env 命中即为 CLI / 任意宿主
|
|
94
|
+
"features": ("repo", "identity", "context", "memory", "mcp"),
|
|
95
|
+
# 本地 stdio transport 经 mcp_launcher spawn 子进程, 不依赖宿主原生 MCP。
|
|
96
|
+
# 故 CLI 能起全部本地 server (kg/zentao/mysql/lanhu), 与 QoderWork 等价。
|
|
97
|
+
"mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
|
|
98
|
+
"note": "纯 CLI 兜底; MCP 走本地 spawn (非宿主原生), 其余走文件降级",
|
|
99
|
+
},
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def detect_host() -> str:
|
|
104
|
+
"""探测当前宿主名。
|
|
105
|
+
|
|
106
|
+
遍历 HOST_TABLE,第一个 env 命中的返回;无则 'cli'。
|
|
107
|
+
单一事实源 —— 替代散落在 active_task / autotest / mcp_launcher 的多处宿主探测。
|
|
108
|
+
"""
|
|
109
|
+
for name, info in HOST_TABLE.items():
|
|
110
|
+
if name == "cli":
|
|
111
|
+
continue
|
|
112
|
+
for env_var in info.get("detect", ()):
|
|
113
|
+
if os.environ.get(env_var):
|
|
114
|
+
return name
|
|
115
|
+
return "cli"
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
# =============================================================================
|
|
119
|
+
# Nexus Facade
|
|
120
|
+
# =============================================================================
|
|
121
|
+
|
|
122
|
+
class Nexus:
|
|
123
|
+
"""宿主能力 Facade —— 聚合所有能力,对外统一入口。
|
|
124
|
+
|
|
125
|
+
工作流永远只调 resolve() 拿到本对象,再访问 .memory/.mcp/...,
|
|
126
|
+
不直接 import 任何 adapter(Facade 模式)。
|
|
127
|
+
"""
|
|
128
|
+
|
|
129
|
+
def __init__(self, host_name: str, repo, identity, context, memory,
|
|
130
|
+
cron, notify, present, sandbox, mcp):
|
|
131
|
+
self.host_name = host_name
|
|
132
|
+
self.repo = repo
|
|
133
|
+
self.identity = identity
|
|
134
|
+
self.context = context
|
|
135
|
+
self.memory = memory
|
|
136
|
+
self.cron = cron
|
|
137
|
+
self.notify = notify
|
|
138
|
+
self.present = present
|
|
139
|
+
self.sandbox = sandbox
|
|
140
|
+
self.mcp = mcp
|
|
141
|
+
|
|
142
|
+
def describe(self) -> dict:
|
|
143
|
+
"""诊断:当前宿主 + 各能力 available 状态。"""
|
|
144
|
+
return {
|
|
145
|
+
"host": self.host_name,
|
|
146
|
+
"capabilities": {
|
|
147
|
+
"repo": _avail(self.repo),
|
|
148
|
+
"identity": _avail(self.identity),
|
|
149
|
+
"context": _avail(self.context),
|
|
150
|
+
"memory": _avail(self.memory),
|
|
151
|
+
"cron": _avail(self.cron),
|
|
152
|
+
"notify": _avail(self.notify),
|
|
153
|
+
"present": _avail(self.present),
|
|
154
|
+
"sandbox": _avail(self.sandbox),
|
|
155
|
+
"mcp": _avail(self.mcp),
|
|
156
|
+
},
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def _avail(cap) -> bool:
|
|
161
|
+
return bool(getattr(cap, "available", False))
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
# =============================================================================
|
|
165
|
+
# 能力装配(Bridge: Cap 抽象 × 宿主实现 正交)
|
|
166
|
+
# -----------------------------------------------------------------------------
|
|
167
|
+
# 每个 _resolve_xxx 是一个能力的装配点。新增能力(场景 B)= 加一个 _resolve_xxx
|
|
168
|
+
# + Nexus 属性。新增宿主实现 = 在对应 _resolve_xxx 里按 host 名分支。
|
|
169
|
+
# =============================================================================
|
|
170
|
+
|
|
171
|
+
def _resolve_repo(host: str):
|
|
172
|
+
"""核心能力:所有宿主都用文件降级版(无 ~/.qoderwork 依赖)。"""
|
|
173
|
+
from .adapters.cli import FileRepoCap
|
|
174
|
+
return FileRepoCap()
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _resolve_identity(host: str):
|
|
178
|
+
from .adapters.cli import FileIdentityCap
|
|
179
|
+
return FileIdentityCap()
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
def _resolve_context(host: str):
|
|
183
|
+
from .adapters.cli import FileContextCap
|
|
184
|
+
return FileContextCap()
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def _resolve_memory(host: str):
|
|
188
|
+
"""memory —— 职责链样板(见 memory_chain.py)。"""
|
|
189
|
+
from .memory_chain import build_memory_chain
|
|
190
|
+
return build_memory_chain(host)
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def _resolve_cron(host: str):
|
|
194
|
+
from .adapters.qw import QwCronCap
|
|
195
|
+
return QwCronCap() # 文件系统 cron,不依赖宿主
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def _resolve_notify(host: str):
|
|
199
|
+
"""L2 通知 —— 配了 WLKJ_NOTIFY_WEBHOOKS→WebhookNotifyCap(飞书/企微/钉钉);否则 NoOp 降级。"""
|
|
200
|
+
from .caps.notify import default_notify
|
|
201
|
+
return default_notify()
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _resolve_present(host: str):
|
|
205
|
+
"""L2 富展示 —— Qoder Desktop/Work 调 qoder_show_widget 嵌入对话; 其余 NoOp 降级表格。"""
|
|
206
|
+
if host in ("qoder-desktop", "qoder-work"):
|
|
207
|
+
try:
|
|
208
|
+
from .adapters.qw import QwPresentCap
|
|
209
|
+
return QwPresentCap()
|
|
210
|
+
except Exception:
|
|
211
|
+
pass
|
|
212
|
+
return NoOpPresentCap()
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def _resolve_sandbox(host: str):
|
|
216
|
+
"""L2 安全执行 —— env WLKJ_SANDBOX≠off→SubprocessSandboxCap(进程级隔离+超时);off→NoOp。"""
|
|
217
|
+
from .caps.sandbox import default_sandbox
|
|
218
|
+
return default_sandbox()
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _resolve_mcp(host: str):
|
|
222
|
+
"""L1 MCP 统一入口 —— 根据宿主声明的 mcp_servers 决定 spawn 哪些。"""
|
|
223
|
+
from .adapters.mcp import McpCap
|
|
224
|
+
info = HOST_TABLE.get(host, {})
|
|
225
|
+
mcp_servers = info.get("mcp_servers")
|
|
226
|
+
return McpCap(mcp_servers=mcp_servers)
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def resolve() -> Nexus:
|
|
230
|
+
"""解析当前环境,返回 Nexus Facade。
|
|
231
|
+
|
|
232
|
+
一行入口: cap = resolve()
|
|
233
|
+
内部: detect_host → 按宿主装配各 Cap → 注入 NoOp 兜底。
|
|
234
|
+
工作流代码零宿主感知。
|
|
235
|
+
"""
|
|
236
|
+
host = detect_host()
|
|
237
|
+
return Nexus(
|
|
238
|
+
host_name=host,
|
|
239
|
+
repo=_resolve_repo(host),
|
|
240
|
+
identity=_resolve_identity(host),
|
|
241
|
+
context=_resolve_context(host),
|
|
242
|
+
memory=_resolve_memory(host),
|
|
243
|
+
cron=_resolve_cron(host),
|
|
244
|
+
notify=_resolve_notify(host),
|
|
245
|
+
present=_resolve_present(host),
|
|
246
|
+
sandbox=_resolve_sandbox(host),
|
|
247
|
+
mcp=_resolve_mcp(host),
|
|
248
|
+
)
|
|
@@ -51,7 +51,7 @@ _KNOWLEDGE_SERVER_ALIASES = ["wlinkj-knowledge", "qoder-knowledge-graph"]
|
|
|
51
51
|
SERVERS: dict[str, dict] = {
|
|
52
52
|
"qoder-knowledge-graph": {
|
|
53
53
|
"kind": "http",
|
|
54
|
-
"url":
|
|
54
|
+
"url": "http://127.0.0.1:10010/mcp",
|
|
55
55
|
"note": "知识图谱。已改为 http 模式,指向资产平台 MCP 服务(POST /mcp JSON-RPC)",
|
|
56
56
|
},
|
|
57
57
|
"qoder-zentao": {
|
|
@@ -73,22 +73,16 @@ SERVERS: dict[str, dict] = {
|
|
|
73
73
|
|
|
74
74
|
|
|
75
75
|
def _mcp_config_path() -> Path:
|
|
76
|
-
"""定位 mcp_config.json(在仓库根/宿主下)。
|
|
77
|
-
|
|
78
|
-
★ switch_project.py 实际写入位置是 {repo}/.qoder/mcp_config.json(云模式连云 bind 后),
|
|
79
|
-
必须优先查这里——否则读不到 token,transport 用空 token 调云 MCP 鉴权失败(历史 bug:
|
|
80
|
-
引擎 search 全返回"MCP返回非JSON"+递归降级套娃)。老形态 repo/mcp_config.json 兼容。
|
|
81
|
-
"""
|
|
76
|
+
"""定位 mcp_config.json(在仓库根/宿主下)。"""
|
|
82
77
|
repo = _get_repo_root()
|
|
83
78
|
# registry_mcp.py 在 .../scripts/capability/, mcp_config.json 在宿主根(.qoder)。
|
|
84
79
|
for cand in [
|
|
85
|
-
repo / "
|
|
86
|
-
repo / "mcp_config.json", # 老形态:仓库根
|
|
80
|
+
repo / "mcp_config.json",
|
|
87
81
|
repo / "registry_mcp_config.json",
|
|
88
82
|
]:
|
|
89
83
|
if cand.is_file():
|
|
90
84
|
return cand
|
|
91
|
-
return repo / "
|
|
85
|
+
return repo / "mcp_config.json"
|
|
92
86
|
|
|
93
87
|
|
|
94
88
|
def _load_servers() -> dict[str, dict]:
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
{
|
|
2
|
+
"timestamp": "2026-06-26 21:25:55",
|
|
3
|
+
"servers": {
|
|
4
|
+
"qoder-knowledge-graph": {
|
|
5
|
+
"available": true,
|
|
6
|
+
"tools_indexed": 17,
|
|
7
|
+
"latency_ms": 437.0,
|
|
8
|
+
"sample_tools": [
|
|
9
|
+
"search_code",
|
|
10
|
+
"search_api",
|
|
11
|
+
"search_prd",
|
|
12
|
+
"get_impact",
|
|
13
|
+
"context_360"
|
|
14
|
+
],
|
|
15
|
+
"spawn_pid": 38616,
|
|
16
|
+
"status": "PASS"
|
|
17
|
+
},
|
|
18
|
+
"qoder-zentao": {
|
|
19
|
+
"available": true,
|
|
20
|
+
"tools_indexed": 66,
|
|
21
|
+
"latency_ms": 3657.0,
|
|
22
|
+
"sample_tools": [
|
|
23
|
+
"check_zentao_status",
|
|
24
|
+
"get_zentao_url",
|
|
25
|
+
"list_products",
|
|
26
|
+
"get_product",
|
|
27
|
+
"create_product"
|
|
28
|
+
],
|
|
29
|
+
"spawn_pid": 11224,
|
|
30
|
+
"status": "PASS"
|
|
31
|
+
},
|
|
32
|
+
"qoder-mysql": {
|
|
33
|
+
"available": true,
|
|
34
|
+
"tools_indexed": 6,
|
|
35
|
+
"latency_ms": 3484.0,
|
|
36
|
+
"sample_tools": [
|
|
37
|
+
"list_envs",
|
|
38
|
+
"query_schema",
|
|
39
|
+
"query_data",
|
|
40
|
+
"query_distinct",
|
|
41
|
+
"list_databases"
|
|
42
|
+
],
|
|
43
|
+
"spawn_pid": 37868,
|
|
44
|
+
"status": "PASS"
|
|
45
|
+
},
|
|
46
|
+
"lanhu": {
|
|
47
|
+
"available": true,
|
|
48
|
+
"tools_indexed": 13,
|
|
49
|
+
"latency_ms": 3156.0,
|
|
50
|
+
"sample_tools": [
|
|
51
|
+
"lanhu_resolve_invite_link",
|
|
52
|
+
"lanhu_list_product_documents",
|
|
53
|
+
"lanhu_get_pages",
|
|
54
|
+
"lanhu_get_ai_analyze_page_result",
|
|
55
|
+
"lanhu_get_designs"
|
|
56
|
+
],
|
|
57
|
+
"spawn_pid": 36836,
|
|
58
|
+
"status": "PASS"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"call_tool": {
|
|
62
|
+
"status": "PASS",
|
|
63
|
+
"latency_ms": 3953.0,
|
|
64
|
+
"text_preview": "Chinese: 保险 -> English: ins insurance vehlife/insurance\n\n[Carmg-H5] 12 files\n Carmg-H5/src/.../main/List.vue -> data/code/Carmg-H5/src/modules/icsAbnormalCenter/module/main/List.vue\n Carmg-H5/src/",
|
|
65
|
+
"is_error": false
|
|
66
|
+
},
|
|
67
|
+
"memory": {
|
|
68
|
+
"available": true,
|
|
69
|
+
"providers": [
|
|
70
|
+
{
|
|
71
|
+
"provider": "McpMemoryProvider",
|
|
72
|
+
"available": true,
|
|
73
|
+
"hit": true
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"provider": "FileMemoryCap",
|
|
77
|
+
"available": true,
|
|
78
|
+
"hit": false
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"provider": "NoOpMemoryCap",
|
|
82
|
+
"available": false,
|
|
83
|
+
"hit": false
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"status": "PASS"
|
|
87
|
+
},
|
|
88
|
+
"summary": {
|
|
89
|
+
"all_pass": true,
|
|
90
|
+
"active_servers": 4,
|
|
91
|
+
"total_servers": 4,
|
|
92
|
+
"total_tools": 102
|
|
93
|
+
}
|
|
94
|
+
}
|