@hupan56/wlkj 2.7.12 → 3.1.2
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 -1107
- package/package.json +29 -29
- package/templates/qoder/agents/insight-planning.md +1 -1
- package/templates/qoder/agents/insight-research.md +28 -15
- package/templates/qoder/commands/optional/wl-insight.md +161 -161
- 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 +6 -6
- 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 +43 -0
- 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 +43 -17
- package/templates/qoder/config.yaml +52 -14
- package/templates/qoder/hooks/post-tool-use.py +181 -0
- package/templates/qoder/hooks/session-start.py +94 -23
- 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 +85 -49
- package/templates/qoder/scripts/README.md +102 -0
- 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/deployment/setup/__init__.py +11 -0
- package/templates/qoder/scripts/deployment/setup/carriers.py +669 -0
- package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
- package/templates/qoder/scripts/{init_doctor.py → deployment/setup/init_doctor.py} +100 -39
- package/templates/qoder/scripts/{install_qoderwork.py → deployment/setup/install_qoderwork.py} +48 -30
- package/templates/qoder/scripts/{platform_doctor.py → deployment/setup/platform_doctor.py} +271 -259
- package/templates/qoder/scripts/{repo_root.py → deployment/setup/repo_root.py} +9 -2
- package/templates/qoder/scripts/{setup.py → deployment/setup/setup.py} +143 -14
- package/templates/qoder/scripts/{setup_lanhu.py → deployment/setup/setup_lanhu.py} +979 -963
- package/templates/qoder/scripts/domain/design/__init__.py +0 -0
- package/templates/qoder/scripts/{fill_prototype.py → domain/design/fill_prototype.py} +17 -5
- package/templates/qoder/scripts/{gen_design_doc.py → domain/design/gen_design_doc.py} +406 -394
- package/templates/qoder/scripts/domain/kg/__init__.py +11 -0
- package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
- package/templates/qoder/scripts/domain/kg/build/build_entity_registry.py +201 -0
- package/templates/qoder/scripts/domain/kg/build/build_relations.py +132 -0
- package/templates/qoder/scripts/{build_style_index.py → domain/kg/build/build_style_index.py} +50 -15
- package/templates/qoder/scripts/domain/kg/build/build_workflows.py +149 -0
- package/templates/qoder/scripts/{kg_build.py → domain/kg/build/kg_build.py} +685 -612
- package/templates/qoder/scripts/{kg_build_db.py → domain/kg/build/kg_build_db.py} +338 -327
- package/templates/qoder/scripts/{kg_incremental.py → domain/kg/build/kg_incremental.py} +425 -393
- package/templates/qoder/scripts/{learn_aggregate.py → domain/kg/build/learn_aggregate.py} +212 -201
- 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/domain/kg/extract/test_extract.py +115 -0
- 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_link_db.py → domain/kg/graph/kg_link_db.py} +235 -224
- package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
- package/templates/qoder/scripts/{kg.py → domain/kg/kg.py} +871 -708
- package/templates/qoder/scripts/domain/kg/kg_capabilities.py +182 -0
- package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
- package/templates/qoder/scripts/{context_pack.py → domain/kg/search/context_pack.py} +45 -17
- package/templates/qoder/scripts/{enrich_prompt.py → domain/kg/search/enrich_prompt.py} +238 -226
- package/templates/qoder/scripts/domain/kg/search/prefetch.py +384 -0
- package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
- package/templates/qoder/scripts/{search_index.py → domain/kg/search/search_index.py} +210 -88
- 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_duckdb.py → domain/kg/storage/kg_duckdb.py} +70 -45
- package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
- package/templates/qoder/scripts/{learn.py → domain/learning/learn.py} +157 -146
- package/templates/qoder/scripts/domain/report/__init__.py +11 -0
- package/templates/qoder/scripts/{add_session.py → domain/report/add_session.py} +256 -244
- package/templates/qoder/scripts/{export.py → domain/report/export.py} +72 -4
- package/templates/qoder/scripts/{report.py → domain/report/report.py} +292 -281
- package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
- package/templates/qoder/scripts/domain/report/role.py +39 -0
- package/templates/qoder/scripts/{status.py → domain/report/status.py} +737 -628
- 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/{archive_prd.py → domain/requirement/archive_prd.py} +389 -377
- package/templates/qoder/scripts/domain/requirement/req.py +228 -0
- package/templates/qoder/scripts/domain/task/__init__.py +11 -0
- package/templates/qoder/scripts/{git_sync.py → domain/task/git_sync.py} +90 -50
- package/templates/qoder/scripts/{syncgate.py → domain/task/syncgate.py} +18 -7
- package/templates/qoder/scripts/domain/task/task.py +229 -0
- package/templates/qoder/scripts/domain/task/task_lifecycle.py +606 -0
- package/templates/qoder/scripts/domain/task/task_query.py +162 -0
- package/templates/qoder/scripts/domain/task/task_relations.py +425 -0
- package/templates/qoder/scripts/{team_sync.py → domain/task/team_sync.py} +101 -23
- 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/bootstrap.py +145 -0
- package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/core/cmd_registry.py +112 -0
- package/templates/qoder/scripts/foundation/core/config.py +187 -0
- package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -400
- package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/data/contract.py +317 -0
- package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
- package/templates/qoder/scripts/foundation/data/result.py +223 -0
- package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -392
- package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
- package/templates/qoder/scripts/foundation/identity/check_publish.py +103 -0
- package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -238
- package/templates/qoder/scripts/foundation/identity/guard.py +159 -0
- package/templates/qoder/scripts/{common → foundation/identity}/identity.py +132 -9
- package/templates/qoder/scripts/foundation/identity/roles.py +60 -0
- 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 +11 -10
- 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/{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/foundation/protocol/mcp_base.py +268 -0
- 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/{lanhu_stdio_wrapper.py → protocol/mcp/lanhu_stdio_wrapper.py} +131 -119
- package/templates/qoder/scripts/protocol/mcp/mcp_doctor.py +548 -0
- package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
- package/templates/qoder/scripts/protocol/mcp/mysql_mcp_server.py +461 -0
- 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/{eval_prd.py → validation/metrics/eval_prd.py} +84 -15
- 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/{autotest.py → validation/test/autotest.py} +1234 -1751
- package/templates/qoder/scripts/validation/test/autotest_auth.py +109 -0
- package/templates/qoder/scripts/{autotest_batch.py → validation/test/autotest_batch.py} +255 -224
- package/templates/qoder/scripts/validation/test/autotest_data.py +680 -0
- package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
- package/templates/qoder/scripts/{autotest_run.py → validation/test/autotest_run.py} +323 -297
- package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
- package/templates/qoder/scripts/{benchmark.py → validation/test/benchmark.py} +17 -5
- package/templates/qoder/scripts/{kg_auto_login.py → validation/test/kg_auto_login.py} +208 -196
- package/templates/qoder/scripts/{kg_test_runner.py → validation/test/kg_test_runner.py} +13 -2
- package/templates/qoder/scripts/{page_probe.py → validation/test/page_probe.py} +470 -459
- package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
- package/templates/qoder/settings.json +23 -2
- package/templates/qoder/skills/design-import/SKILL.md +235 -226
- package/templates/qoder/skills/design-review/SKILL.md +91 -82
- package/templates/qoder/skills/prd-generator/SKILL.md +38 -24
- package/templates/qoder/skills/prd-review/SKILL.md +8 -6
- package/templates/qoder/skills/prototype-generator/SKILL.md +296 -247
- package/templates/qoder/skills/spec-coder/SKILL.md +24 -15
- package/templates/qoder/skills/spec-generator/SKILL.md +24 -12
- package/templates/qoder/skills/test-generator/SKILL.md +9 -7
- package/templates/qoder/skills/wl-code/SKILL.md +25 -13
- package/templates/qoder/skills/wl-commit/SKILL.md +10 -9
- package/templates/qoder/skills/wl-design/SKILL.md +7 -5
- package/templates/qoder/skills/wl-init/SKILL.md +8 -8
- package/templates/qoder/skills/wl-insight/SKILL.md +25 -12
- package/templates/qoder/skills/wl-prd-full/SKILL.md +59 -8
- package/templates/qoder/skills/wl-prd-quick/SKILL.md +7 -7
- package/templates/qoder/skills/wl-prd-review/SKILL.md +18 -6
- package/templates/qoder/skills/wl-report/SKILL.md +27 -25
- package/templates/qoder/skills/wl-search/SKILL.md +151 -80
- package/templates/qoder/skills/wl-spec/SKILL.md +9 -7
- package/templates/qoder/skills/wl-status/SKILL.md +50 -18
- package/templates/qoder/skills/wl-task/SKILL.md +94 -12
- package/templates/qoder/skills/wl-test/SKILL.md +154 -45
- package/templates/qoder/templates/prd-full-template.md +7 -0
- package/templates/root/AGENTS.md +275 -237
- 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/hooks/inject-workflow-state.py +0 -169
- package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
- package/templates/qoder/scripts/check_carriers.py +0 -238
- package/templates/qoder/scripts/check_mcp.py +0 -298
- package/templates/qoder/scripts/check_mcp_launch.py +0 -183
- package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
- package/templates/qoder/scripts/collect_prds.py +0 -31
- package/templates/qoder/scripts/common/mentions.py +0 -134
- package/templates/qoder/scripts/common/utf8.py +0 -38
- package/templates/qoder/scripts/extract_api_params.py +0 -246
- package/templates/qoder/scripts/extract_routes.py +0 -54
- package/templates/qoder/scripts/extract_routes_tree.py +0 -78
- package/templates/qoder/scripts/handoff.py +0 -22
- package/templates/qoder/scripts/init_developer.py +0 -76
- package/templates/qoder/scripts/kg_mcp_server.py +0 -801
- package/templates/qoder/scripts/kg_semantic.py +0 -150
- package/templates/qoder/scripts/mcp_launcher.py +0 -414
- package/templates/qoder/scripts/mysql_mcp_server.py +0 -396
- package/templates/qoder/scripts/parse_prds.py +0 -33
- package/templates/qoder/scripts/role.py +0 -51
- package/templates/qoder/scripts/sync_carriers.py +0 -259
- package/templates/qoder/scripts/task.py +0 -1261
- package/templates/qoder/scripts/workspace_init.py +0 -102
- package/templates/qoder/scripts/zentao_mcp_server.py +0 -424
- package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
- /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
- /package/templates/qoder/{skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp → scripts/domain/__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/{secure-ls.js → validation/test/secure-ls.js} +0 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
CronCap —— 定时任务能力契约。
|
|
4
|
+
|
|
5
|
+
增强能力(NoOp 兜底即可)。
|
|
6
|
+
工作流场景: 每周自动拉禅道任务排优先级、每日 git 同步等。
|
|
7
|
+
|
|
8
|
+
各宿主语义不同(场景 E):
|
|
9
|
+
- QoderWork: qoder_cron 工具
|
|
10
|
+
- CLI: 系统 crontab
|
|
11
|
+
- 未来: MCP cron server
|
|
12
|
+
通过 Provider Chain 统一,各 provider 自治。
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Protocol, runtime_checkable
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class CronCap(Protocol):
|
|
21
|
+
"""定时任务能力。"""
|
|
22
|
+
|
|
23
|
+
available: bool
|
|
24
|
+
|
|
25
|
+
def add(self, name: str, schedule: str, prompt: str) -> str:
|
|
26
|
+
"""添加定时任务,返回 job_id(失败返回空串)。"""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
def list(self) -> list[dict]:
|
|
30
|
+
"""列出所有定时任务。"""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
def remove(self, job_id: str) -> bool:
|
|
34
|
+
"""删除定时任务。"""
|
|
35
|
+
...
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class NoOpCronCap:
|
|
39
|
+
"""CronCap 空实现 —— 无定时能力时静默返回。"""
|
|
40
|
+
|
|
41
|
+
available = False
|
|
42
|
+
|
|
43
|
+
def add(self, name: str, schedule: str, prompt: str) -> str:
|
|
44
|
+
return ""
|
|
45
|
+
|
|
46
|
+
def list(self) -> list[dict]:
|
|
47
|
+
return []
|
|
48
|
+
|
|
49
|
+
def remove(self, job_id: str) -> bool:
|
|
50
|
+
return False
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
IdentityCap —— 操作者身份能力契约。
|
|
4
|
+
|
|
5
|
+
核心能力(必有降级)。工作流需要知道"谁在操作"(whoami / 角色 / 禅道账号)。
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from typing import Protocol, runtime_checkable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@runtime_checkable
|
|
13
|
+
class IdentityCap(Protocol):
|
|
14
|
+
"""操作者身份能力。"""
|
|
15
|
+
|
|
16
|
+
available: bool
|
|
17
|
+
|
|
18
|
+
def who(self) -> str | None:
|
|
19
|
+
"""developer 名(.developer 文件)。"""
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
def role(self) -> str | None:
|
|
23
|
+
"""角色: pm / dev / qa。"""
|
|
24
|
+
...
|
|
25
|
+
|
|
26
|
+
def zentao_account(self) -> str | None:
|
|
27
|
+
"""禅道账号映射(后续接入禅道时用)。"""
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class NoOpIdentityCap:
|
|
32
|
+
"""IdentityCap 空实现。仅占位 —— 核心能力总有文件降级。"""
|
|
33
|
+
|
|
34
|
+
available = False
|
|
35
|
+
|
|
36
|
+
def who(self) -> str | None:
|
|
37
|
+
return None
|
|
38
|
+
|
|
39
|
+
def role(self) -> str | None:
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
def zentao_account(self) -> str | None:
|
|
43
|
+
return None
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
MemoryCap —— 跨会话持久记忆能力契约。
|
|
4
|
+
|
|
5
|
+
设计模式: Capability Protocol + Null Object
|
|
6
|
+
|
|
7
|
+
工作流面向能力编程:
|
|
8
|
+
cap = nexus.resolve()
|
|
9
|
+
if cap.memory.available:
|
|
10
|
+
facts = cap.memory.recall("本周执行任务")
|
|
11
|
+
|
|
12
|
+
L2 宿主原生能力。各宿主实现见 nexus/adapters/。
|
|
13
|
+
未实现的宿主 → NoOpMemoryCap(available=False,方法静默返回空)。
|
|
14
|
+
|
|
15
|
+
演进: 未来 mem0/Zep MCP server 成熟后,记忆能力 MCP 化,
|
|
16
|
+
McpMemoryProvider 抢占职责链链头,本契约不变。
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
from typing import Protocol, runtime_checkable
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@runtime_checkable
|
|
24
|
+
class MemoryCap(Protocol):
|
|
25
|
+
"""跨会话记忆能力契约。
|
|
26
|
+
|
|
27
|
+
各宿主实现:
|
|
28
|
+
- QwMemoryCap: QoderWork 的 qw memory 工具(adapters/qw.py)
|
|
29
|
+
- FileMemoryCap: 文件降级 journal(adapters/cli.py)
|
|
30
|
+
- McpMemoryProvider:未来 mem0/Zep MCP server(adapters/mcp.py)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
available: bool
|
|
34
|
+
|
|
35
|
+
def recall(self, query: str) -> list[dict]:
|
|
36
|
+
"""语义检索记忆,返回相关条目列表。"""
|
|
37
|
+
...
|
|
38
|
+
|
|
39
|
+
def remember(self, key: str, content: str) -> None:
|
|
40
|
+
"""写入一条记忆。"""
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
def get_fact(self, key: str) -> str | None:
|
|
44
|
+
"""按 key 取一条事实,无则 None。"""
|
|
45
|
+
...
|
|
46
|
+
|
|
47
|
+
def list_recent(self, limit: int = 10) -> list[dict]:
|
|
48
|
+
"""最近 N 条记忆。"""
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class NoOpMemoryCap:
|
|
53
|
+
"""MemoryCap 空实现 —— Null Object 模式。
|
|
54
|
+
|
|
55
|
+
available=False,所有方法静默返回空值,绝不抛错。
|
|
56
|
+
作为 memory 职责链链尾兜底,保证无记忆能力时工作流不崩。
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
available = False
|
|
60
|
+
|
|
61
|
+
def recall(self, query: str) -> list[dict]:
|
|
62
|
+
return []
|
|
63
|
+
|
|
64
|
+
def remember(self, key: str, content: str) -> None:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
def get_fact(self, key: str) -> str | None:
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
def list_recent(self, limit: int = 10) -> list[dict]:
|
|
71
|
+
return []
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
NotifyCap —— IM 通知能力契约。
|
|
4
|
+
|
|
5
|
+
增强能力(NoOp 兜底)。
|
|
6
|
+
工作流场景: 日报/任务变更/评审结果推送 IM。
|
|
7
|
+
|
|
8
|
+
各宿主实现:
|
|
9
|
+
- QoderWork: 微信/飞书连接器
|
|
10
|
+
- CLI: 飞书 webhook(已有降级)
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Protocol, runtime_checkable
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@runtime_checkable
|
|
18
|
+
class NotifyCap(Protocol):
|
|
19
|
+
"""IM 通知能力。"""
|
|
20
|
+
|
|
21
|
+
available: bool
|
|
22
|
+
|
|
23
|
+
def send(self, channel: str, message: str) -> bool:
|
|
24
|
+
"""发送消息到指定渠道,返回是否成功。"""
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
def list_channels(self) -> list[dict]:
|
|
28
|
+
"""列出可用渠道。"""
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class NoOpNotifyCap:
|
|
33
|
+
"""NotifyCap 空实现。"""
|
|
34
|
+
|
|
35
|
+
available = False
|
|
36
|
+
|
|
37
|
+
def send(self, channel: str, message: str) -> bool:
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
def list_channels(self) -> list[dict]:
|
|
41
|
+
return []
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
PresentCap —— 富展示能力契约。
|
|
4
|
+
|
|
5
|
+
增强能力(NoOp 兜底)。
|
|
6
|
+
工作流场景: 任务看板、甘特图、文件卡片、交互 widget。
|
|
7
|
+
|
|
8
|
+
各宿主实现:
|
|
9
|
+
- QoderWork: show_widget / present_files
|
|
10
|
+
- CLI: markdown 表格降级
|
|
11
|
+
"""
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
from typing import Protocol, runtime_checkable
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@runtime_checkable
|
|
18
|
+
class PresentCap(Protocol):
|
|
19
|
+
"""富展示能力。"""
|
|
20
|
+
|
|
21
|
+
available: bool
|
|
22
|
+
|
|
23
|
+
def table(self, rows: list, headers: list | None = None) -> str:
|
|
24
|
+
"""渲染表格,返回可展示文本。"""
|
|
25
|
+
...
|
|
26
|
+
|
|
27
|
+
def widget(self, html: str) -> bool:
|
|
28
|
+
"""展示交互 widget(仅富宿主),返回是否成功。"""
|
|
29
|
+
...
|
|
30
|
+
|
|
31
|
+
def files(self, paths: list) -> bool:
|
|
32
|
+
"""以文件卡片形式展示。"""
|
|
33
|
+
...
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class NoOpPresentCap:
|
|
37
|
+
"""PresentCap 空实现 —— 无富展示时退化为空。"""
|
|
38
|
+
|
|
39
|
+
available = False
|
|
40
|
+
|
|
41
|
+
def table(self, rows: list, headers: list | None = None) -> str:
|
|
42
|
+
return ""
|
|
43
|
+
|
|
44
|
+
def widget(self, html: str) -> bool:
|
|
45
|
+
return False
|
|
46
|
+
|
|
47
|
+
def files(self, paths: list) -> bool:
|
|
48
|
+
return False
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
RepoCap —— 仓库根发现能力契约。
|
|
4
|
+
|
|
5
|
+
核心能力(必有降级)。替代散落在 skill 里的 ~/.qoderwork/repo_root.py 硬编码。
|
|
6
|
+
让"仓库根发现"宿主无关:向上找含 .qoder/scripts/ 的目录即可。
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Protocol, runtime_checkable
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@runtime_checkable
|
|
15
|
+
class RepoCap(Protocol):
|
|
16
|
+
"""仓库根发现能力。"""
|
|
17
|
+
|
|
18
|
+
available: bool
|
|
19
|
+
|
|
20
|
+
def root(self) -> Path:
|
|
21
|
+
"""返回项目仓库根路径。"""
|
|
22
|
+
...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class NoOpRepoCap:
|
|
26
|
+
"""RepoCap 空实现。仅占位 —— 核心能力总有文件降级,不会真用到 NoOp。"""
|
|
27
|
+
|
|
28
|
+
available = False
|
|
29
|
+
|
|
30
|
+
def root(self) -> Path:
|
|
31
|
+
return Path.cwd()
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
SandboxCap —— 安全执行能力契约。
|
|
4
|
+
|
|
5
|
+
执行安全类(宿主差异大,NoOp 兜底)。
|
|
6
|
+
工作流场景: 在隔离环境跑命令/测试/构建。
|
|
7
|
+
|
|
8
|
+
各宿主实现:
|
|
9
|
+
- Claude Code: container / seatbelt
|
|
10
|
+
- Codex CLI: Docker + seatbelt
|
|
11
|
+
- QoderWork: (暂无原生沙箱)
|
|
12
|
+
- CLI: 直接执行(无沙箱,approval 把关)
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
from typing import Protocol, runtime_checkable
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class SandboxCap(Protocol):
|
|
21
|
+
"""安全执行能力。"""
|
|
22
|
+
|
|
23
|
+
available: bool
|
|
24
|
+
|
|
25
|
+
def run(self, command: str, cwd: str | None = None, timeout: int = 60) -> dict:
|
|
26
|
+
"""在沙箱内执行命令,返回 {ok, stdout, stderr, returncode}。"""
|
|
27
|
+
...
|
|
28
|
+
|
|
29
|
+
def approval_mode(self) -> str:
|
|
30
|
+
"""当前自主等级: suggest / auto-edit / full-auto / plan。"""
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class NoOpSandboxCap:
|
|
35
|
+
"""SandboxCap 空实现 —— 无沙箱时拒绝执行。"""
|
|
36
|
+
|
|
37
|
+
available = False
|
|
38
|
+
|
|
39
|
+
def run(self, command: str, cwd: str | None = None, timeout: int = 60) -> dict:
|
|
40
|
+
return {"ok": False, "reason": "no sandbox available"}
|
|
41
|
+
|
|
42
|
+
def approval_mode(self) -> str:
|
|
43
|
+
return "suggest"
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
ProviderChain —— 能力 Provider 职责链。
|
|
4
|
+
|
|
5
|
+
设计模式:
|
|
6
|
+
- Chain of Responsibility(职责链): 按优先级遍历,第一个 available 的命中
|
|
7
|
+
- Strategy(策略组合): 每个 provider 是一种策略实现
|
|
8
|
+
- Decorator(装饰器): 可选地对命中的 provider 增强(缓存/日志/统计)
|
|
9
|
+
|
|
10
|
+
透明代理: ProviderChain 把方法调用转发给命中的 provider,
|
|
11
|
+
对调用方而言与直接用 Cap 无异。
|
|
12
|
+
|
|
13
|
+
chain = ProviderChain([McpMemoryProvider(), QwMemoryCap(),
|
|
14
|
+
FileMemoryCap(), NoOpMemoryCap()])
|
|
15
|
+
chain.recall("本周执行") # 自动代理到第一个 available 的 provider
|
|
16
|
+
|
|
17
|
+
链尾永远是 NoOp,保证无能力时不抛错(Null Object 兜底)。
|
|
18
|
+
|
|
19
|
+
演进(扩展场景 C: 能力 MCP 化迁移):
|
|
20
|
+
mem0 MCP server 成熟 → 链头插入 McpMemoryProvider →
|
|
21
|
+
available=True 自动抢占 → 旧的 QwMemoryCap 沉到链尾静默退役 →
|
|
22
|
+
调用方代码零改动。这就是"未来 vs 现实"的机制化。
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from typing import Any, Callable
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ProviderChain:
|
|
30
|
+
"""能力 Provider 职责链。
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
providers: 按优先级排列的 provider 列表,链尾应为 NoOp。
|
|
34
|
+
decorators: 可选装饰器列表,每个形式 func(provider_method, provider) -> wrapped,
|
|
35
|
+
对命中的 provider 的方法做增强(缓存/日志/降级统计),不改原 provider。
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
def __init__(self, providers: list, decorators: list | None = None):
|
|
39
|
+
# 用 object.__setattr__ 绕过自定义 __getattr__,避免初始化期递归
|
|
40
|
+
object.__setattr__(self, "_providers", list(providers))
|
|
41
|
+
object.__setattr__(self, "_decorators", list(decorators or []))
|
|
42
|
+
object.__setattr__(self, "_active", None)
|
|
43
|
+
object.__setattr__(self, "_probed", False)
|
|
44
|
+
|
|
45
|
+
@property
|
|
46
|
+
def available(self) -> bool:
|
|
47
|
+
"""是否有任一 provider 可用。"""
|
|
48
|
+
return self._probe() is not None
|
|
49
|
+
|
|
50
|
+
def _probe(self) -> Any:
|
|
51
|
+
"""返回第一个 available 的 provider,缓存结果(首次探测后不再变)。"""
|
|
52
|
+
if self._probed:
|
|
53
|
+
return self._active
|
|
54
|
+
for p in self._providers:
|
|
55
|
+
if getattr(p, "available", False):
|
|
56
|
+
object.__setattr__(self, "_active", p)
|
|
57
|
+
break
|
|
58
|
+
object.__setattr__(self, "_probed", True)
|
|
59
|
+
return self._active
|
|
60
|
+
|
|
61
|
+
def providers_status(self) -> list[dict]:
|
|
62
|
+
"""诊断用:每个 provider 的 available 状态 + 是否命中。"""
|
|
63
|
+
active = self._probe()
|
|
64
|
+
return [
|
|
65
|
+
{
|
|
66
|
+
"provider": type(p).__name__,
|
|
67
|
+
"available": bool(getattr(p, "available", False)),
|
|
68
|
+
"hit": p is active,
|
|
69
|
+
}
|
|
70
|
+
for p in self._providers
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
def __getattr__(self, name: str) -> Any:
|
|
74
|
+
"""透明代理:把属性/方法调用转发给命中的 provider。
|
|
75
|
+
|
|
76
|
+
调用方写 chain.recall(q) 等价于 active_provider.recall(q)。
|
|
77
|
+
若无任何 provider available,用链尾(NoOp)兜底,绝不抛错。
|
|
78
|
+
"""
|
|
79
|
+
if name.startswith("_"):
|
|
80
|
+
raise AttributeError(name)
|
|
81
|
+
active = self._probe()
|
|
82
|
+
if active is None:
|
|
83
|
+
# 兜底:链尾 NoOp
|
|
84
|
+
active = self._providers[-1] if self._providers else None
|
|
85
|
+
if active is None:
|
|
86
|
+
raise AttributeError(f"ProviderChain 无 provider 可解析 '{name}'")
|
|
87
|
+
attr = getattr(active, name)
|
|
88
|
+
# 应用装饰器(仅对可调用方法)
|
|
89
|
+
if callable(attr) and self._decorators:
|
|
90
|
+
for dec in self._decorators:
|
|
91
|
+
attr = dec(attr, active)
|
|
92
|
+
return attr
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
memory 能力职责链装配。
|
|
4
|
+
|
|
5
|
+
设计模式: Provider Chain + Strategy
|
|
6
|
+
|
|
7
|
+
独立成文件的理由: memory 是最复杂的 L2 能力(4 个 provider),
|
|
8
|
+
未来加 provider(如向量库、mem0 MCP)只改本文件,不动 registry ——
|
|
9
|
+
体现 Plugin/SPI:新实现接入不改核心。
|
|
10
|
+
|
|
11
|
+
优先级(高→低):
|
|
12
|
+
① McpMemoryProvider —— 未来 mem0/Zep MCP server(现状 available=False)
|
|
13
|
+
② QwMemoryCap —— QoderWork 原生(仅 qoderwork 宿主)
|
|
14
|
+
③ FileMemoryCap —— 文件降级(纯 CLI/任意宿主)
|
|
15
|
+
④ NoOpMemoryCap —— 兜底(绝不抛错)
|
|
16
|
+
|
|
17
|
+
演进(扩展场景 C): mem0 MCP 成熟 → 把 McpMemoryProvider 的 available 打开 →
|
|
18
|
+
自动抢占链头 → FileMemoryCap/QwMemoryCap 静默退役 → 调用方零改动。
|
|
19
|
+
"""
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from .chain import ProviderChain
|
|
23
|
+
from .caps import NoOpMemoryCap
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def build_memory_chain(host: str) -> ProviderChain:
|
|
27
|
+
"""装配 memory 职责链。
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
host: detect_host() 返回的宿主名。
|
|
31
|
+
"""
|
|
32
|
+
from .adapters.mcp import McpMemoryProvider
|
|
33
|
+
from .adapters.cli import FileMemoryCap
|
|
34
|
+
|
|
35
|
+
providers: list = [McpMemoryProvider()]
|
|
36
|
+
if host == "qoderwork":
|
|
37
|
+
from .adapters.qw import QwMemoryCap
|
|
38
|
+
providers.append(QwMemoryCap())
|
|
39
|
+
providers.append(FileMemoryCap())
|
|
40
|
+
providers.append(NoOpMemoryCap())
|
|
41
|
+
return ProviderChain(providers)
|