@hupan56/wlkj 3.3.13 → 3.3.15

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.
Files changed (54) hide show
  1. package/bin/cli.js +0 -7
  2. package/package.json +29 -29
  3. package/templates/qoder/commands/optional/wl-spec.md +0 -8
  4. package/templates/qoder/commands/optional/wl-status.md +0 -8
  5. package/templates/qoder/commands/wl-code.md +0 -8
  6. package/templates/qoder/commands/wl-commit.md +0 -8
  7. package/templates/qoder/commands/wl-init.md +129 -129
  8. package/templates/qoder/commands/wl-search.md +0 -8
  9. package/templates/qoder/commands/wl-task.md +0 -8
  10. package/templates/qoder/commands/wl-test.md +0 -8
  11. package/templates/qoder/config.yaml +2 -3
  12. package/templates/qoder/contracts/insight.md +55 -55
  13. package/templates/qoder/hooks/pre-tool-use-commit.py +124 -124
  14. package/templates/qoder/hooks/session-start.py +384 -384
  15. package/templates/qoder/hooks/stop-eval.py +383 -383
  16. package/templates/qoder/scripts/capability/adapters/mcp.py +322 -322
  17. package/templates/qoder/scripts/capability/registry.py +245 -245
  18. package/templates/qoder/scripts/deployment/setup/install_qoderwork.py +14 -0
  19. package/templates/qoder/scripts/deployment/setup/setup.py +0 -11
  20. package/templates/qoder/scripts/domain/task/wlkj_panel.py +1503 -1503
  21. package/templates/qoder/scripts/foundation/bootstrap.py +145 -156
  22. package/templates/qoder/scripts/foundation/io/context_cache.py +94 -94
  23. package/templates/qoder/scripts/orchestration/wlkj.py +295 -306
  24. package/templates/qoder/scripts/tool_guide.md +70 -70
  25. package/templates/qoder/scripts/validation/eval/alignment_matrix.py +176 -176
  26. package/templates/qoder/scripts/validation/eval/bf2_content_fidelity.py +110 -110
  27. package/templates/qoder/scripts/validation/eval/bf2_llmjudge.py +104 -104
  28. package/templates/qoder/scripts/validation/eval/bf_score.py +218 -218
  29. package/templates/qoder/scripts/validation/eval/code_flywheel.py +150 -150
  30. package/templates/qoder/scripts/validation/eval/dispatcher_ab.py +156 -156
  31. package/templates/qoder/scripts/validation/eval/dispatcher_ab_2026-07-21.json +23 -23
  32. package/templates/qoder/scripts/validation/eval/feature_fidelity_flywheel.py +143 -143
  33. package/templates/qoder/scripts/validation/eval/gradient_matrix.py +261 -261
  34. package/templates/qoder/scripts/validation/eval/gradient_matrix_baseline_2026-07-21.json +33 -33
  35. package/templates/qoder/scripts/validation/eval/metrics_dashboard.py +105 -105
  36. package/templates/qoder/scripts/validation/eval/multi_turn_flywheel.py +118 -118
  37. package/templates/qoder/scripts/validation/eval/prd_fidelity_flywheel.py +128 -128
  38. package/templates/qoder/scripts/validation/eval/prd_flywheel.py +148 -148
  39. package/templates/qoder/scripts/validation/eval/prototype_fidelity_flywheel.py +166 -166
  40. package/templates/qoder/scripts/validation/eval/recall_flywheel.py +148 -148
  41. package/templates/qoder/scripts/validation/eval/robustness_flywheel.py +139 -139
  42. package/templates/qoder/scripts/validation/eval/speed_accuracy_flywheel.py +188 -188
  43. package/templates/qoder/scripts/validation/eval/task_flywheel.py +124 -124
  44. package/templates/qoder/scripts/validation/eval/token_flywheel.py +88 -88
  45. package/templates/qoder/scripts/validation/metrics/eval_code_ac.py +177 -177
  46. package/templates/qoder/scripts/validation/metrics/lint_cases.py +170 -170
  47. package/templates/qoder/scripts/validation/test/test_context_cache.py +78 -78
  48. package/templates/qoder/scripts/validation/test/test_lint_cases.py +60 -60
  49. package/templates/qoder/scripts/validation/test/test_pre_tool_use_commit.py +70 -70
  50. package/templates/qoder/commands/wl-data.md +0 -46
  51. package/templates/qoder/commands/wl-fix.md +0 -47
  52. package/templates/qoder/commands/wl-knowledge.md +0 -41
  53. package/templates/qoder/commands/wl-review.md +0 -49
  54. package/templates/workspace/specs/REQ-TEST-CTX/.context-cache.json +0 -1
