@hupan56/wlkj 3.2.0 → 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 (122) hide show
  1. package/bin/cli.js +117 -0
  2. package/package.json +1 -1
  3. package/templates/qoder/commands/optional/wl-insight.md +276 -276
  4. package/templates/qoder/commands/optional/wl-report.md +1 -1
  5. package/templates/qoder/commands/optional/wl-spec.md +13 -1
  6. package/templates/qoder/commands/optional/wl-status.md +12 -1
  7. package/templates/qoder/commands/wl-code.md +76 -4
  8. package/templates/qoder/commands/wl-commit.md +12 -1
  9. package/templates/qoder/commands/wl-design.md +69 -5
  10. package/templates/qoder/commands/wl-init.md +27 -0
  11. package/templates/qoder/commands/wl-prd.md +145 -4
  12. package/templates/qoder/commands/wl-search.md +74 -20
  13. package/templates/qoder/commands/wl-task.md +613 -613
  14. package/templates/qoder/commands/wl-test.md +16 -1
  15. package/templates/qoder/contracts/spec.md +4 -0
  16. package/templates/qoder/hooks/post-tool-use.py +41 -0
  17. package/templates/qoder/hooks/session-start.py +34 -66
  18. package/templates/qoder/scripts/capability/__pycache__/__init__.cpython-39.pyc +0 -0
  19. package/templates/qoder/scripts/capability/__pycache__/registry.cpython-39.pyc +0 -0
  20. package/templates/qoder/scripts/capability/__pycache__/registry_mcp.cpython-39.pyc +0 -0
  21. package/templates/qoder/scripts/capability/adapters/__init__.py +1 -1
  22. package/templates/qoder/scripts/capability/adapters/__pycache__/__init__.cpython-39.pyc +0 -0
  23. package/templates/qoder/scripts/capability/adapters/__pycache__/cli.cpython-39.pyc +0 -0
  24. package/templates/qoder/scripts/capability/adapters/__pycache__/mcp.cpython-39.pyc +0 -0
  25. package/templates/qoder/scripts/capability/adapters/__pycache__/qw.cpython-39.pyc +0 -0
  26. package/templates/qoder/scripts/capability/adapters/mcp.py +76 -100
  27. package/templates/qoder/scripts/capability/adapters/qw.py +295 -295
  28. package/templates/qoder/scripts/capability/caps/__init__.py +1 -1
  29. package/templates/qoder/scripts/capability/caps/__pycache__/__init__.cpython-39.pyc +0 -0
  30. package/templates/qoder/scripts/capability/caps/__pycache__/context.cpython-39.pyc +0 -0
  31. package/templates/qoder/scripts/capability/caps/__pycache__/cron.cpython-39.pyc +0 -0
  32. package/templates/qoder/scripts/capability/caps/__pycache__/identity.cpython-39.pyc +0 -0
  33. package/templates/qoder/scripts/capability/caps/__pycache__/memory.cpython-39.pyc +0 -0
  34. package/templates/qoder/scripts/capability/caps/__pycache__/notify.cpython-39.pyc +0 -0
  35. package/templates/qoder/scripts/capability/caps/__pycache__/present.cpython-39.pyc +0 -0
  36. package/templates/qoder/scripts/capability/caps/__pycache__/repo.cpython-39.pyc +0 -0
  37. package/templates/qoder/scripts/capability/caps/__pycache__/sandbox.cpython-39.pyc +0 -0
  38. package/templates/qoder/scripts/capability/caps/memory.py +1 -1
  39. package/templates/qoder/scripts/capability/registry.py +21 -23
  40. package/templates/qoder/scripts/capability/registry_mcp.py +69 -5
  41. package/templates/qoder/scripts/capability/smoke_test_report.json +34 -20
  42. package/templates/qoder/scripts/deployment/setup/carriers.py +3 -1
  43. package/templates/qoder/scripts/deployment/setup/init_doctor.py +10 -3
  44. package/templates/qoder/scripts/domain/__pycache__/__init__.cpython-39.pyc +0 -0
  45. package/templates/qoder/scripts/domain/integration/__init__.py +0 -0
  46. package/templates/qoder/scripts/domain/integration/__pycache__/__init__.cpython-39.pyc +0 -0
  47. package/templates/qoder/scripts/domain/integration/__pycache__/return_to_platform.cpython-39.pyc +0 -0
  48. package/templates/qoder/scripts/domain/integration/return_to_platform.py +392 -0
  49. package/templates/qoder/scripts/domain/integration/spec_upload.py +209 -0
  50. package/templates/qoder/scripts/domain/kg/build/kg_build.py +27 -3
  51. package/templates/qoder/scripts/domain/kg/extract/asset/__init__.py +10 -0
  52. package/templates/qoder/scripts/domain/kg/extract/asset/asset_tree.py +57 -0
  53. package/templates/qoder/scripts/domain/kg/extract/asset/discussion_importer.py +62 -0
  54. package/templates/qoder/scripts/domain/kg/extract/asset/prd_importer.py +146 -0
  55. package/templates/qoder/scripts/domain/kg/extract/asset/prototype_importer.py +64 -0
  56. package/templates/qoder/scripts/domain/kg/extract/asset/returns_importer.py +52 -0
  57. package/templates/qoder/scripts/domain/kg/extract/build_goal3.py +104 -0
  58. package/templates/qoder/scripts/domain/kg/extract/build_goal4.py +55 -0
  59. package/templates/qoder/scripts/domain/kg/extract/build_goal5.py +95 -0
  60. package/templates/qoder/scripts/domain/kg/extract/db/__init__.py +8 -0
  61. package/templates/qoder/scripts/domain/kg/extract/db/data_profile.py +22 -0
  62. package/templates/qoder/scripts/domain/kg/extract/db/fk_extractor.py +55 -0
  63. package/templates/qoder/scripts/domain/kg/extract/db/schema_extractor.py +90 -0
  64. package/templates/qoder/scripts/domain/kg/extract/extract.py +84 -0
  65. package/templates/qoder/scripts/domain/kg/extract/extract.py.bak +430 -0
  66. package/templates/qoder/scripts/domain/kg/extract/inference/__init__.py +9 -0
  67. package/templates/qoder/scripts/domain/kg/extract/inference/community_summarizer.py +206 -0
  68. package/templates/qoder/scripts/domain/kg/extract/inference/embed_builder.py +132 -0
  69. package/templates/qoder/scripts/domain/kg/extract/inference/naming_matcher.py +80 -0
  70. package/templates/qoder/scripts/domain/kg/extract/inference/promote.py +59 -0
  71. package/templates/qoder/scripts/domain/kg/extract/inference/recompute.py +93 -0
  72. package/templates/qoder/scripts/domain/kg/extract/inference/weak_link.py +421 -0
  73. package/templates/qoder/scripts/domain/kg/extract/java/__init__.py +15 -0
  74. package/templates/qoder/scripts/domain/kg/extract/java/_parser.py +271 -0
  75. package/templates/qoder/scripts/domain/kg/extract/java/all.py +145 -0
  76. package/templates/qoder/scripts/domain/kg/extract/java/build_java_to_pg.py +102 -0
  77. package/templates/qoder/scripts/domain/kg/extract/java/call_chain.py +49 -0
  78. package/templates/qoder/scripts/domain/kg/extract/java/class_extractor.py +141 -0
  79. package/templates/qoder/scripts/domain/kg/extract/java/domain_extractor.py +148 -0
  80. package/templates/qoder/scripts/domain/kg/extract/java/dubbo_extractor.py +33 -0
  81. package/templates/qoder/scripts/domain/kg/extract/java/endpoint_extractor.py +36 -0
  82. package/templates/qoder/scripts/domain/kg/extract/java/javadoc_extractor.py +110 -0
  83. package/templates/qoder/scripts/domain/kg/extract/java/llm_cn_filler.py +150 -0
  84. package/templates/qoder/scripts/domain/kg/extract/java/member_extractor.py +157 -0
  85. package/templates/qoder/scripts/domain/kg/extract/java/mybatisplus_extractor.py +34 -0
  86. package/templates/qoder/scripts/domain/kg/extract/java/pg_upsert.py +165 -0
  87. package/templates/qoder/scripts/domain/kg/extract/java/satoken_extractor.py +30 -0
  88. package/templates/qoder/scripts/domain/kg/extract/java/spring_extractor.py +39 -0
  89. package/templates/qoder/scripts/domain/kg/extract/java/validation_extractor.py +33 -0
  90. package/templates/qoder/scripts/domain/kg/extract/mybatis/__init__.py +9 -0
  91. package/templates/qoder/scripts/domain/kg/extract/mybatis/all.py +79 -0
  92. package/templates/qoder/scripts/domain/kg/extract/mybatis/mapper_parser.py +99 -0
  93. package/templates/qoder/scripts/domain/kg/extract/mybatis/relation_builder.py +69 -0
  94. package/templates/qoder/scripts/domain/kg/extract/mybatis/sql_extractor.py +78 -0
  95. package/templates/qoder/scripts/domain/kg/extract/prd/__init__.py +8 -0
  96. package/templates/qoder/scripts/domain/kg/extract/prd/prd_chunk_embed.py +105 -0
  97. package/templates/qoder/scripts/domain/kg/extract/prd/prd_llm_extract.py +153 -0
  98. package/templates/qoder/scripts/domain/kg/extract/prd/req_anchor.py +120 -0
  99. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +4 -2
  100. package/templates/qoder/scripts/domain/kg/kg.py +42 -5
  101. package/templates/qoder/scripts/domain/kg/search/_remote.py +187 -0
  102. package/templates/qoder/scripts/domain/kg/search/context_pack.py +32 -2
  103. package/templates/qoder/scripts/domain/kg/search/search_index.py +74 -20
  104. package/templates/qoder/scripts/domain/kg/switch_project.py +159 -0
  105. package/templates/qoder/scripts/domain/kg/sync_repowiki.py +109 -0
  106. package/templates/qoder/scripts/domain/task/__pycache__/wlkj_panel.cpython-39.pyc +0 -0
  107. package/templates/qoder/scripts/domain/task/{zentao_panel.py → wlkj_panel.py} +315 -53
  108. package/templates/qoder/scripts/engine/poller.py +219 -0
  109. package/templates/qoder/scripts/foundation/__pycache__/__init__.cpython-39.pyc +0 -0
  110. package/templates/qoder/scripts/foundation/core/__pycache__/__init__.cpython-39.pyc +0 -0
  111. package/templates/qoder/scripts/foundation/core/__pycache__/paths.cpython-39.pyc +0 -0
  112. package/templates/qoder/scripts/foundation/integrations/active_task.py +2 -1
  113. package/templates/qoder/scripts/orchestration/wlkj.py +4 -0
  114. package/templates/qoder/scripts/protocol/__pycache__/__init__.cpython-39.pyc +0 -0
  115. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1 -1
  116. package/templates/qoder/scripts/protocol/transports/__pycache__/__init__.cpython-39.pyc +0 -0
  117. package/templates/qoder/scripts/protocol/transports/__pycache__/base.cpython-39.pyc +0 -0
  118. package/templates/qoder/scripts/protocol/transports/__pycache__/cli.cpython-39.pyc +0 -0
  119. package/templates/qoder/scripts/protocol/transports/__pycache__/http.cpython-39.pyc +0 -0
  120. package/templates/qoder/scripts/protocol/transports/__pycache__/stdio.cpython-39.pyc +0 -0
  121. package/templates/qoder/scripts/protocol/transports/http.py +7 -1
  122. package/templates/root/AGENTS.md +9 -10
@@ -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