@hupan56/wlkj 3.1.32 → 3.3.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.
Files changed (178) hide show
  1. package/bin/cli.js +117 -0
  2. package/package.json +1 -1
  3. package/templates/qoder/agents/insight-planning.md +67 -67
  4. package/templates/qoder/agents/prd-reference.md +47 -47
  5. package/templates/qoder/commands/optional/wl-insight.md +4 -4
  6. package/templates/qoder/commands/optional/wl-report.md +1 -1
  7. package/templates/qoder/commands/optional/wl-spec.md +23 -3
  8. package/templates/qoder/commands/optional/wl-status.md +12 -1
  9. package/templates/qoder/commands/wl-code.md +138 -7
  10. package/templates/qoder/commands/wl-commit.md +12 -1
  11. package/templates/qoder/commands/wl-design.md +70 -6
  12. package/templates/qoder/commands/wl-init.md +27 -0
  13. package/templates/qoder/commands/wl-prd.md +230 -15
  14. package/templates/qoder/commands/wl-req.md +10 -3
  15. package/templates/qoder/commands/wl-search.md +74 -20
  16. package/templates/qoder/commands/wl-task.md +3 -3
  17. package/templates/qoder/commands/wl-test.md +17 -2
  18. package/templates/qoder/contracts/CHANGELOG.md +418 -0
  19. package/templates/qoder/contracts/README.md +180 -0
  20. package/templates/qoder/contracts/code.md +82 -0
  21. package/templates/qoder/contracts/commit.md +86 -0
  22. package/templates/qoder/contracts/contract-header.md +76 -0
  23. package/templates/qoder/contracts/design.md +106 -0
  24. package/templates/qoder/contracts/fallback.md +126 -0
  25. package/templates/qoder/contracts/isolation.md +119 -0
  26. package/templates/qoder/contracts/prd.md +118 -0
  27. package/templates/qoder/contracts/schemas/design-spec.schema.json +46 -0
  28. package/templates/qoder/contracts/schemas/prd.schema.json +36 -0
  29. package/templates/qoder/contracts/schemas/test-cases.schema.json +40 -0
  30. package/templates/qoder/contracts/spec.md +116 -0
  31. package/templates/qoder/contracts/task.md +125 -0
  32. package/templates/qoder/contracts/test.md +112 -0
  33. package/templates/qoder/hooks/post-tool-use.py +61 -0
  34. package/templates/qoder/hooks/session-start.py +34 -66
  35. package/templates/qoder/hooks/stop-eval.py +47 -0
  36. package/templates/qoder/rules/wl-pipeline.md +37 -0
  37. package/templates/qoder/scripts/capability/__pycache__/__init__.cpython-39.pyc +0 -0
  38. package/templates/qoder/scripts/capability/__pycache__/registry.cpython-39.pyc +0 -0
  39. package/templates/qoder/scripts/capability/__pycache__/registry_mcp.cpython-39.pyc +0 -0
  40. package/templates/qoder/scripts/capability/adapters/__init__.py +1 -1
  41. package/templates/qoder/scripts/capability/adapters/__pycache__/__init__.cpython-39.pyc +0 -0
  42. package/templates/qoder/scripts/capability/adapters/__pycache__/cli.cpython-39.pyc +0 -0
  43. package/templates/qoder/scripts/capability/adapters/__pycache__/mcp.cpython-39.pyc +0 -0
  44. package/templates/qoder/scripts/capability/adapters/__pycache__/qw.cpython-39.pyc +0 -0
  45. package/templates/qoder/scripts/capability/adapters/mcp.py +76 -100
  46. package/templates/qoder/scripts/capability/adapters/qw.py +295 -295
  47. package/templates/qoder/scripts/capability/caps/__init__.py +1 -1
  48. package/templates/qoder/scripts/capability/caps/__pycache__/__init__.cpython-39.pyc +0 -0
  49. package/templates/qoder/scripts/capability/caps/__pycache__/context.cpython-39.pyc +0 -0
  50. package/templates/qoder/scripts/capability/caps/__pycache__/cron.cpython-39.pyc +0 -0
  51. package/templates/qoder/scripts/capability/caps/__pycache__/identity.cpython-39.pyc +0 -0
  52. package/templates/qoder/scripts/capability/caps/__pycache__/memory.cpython-39.pyc +0 -0
  53. package/templates/qoder/scripts/capability/caps/__pycache__/notify.cpython-39.pyc +0 -0
  54. package/templates/qoder/scripts/capability/caps/__pycache__/present.cpython-39.pyc +0 -0
  55. package/templates/qoder/scripts/capability/caps/__pycache__/repo.cpython-39.pyc +0 -0
  56. package/templates/qoder/scripts/capability/caps/__pycache__/sandbox.cpython-39.pyc +0 -0
  57. package/templates/qoder/scripts/capability/caps/memory.py +1 -1
  58. package/templates/qoder/scripts/capability/registry.py +21 -23
  59. package/templates/qoder/scripts/capability/registry_mcp.py +69 -5
  60. package/templates/qoder/scripts/capability/smoke_test_report.json +34 -20
  61. package/templates/qoder/scripts/deployment/setup/carriers.py +3 -1
  62. package/templates/qoder/scripts/deployment/setup/init_doctor.py +10 -3
  63. package/templates/qoder/scripts/deployment/setup/install_qoderwork.py +11 -0
  64. package/templates/qoder/scripts/deployment/setup/wlkj_shim.py +104 -0
  65. package/templates/qoder/scripts/domain/__pycache__/__init__.cpython-39.pyc +0 -0
  66. package/templates/qoder/scripts/domain/deployment/deploy_to_test.py +298 -0
  67. package/templates/qoder/scripts/domain/integration/__init__.py +0 -0
  68. package/templates/qoder/scripts/domain/integration/__pycache__/__init__.cpython-39.pyc +0 -0
  69. package/templates/qoder/scripts/domain/integration/__pycache__/return_to_platform.cpython-39.pyc +0 -0
  70. package/templates/qoder/scripts/domain/integration/return_to_platform.py +392 -0
  71. package/templates/qoder/scripts/domain/integration/spec_upload.py +209 -0
  72. package/templates/qoder/scripts/domain/kg/build/kg_build.py +268 -25
  73. package/templates/qoder/scripts/domain/kg/build/kg_incremental.py +108 -3
  74. package/templates/qoder/scripts/domain/kg/build/kg_signatures.py +169 -0
  75. package/templates/qoder/scripts/domain/kg/extract/asset/__init__.py +10 -0
  76. package/templates/qoder/scripts/domain/kg/extract/asset/asset_tree.py +57 -0
  77. package/templates/qoder/scripts/domain/kg/extract/asset/discussion_importer.py +62 -0
  78. package/templates/qoder/scripts/domain/kg/extract/asset/prd_importer.py +146 -0
  79. package/templates/qoder/scripts/domain/kg/extract/asset/prototype_importer.py +64 -0
  80. package/templates/qoder/scripts/domain/kg/extract/asset/returns_importer.py +52 -0
  81. package/templates/qoder/scripts/domain/kg/extract/build_goal3.py +104 -0
  82. package/templates/qoder/scripts/domain/kg/extract/build_goal4.py +55 -0
  83. package/templates/qoder/scripts/domain/kg/extract/build_goal5.py +95 -0
  84. package/templates/qoder/scripts/domain/kg/extract/db/__init__.py +8 -0
  85. package/templates/qoder/scripts/domain/kg/extract/db/data_profile.py +22 -0
  86. package/templates/qoder/scripts/domain/kg/extract/db/fk_extractor.py +55 -0
  87. package/templates/qoder/scripts/domain/kg/extract/db/schema_extractor.py +90 -0
  88. package/templates/qoder/scripts/domain/kg/extract/extract.py +84 -0
  89. package/templates/qoder/scripts/domain/kg/extract/extract.py.bak +430 -0
  90. package/templates/qoder/scripts/domain/kg/extract/inference/__init__.py +9 -0
  91. package/templates/qoder/scripts/domain/kg/extract/inference/community_summarizer.py +206 -0
  92. package/templates/qoder/scripts/domain/kg/extract/inference/embed_builder.py +132 -0
  93. package/templates/qoder/scripts/domain/kg/extract/inference/naming_matcher.py +80 -0
  94. package/templates/qoder/scripts/domain/kg/extract/inference/promote.py +59 -0
  95. package/templates/qoder/scripts/domain/kg/extract/inference/recompute.py +93 -0
  96. package/templates/qoder/scripts/domain/kg/extract/inference/weak_link.py +421 -0
  97. package/templates/qoder/scripts/domain/kg/extract/java/__init__.py +15 -0
  98. package/templates/qoder/scripts/domain/kg/extract/java/_parser.py +271 -0
  99. package/templates/qoder/scripts/domain/kg/extract/java/all.py +145 -0
  100. package/templates/qoder/scripts/domain/kg/extract/java/build_java_to_pg.py +102 -0
  101. package/templates/qoder/scripts/domain/kg/extract/java/call_chain.py +49 -0
  102. package/templates/qoder/scripts/domain/kg/extract/java/class_extractor.py +141 -0
  103. package/templates/qoder/scripts/domain/kg/extract/java/domain_extractor.py +148 -0
  104. package/templates/qoder/scripts/domain/kg/extract/java/dubbo_extractor.py +33 -0
  105. package/templates/qoder/scripts/domain/kg/extract/java/endpoint_extractor.py +36 -0
  106. package/templates/qoder/scripts/domain/kg/extract/java/javadoc_extractor.py +110 -0
  107. package/templates/qoder/scripts/domain/kg/extract/java/llm_cn_filler.py +150 -0
  108. package/templates/qoder/scripts/domain/kg/extract/java/member_extractor.py +157 -0
  109. package/templates/qoder/scripts/domain/kg/extract/java/mybatisplus_extractor.py +34 -0
  110. package/templates/qoder/scripts/domain/kg/extract/java/pg_upsert.py +165 -0
  111. package/templates/qoder/scripts/domain/kg/extract/java/satoken_extractor.py +30 -0
  112. package/templates/qoder/scripts/domain/kg/extract/java/spring_extractor.py +39 -0
  113. package/templates/qoder/scripts/domain/kg/extract/java/validation_extractor.py +33 -0
  114. package/templates/qoder/scripts/domain/kg/extract/mybatis/__init__.py +9 -0
  115. package/templates/qoder/scripts/domain/kg/extract/mybatis/all.py +79 -0
  116. package/templates/qoder/scripts/domain/kg/extract/mybatis/mapper_parser.py +99 -0
  117. package/templates/qoder/scripts/domain/kg/extract/mybatis/relation_builder.py +69 -0
  118. package/templates/qoder/scripts/domain/kg/extract/mybatis/sql_extractor.py +78 -0
  119. package/templates/qoder/scripts/domain/kg/extract/prd/__init__.py +8 -0
  120. package/templates/qoder/scripts/domain/kg/extract/prd/prd_chunk_embed.py +105 -0
  121. package/templates/qoder/scripts/domain/kg/extract/prd/prd_llm_extract.py +153 -0
  122. package/templates/qoder/scripts/domain/kg/extract/prd/req_anchor.py +120 -0
  123. package/templates/qoder/scripts/domain/kg/extract/ts_extract.py +111 -0
  124. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +4 -2
  125. package/templates/qoder/scripts/domain/kg/kg.py +42 -5
  126. package/templates/qoder/scripts/domain/kg/search/_remote.py +187 -0
  127. package/templates/qoder/scripts/domain/kg/search/context_pack.py +32 -2
  128. package/templates/qoder/scripts/domain/kg/search/search_index.py +74 -20
  129. package/templates/qoder/scripts/domain/kg/storage/kg_duckdb.py +43 -0
  130. package/templates/qoder/scripts/domain/kg/switch_project.py +159 -0
  131. package/templates/qoder/scripts/domain/kg/sync_repowiki.py +109 -0
  132. package/templates/qoder/scripts/domain/requirement/req.py +134 -28
  133. package/templates/qoder/scripts/domain/task/__pycache__/wlkj_panel.cpython-39.pyc +0 -0
  134. package/templates/qoder/scripts/domain/task/wlkj_panel.py +1348 -0
  135. package/templates/qoder/scripts/engine/poller.py +219 -0
  136. package/templates/qoder/scripts/foundation/__pycache__/__init__.cpython-39.pyc +0 -0
  137. package/templates/qoder/scripts/foundation/core/__pycache__/__init__.cpython-39.pyc +0 -0
  138. package/templates/qoder/scripts/foundation/core/__pycache__/paths.cpython-39.pyc +0 -0
  139. package/templates/qoder/scripts/foundation/core/paths.py +102 -0
  140. package/templates/qoder/scripts/foundation/integrations/active_task.py +2 -1
  141. package/templates/qoder/scripts/orchestration/wlkj.py +4 -0
  142. package/templates/qoder/scripts/protocol/__pycache__/__init__.cpython-39.pyc +0 -0
  143. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +24 -11
  144. package/templates/qoder/scripts/protocol/transports/__pycache__/__init__.cpython-39.pyc +0 -0
  145. package/templates/qoder/scripts/protocol/transports/__pycache__/base.cpython-39.pyc +0 -0
  146. package/templates/qoder/scripts/protocol/transports/__pycache__/cli.cpython-39.pyc +0 -0
  147. package/templates/qoder/scripts/protocol/transports/__pycache__/http.cpython-39.pyc +0 -0
  148. package/templates/qoder/scripts/protocol/transports/__pycache__/stdio.cpython-39.pyc +0 -0
  149. package/templates/qoder/scripts/protocol/transports/http.py +7 -1
  150. package/templates/qoder/scripts/validation/eval/qwork_harness.py +1 -1
  151. package/templates/qoder/scripts/validation/eval/report-commands.md +2 -2
  152. package/templates/qoder/settings.json +27 -9
  153. package/templates/qoder/skills/design-import/SKILL.md +3 -3
  154. package/templates/qoder/skills/design-review/SKILL.md +1 -1
  155. package/templates/qoder/skills/prd-generator/SKILL.md +4 -4
  156. package/templates/qoder/skills/prd-review/SKILL.md +1 -1
  157. package/templates/qoder/skills/prototype-generator/SKILL.md +3 -3
  158. package/templates/qoder/skills/spec-coder/SKILL.md +1 -1
  159. package/templates/qoder/skills/spec-generator/SKILL.md +80 -23
  160. package/templates/qoder/skills/test-generator/SKILL.md +1 -1
  161. package/templates/qoder/skills/wl-code/SKILL.md +13 -1
  162. package/templates/qoder/skills/wl-commit/SKILL.md +1 -1
  163. package/templates/qoder/skills/wl-design/SKILL.md +6 -6
  164. package/templates/qoder/skills/wl-init/SKILL.md +2 -2
  165. package/templates/qoder/skills/wl-insight/SKILL.md +5 -5
  166. package/templates/qoder/skills/wl-prd/SKILL.md +60 -0
  167. package/templates/qoder/skills/wl-report/SKILL.md +2 -2
  168. package/templates/qoder/skills/wl-search/SKILL.md +1 -1
  169. package/templates/qoder/skills/wl-spec/SKILL.md +2 -2
  170. package/templates/qoder/skills/wl-status/SKILL.md +2 -2
  171. package/templates/qoder/skills/wl-task/SKILL.md +3 -3
  172. package/templates/qoder/skills/wl-test/SKILL.md +2 -2
  173. package/templates/qoder/templates/spec-template.md +124 -0
  174. package/templates/root/AGENTS.md +41 -14
  175. package/templates/qoder/scripts/domain/task/zentao_panel.py +0 -451
  176. package/templates/qoder/skills/wl-prd-full/SKILL.md +0 -121
  177. package/templates/qoder/skills/wl-prd-quick/SKILL.md +0 -50
  178. package/templates/qoder/skills/wl-prd-review/SKILL.md +0 -47
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- nexus.registry —— 宿主发现 + Nexus Facade。
3
+ capability.registry —— 宿主发现 + Nexus Facade。
4
4
 