@@ -1,245 +1,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
- NoOpPresentCap,
21
- )
22
-
23
-
24
- # =============================================================================
25
- # HOST_TABLE —— 宿主注册表
26
- # -----------------------------------------------------------------------------
27
- # 泛化 common/active_task.py:_ENV_SESSION_KEYS 的 7 宿主表:
28
- # 从"只探测身份"扩展为"身份 + 能力清单"。
29
- #
30
- # 现在最小形态: Python dict。
31
- # 未来完整形态: manifests/*.yaml 声明式文件(每宿主一份)。
32
- # 迁移路径: dict → yaml,resolve() 接口不变,工作流零改动。
33
- # =============================================================================
34
-
35
- HOST_TABLE: dict[str, dict] = {
36
- # ── Qoder 系列(第一宿主系列,2026-07 对齐最新产品线)─────────────
37
- # 主开发宿主 + 办公产品。(Qoder CLI / Cloud Agents 后续按需再加;QoderWake 架构性不接。)
38
- # features = 引擎已接(非 NoOp adapter);native = 产品原生能力(仅建模,不算实现)。
39
- "qoder-desktop": {
40
- # Qoder 1.0 "Autonomous Development Desktop"(原 qoder-ide;Quest Window/Agent Mode 是其模式,故原 qoder-quest 合并于此)
41
- "detect": ("QODER_DESKTOP", "QODER_IDE"),
42
- "features": ("mcp", "memory", "cron", "present"),
43
- "native": ("agent-mode", "context-engine", "vm-sandbox", "hooks", "skills", "mcp-sse"),
44
- "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
45
- "note": "Qoder Desktop/IDE 1.0(主开发宿主;Quest 是其模式,非独立宿主)",
46
- },
47
- "qoder-work": {
48
- # QoderWork:办公产品(非开发者,文档/报告/PPT/M365)。~/.qoderwork/ 投影 + qoder_show_widget 是其接入点。
49
- "detect": ("QODER_SESSION_ID",),
50
- "features": ("mcp", "memory", "cron", "present"),
51
- "native": ("office-agent", "m365", "human-in-loop", "hooks", "show-widget"),
52
- "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
53
- "note": "QoderWork 桌面办公 Agent(非开发者;文档/PPT/M365);~/.qoderwork/ 投影入口",
54
- },
55
- # ── 其他宿主(通用 AI 工具)────────────────────────────────
56
- "codex": {
57
- "detect": ("CODEX_SESSION_ID", "CODEX_THREAD_ID"),
58
- "features": ("repo", "identity"),
59
- "mcp_servers": [],
60
- "note": "OpenAI Codex CLI",
61
- },
62
- "claude": {
63
- "detect": ("CLAUDE_SESSION_ID", "CLAUDE_CODE_SESSION_ID"),
64
- "features": ("repo", "identity"),
65
- "mcp_servers": [],
66
- "note": "Claude Code",
67
- },
68
- "cursor": {
69
- "detect": ("CURSOR_SESSION_ID",),
70
- "features": ("repo", "identity"),
71
- "mcp_servers": [],
72
- },
73
- "opencode": {
74
- "detect": ("OPENCODE_SESSION_ID", "OPENCODE_RUN_ID"),
75
- "features": ("repo", "identity"),
76
- "mcp_servers": [],
77
- },
78
- "gemini": {
79
- "detect": ("GEMINI_SESSION_ID",),
80
- "features": ("repo", "identity"),
81
- "mcp_servers": [],
82
- },
83
- "copilot": {
84
- "detect": ("COPILOT_SESSION_ID",),
85
- "features": ("repo", "identity"),
86
- "mcp_servers": [],
87
- },
88
- # ── 兜底 ──────────────────────────────────────────────────
89
- "cli": {
90
- "detect": (), # 兜底:无 env 命中即为 CLI / 任意宿主
91
- "features": ("repo", "identity", "context", "memory", "mcp"),
92
- # 本地 stdio transport 经 mcp_launcher spawn 子进程, 不依赖宿主原生 MCP。
93
- # 故 CLI 能起全部本地 server (kg/zentao/mysql/lanhu), 与 QoderWork 等价。
94
- "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
95
- "note": "纯 CLI 兜底; MCP 走本地 spawn (非宿主原生), 其余走文件降级",
96
- },
97
- }
98
-
99
-
100
- def detect_host() -> str:
101
- """探测当前宿主名。
102
-
103
- 遍历 HOST_TABLE,第一个 env 命中的返回;无则 'cli'。
104
- 单一事实源 —— 替代散落在 active_task / autotest / mcp_launcher 的多处宿主探测。
105
- """
106
- for name, info in HOST_TABLE.items():
107
- if name == "cli":
108
- continue
109
- for env_var in info.get("detect", ()):
110
- if os.environ.get(env_var):
111
- return name
112
- return "cli"
113
-
114
-
115
- # =============================================================================
116
- # Nexus Facade
117
- # =============================================================================
118
-
119
- class Nexus:
120
- """宿主能力 Facade —— 聚合所有能力,对外统一入口。
121
-
122
- 工作流永远只调 resolve() 拿到本对象,再访问 .memory/.mcp/...,
123
- 不直接 import 任何 adapter(Facade 模式)。
124
- """
125
-
126
- def __init__(self, host_name: str, repo, identity, context, memory,
127
- cron, notify, present, sandbox, mcp):
128
- self.host_name = host_name
129
- self.repo = repo
130
- self.identity = identity
131
- self.context = context
132
- self.memory = memory
133
- self.cron = cron
134
- self.notify = notify
135
- self.present = present
136
- self.sandbox = sandbox
137
- self.mcp = mcp
138
-
139
- def describe(self) -> dict:
140
- """诊断:当前宿主 + 各能力 available 状态。"""
141
- return {
142
- "host": self.host_name,
143
- "capabilities": {
144
- "repo": _avail(self.repo),
145
- "identity": _avail(self.identity),
146
- "context": _avail(self.context),
147
- "memory": _avail(self.memory),
148
- "cron": _avail(self.cron),
149
- "notify": _avail(self.notify),
150
- "present": _avail(self.present),
151
- "sandbox": _avail(self.sandbox),
152
- "mcp": _avail(self.mcp),
153
- },
154
- }
155
-
156
-
157
- def _avail(cap) -> bool:
158
- return bool(getattr(cap, "available", False))
159
-
160
-
161
- # =============================================================================
162
- # 能力装配(Bridge: Cap 抽象 × 宿主实现 正交)
163
- # -----------------------------------------------------------------------------
164
- # 每个 _resolve_xxx 是一个能力的装配点。新增能力(场景 B)= 加一个 _resolve_xxx
165
- # + Nexus 属性。新增宿主实现 = 在对应 _resolve_xxx 里按 host 名分支。
166
- # =============================================================================
167
-
168
- def _resolve_repo(host: str):
169
- """核心能力:所有宿主都用文件降级版(无 ~/.qoderwork 依赖)。"""
170
- from .adapters.cli import FileRepoCap
171
- return FileRepoCap()
172
-
173
-
174
- def _resolve_identity(host: str):
175
- from .adapters.cli import FileIdentityCap
176
- return FileIdentityCap()
177
-
178
-
179
- def _resolve_context(host: str):
180
- from .adapters.cli import FileContextCap
181
- return FileContextCap()
182
-
183
-
184
- def _resolve_memory(host: str):
185
- """memory —— 职责链样板(见 memory_chain.py)。"""
186
- from .memory_chain import build_memory_chain
187
- return build_memory_chain(host)
188
-
189
-
190
- def _resolve_cron(host: str):
191
- from .adapters.qw import QwCronCap
192
- return QwCronCap() # 文件系统 cron,不依赖宿主
193
-
194
-
195
- def _resolve_notify(host: str):
196
- """L2 通知 —— 配了 WLKJ_NOTIFY_WEBHOOKS→WebhookNotifyCap(飞书/企微/钉钉);否则 NoOp 降级。"""
197
- from .caps.notify import default_notify
198
- return default_notify()
199
-
200
-
201
- def _resolve_present(host: str):
202
- """L2 富展示 —— Qoder Desktop/Work 调 qoder_show_widget 嵌入对话; 其余 NoOp 降级表格。"""
203
- if host in ("qoder-desktop", "qoder-work"):
204
- try:
205
- from .adapters.qw import QwPresentCap
206
- return QwPresentCap()
207
- except Exception:
208
- pass
209
- return NoOpPresentCap()
210
-
211
-
212
- def _resolve_sandbox(host: str):
213
- """L2 安全执行 —— env WLKJ_SANDBOX≠off→SubprocessSandboxCap(进程级隔离+超时);off→NoOp。"""
214
- from .caps.sandbox import default_sandbox
215
- return default_sandbox()
216
-
217
-
218
- def _resolve_mcp(host: str):
219
- """L1 MCP 统一入口 —— 根据宿主声明的 mcp_servers 决定 spawn 哪些。"""
220
- from .adapters.mcp import McpCap
221
- info = HOST_TABLE.get(host, {})
222
- mcp_servers = info.get("mcp_servers")
223
- return McpCap(mcp_servers=mcp_servers)
224
-
225
-
226
- def resolve() -> Nexus:
227
- """解析当前环境,返回 Nexus Facade。
228
-
229
- 一行入口: cap = resolve()
230
- 内部: detect_host → 按宿主装配各 Cap → 注入 NoOp 兜底。
231
- 工作流代码零宿主感知。
232
- """
233
- host = detect_host()
234
- return Nexus(
235
- host_name=host,
236
- repo=_resolve_repo(host),
237
- identity=_resolve_identity(host),
238
- context=_resolve_context(host),
239
- memory=_resolve_memory(host),
240
- cron=_resolve_cron(host),
241
- notify=_resolve_notify(host),
242
- present=_resolve_present(host),
243
- sandbox=_resolve_sandbox(host),
244
- mcp=_resolve_mcp(host),
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
+ NoOpPresentCap,
21
+ )
22
+
23
+
24
+ # =============================================================================
25
+ # HOST_TABLE —— 宿主注册表
26
+ # -----------------------------------------------------------------------------
27
+ # 泛化 common/active_task.py:_ENV_SESSION_KEYS 的 7 宿主表:
28
+ # 从"只探测身份"扩展为"身份 + 能力清单"。
29
+ #
30
+ # 现在最小形态: Python dict。
31
+ # 未来完整形态: manifests/*.yaml 声明式文件(每宿主一份)。
32
+ # 迁移路径: dict → yaml,resolve() 接口不变,工作流零改动。
33
+ # =============================================================================
34
+
35
+ HOST_TABLE: dict[str, dict] = {
36
+ # ── Qoder 系列(第一宿主系列,2026-07 对齐最新产品线)─────────────
37
+ # 主开发宿主 + 办公产品。(Qoder CLI / Cloud Agents 后续按需再加;QoderWake 架构性不接。)
38
+ # features = 引擎已接(非 NoOp adapter);native = 产品原生能力(仅建模,不算实现)。
39
+ "qoder-desktop": {
40
+ # Qoder 1.0 "Autonomous Development Desktop"(原 qoder-ide;Quest Window/Agent Mode 是其模式,故原 qoder-quest 合并于此)
41
+ "detect": ("QODER_DESKTOP", "QODER_IDE"),
42
+ "features": ("mcp", "memory", "cron", "present"),
43
+ "native": ("agent-mode", "context-engine", "vm-sandbox", "hooks", "skills", "mcp-sse"),
44
+ "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
45
+ "note": "Qoder Desktop/IDE 1.0(主开发宿主;Quest 是其模式,非独立宿主)",
46
+ },
47
+ "qoder-work": {
48
+ # QoderWork:办公产品(非开发者,文档/报告/PPT/M365)。~/.qoderwork/ 投影 + qoder_show_widget 是其接入点。
49
+ "detect": ("QODER_SESSION_ID",),
50
+ "features": ("mcp", "memory", "cron", "present"),
51
+ "native": ("office-agent", "m365", "human-in-loop", "hooks", "show-widget"),
52
+ "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
53
+ "note": "QoderWork 桌面办公 Agent(非开发者;文档/PPT/M365);~/.qoderwork/ 投影入口",
54
+ },
55
+ # ── 其他宿主(通用 AI 工具)────────────────────────────────
56
+ "codex": {
57
+ "detect": ("CODEX_SESSION_ID", "CODEX_THREAD_ID"),
58
+ "features": ("repo", "identity"),
59
+ "mcp_servers": [],
60
+ "note": "OpenAI Codex CLI",
61
+ },
62
+ "claude": {
63
+ "detect": ("CLAUDE_SESSION_ID", "CLAUDE_CODE_SESSION_ID"),
64
+ "features": ("repo", "identity"),
65
+ "mcp_servers": [],
66
+ "note": "Claude Code",
67
+ },
68
+ "cursor": {
69
+ "detect": ("CURSOR_SESSION_ID",),
70
+ "features": ("repo", "identity"),
71
+ "mcp_servers": [],
72
+ },
73
+ "opencode": {
74
+ "detect": ("OPENCODE_SESSION_ID", "OPENCODE_RUN_ID"),
75
+ "features": ("repo", "identity"),
76
+ "mcp_servers": [],
77
+ },
78
+ "gemini": {
79
+ "detect": ("GEMINI_SESSION_ID",),
80
+ "features": ("repo", "identity"),
81
+ "mcp_servers": [],
82
+ },
83
+ "copilot": {
84
+ "detect": ("COPILOT_SESSION_ID",),
85
+ "features": ("repo", "identity"),
86
+ "mcp_servers": [],
87
+ },
88
+ # ── 兜底 ──────────────────────────────────────────────────
89
+ "cli": {
90
+ "detect": (), # 兜底:无 env 命中即为 CLI / 任意宿主
91
+ "features": ("repo", "identity", "context", "memory", "mcp"),
92
+ # 本地 stdio transport 经 mcp_launcher spawn 子进程, 不依赖宿主原生 MCP。
93
+ # 故 CLI 能起全部本地 server (kg/zentao/mysql/lanhu), 与 QoderWork 等价。
94
+ "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
95
+ "note": "纯 CLI 兜底; MCP 走本地 spawn (非宿主原生), 其余走文件降级",
96
+ },
97
+ }
98
+
99
+
100
+ def detect_host() -> str:
101
+ """探测当前宿主名。
102
+
103
+ 遍历 HOST_TABLE,第一个 env 命中的返回;无则 'cli'。
104
+ 单一事实源 —— 替代散落在 active_task / autotest / mcp_launcher 的多处宿主探测。
105
+ """
106
+ for name, info in HOST_TABLE.items():
107
+ if name == "cli":
108
+ continue
109
+ for env_var in info.get("detect", ()):
110
+ if os.environ.get(env_var):
111
+ return name
112
+ return "cli"
113
+
114
+
115
+ # =============================================================================
116
+ # Nexus Facade
117
+ # =============================================================================
118
+
119
+ class Nexus:
120
+ """宿主能力 Facade —— 聚合所有能力,对外统一入口。
121
+
122
+ 工作流永远只调 resolve() 拿到本对象,再访问 .memory/.mcp/...,
123
+ 不直接 import 任何 adapter(Facade 模式)。
124
+ """
125
+
126
+ def __init__(self, host_name: str, repo, identity, context, memory,
127
+ cron, notify, present, sandbox, mcp):
128
+ self.host_name = host_name
129
+ self.repo = repo
130
+ self.identity = identity
131
+ self.context = context
132
+ self.memory = memory
133
+ self.cron = cron
134
+ self.notify = notify
135
+ self.present = present
136
+ self.sandbox = sandbox
137
+ self.mcp = mcp
138
+
139
+ def describe(self) -> dict:
140
+ """诊断:当前宿主 + 各能力 available 状态。"""
141
+ return {
142
+ "host": self.host_name,
143
+ "capabilities": {
144
+ "repo": _avail(self.repo),
145
+ "identity": _avail(self.identity),
146
+ "context": _avail(self.context),
147
+ "memory": _avail(self.memory),
148
+ "cron": _avail(self.cron),
149
+ "notify": _avail(self.notify),
150
+ "present": _avail(self.present),
151
+ "sandbox": _avail(self.sandbox),
152
+ "mcp": _avail(self.mcp),
153
+ },
154
+ }
155
+
156
+
157
+ def _avail(cap) -> bool:
158
+ return bool(getattr(cap, "available", False))
159
+
160
+
161
+ # =============================================================================
162
+ # 能力装配(Bridge: Cap 抽象 × 宿主实现 正交)
163
+ # -----------------------------------------------------------------------------
164
+ # 每个 _resolve_xxx 是一个能力的装配点。新增能力(场景 B)= 加一个 _resolve_xxx
165
+ # + Nexus 属性。新增宿主实现 = 在对应 _resolve_xxx 里按 host 名分支。
166
+ # =============================================================================
167
+
168
+ def _resolve_repo(host: str):
169
+ """核心能力:所有宿主都用文件降级版(无 ~/.qoderwork 依赖)。"""
170
+ from .adapters.cli import FileRepoCap
171
+ return FileRepoCap()
172
+
173
+
174
+ def _resolve_identity(host: str):
175
+ from .adapters.cli import FileIdentityCap
176
+ return FileIdentityCap()
177
+
178
+
179
+ def _resolve_context(host: str):
180
+ from .adapters.cli import FileContextCap
181
+ return FileContextCap()
182
+
183
+
184
+ def _resolve_memory(host: str):
185
+ """memory —— 职责链样板(见 memory_chain.py)。"""
186
+ from .memory_chain import build_memory_chain
187
+ return build_memory_chain(host)
188
+
189
+
190
+ def _resolve_cron(host: str):
191
+ from .adapters.qw import QwCronCap
192
+ return QwCronCap() # 文件系统 cron,不依赖宿主
193
+
194
+
195
+ def _resolve_notify(host: str):
196
+ """L2 通知 —— 配了 WLKJ_NOTIFY_WEBHOOKS→WebhookNotifyCap(飞书/企微/钉钉);否则 NoOp 降级。"""
197
+ from .caps.notify import default_notify
198
+ return default_notify()
199
+
200
+
201
+ def _resolve_present(host: str):
202
+ """L2 富展示 —— Qoder Desktop/Work 调 qoder_show_widget 嵌入对话; 其余 NoOp 降级表格。"""
203
+ if host in ("qoder-desktop", "qoder-work"):
204
+ try:
205
+ from .adapters.qw import QwPresentCap
206
+ return QwPresentCap()
207
+ except Exception:
208
+ pass
209
+ return NoOpPresentCap()
210
+
211
+
212
+ def _resolve_sandbox(host: str):
213
+ """L2 安全执行 —— env WLKJ_SANDBOX≠off→SubprocessSandboxCap(进程级隔离+超时);off→NoOp。"""
214
+ from .caps.sandbox import default_sandbox
215
+ return default_sandbox()
216
+
217
+
218
+ def _resolve_mcp(host: str):
219
+ """L1 MCP 统一入口 —— 根据宿主声明的 mcp_servers 决定 spawn 哪些。"""
220
+ from .adapters.mcp import McpCap
221
+ info = HOST_TABLE.get(host, {})
222
+ mcp_servers = info.get("mcp_servers")
223
+ return McpCap(mcp_servers=mcp_servers)
224
+
225
+
226
+ def resolve() -> Nexus:
227
+ """解析当前环境,返回 Nexus Facade。
228
+
229
+ 一行入口: cap = resolve()
230
+ 内部: detect_host → 按宿主装配各 Cap → 注入 NoOp 兜底。
231
+ 工作流代码零宿主感知。
232
+ """
233
+ host = detect_host()
234
+ return Nexus(
235
+ host_name=host,
236
+ repo=_resolve_repo(host),
237
+ identity=_resolve_identity(host),
238
+ context=_resolve_context(host),
239
+ memory=_resolve_memory(host),
240
+ cron=_resolve_cron(host),
241
+ notify=_resolve_notify(host),
242
+ present=_resolve_present(host),
243
+ sandbox=_resolve_sandbox(host),
244
+ mcp=_resolve_mcp(host),
245
+ )
@@ -438,6 +438,20 @@ def rewrite_mcp_json_for_launcher():
438
438
  }
