@hupan56/wlkj 3.0.0 → 3.1.3
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 +1435 -1373
- package/package.json +1 -1
- package/templates/qoder/commands/optional/wl-insight.md +6 -4
- package/templates/qoder/commands/optional/wl-report.md +20 -39
- package/templates/qoder/commands/optional/wl-status.md +4 -4
- package/templates/qoder/commands/wl-code.md +2 -2
- package/templates/qoder/commands/wl-design.md +5 -5
- package/templates/qoder/commands/wl-init.md +3 -3
- package/templates/qoder/commands/wl-prd.md +26 -13
- package/templates/qoder/commands/wl-req.md +3 -3
- package/templates/qoder/commands/wl-search.md +78 -47
- package/templates/qoder/commands/wl-task.md +343 -40
- package/templates/qoder/commands/wl-test.md +10 -10
- package/templates/qoder/config.yaml +35 -13
- package/templates/qoder/hooks/post-tool-use.py +181 -0
- package/templates/qoder/hooks/session-start.py +82 -1
- package/templates/qoder/hooks/stop-eval.py +207 -0
- package/templates/qoder/hooks/user-prompt-submit.py +139 -0
- package/templates/qoder/rules/wl-pipeline.md +70 -8
- package/templates/qoder/scripts/README.md +78 -115
- package/templates/qoder/scripts/capability/__init__.py +26 -0
- package/templates/qoder/scripts/capability/__main__.py +72 -0
- package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
- package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
- package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
- package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
- package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
- package/templates/qoder/scripts/capability/caps/context.py +36 -0
- package/templates/qoder/scripts/capability/caps/cron.py +50 -0
- package/templates/qoder/scripts/capability/caps/identity.py +43 -0
- package/templates/qoder/scripts/capability/caps/memory.py +71 -0
- package/templates/qoder/scripts/capability/caps/notify.py +41 -0
- package/templates/qoder/scripts/capability/caps/present.py +48 -0
- package/templates/qoder/scripts/capability/caps/repo.py +31 -0
- package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
- package/templates/qoder/scripts/capability/chain.py +92 -0
- package/templates/qoder/scripts/capability/memory_chain.py +41 -0
- package/templates/qoder/scripts/capability/registry.py +246 -0
- package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
- package/templates/qoder/scripts/capability/smoke_test.py +211 -0
- package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
- package/templates/qoder/scripts/{report → deployment/setup}/__init__.py +11 -11
- package/templates/qoder/scripts/{setup → deployment/setup}/carriers.py +33 -26
- package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
- package/templates/qoder/scripts/{setup → deployment/setup}/init_doctor.py +55 -23
- package/templates/qoder/scripts/{setup → deployment/setup}/install_qoderwork.py +20 -12
- package/templates/qoder/scripts/{setup → deployment/setup}/platform_doctor.py +8 -2
- package/templates/qoder/scripts/{setup → deployment/setup}/repo_root.py +113 -112
- package/templates/qoder/scripts/{setup → deployment/setup}/setup.py +35 -12
- package/templates/qoder/scripts/{setup → deployment/setup}/setup_lanhu.py +13 -7
- package/templates/qoder/scripts/domain/__init__.py +0 -0
- package/templates/qoder/scripts/domain/design/__init__.py +0 -0
- package/templates/qoder/scripts/{report → domain/design}/fill_prototype.py +12 -6
- package/templates/qoder/scripts/{report → domain/design}/gen_design_doc.py +8 -2
- package/templates/qoder/scripts/{setup → domain/kg}/__init__.py +11 -11
- package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
- package/templates/qoder/scripts/{kg → domain/kg/build}/build_entity_registry.py +7 -2
- package/templates/qoder/scripts/{kg → domain/kg/build}/build_relations.py +7 -2
- package/templates/qoder/scripts/{kg → domain/kg/build}/build_style_index.py +13 -7
- package/templates/qoder/scripts/{kg → domain/kg/build}/build_workflows.py +7 -2
- package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build.py +76 -9
- package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build_db.py +7 -2
- package/templates/qoder/scripts/{kg → domain/kg/build}/kg_incremental.py +11 -6
- package/templates/qoder/scripts/{report → domain/kg/build}/learn_aggregate.py +9 -4
- package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
- package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
- package/templates/qoder/scripts/{common → domain/kg/extract}/test_extract.py +115 -115
- package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
- package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
- package/templates/qoder/scripts/{kg → domain/kg/graph}/kg_link_db.py +7 -2
- package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
- package/templates/qoder/scripts/{kg → domain/kg}/kg.py +263 -30
- package/templates/qoder/scripts/{common → domain/kg}/kg_capabilities.py +182 -182
- package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
- package/templates/qoder/scripts/{kg → domain/kg/search}/context_pack.py +30 -9
- package/templates/qoder/scripts/{kg → domain/kg/search}/enrich_prompt.py +10 -4
- package/templates/qoder/scripts/{kg → domain/kg/search}/prefetch.py +33 -8
- package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
- package/templates/qoder/scripts/{kg → domain/kg/search}/search_index.py +143 -77
- package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
- package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
- package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
- package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
- package/templates/qoder/scripts/{kg → domain/kg/storage}/kg_duckdb.py +38 -14
- package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
- package/templates/qoder/scripts/{report → domain/learning}/learn.py +8 -3
- package/templates/qoder/scripts/{mcp → domain/report}/__init__.py +11 -11
- package/templates/qoder/scripts/{report → domain/report}/add_session.py +9 -3
- package/templates/qoder/scripts/{report → domain/report}/export.py +10 -5
- package/templates/qoder/scripts/{report → domain/report}/report.py +9 -4
- package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
- package/templates/qoder/scripts/{report → domain/report}/role.py +10 -4
- package/templates/qoder/scripts/{report → domain/report}/status.py +112 -9
- package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
- package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
- package/templates/qoder/scripts/{report → domain/requirement}/archive_prd.py +8 -2
- package/templates/qoder/scripts/{report → domain/requirement}/req.py +228 -222
- package/templates/qoder/scripts/{kg → domain/task}/__init__.py +11 -11
- package/templates/qoder/scripts/domain/task/__pycache__/syncgate.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/{task → domain/task}/git_sync.py +40 -21
- package/templates/qoder/scripts/{task → domain/task}/syncgate.py +13 -8
- package/templates/qoder/scripts/{task → domain/task}/task.py +13 -5
- package/templates/qoder/scripts/{task → domain/task}/task_lifecycle.py +606 -596
- package/templates/qoder/scripts/{task → domain/task}/task_query.py +162 -161
- package/templates/qoder/scripts/{task → domain/task}/task_relations.py +425 -424
- package/templates/qoder/scripts/{task → domain/task}/team_sync.py +9 -4
- package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
- package/templates/qoder/scripts/foundation/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/foundation/__pycache__/bootstrap.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/{common → foundation}/bootstrap.py +10 -10
- package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/core/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/foundation/core/__pycache__/paths.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/{common → foundation/core}/cmd_registry.py +1 -1
- package/templates/qoder/scripts/{common → foundation/core}/config.py +1 -1
- package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -586
- package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
- package/templates/qoder/scripts/{common → foundation/data}/contract.py +2 -2
- package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
- package/templates/qoder/scripts/{common → foundation/data}/result.py +1 -1
- package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -404
- package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/identity/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/foundation/identity/__pycache__/identity.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/{common → foundation/identity}/check_publish.py +103 -98
- package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -239
- package/templates/qoder/scripts/{common → foundation/identity}/guard.py +2 -2
- package/templates/qoder/scripts/{common → foundation/identity}/identity.py +14 -10
- package/templates/qoder/scripts/{common → foundation/identity}/roles.py +1 -1
- package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
- package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
- package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +2 -2
- package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
- package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
- package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/io/__pycache__/__init__.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/foundation/io/__pycache__/atomicio.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/foundation/io/__pycache__/filelock.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
- package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
- package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
- package/templates/qoder/scripts/{common → foundation/protocol}/mcp_base.py +1 -1
- package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
- package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
- package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
- package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
- package/templates/qoder/scripts/orchestration/__init__.py +0 -0
- package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
- package/templates/qoder/scripts/protocol/__init__.py +0 -0
- package/templates/qoder/scripts/protocol/browser/README.md +207 -0
- package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
- package/templates/qoder/scripts/protocol/browser/config.env +9 -0
- package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
- package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
- package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
- package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
- package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
- package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
- package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
- package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
- package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
- package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
- package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
- package/templates/qoder/scripts/{mcp → protocol/mcp}/lanhu_stdio_wrapper.py +11 -5
- package/templates/qoder/scripts/{mcp → protocol/mcp}/mcp_doctor.py +47 -14
- package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
- package/templates/qoder/scripts/{mcp → protocol/mcp}/mysql_mcp_server.py +181 -67
- package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
- package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
- package/templates/qoder/scripts/protocol/transports/base.py +87 -0
- package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
- package/templates/qoder/scripts/protocol/transports/http.py +141 -0
- package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
- package/templates/qoder/scripts/run_weekly_update.bat +27 -18
- package/templates/qoder/scripts/run_weekly_update.sh +22 -13
- package/templates/qoder/scripts/validation/__init__.py +0 -0
- package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
- package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
- package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
- package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
- package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
- package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
- package/templates/qoder/scripts/{report → validation/metrics}/eval_prd.py +17 -10
- package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
- package/templates/qoder/scripts/validation/test/__init__.py +11 -0
- package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
- package/templates/qoder/scripts/{test → validation/test}/autotest.py +64 -4
- package/templates/qoder/scripts/{common → validation/test}/autotest_auth.py +1 -1
- package/templates/qoder/scripts/{test → validation/test}/autotest_batch.py +16 -3
- package/templates/qoder/scripts/{test → validation/test}/autotest_data.py +17 -12
- package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
- package/templates/qoder/scripts/{test → validation/test}/autotest_run.py +17 -3
- package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
- package/templates/qoder/scripts/{test → validation/test}/benchmark.py +12 -6
- package/templates/qoder/scripts/{test → validation/test}/kg_auto_login.py +8 -2
- package/templates/qoder/scripts/{test → validation/test}/kg_test_runner.py +7 -2
- package/templates/qoder/scripts/{test → validation/test}/page_probe.py +8 -3
- package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
- package/templates/qoder/settings.json +30 -0
- package/templates/qoder/skills/design-import/SKILL.md +22 -13
- package/templates/qoder/skills/design-review/SKILL.md +19 -10
- package/templates/qoder/skills/prd-generator/SKILL.md +22 -18
- package/templates/qoder/skills/prd-review/SKILL.md +6 -4
- package/templates/qoder/skills/prototype-generator/SKILL.md +63 -14
- package/templates/qoder/skills/spec-coder/SKILL.md +22 -13
- package/templates/qoder/skills/spec-generator/SKILL.md +22 -10
- package/templates/qoder/skills/test-generator/SKILL.md +7 -5
- package/templates/qoder/skills/wl-code/SKILL.md +23 -11
- package/templates/qoder/skills/wl-commit/SKILL.md +9 -8
- package/templates/qoder/skills/wl-design/SKILL.md +5 -3
- package/templates/qoder/skills/wl-init/SKILL.md +6 -6
- package/templates/qoder/skills/wl-insight/SKILL.md +23 -10
- package/templates/qoder/skills/wl-prd-full/SKILL.md +57 -6
- package/templates/qoder/skills/wl-prd-quick/SKILL.md +3 -3
- package/templates/qoder/skills/wl-prd-review/SKILL.md +16 -4
- package/templates/qoder/skills/wl-report/SKILL.md +25 -23
- package/templates/qoder/skills/wl-search/SKILL.md +149 -78
- package/templates/qoder/skills/wl-spec/SKILL.md +7 -5
- package/templates/qoder/skills/wl-status/SKILL.md +48 -16
- package/templates/qoder/skills/wl-task/SKILL.md +92 -10
- package/templates/qoder/skills/wl-test/SKILL.md +75 -29
- package/templates/qoder/templates/prd-full-template.md +7 -0
- package/templates/root/AGENTS.md +275 -236
- package/templates/root/requirements.txt +3 -0
- package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
- package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
- package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +0 -23
- package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +0 -23
- package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +0 -1
- package/templates/.qoder/learning/eval-history.jsonl +0 -28
- package/templates/data/index/wiki-index.json +0 -8
- package/templates/qoder/nul +0 -4
- package/templates/qoder/scripts/kg/extract.py +0 -398
- package/templates/qoder/scripts/kg/kg_semantic.py +0 -156
- package/templates/qoder/scripts/mcp/kg_mcp_server.py +0 -606
- package/templates/qoder/scripts/mcp/mcp_launcher.py +0 -442
- package/templates/qoder/scripts/mcp/zentao_mcp_server.py +0 -384
- package/templates/qoder/scripts/task/__init__.py +0 -11
- package/templates/qoder/scripts/test/__init__.py +0 -11
- package/templates/qoder/scripts/wlkj.py +0 -116
- /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
- /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
- /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
- /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
- /package/templates/qoder/scripts/{test → validation/test}/secure-ls.js +0 -0
|
@@ -1,9 +1,15 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
# v3.0 路径自举: 引导到 common/bootstrap, 统一 sys.path 逻辑
|
|
3
3
|
import os as _o, sys as _s
|
|
4
|
-
|
|
4
|
+
_f = _o.path.abspath(__file__)
|
|
5
|
+
for _ in range(10):
|
|
6
|
+
_f = _o.path.dirname(_f)
|
|
7
|
+
_cp = _o.path.join(_f, 'foundation')
|
|
8
|
+
if _o.path.isfile(_o.path.join(_cp, 'bootstrap.py')):
|
|
9
|
+
break
|
|
5
10
|
if _cp not in _s.path: _s.path.insert(0, _cp)
|
|
6
11
|
from bootstrap import setup; setup()
|
|
12
|
+
from foundation.core.paths import get_repo_root
|
|
7
13
|
|
|
8
14
|
"""
|
|
9
15
|
kg.py — QODER 知识图谱统一 CLI 入口(全系列通用)
|
|
@@ -16,7 +22,7 @@ kg.py — QODER 知识图谱统一 CLI 入口(全系列通用)
|
|
|
16
22
|
1. 不复制逻辑 — 调底层: search_index / context_pack / graph_traverse /
|
|
17
23
|
kg_duckdb / repowiki / fill_prototype / gen_design_doc
|
|
18
24
|
2. 全容错 — DuckDB/索引缺失优雅降级,给修复提示,绝不抛栈给用户
|
|
19
|
-
3. 参数统一 —
|
|
25
|
+
3. 参数统一 — 15 个子命令风格一致,对标 MCP 工具名
|
|
20
26
|
4. 纯文本输出 — UTF-8,无日志噪音,AI 直接读
|
|
21
27
|
|
|
22
28
|
用法:
|
|
@@ -40,8 +46,8 @@ try:
|
|
|
40
46
|
except Exception:
|
|
41
47
|
pass
|
|
42
48
|
|
|
43
|
-
SCRIPTS_DIR =
|
|
44
|
-
BASE_DIR =
|
|
49
|
+
SCRIPTS_DIR = get_repo_root()
|
|
50
|
+
BASE_DIR = get_repo_root()
|
|
45
51
|
sys.path.insert(0, SCRIPTS_DIR)
|
|
46
52
|
_KG_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
47
53
|
if _KG_DIR not in sys.path: sys.path.insert(0, _KG_DIR) # 同包import
|
|
@@ -51,7 +57,7 @@ if _KG_DIR not in sys.path: sys.path.insert(0, _KG_DIR) # 同包import
|
|
|
51
57
|
def _index_dir():
|
|
52
58
|
"""获取 data/index 目录(延迟导入,避免顶层崩)。"""
|
|
53
59
|
try:
|
|
54
|
-
from
|
|
60
|
+
from foundation.core.paths import DATA_INDEX_DIR
|
|
55
61
|
return str(DATA_INDEX_DIR)
|
|
56
62
|
except Exception:
|
|
57
63
|
# 兜底: 常规布局
|
|
@@ -89,7 +95,7 @@ def cmd_search(args):
|
|
|
89
95
|
kw, plat = _split_kw_platform(args)
|
|
90
96
|
if not kw:
|
|
91
97
|
return "请提供搜索关键词"
|
|
92
|
-
import search_index as S
|
|
98
|
+
from domain.kg.search import search_index as S
|
|
93
99
|
# search_keywords(query, platform=None) 自带中文扩展,不需外层 expand
|
|
94
100
|
return _capture(S.search_keywords, kw, plat) or "无匹配结果"
|
|
95
101
|
|
|
@@ -98,7 +104,7 @@ def cmd_api(args):
|
|
|
98
104
|
"""搜 API 端点。"""
|
|
99
105
|
if not args:
|
|
100
106
|
return "用法: kg.py api <关键词>"
|
|
101
|
-
import search_index as S
|
|
107
|
+
from domain.kg.search import search_index as S
|
|
102
108
|
return _capture(S.search_api, args[0]) or "无匹配 API"
|
|
103
109
|
|
|
104
110
|
|
|
@@ -106,7 +112,7 @@ def cmd_prd(args):
|
|
|
106
112
|
"""搜 PRD(防重复造轮子)。"""
|
|
107
113
|
if not args:
|
|
108
114
|
return "用法: kg.py prd <关键词>"
|
|
109
|
-
import search_index as S
|
|
115
|
+
from domain.kg.search import search_index as S
|
|
110
116
|
return _capture(S.search_prds, args[0]) or "无匹配 PRD"
|
|
111
117
|
|
|
112
118
|
|
|
@@ -114,7 +120,7 @@ def cmd_impact(args):
|
|
|
114
120
|
"""影响分析: 改某接口影响哪些前端页面/按钮。"""
|
|
115
121
|
if not args:
|
|
116
122
|
return "用法: kg.py impact <端点或关键词> 例: /asset 或 export"
|
|
117
|
-
import search_index as S
|
|
123
|
+
from domain.kg.search import search_index as S
|
|
118
124
|
return _capture(S.search_impact, args[0]) or "未找到匹配端点"
|
|
119
125
|
|
|
120
126
|
|
|
@@ -122,7 +128,7 @@ def cmd_context360(args):
|
|
|
122
128
|
"""符号 360 度视图: 端点/函数/处理器的全部关联。"""
|
|
123
129
|
if not args:
|
|
124
130
|
return "用法: kg.py context360 <符号> 例: handleExport 或 /system/role"
|
|
125
|
-
import search_index as S
|
|
131
|
+
from domain.kg.search import search_index as S
|
|
126
132
|
return _capture(S.search_context360, args[0]) or "未找到匹配符号"
|
|
127
133
|
|
|
128
134
|
|
|
@@ -147,7 +153,7 @@ def cmd_context(args):
|
|
|
147
153
|
kw = rest2[0] if rest2 else ''
|
|
148
154
|
if not kw:
|
|
149
155
|
return "请提供业务关键词"
|
|
150
|
-
import context_pack as C
|
|
156
|
+
from domain.kg.search import context_pack as C
|
|
151
157
|
full = _capture(C._compute_and_print, kw, plat, '')
|
|
152
158
|
if not full:
|
|
153
159
|
return "无匹配上下文"
|
|
@@ -177,11 +183,11 @@ def cmd_prefetch(args):
|
|
|
177
183
|
query = ' '.join(rest2) if rest2 else ''
|
|
178
184
|
if not query:
|
|
179
185
|
return "请提供需求描述(一句话)"
|
|
180
|
-
import prefetch as P
|
|
186
|
+
from domain.kg.search import prefetch as P
|
|
181
187
|
primary_cn, en_words = P.predict_words(query)
|
|
182
188
|
if not en_words:
|
|
183
189
|
# 降级: 预测不出词 → 单词 context_pack
|
|
184
|
-
import context_pack as C
|
|
190
|
+
from domain.kg.search import context_pack as C
|
|
185
191
|
return _capture(C._compute_and_print, query, plat, '') or "无匹配上下文"
|
|
186
192
|
targets = []
|
|
187
193
|
if plat and plat.lower() not in ('both', '两端'):
|
|
@@ -194,7 +200,7 @@ def cmd_prefetch(args):
|
|
|
194
200
|
|
|
195
201
|
def cmd_coverage(args):
|
|
196
202
|
"""功能×测试覆盖矩阵: 哪些功能有测试,哪些是盲区。"""
|
|
197
|
-
from
|
|
203
|
+
from domain.kg.graph.graph_traverse import CodeGraph
|
|
198
204
|
g = CodeGraph(_index_dir())
|
|
199
205
|
return g.coverage_matrix() or "无法生成覆盖矩阵(索引可能为空)"
|
|
200
206
|
|
|
@@ -222,7 +228,7 @@ def cmd_feature(args):
|
|
|
222
228
|
try: con.close()
|
|
223
229
|
except Exception: pass
|
|
224
230
|
# 回退: CodeGraph 的 JSON 实现(entity-registry.json 通常不存在)
|
|
225
|
-
from
|
|
231
|
+
from domain.kg.graph.graph_traverse import CodeGraph
|
|
226
232
|
g = CodeGraph(_index_dir())
|
|
227
233
|
return g.feature_overview(feat) or "未找到功能 '%s'" % feat
|
|
228
234
|
|
|
@@ -386,7 +392,7 @@ def cmd_workflow(args):
|
|
|
386
392
|
|
|
387
393
|
def _workflow_query(con, q):
|
|
388
394
|
"""workflows 表查询 — v3.0 f3: 转发到 common.kg_capabilities (单一真源, CLI/MCP共用)。"""
|
|
389
|
-
from
|
|
395
|
+
from domain.kg.kg_capabilities import workflow_query
|
|
390
396
|
return workflow_query(con, q)
|
|
391
397
|
|
|
392
398
|
|
|
@@ -404,11 +410,11 @@ def cmd_hop(args):
|
|
|
404
410
|
import duckdb
|
|
405
411
|
except ImportError:
|
|
406
412
|
return "未安装 duckdb。请运行: pip install duckdb"
|
|
407
|
-
import kg_duckdb as K
|
|
413
|
+
from domain.kg.storage import kg_duckdb as K
|
|
408
414
|
con = duckdb.connect(_kg_db_path(), read_only=True)
|
|
409
415
|
try:
|
|
410
416
|
# v3.0 f3: 核心查询转发到 common.kg_capabilities.hop_query (CLI/MCP共用)
|
|
411
|
-
from
|
|
417
|
+
from domain.kg.kg_capabilities import hop_query
|
|
412
418
|
return hop_query(con, symbol, depth, multi_hop_fn=K.multi_hop)
|
|
413
419
|
finally:
|
|
414
420
|
try: con.close()
|
|
@@ -419,7 +425,7 @@ def cmd_wiki(args):
|
|
|
419
425
|
"""Repo Wiki 搜索 — v3.0 f3: 转发到 common.kg_capabilities.wiki_query (CLI/MCP共用)。"""
|
|
420
426
|
if not args:
|
|
421
427
|
return "用法: kg.py wiki <关键词>"
|
|
422
|
-
from
|
|
428
|
+
from domain.kg.kg_capabilities import wiki_query
|
|
423
429
|
result = wiki_query(args[0])
|
|
424
430
|
# CLI 额外提示
|
|
425
431
|
if 'matching' in result:
|
|
@@ -434,13 +440,14 @@ def cmd_fill_prototype(args):
|
|
|
434
440
|
kw, plat = _split_kw_platform(args)
|
|
435
441
|
plat = plat or 'web'
|
|
436
442
|
import subprocess as _sp
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
443
|
+
from foundation.core.paths import find_script
|
|
444
|
+
script = find_script('fill_prototype.py')
|
|
445
|
+
if script is None:
|
|
446
|
+
return "fill_prototype.py 未找到 (脚本迁移后路径未更新)"
|
|
440
447
|
try:
|
|
441
|
-
r = _sp.run([sys.executable, script, kw, '--platform', plat],
|
|
448
|
+
r = _sp.run([sys.executable, str(script), kw, '--platform', plat],
|
|
442
449
|
capture_output=True, text=True, encoding='utf-8',
|
|
443
|
-
errors='replace', timeout=30, cwd=
|
|
450
|
+
errors='replace', timeout=30, cwd=str(script.parent))
|
|
444
451
|
return r.stdout or "fill_prototype 无输出(可能索引缺失)"
|
|
445
452
|
except Exception as e:
|
|
446
453
|
return "[error] fill_prototype: %s" % str(e)
|
|
@@ -454,9 +461,10 @@ def cmd_design_system(args):
|
|
|
454
461
|
import subprocess as _sp
|
|
455
462
|
design_md = os.path.join(BASE_DIR, 'data', 'design', 'DESIGN.md')
|
|
456
463
|
if not os.path.isfile(design_md):
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
464
|
+
from foundation.core.paths import find_script
|
|
465
|
+
gen_script = find_script('gen_design_doc.py')
|
|
466
|
+
if gen_script is not None:
|
|
467
|
+
_sp.run([sys.executable, str(gen_script)], capture_output=True, timeout=30)
|
|
460
468
|
if os.path.isfile(design_md):
|
|
461
469
|
content = open(design_md, encoding='utf-8').read()
|
|
462
470
|
if plat:
|
|
@@ -472,7 +480,193 @@ def cmd_design_system(args):
|
|
|
472
480
|
result.append(line)
|
|
473
481
|
return '\n'.join(result) if result else content
|
|
474
482
|
return content
|
|
475
|
-
return "DESIGN.md 不存在且生成失败。请手动跑: python .qoder/scripts/gen_design_doc.py"
|
|
483
|
+
return "DESIGN.md 不存在且生成失败。请手动跑: python .qoder/scripts/design/gen_design_doc.py"
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
def cmd_semantic(args):
|
|
487
|
+
"""语义搜索: 用自然语言找代码/API (概念检索, 不依赖精确关键词)。
|
|
488
|
+
|
|
489
|
+
需先构建 embedding 向量 (管理员): kg_semantic.py build-embeddings。
|
|
490
|
+
模型未装时给出安装提示, 不崩溃。
|
|
491
|
+
"""
|
|
492
|
+
if not args:
|
|
493
|
+
return ("用法: kg.py semantic <自然语言查询> [--top N]\n"
|
|
494
|
+
" 语义检索: 查'报销'能命中 expense/reimburse\n"
|
|
495
|
+
" 需先构建: python .qoder/scripts/domain/kg/graph/kg_semantic.py build-embeddings")
|
|
496
|
+
query = args[0]
|
|
497
|
+
top_k = 10
|
|
498
|
+
if '--top' in args:
|
|
499
|
+
idx = args.index('--top')
|
|
500
|
+
if idx + 1 < len(args):
|
|
501
|
+
try:
|
|
502
|
+
top_k = int(args[idx + 1])
|
|
503
|
+
except ValueError:
|
|
504
|
+
pass
|
|
505
|
+
from domain.kg.graph.kg_semantic import semantic_search, embedding_status
|
|
506
|
+
results = semantic_search(query, top_k=top_k)
|
|
507
|
+
if results is None:
|
|
508
|
+
st = embedding_status()
|
|
509
|
+
if not st['available']:
|
|
510
|
+
return ("语义检索未启用: sentence-transformers 未安装。\n"
|
|
511
|
+
"启用: pip install sentence-transformers (95MB模型首次自动下载)")
|
|
512
|
+
elif st['embeddings_count'] == 0:
|
|
513
|
+
return ("语义检索未构建向量。请管理员运行:\n"
|
|
514
|
+
" python .qoder/scripts/domain/kg/graph/kg_semantic.py build-embeddings")
|
|
515
|
+
if not results:
|
|
516
|
+
return "无匹配结果"
|
|
517
|
+
out = ["语义搜索: %s (top %d)" % (query, len(results))]
|
|
518
|
+
for eid, text, score in results:
|
|
519
|
+
out.append(" %.3f %s" % (score, text[:70]))
|
|
520
|
+
return '\n'.join(out)
|
|
521
|
+
|
|
522
|
+
|
|
523
|
+
# ── 中文文案/报错溯源 (grep-text): 单进程安全兜底, 替代 findstr/s 全盘扫描 ──
|
|
524
|
+
# 设计动机: 用户查"车辆不存在""项目车号"这类中文文案时, kg.py 的代码标识符索引
|
|
525
|
+
# 天然查不到 (索引按英文标识符建)。AI 若兜底去 findstr /s 或 os.walk 全库
|
|
526
|
+
# (8973+ 文件) → Windows 卡死 + 疯狂弹 cmd 窗口。本命令是这类需求的唯一安全通道:
|
|
527
|
+
# 单进程、限定 data/code、限定扩展名、有行数上限, 绝不递归弹子进程。
|
|
528
|
+
_GREP_EXTS = ('.java', '.vue', '.ts', '.tsx', '.js', '.jsx', '.xml', '.html',
|
|
529
|
+
'.json', '.sql', '.properties', '.yml', '.yaml', '.ftl', '.txt')
|
|
530
|
+
|
|
531
|
+
|
|
532
|
+
def cmd_grep_text(args):
|
|
533
|
+
"""中文文案/报错溯源: 在 data/code 里搜中文短语 (报错文案/字段标签/业务词)。
|
|
534
|
+
|
|
535
|
+
单进程 Python, 限定扩展名, 上限 200 命中 + 30 文件。绝不弹子进程窗口。
|
|
536
|
+
用法: kg.py grep-text <中文短语> [--ext java,vue] [--limit N] [--platform web|app]
|
|
537
|
+
"""
|
|
538
|
+
if not args:
|
|
539
|
+
return ("用法: kg.py grep-text <中文短语> [选项]\n"
|
|
540
|
+
" 在 data/code 里搜中文文案/报错/字段标签 (kg.py search 查不到中文时用这个)\n"
|
|
541
|
+
" --ext java,vue 限定文件类型 (默认: java/vue/ts/xml/json...)\n"
|
|
542
|
+
" --limit N 最多返回 N 条命中 (默认 50)\n"
|
|
543
|
+
" --platform web|app 只搜某平台源码\n"
|
|
544
|
+
"示例: kg.py grep-text 车辆不存在")
|
|
545
|
+
import os as _os
|
|
546
|
+
# kg.py 在 .qoder/scripts/domain/kg/ 下, 往上 4 级到 repo 根
|
|
547
|
+
here = _os.path.dirname(_os.path.abspath(__file__)) # .../domain/kg/
|
|
548
|
+
base = _os.path.dirname(_os.path.dirname(_os.path.dirname(_os.path.dirname(here)))) # repo 根
|
|
549
|
+
code_root = _os.path.join(base, 'data', 'code')
|
|
550
|
+
if not _os.path.isdir(code_root):
|
|
551
|
+
return ('data/code 不存在 (源码未克隆)。跑 python .qoder/scripts/deployment/setup/init_doctor.py --fix')
|
|
552
|
+
|
|
553
|
+
query = args[0]
|
|
554
|
+
# 解析选项
|
|
555
|
+
exts = set(_GREP_EXTS)
|
|
556
|
+
limit = 50
|
|
557
|
+
user_limit = None # 记录用户是否显式传了 --limit (决定是否启用 early_stop)
|
|
558
|
+
plat = ''
|
|
559
|
+
i = 1
|
|
560
|
+
while i < len(args):
|
|
561
|
+
a = args[i]
|
|
562
|
+
if a == '--ext' and i + 1 < len(args):
|
|
563
|
+
exts = set('.' + e.lstrip('.') for e in args[i + 1].split(',') if e.strip())
|
|
564
|
+
i += 2; continue
|
|
565
|
+
if a == '--limit' and i + 1 < len(args):
|
|
566
|
+
try:
|
|
567
|
+
limit = max(1, int(args[i + 1]))
|
|
568
|
+
user_limit = limit # 用户显式指定了, early_stop 不再介入
|
|
569
|
+
except ValueError: pass
|
|
570
|
+
i += 2; continue
|
|
571
|
+
if a == '--platform' and i + 1 < len(args):
|
|
572
|
+
plat = args[i + 1]; i += 2; continue
|
|
573
|
+
i += 1
|
|
574
|
+
|
|
575
|
+
# 平台 → 子目录过滤
|
|
576
|
+
proj_dirs = []
|
|
577
|
+
if not plat:
|
|
578
|
+
for d in sorted(_os.listdir(code_root)):
|
|
579
|
+
if _os.path.isdir(_os.path.join(code_root, d)) and not d.startswith('.'):
|
|
580
|
+
proj_dirs.append(d)
|
|
581
|
+
elif plat in ('web', 'pc'):
|
|
582
|
+
proj_dirs = [d for d in ('fywl-ui',) if _os.path.isdir(_os.path.join(code_root, d))]
|
|
583
|
+
elif plat in ('app', 'h5'):
|
|
584
|
+
proj_dirs = [d for d in ('Carmg-H5',) if _os.path.isdir(_os.path.join(code_root, d))]
|
|
585
|
+
else:
|
|
586
|
+
proj_dirs = [d for d in sorted(_os.listdir(code_root))
|
|
587
|
+
if _os.path.isdir(_os.path.join(code_root, d)) and not d.startswith('.')]
|
|
588
|
+
|
|
589
|
+
hits = []
|
|
590
|
+
files_hit = 0
|
|
591
|
+
scanned = 0
|
|
592
|
+
import time as _time
|
|
593
|
+
deadline = _time.monotonic() + 15 # 硬超时 15s: data/code 大目录上避免 30s+ 卡死
|
|
594
|
+
timed_out = False
|
|
595
|
+
# 够用即停阈值: 仅当用户没显式指定 --limit 时启用 (默认场景快速溯源)。
|
|
596
|
+
# 用户传了 --limit 就完全尊重它, 不被 early_stop 截断 (原 max(10,min(limit,30))
|
|
597
|
+
# 会把 --limit 50 截成 30、把 --limit 5 抬到 10, 违背用户契约)。
|
|
598
|
+
early_stop = 30 if user_limit is None else None
|
|
599
|
+
for proj in proj_dirs:
|
|
600
|
+
proj_path = _os.path.join(code_root, proj)
|
|
601
|
+
for dirpath, dirnames, filenames in _os.walk(proj_path):
|
|
602
|
+
# 跳过明显的依赖/构建目录, 加速
|
|
603
|
+
dirnames[:] = [d for d in dirnames if d not in
|
|
604
|
+
('node_modules', '.git', 'target', 'dist', 'build', '.idea', '__pycache__')]
|
|
605
|
+
for fn in filenames:
|
|
606
|
+
# 文件级超时检查: 避免单个大文件卡死目录内循环 (15s 硬超时在目录级
|
|
607
|
+
# 检查时形同虚设)。已找到结果才超时退出, 没找到继续扫。
|
|
608
|
+
if hits and _time.monotonic() > deadline:
|
|
609
|
+
timed_out = True
|
|
610
|
+
break
|
|
611
|
+
ext = _os.path.splitext(fn)[1].lower()
|
|
612
|
+
if ext not in exts:
|
|
613
|
+
continue
|
|
614
|
+
fp = _os.path.join(dirpath, fn)
|
|
615
|
+
# 跳过大文件 (>500KB 多半是生成/压缩文件, 拖慢扫描)
|
|
616
|
+
try:
|
|
617
|
+
if _os.path.getsize(fp) > 500_000:
|
|
618
|
+
continue
|
|
619
|
+
except OSError:
|
|
620
|
+
continue
|
|
621
|
+
scanned += 1
|
|
622
|
+
done = False
|
|
623
|
+
try:
|
|
624
|
+
with open(fp, 'r', encoding='utf-8', errors='ignore') as fh:
|
|
625
|
+
for lineno, line in enumerate(fh, 1):
|
|
626
|
+
# 逐文件行级超时检查: 极大文件逐行读也能及时退出
|
|
627
|
+
if lineno % 20000 == 0 and hits and _time.monotonic() > deadline:
|
|
628
|
+
timed_out = True
|
|
629
|
+
done = True
|
|
630
|
+
break
|
|
631
|
+
if query in line:
|
|
632
|
+
rel = _os.path.relpath(fp, code_root).replace('\\', '/')
|
|
633
|
+
snippet = line.strip()[:120]
|
|
634
|
+
hits.append((rel, lineno, snippet))
|
|
635
|
+
if len(hits) >= limit:
|
|
636
|
+
done = True
|
|
637
|
+
break
|
|
638
|
+
# 够用即停 (仅默认场景): 与 limit 同级行内检查,
|
|
639
|
+
# 避免单文件多行命中跨过 early_stop (原34>30问题)
|
|
640
|
+
if early_stop is not None and len(hits) >= early_stop:
|
|
641
|
+
done = True
|
|
642
|
+
break
|
|
643
|
+
except (OSError, UnicodeDecodeError):
|
|
644
|
+
pass
|
|
645
|
+
if done or len(hits) >= limit:
|
|
646
|
+
break
|
|
647
|
+
# 够用即停 (仅默认场景; 用户显式 limit 时 early_stop=None 跳过)
|
|
648
|
+
if early_stop is not None and len(hits) >= early_stop:
|
|
649
|
+
break
|
|
650
|
+
if timed_out or len(hits) >= limit or (early_stop is not None and len(hits) >= early_stop):
|
|
651
|
+
break
|
|
652
|
+
if timed_out or len(hits) >= limit or (early_stop is not None and len(hits) >= early_stop):
|
|
653
|
+
break
|
|
654
|
+
|
|
655
|
+
# 统计命中文件数 (去重)
|
|
656
|
+
files_hit = len(set(h[0] for h in hits))
|
|
657
|
+
if not hits:
|
|
658
|
+
return ('未找到 "%s" (扫描 %d 个文件, %s)\n'
|
|
659
|
+
'提示: 换近义词, 或用 kg.py semantic "%s" 语义检索' % (
|
|
660
|
+
query, scanned, '/'.join(proj_dirs) or 'data/code', query))
|
|
661
|
+
out = ['grep-text: "%s" → %d 命中 / %d 文件 (扫描 %d 文件%s)' % (
|
|
662
|
+
query, len(hits), files_hit, scanned, ', ⏱15s超时已返回部分结果' if timed_out else '')]
|
|
663
|
+
last_file = ''
|
|
664
|
+
for rel, lineno, snippet in hits:
|
|
665
|
+
if rel != last_file:
|
|
666
|
+
out.append('\n■ %s' % rel)
|
|
667
|
+
last_file = rel
|
|
668
|
+
out.append(' L%d: %s' % (lineno, snippet))
|
|
669
|
+
return '\n'.join(out)
|
|
476
670
|
|
|
477
671
|
|
|
478
672
|
# ── 工具函数 ──────────────────────────────────────────────────────────
|
|
@@ -525,7 +719,7 @@ def _split_symbol_depth(args):
|
|
|
525
719
|
# Role-based section filtering for context_pack output
|
|
526
720
|
# v3.0: 单一真源移到 common/roles.py, 消除与 kg_mcp_server.py 的逐字重复
|
|
527
721
|
try:
|
|
528
|
-
from
|
|
722
|
+
from foundation.identity.roles import ROLE_SECTIONS, filter_by_role as _filter_by_role_imported
|
|
529
723
|
_filter_by_role = _filter_by_role_imported # 保持旧调用名 _filter_by_role 兼容
|
|
530
724
|
except Exception:
|
|
531
725
|
# 回退: 内联定义 (common 不可用时, 与 common/roles.py 保持一致)
|
|
@@ -574,6 +768,8 @@ COMMANDS = [
|
|
|
574
768
|
('wiki', cmd_wiki, 'Repo Wiki 搜索(模块语义文档)'),
|
|
575
769
|
('fill-prototype', cmd_fill_prototype, '原型预填(真实数据填模板,输出 80% HTML)'),
|
|
576
770
|
('design-system', cmd_design_system, '设计系统查询(布局指纹/颜色token/组件表)'),
|
|
771
|
+
('semantic', cmd_semantic, '语义搜索(概念检索:查"报销"命中 expense)'),
|
|
772
|
+
('grep-text', cmd_grep_text, '中文文案/报错溯源(findstr 替代,单进程不弹窗)'),
|
|
577
773
|
]
|
|
578
774
|
|
|
579
775
|
|
|
@@ -584,7 +780,7 @@ def _usage():
|
|
|
584
780
|
'',
|
|
585
781
|
'用法: python .qoder/scripts/kg.py <子命令> [参数]',
|
|
586
782
|
'',
|
|
587
|
-
'
|
|
783
|
+
'16 个子命令:',
|
|
588
784
|
]
|
|
589
785
|
for name, _, desc in COMMANDS:
|
|
590
786
|
lines.append(' %-16s %s' % (name, desc))
|
|
@@ -599,14 +795,41 @@ def _usage():
|
|
|
599
795
|
' kg.py workflow assets # 资产模块业务流程',
|
|
600
796
|
' kg.py hop 资产管理 --depth 3 # 从资产管理出发 3 跳遍历',
|
|
601
797
|
' kg.py context 车辆 --role pm # PM 视角的上下文打包',
|
|
798
|
+
' kg.py grep-text 车辆不存在 # 中文报错文案溯源 (findstr 安全替代)',
|
|
602
799
|
'',
|
|
603
800
|
'QoderWork 环境: AI 也会直接调 MCP 工具(mcp__qoder-knowledge-graph__*),功能等价。',
|
|
604
801
|
]
|
|
605
802
|
return '\n'.join(lines)
|
|
606
803
|
|
|
607
804
|
|
|
805
|
+
def _try_daemon(cmd, rest):
|
|
806
|
+
"""尝试走 daemon 热路径。命中返回 True (已输出结果), 未命中返回 False (回退冷路径)。
|
|
807
|
+
|
|
808
|
+
daemon 常驻模型+连接, semantic 26.8s→0.08s。连不上/出错则透明回退。
|
|
809
|
+
"""
|
|
810
|
+
try:
|
|
811
|
+
from kgd import kgd_client, DAEMON_COMMANDS
|
|
812
|
+
except Exception:
|
|
813
|
+
return False # kgd 模块不可用 → 回退
|
|
814
|
+
if cmd not in DAEMON_COMMANDS:
|
|
815
|
+
return False # 该命令不走 daemon
|
|
816
|
+
res = kgd_client.call(cmd, rest)
|
|
817
|
+
if res is None:
|
|
818
|
+
return False # daemon 不在线/出错 → 回退
|
|
819
|
+
text, _secs = res
|
|
820
|
+
print(text)
|
|
821
|
+
return True
|
|
822
|
+
|
|
823
|
+
|
|
608
824
|
def main(argv=None):
|
|
609
825
|
argv = argv if argv is not None else sys.argv[1:]
|
|
826
|
+
|
|
827
|
+
# 解析 --no-daemon: 强制冷路径 (调试用)。剥离后不影响后续参数解析。
|
|
828
|
+
use_daemon = True
|
|
829
|
+
if '--no-daemon' in argv:
|
|
830
|
+
use_daemon = False
|
|
831
|
+
argv = [a for a in argv if a != '--no-daemon']
|
|
832
|
+
|
|
610
833
|
if not argv or argv[0] in ('-h', '--help', 'help'):
|
|
611
834
|
print(_usage())
|
|
612
835
|
return 0
|
|
@@ -622,6 +845,16 @@ def main(argv=None):
|
|
|
622
845
|
print("未知子命令: %s" % cmd)
|
|
623
846
|
print(_usage())
|
|
624
847
|
return 1
|
|
848
|
+
|
|
849
|
+
# ⚡ 优先走 daemon 热路径 (模型/连接已常驻, 秒回)
|
|
850
|
+
if use_daemon and _try_daemon(cmd, rest):
|
|
851
|
+
return 0
|
|
852
|
+
|
|
853
|
+
# 冷路径: 直接执行 handler (daemon 不在线 / --no-daemon / 不支持的命令)
|
|
854
|
+
# semantic 在 daemon 不在线时给加速提示 (它单次要 ~27s)
|
|
855
|
+
if cmd == 'semantic' and use_daemon:
|
|
856
|
+
print('[提示] daemon 未运行, semantic 将冷启动 (~27s)。')
|
|
857
|
+
print(' 加速: python .qoder/scripts/domain/kg/server/kgd.py start (常驻后 semantic → 0.08s)')
|
|
625
858
|
# 执行(全容错,绝不抛栈)
|
|
626
859
|
try:
|
|
627
860
|
result = handler(rest)
|