5
5
  设计模式:
6
6
  - Registry(HOST_TABLE 单一事实源,泛化 common.active_task._ENV_SESSION_KEYS)
@@ -8,7 +8,7 @@ nexus.registry —— 宿主发现 + Nexus Facade。
8
8
  - Bridge(Cap 抽象 × 宿主实现 正交)
9
9
 
10
10
  主轴: 工作流面向能力编程,不面向宿主。
11
- cap = nexus.resolve()
11
+ cap = resolve()
12
12
  cap.memory.recall(...) # 不管在 QoderWork 还是 CLI,同一行代码
13
13
  """
14
14
  from __future__ import annotations
@@ -36,26 +36,24 @@ from .caps import (
36
36
  # =============================================================================
37
37
 
38
38
  HOST_TABLE: dict[str, dict] = {
39
- # ── Qoder 产品线(第一宿主系列)─────────────────────────────
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
+ },
40
50
  "qoder-work": {
51
+ # QoderWork:办公产品(非开发者,文档/报告/PPT/M365)。~/.qoderwork/ 投影 + qoder_show_widget 是其接入点。
41
52
  "detect": ("QODER_SESSION_ID",),
42
- # features = 当前已实现 (非 NoOp) 的能力。notify/present/sandbox 暂无
43
- # 宿主原生 Adapter,声明即误报可用,故不列。后续补齐 Adapter 再加。
44
- "features": ("mcp", "memory", "cron"),
53
+ "features": ("mcp", "memory", "cron", "present"),
54
+ "native": ("office-agent", "m365", "human-in-loop", "hooks", "show-widget"),
45
55
  "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql", "lanhu"],
46
- "note": "QoderWork 桌面 Agent,全能力",
47
- },
48
- "qoder-ide": {
49
- "detect": ("QODER_IDE",),
50
- "features": ("mcp", "memory"),
51
- "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao", "qoder-mysql"],
52
- "note": "Qoder IDE (VSCode 扩展)",
53
- },
54
- "qoder-quest": {
55
- "detect": ("QODER_QUEST",),
56
- "features": ("mcp", "memory"),
57
- "mcp_servers": ["qoder-knowledge-graph", "qoder-zentao"],
58
- "note": "Qoder Quest,自然语言入口",
56
+ "note": "QoderWork 桌面办公 Agent(非开发者;文档/PPT/M365);~/.qoderwork/ 投影入口",
59
57
  },
60
58
  # ── 其他宿主(通用 AI 工具)────────────────────────────────
61
59
  "codex": {
@@ -124,7 +122,7 @@ def detect_host() -> str:
124
122
  class Nexus:
125
123
  """宿主能力 Facade —— 聚合所有能力,对外统一入口。