439
439
  changed = False
440
440
  for srv, sub in name_map.items():
441
+ # 共识:kg 走云平台(默认 10.89.7.120:10010/mcp,config platform_mcp.url 可覆盖)
442
+ if srv == "qoder-knowledge-graph":
443
+ _pm = "http://10.89.7.120:10010/mcp"
444
+ try:
445
+ import yaml as _y
446
+ _cfg_p = get_repo_root() / ".qoder" / "config.yaml"
447
+ if _cfg_p.is_file():
448
+ _cfg = _y.safe_load(_cfg_p.read_text(encoding="utf-8")) or {}
449
+ _pm = (_cfg.get("platform_mcp") or {}).get("url", "") or _pm
450
+ except Exception:
451
+ pass
452
+ servers[srv] = {"url": _pm, "type": "sse", "enabled": True}
453
+ changed = True
454
+ continue
441
455
  entry = servers.get(srv)
442
456
  # 全新机器: kg/mysql/lanhu 条目可能不存在 → 创建它 (launcher 模式)
443
457
  if not entry:
@@ -1,16 +1,5 @@
1
1
  #!/usr/bin/env python3
2
2
  # -*- coding: utf-8 -*-
3
- # Windows 控制台 UTF-8 修复(ctypes 直调 Windows API,非子shell chcp)
4
- import sys as _s
5
- if _s.platform == 'win32':
6
- import ctypes as _ct, io as _io
7
- try:
8
- _ct.windll.kernel32.SetConsoleOutputCP(65001)
9
- _ct.windll.kernel32.SetConsoleCP(65001)
10
- _s.stdout = _io.TextIOWrapper(_s.stdout.buffer, encoding='utf-8', errors='replace')
11
- _s.stderr = _io.TextIOWrapper(_s.stderr.buffer, encoding='utf-8', errors='replace')
12
- except Exception:
13
- pass
14
3
  # v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
15
4
  import os as _o, sys as _s
16
5
  _f = _o.path.abspath(__file__)