126
124
 
127
- 工作流永远只调 nexus.resolve() 拿到本对象,再访问 .memory/.mcp/...,
125
+ 工作流永远只调 resolve() 拿到本对象,再访问 .memory/.mcp/...,
128
126
  不直接 import 任何 adapter(Facade 模式)。
129
127
  """
130
128
 
@@ -202,8 +200,8 @@ def _resolve_notify(host: str):
202
200
 
203
201
 
204
202
  def _resolve_present(host: str):
205
- """L2 富展示 —— QoderWork 调 qoder_show_widget 嵌入对话; 其余 NoOp 降级表格。"""
206
- if host in ("qoder-work", "qoder-ide"):
203
+ """L2 富展示 —— Qoder Desktop/Work 调 qoder_show_widget 嵌入对话; 其余 NoOp 降级表格。"""
204
+ if host in ("qoder-desktop", "qoder-work"):
207
205
  try:
208
206
  from .adapters.qw import QwPresentCap
209
207
  return QwPresentCap()
@@ -227,7 +225,7 @@ def _resolve_mcp(host: str):
227
225
  def resolve() -> Nexus:
228
226
  """解析当前环境,返回 Nexus Facade。
229
227
 
230
- 一行入口: cap = nexus.resolve()
228
+ 一行入口: cap = resolve()
231
229
  内部: detect_host → 按宿主装配各 Cap → 注入 NoOp 兜底。
232
230
  工作流代码零宿主感知。
233
231
  """
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  """
3
- nexus.registry_mcp —— MCP 工具路由(tool → server → transport)。
3
+ capability.registry_mcp —— MCP 工具路由(tool → server → transport)。
4
4
 
5
5
  设计模式: Registry + Strategy(配合 transports 层)
6
6
 
@@ -34,11 +34,25 @@ from protocol.transports import get_transport, Transport, NoOpTransport, ToolRes
34
34
  # 未来改这里即可切换部署形态,工作流零改动。
35
35
  # =============================================================================
36
36
 
37
+ # =============================================================================
38
+ # mcp_config.json 消费 —— 让配置文件真正生效(单一事实源)
39
+ # -----------------------------------------------------------------------------
40
+ # 历史 bug: mcp_config.json / registry_mcp_config.json 是"死配置"(全仓 0 读取),
41
+ # registry 用硬编码 SERVERS。改配置文件不生效。
42
+ # 现在: 优先读 wlinkj-workflow/mcp_config.json 的 mcpServers,读不到才 fallback。
43
+ # =============================================================================
44
+ # 配置文件中知识层 server 的别名映射(统一命名,两边都支持):
45
+ # mcp_config.json 里叫 "wlinkj-knowledge",本地硬编码叫 "qoder-knowledge-graph"。
46
+ # 让 _load_servers 把 config 的 server 也注册成 "qoder-knowledge-graph" 别名,
47
+ # 这样反向索引 / 显式 server 调用两边名字都能命中。
48
+ _KNOWLEDGE_SERVER_ALIASES = ["wlinkj-knowledge", "qoder-knowledge-graph"]
49
+
50
+ # 硬编码 fallback(配置文件读不到时兜底,保证引擎不崩)
37
51
  SERVERS: dict[str, dict] = {
38
52
  "qoder-knowledge-graph": {
39
- "kind": "stdio",
40
- "launcher_arg": "kg",
41
- "note": "知识图谱。本地分发;未来可上服务器 kind=http + url",
53
+ "kind": "http",
54
+ "url": "http://127.0.0.1:10010/mcp",
55
+ "note": "知识图谱。已改为 http 模式,指向资产平台 MCP 服务(POST /mcp JSON-RPC)",
42
56
  },
43
57
  "qoder-zentao": {
44
58
  "kind": "stdio",
@@ -58,6 +72,55 @@ SERVERS: dict[str, dict] = {
58
72
  }
59
73
 
60
74
 
75
+ def _mcp_config_path() -> Path:
76
+ """定位 wlinkj-workflow/mcp_config.json(在仓库根下)。"""
77
+ repo = _get_repo_root()
78
+ # registry_mcp.py 在 .../scripts/capability/, mcp_config.json 在 wlinkj-workflow/
79
+ # 仓库根可能就是 wlinkj-workflow/, 或是其上层。两级查找。
80
+ for cand in [
81
+ repo / "mcp_config.json",
82
+ repo / "wlinkj-workflow" / "mcp_config.json",
83
+ repo / "registry_mcp_config.json",
84
+ ]:
85
+ if cand.is_file():
86
+ return cand
87
+ return repo / "mcp_config.json"
88
+
89
+
90
+ def _load_servers() -> dict[str, dict]:
91
+ """从 mcp_config.json 加载 mcpServers,合并到硬编码 SERVERS 上。
92
+
93
+ 配置文件优先(改配置真生效),硬编码兜底(配置缺失也不崩)。
94
+ 同时把知识层 server 注册多个别名(wlinkj-knowledge / qoder-knowledge-graph),
95
+ 让引擎用任一名字都能调到。
96
+ """
97
+ import json as _json
98
+
99
+ merged: dict[str, dict] = {k: dict(v) for k, v in SERVERS.items()}
100
+ try:
101
+ cfg_path = _mcp_config_path()
102
+ if not cfg_path.is_file():
103
+ return merged
104
+ with open(cfg_path, encoding="utf-8") as f:
105
+ cfg = _json.load(f)
106
+ mcp_servers = cfg.get("mcpServers") or {}
107
+ for name, spec in mcp_servers.items():
108
+ if not isinstance(spec, dict):
109
+ continue
110
+ # 剥离 _comment / _usage 等说明字段,只留 kind/url/token/env/launcher_arg/note
111
+ clean = {k: v for k, v in spec.items() if not k.startswith("_")}
112
+ # 知识层 server: 注册全部别名,都指向同一份配置
113
+ if name in _KNOWLEDGE_SERVER_ALIASES:
114
+ for alias in _KNOWLEDGE_SERVER_ALIASES:
115
+ merged[alias] = clean
116
+ else:
117
+ merged[name] = clean
118
+ except Exception:
119
+ # 读配置失败绝不能让引擎崩 —— 退回硬编码
120
+ pass
121
+ return merged
122
+
123
+
61
124
  def _get_repo_root() -> Path:
62
125
  """从 common.paths 获取仓库根(复用既有工具,不重复造轮子)。"""
63
126
  try:
@@ -76,7 +139,8 @@ class McpRegistry:
76
139
 
77
140
  def __init__(self, repo_root: Optional[Path] = None, servers: Optional[dict] = None):
78
141
  self._repo = repo_root or _get_repo_root()
79
- self._servers = servers if servers is not None else SERVERS
142
+ # 默认从 mcp_config.json 加载(改配置真生效),显式传 servers 时覆盖
143
+ self._servers = servers if servers is not None else _load_servers()
80
144
  self._pool: dict[str, Transport] = {}
81
145
  self._tool_to_server: Optional[dict[str, str]] = None # 懒构建
82
146
  self._index_lock_built = False
@@ -1,24 +1,24 @@
1
1
  {
2
- "timestamp": "2026-06-29 11:20:28",
2
+ "timestamp": "2026-07-02 11:13:44",
3
3
  "servers": {
4
4
  "qoder-knowledge-graph": {
5
5
  "available": true,
6
- "tools_indexed": 17,
7
- "latency_ms": 484.0,
6
+ "tools_indexed": 35,
7
+ "latency_ms": 16.0,
8
8
  "sample_tools": [
9
9
  "search_code",
10
10
  "search_api",
11
- "search_prd",
12
- "get_impact",
11
+ "search_field",
12
+ "search_style",
13
13
  "context_360"
14
14
  ],
15
- "spawn_pid": 66880,
15
+ "spawn_pid": null,
16
16
  "status": "PASS"
17
17
  },
18
18
  "qoder-zentao": {
19
19
  "available": true,
20
20
  "tools_indexed": 68,
21
- "latency_ms": 766.0,
21
+ "latency_ms": 1625.0,
22
22
  "sample_tools": [
23
23
  "check_zentao_status",
24
24
  "get_zentao_url",
@@ -26,13 +26,13 @@
26
26
  "get_product",
27
27
  "create_product"
28
28
  ],
29
- "spawn_pid": 48620,
29
+ "spawn_pid": 76064,
30
30
  "status": "PASS"
31
31
  },
32
32
  "qoder-mysql": {
33
33
  "available": true,
34
34
  "tools_indexed": 6,
35
- "latency_ms": 609.0,
35
+ "latency_ms": 500.0,
36
36
  "sample_tools": [
37
37
  "list_envs",
38
38
  "query_schema",
@@ -40,13 +40,13 @@
40
40
  "query_distinct",
41
41
  "list_databases"
42
42
  ],
43
- "spawn_pid": 67572,
43
+ "spawn_pid": 26784,
44
44
  "status": "PASS"
45
45
  },
46
46
  "lanhu": {
47
47
  "available": true,
48
48
  "tools_indexed": 13,
49
- "latency_ms": 3313.0,
49
+ "latency_ms": 4906.0,
50
50
  "sample_tools": [
51
51
  "lanhu_resolve_invite_link",
52
52
  "lanhu_list_product_documents",
@@ -54,14 +54,28 @@
54
54
  "lanhu_get_ai_analyze_page_result",
55
55
  "lanhu_get_designs"
56
56
  ],
57
- "spawn_pid": 32460,
57
+ "spawn_pid": 14148,
58
+ "status": "PASS"
59
+ },
60
+ "wlinkj-knowledge": {
61
+ "available": true,
62
+ "tools_indexed": 35,
63
+ "latency_ms": 32.0,
64
+ "sample_tools": [
65
+ "search_code",
66
+ "search_api",
67
+ "search_field",
68
+ "search_style",
69
+ "context_360"
70
+ ],
71
+ "spawn_pid": null,
58
72
  "status": "PASS"
59
73
  }
60
74
  },
61
75
  "call_tool": {
62
76
  "status": "PASS",
63
- "latency_ms": 3547.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/",
77
+ "latency_ms": 7281.0,
78
+ "text_preview": "{\"query\": \"保险\", \"platform\": null, \"module\": null, \"total\": 1, \"items\": [{\"type\": \"BUTTON\", \"name\": \"history\", \"label\": \"保险记录\"}]}",
65
79
  "is_error": false
66
80
  },
67
81
  "memory": {
@@ -69,13 +83,13 @@
69
83
  "providers": [
70
84
  {
71
85
  "provider": "McpMemoryProvider",
72
- "available": true,
73
- "hit": true
86
+ "available": false,
87
+ "hit": false
74
88
  },
75
89
  {
76
90
  "provider": "FileMemoryCap",
77
91
  "available": true,
78
- "hit": false
92
+ "hit": true
79
93
  },
80
94
  {
81
95
  "provider": "NoOpMemoryCap",
@@ -87,8 +101,8 @@
87
101
  },
88
102
  "summary": {
89
103
  "all_pass": true,
90
- "active_servers": 4,
91
- "total_servers": 4,
92
- "total_tools": 104
104
+ "active_servers": 5,
105
+ "total_servers": 5,
106
+ "total_tools": 157
93
107
  }
94
108
  }
@@ -3,7 +3,9 @@
3
3
  """carriers.py - 四载体一致性 (Facade 外观模式)
4
4
 
5
5
  v3.0 合并自: check_carriers + check_qoderwork_consistency + sync_carriers。
6
- 四载体: Qoder IDE / Quest / CLI / QoderWork。三者都是"四载体"这一个领域,
6
+ 四载体 = 命令/技能的 4 个部署面: Qoder Desktop(含 Quest 模式) / CLI / QoderWork / npm 镜像。
7
+ 注意: 这是"部署面"轴,与 capability/registry.py:HOST_TABLE 的"宿主产品"轴正交
8
+ (HOST_TABLE 现列 desktop/work;cli/cloud 后续按需)。
7
9
  对外应是 1 个 carriers 命令的子操作 (Facade: 多个细粒度检查统一入口)。
8
10
 
9
11
  用法:
@@ -485,7 +485,11 @@ def check_index(fix):
485
485
  print('\n--- 5. 知识图谱 (data/index/) ---')
486
486
  age = index_age_days()
487
487
  if age is None:
488
- # 完全缺失 先尝试 team_sync pull 拉管理员建好的 kg.duckdb
488
+ # 全迁 PG kg.duckdb 废弃:环境配了 PG → 知识层在平台,不报缺失
489
+ if os.environ.get('KNOWLEDGE_BACKEND', '').lower() == 'pg' or 'postgresql' in os.environ.get('DATABASE_URL', ''):
490
+ say(OK, '知识层在平台 PostgreSQL(KNOWLEDGE_BACKEND=pg / DATABASE_URL=pg,不依赖本地 kg.duckdb)')
491
+ return
492
+ # 完全缺失(非 PG 环境)→ 先尝试 team_sync pull 拉管理员建好的 kg.duckdb
489
493
  if fix:
490
494
  print(' 索引缺失, 先从团队仓库拉取 (team_sync pull)...')
491
495
  if run_script('team_sync.py', 'pull', timeout=120):
@@ -549,7 +553,8 @@ def check_style(fix):
549
553
  else:
550
554
  problem(fname + ' 缺失', '该文件提交在 git 中, 先解决团队同步 (team_sync pull)')
551
555
 
552
- # kg.duckdb 知识图谱 (统一存储)
556
+ # kg.duckdb 知识图谱 (统一存储) — 全迁 PG 后知识层在平台,本地 duckdb 废弃
557
+ _pg_mode = os.environ.get('KNOWLEDGE_BACKEND', '').lower() == 'pg' or 'postgresql' in os.environ.get('DATABASE_URL', '')
553
558
  kg_path = os.path.join(INDEX_DIR, 'kg.duckdb')
554
559
  role = ''
555
560
  try:
@@ -561,7 +566,9 @@ def check_style(fix):
561
566
  except Exception:
562
567
  pass
563
568
 
564
- if os.path.isfile(kg_path):
569
+ if _pg_mode:
570
+ say(OK, '知识层在平台 PostgreSQL(不依赖本地 kg.duckdb)')
571
+ elif os.path.isfile(kg_path):
565
572
  say(OK, 'kg.duckdb 知识图谱 (%d KB)' % (os.path.getsize(kg_path) // 1024))
566
573
  # 过期检测
567
574
  import time as _t
@@ -537,6 +537,17 @@ def main():
537
537
  print(f" [SKIP] .repo-root 未更新 ({PROJECT_ROOT} 非真仓库, 缺 workspace/data/.git)")
538
538
  except OSError:
539
539
  pass
540
+ # 5. 复制 wlkj 薄壳 (QoderWork 桌面端任意 cwd 直跑 wlkj, 不用每次先算 R)
541
+ # 治"相对路径在会话临时 cwd 失效"踩坑 (真实: 连续 2 条命令报错浪费一轮)
542
+ shim_src = SOURCE_COMMANDS_DIR.parent / "scripts" / "deployment" / "setup" / "wlkj_shim.py"
543
+ shim_dst = _HOME / ".qoderwork" / "wlkj.py"
544
+ try:
545
+ if shim_src.is_file():
546
+ import shutil as _sh2
547
+ _sh2.copy2(str(shim_src), str(shim_dst))
548
+ print(f" [OK] wlkj 薄壳: {shim_dst} (任意 cwd 可跑: python ~/.qoderwork/wlkj.py ...)")
549
+ except OSError as e:
550
+ print(f" [ERR] wlkj 薄壳复制失败: {e}")
540
551
  return
541
552
 
542
553
  print("=" * 56)
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # wlkj_shim.py — QoderWork 桌面端 wlkj 薄壳 (零 import 依赖, 任意 cwd 直接跑)
4
+ #
5
+ # 为什么需要它:
6
+ # QoderWork 桌面端工作目录是临时会话目录 (workspace/xxx), 不是仓库根。
7
+ # 命令文件里写的相对路径 .qoder/scripts/orchestration/wlkj.py 全部失效
8
+ # (真实踩坑: AI 连续 2 条命令报错 "can't open file", 浪费一轮, 拖慢)。
9
+ # 本薄壳放在 ~/.qoderwork/wlkj.py, AI 只需记住一个绝对路径:
10
+ # python ~/.qoderwork/wlkj.py <命令> [参数...]
11
+ # 即可在任意 cwd 跑通工作流, 不用每次先算 R=repo_root。
12
+ #
13
+ # 机制 (与 repo_root.py 一致): 从 ~/.qoderwork/mcp.json 的 kg_mcp_server.py
14
+ # 绝对路径反推仓库根 (换机器重装后 mcp.json 会更新, 无需硬编码)。然后 subprocess
15
+ # 调真正的 wlkj.py, 透传全部 argv 和 exit code。
16
+ #
17
+ # 零依赖: 不能 import 仓库内任何模块 (定位器不能依赖被定位的东西)。
18
+ #
19
+ # 安装: install_qoderwork.py 会把本文件复制到 ~/.qoderwork/wlkj.py。
20
+ """
21
+ wlkj_shim.py — QoderWork 桌面端 wlkj 薄壳。
22
+
23
+ 用法:
24
+ python ~/.qoderwork/wlkj.py <命令> [参数...] # 任意 cwd, 直接转发到真 wlkj.py
25
+ python ~/.qoderwork/wlkj.py --where-repo # 只打印仓库根 (调试用)
26
+
27
+ 等价于在仓库根跑:
28
+ python <repo_root>/.qoder/scripts/orchestration/wlkj.py <命令> [参数...]
29
+ """
30
+ import json
31
+ import os
32
+ import subprocess
33
+ import sys
34
+
35
+ HOME = os.path.expanduser('~')
36
+ REPO_ROOT_SH = os.path.join(HOME, '.qoderwork', 'repo_root.py') # 已验证可用的定位器
37
+
38
+
39
+ def _resolve_repo_root():
40
+ """定位仓库根。优先调已验证的 ~/.qoderwork/repo_root.py (它走 .repo-root 锚点,
41
+ 最可靠); 失败则自己读锚点兜底。返回绝对路径或 None。
42
+
43
+ 与 repo_root.py 同走 ~/.qoderwork/.repo-root 锚点 (install 时写, 主路径)。
44
+ 不重复造定位逻辑 —— repo_root.py 已经被验证可用。
45
+ """
46
+ # 主路径: 调 repo_root.py (它输出仓库根绝对路径, 经 transcript 验证可用)
47
+ if os.path.isfile(REPO_ROOT_SH):
48
+ try:
49
+ out = subprocess.run([sys.executable, REPO_ROOT_SH],
50
+ capture_output=True, text=True, timeout=10)
51
+ line = out.stdout.strip().splitlines()
52
+ # repo_root.py 成功时 stdout 第一行是仓库根; 失败时 stderr 报错 stdout 空
53
+ if line and os.path.isdir(os.path.join(line[0], '.qoder', 'scripts')):
54
+ return line[0]
55
+ except Exception:
56
+ pass
57
+ # 兜底: 直接读锚点文件 (与 repo_root.py 方法1 一致)
58
+ anchor = os.path.join(HOME, '.qoderwork', '.repo-root')
59
+ try:
60
+ if os.path.isfile(anchor):
61
+ r = open(anchor, encoding='utf-8').read().strip()
62
+ if r and os.path.isdir(os.path.join(r, '.qoder', 'scripts')):
63
+ return r
64
+ except OSError:
65
+ pass
66
+ return None
67
+
68
+
69
+ def main():
70
+ argv = sys.argv[1:]
71
+ if not argv or argv[0] in ('-h', '--help', 'help'):
72
+ sys.stderr.write(
73
+ 'wlkj 薄壳 (QoderWork 桌面端专用, 任意 cwd 可跑)\n'
74
+ '用法: python ~/.qoderwork/wlkj.py <命令> [参数...]\n'
75
+ '调试: python ~/.qoderwork/wlkj.py --where-repo\n'
76
+ '命令同仓库内 wlkj.py (kg/search/context/prefetch/task/req/eval/...)\n')
77
+ return 0 if not argv else 0
78
+
79
+ if argv[0] == '--where-repo':
80
+ root = _resolve_repo_root()
81
+ print(root if root else '(未定位到仓库根, 检查 ~/.qoderwork/.repo-root 锚点)')
82
+ return 0
83
+
84
+ repo = _resolve_repo_root()
85
+ if not repo:
86
+ sys.stderr.write(
87
+ '【wlkj 薄壳】未定位到仓库根。\n'
88
+ ' 修复: 在仓库内跑 python .qoder/scripts/deployment/setup/install_qoderwork.py\n'
89
+ ' (会写 ~/.qoderwork/.repo-root 锚点)\n')
90
+ return 1
91
+
92
+ wlkj = os.path.join(repo, '.qoder', 'scripts', 'orchestration', 'wlkj.py')
93
+ if not os.path.isfile(wlkj):
94
+ sys.stderr.write('【wlkj 薄壳】真 wlkj.py 不存在: %s\n' % wlkj)
95
+ return 1
96
+
97
+ # 透传: 切到仓库根跑 (避免被调脚本依赖 cwd), 传全部 argv 和 exit code
98
+ r = subprocess.run([sys.executable, wlkj] + argv, cwd=repo)
99
+ return r.returncode
100
+
101
+
102
+ if __name__ == '__main__':
103
+ sys.exit(main())
104
+