@hupan56/wlkj 3.0.0 → 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.
Files changed (237) hide show
  1. package/bin/cli.js +1435 -1373
  2. package/package.json +1 -1
  3. package/templates/qoder/commands/optional/wl-insight.md +6 -4
  4. package/templates/qoder/commands/optional/wl-report.md +20 -39
  5. package/templates/qoder/commands/optional/wl-status.md +4 -4
  6. package/templates/qoder/commands/wl-code.md +2 -2
  7. package/templates/qoder/commands/wl-design.md +5 -5
  8. package/templates/qoder/commands/wl-init.md +3 -3
  9. package/templates/qoder/commands/wl-prd.md +26 -13
  10. package/templates/qoder/commands/wl-req.md +3 -3
  11. package/templates/qoder/commands/wl-search.md +78 -47
  12. package/templates/qoder/commands/wl-task.md +343 -40
  13. package/templates/qoder/commands/wl-test.md +10 -10
  14. package/templates/qoder/config.yaml +35 -13
  15. package/templates/qoder/hooks/post-tool-use.py +181 -0
  16. package/templates/qoder/hooks/session-start.py +82 -1
  17. package/templates/qoder/hooks/stop-eval.py +207 -0
  18. package/templates/qoder/hooks/user-prompt-submit.py +139 -0
  19. package/templates/qoder/rules/wl-pipeline.md +70 -8
  20. package/templates/qoder/scripts/README.md +78 -115
  21. package/templates/qoder/scripts/capability/__init__.py +26 -0
  22. package/templates/qoder/scripts/capability/__main__.py +72 -0
  23. package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
  24. package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
  25. package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
  26. package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
  27. package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
  28. package/templates/qoder/scripts/capability/caps/context.py +36 -0
  29. package/templates/qoder/scripts/capability/caps/cron.py +50 -0
  30. package/templates/qoder/scripts/capability/caps/identity.py +43 -0
  31. package/templates/qoder/scripts/capability/caps/memory.py +71 -0
  32. package/templates/qoder/scripts/capability/caps/notify.py +41 -0
  33. package/templates/qoder/scripts/capability/caps/present.py +48 -0
  34. package/templates/qoder/scripts/capability/caps/repo.py +31 -0
  35. package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
  36. package/templates/qoder/scripts/capability/chain.py +92 -0
  37. package/templates/qoder/scripts/capability/memory_chain.py +41 -0
  38. package/templates/qoder/scripts/capability/registry.py +246 -0
  39. package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
  40. package/templates/qoder/scripts/capability/smoke_test.py +211 -0
  41. package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
  42. package/templates/qoder/scripts/{report → deployment/setup}/__init__.py +11 -11
  43. package/templates/qoder/scripts/{setup → deployment/setup}/carriers.py +33 -26
  44. package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
  45. package/templates/qoder/scripts/{setup → deployment/setup}/init_doctor.py +40 -16
  46. package/templates/qoder/scripts/{setup → deployment/setup}/install_qoderwork.py +20 -12
  47. package/templates/qoder/scripts/{setup → deployment/setup}/platform_doctor.py +8 -2
  48. package/templates/qoder/scripts/{setup → deployment/setup}/repo_root.py +113 -112
  49. package/templates/qoder/scripts/{setup → deployment/setup}/setup.py +31 -11
  50. package/templates/qoder/scripts/{setup → deployment/setup}/setup_lanhu.py +13 -7
  51. package/templates/qoder/scripts/domain/__init__.py +0 -0
  52. package/templates/qoder/scripts/domain/design/__init__.py +0 -0
  53. package/templates/qoder/scripts/{report → domain/design}/fill_prototype.py +12 -6
  54. package/templates/qoder/scripts/{report → domain/design}/gen_design_doc.py +8 -2
  55. package/templates/qoder/scripts/{setup → domain/kg}/__init__.py +11 -11
  56. package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
  57. package/templates/qoder/scripts/{kg → domain/kg/build}/build_entity_registry.py +7 -2
  58. package/templates/qoder/scripts/{kg → domain/kg/build}/build_relations.py +7 -2
  59. package/templates/qoder/scripts/{kg → domain/kg/build}/build_style_index.py +13 -7
  60. package/templates/qoder/scripts/{kg → domain/kg/build}/build_workflows.py +7 -2
  61. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build.py +76 -9
  62. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_build_db.py +7 -2
  63. package/templates/qoder/scripts/{kg → domain/kg/build}/kg_incremental.py +11 -6
  64. package/templates/qoder/scripts/{report → domain/kg/build}/learn_aggregate.py +9 -4
  65. package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
  66. package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
  67. package/templates/qoder/scripts/{common → domain/kg/extract}/test_extract.py +115 -115
  68. package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
  69. package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
  70. package/templates/qoder/scripts/{kg → domain/kg/graph}/kg_link_db.py +7 -2
  71. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
  72. package/templates/qoder/scripts/{kg → domain/kg}/kg.py +263 -30
  73. package/templates/qoder/scripts/{common → domain/kg}/kg_capabilities.py +182 -182
  74. package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
  75. package/templates/qoder/scripts/{kg → domain/kg/search}/context_pack.py +30 -9
  76. package/templates/qoder/scripts/{kg → domain/kg/search}/enrich_prompt.py +10 -4
  77. package/templates/qoder/scripts/{kg → domain/kg/search}/prefetch.py +33 -8
  78. package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
  79. package/templates/qoder/scripts/{kg → domain/kg/search}/search_index.py +143 -77
  80. package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
  81. package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
  82. package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
  83. package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
  84. package/templates/qoder/scripts/{kg → domain/kg/storage}/kg_duckdb.py +38 -14
  85. package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
  86. package/templates/qoder/scripts/{report → domain/learning}/learn.py +8 -3
  87. package/templates/qoder/scripts/{mcp → domain/report}/__init__.py +11 -11
  88. package/templates/qoder/scripts/{report → domain/report}/add_session.py +9 -3
  89. package/templates/qoder/scripts/{report → domain/report}/export.py +10 -5
  90. package/templates/qoder/scripts/{report → domain/report}/report.py +9 -4
  91. package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
  92. package/templates/qoder/scripts/{report → domain/report}/role.py +10 -4
  93. package/templates/qoder/scripts/{report → domain/report}/status.py +112 -9
  94. package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
  95. package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
  96. package/templates/qoder/scripts/{report → domain/requirement}/archive_prd.py +8 -2
  97. package/templates/qoder/scripts/{report → domain/requirement}/req.py +228 -222
  98. package/templates/qoder/scripts/{kg → domain/task}/__init__.py +11 -11
  99. package/templates/qoder/scripts/{task → domain/task}/git_sync.py +40 -21
  100. package/templates/qoder/scripts/{task → domain/task}/syncgate.py +13 -8
  101. package/templates/qoder/scripts/{task → domain/task}/task.py +13 -5
  102. package/templates/qoder/scripts/{task → domain/task}/task_lifecycle.py +606 -596
  103. package/templates/qoder/scripts/{task → domain/task}/task_query.py +162 -161
  104. package/templates/qoder/scripts/{task → domain/task}/task_relations.py +425 -424
  105. package/templates/qoder/scripts/{task → domain/task}/team_sync.py +9 -4
  106. package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
  107. package/templates/qoder/scripts/foundation/__init__.py +0 -0
  108. package/templates/qoder/scripts/{common → foundation}/bootstrap.py +10 -10
  109. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  110. package/templates/qoder/scripts/{common → foundation/core}/cmd_registry.py +1 -1
  111. package/templates/qoder/scripts/{common → foundation/core}/config.py +1 -1
  112. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -586
  113. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  114. package/templates/qoder/scripts/{common → foundation/data}/contract.py +2 -2
  115. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  116. package/templates/qoder/scripts/{common → foundation/data}/result.py +1 -1
  117. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -404
  118. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  119. package/templates/qoder/scripts/{common → foundation/identity}/check_publish.py +103 -98
  120. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -239
  121. package/templates/qoder/scripts/{common → foundation/identity}/guard.py +2 -2
  122. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +14 -10
  123. package/templates/qoder/scripts/{common → foundation/identity}/roles.py +1 -1
  124. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  125. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  126. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +2 -2
  127. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  128. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  129. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  130. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  131. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  132. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  133. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  134. package/templates/qoder/scripts/{common → foundation/protocol}/mcp_base.py +1 -1
  135. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  136. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  137. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  138. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  139. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  140. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  141. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  142. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  143. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  144. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  145. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  146. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  147. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  148. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  149. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  150. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  151. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  152. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  153. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  154. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  155. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  156. package/templates/qoder/scripts/{mcp → protocol/mcp}/lanhu_stdio_wrapper.py +11 -5
  157. package/templates/qoder/scripts/{mcp → protocol/mcp}/mcp_doctor.py +47 -14
  158. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  159. package/templates/qoder/scripts/{mcp → protocol/mcp}/mysql_mcp_server.py +181 -67
  160. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  161. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  162. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  163. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  164. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  165. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  166. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  167. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  168. package/templates/qoder/scripts/validation/__init__.py +0 -0
  169. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  170. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  171. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  172. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  173. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  174. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  175. package/templates/qoder/scripts/{report → validation/metrics}/eval_prd.py +17 -10
  176. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  177. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  178. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  179. package/templates/qoder/scripts/{test → validation/test}/autotest.py +64 -4
  180. package/templates/qoder/scripts/{common → validation/test}/autotest_auth.py +1 -1
  181. package/templates/qoder/scripts/{test → validation/test}/autotest_batch.py +16 -3
  182. package/templates/qoder/scripts/{test → validation/test}/autotest_data.py +17 -12
  183. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  184. package/templates/qoder/scripts/{test → validation/test}/autotest_run.py +17 -3
  185. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  186. package/templates/qoder/scripts/{test → validation/test}/benchmark.py +12 -6
  187. package/templates/qoder/scripts/{test → validation/test}/kg_auto_login.py +8 -2
  188. package/templates/qoder/scripts/{test → validation/test}/kg_test_runner.py +7 -2
  189. package/templates/qoder/scripts/{test → validation/test}/page_probe.py +8 -3
  190. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  191. package/templates/qoder/settings.json +30 -0
  192. package/templates/qoder/skills/design-import/SKILL.md +22 -13
  193. package/templates/qoder/skills/design-review/SKILL.md +19 -10
  194. package/templates/qoder/skills/prd-generator/SKILL.md +22 -18
  195. package/templates/qoder/skills/prd-review/SKILL.md +6 -4
  196. package/templates/qoder/skills/prototype-generator/SKILL.md +63 -14
  197. package/templates/qoder/skills/spec-coder/SKILL.md +22 -13
  198. package/templates/qoder/skills/spec-generator/SKILL.md +22 -10
  199. package/templates/qoder/skills/test-generator/SKILL.md +7 -5
  200. package/templates/qoder/skills/wl-code/SKILL.md +23 -11
  201. package/templates/qoder/skills/wl-commit/SKILL.md +9 -8
  202. package/templates/qoder/skills/wl-design/SKILL.md +5 -3
  203. package/templates/qoder/skills/wl-init/SKILL.md +6 -6
  204. package/templates/qoder/skills/wl-insight/SKILL.md +23 -10
  205. package/templates/qoder/skills/wl-prd-full/SKILL.md +57 -6
  206. package/templates/qoder/skills/wl-prd-quick/SKILL.md +3 -3
  207. package/templates/qoder/skills/wl-prd-review/SKILL.md +16 -4
  208. package/templates/qoder/skills/wl-report/SKILL.md +25 -23
  209. package/templates/qoder/skills/wl-search/SKILL.md +149 -78
  210. package/templates/qoder/skills/wl-spec/SKILL.md +7 -5
  211. package/templates/qoder/skills/wl-status/SKILL.md +48 -16
  212. package/templates/qoder/skills/wl-task/SKILL.md +92 -10
  213. package/templates/qoder/skills/wl-test/SKILL.md +75 -29
  214. package/templates/qoder/templates/prd-full-template.md +7 -0
  215. package/templates/root/AGENTS.md +275 -236
  216. package/templates/root/requirements.txt +3 -0
  217. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  218. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  219. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +0 -23
  220. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +0 -23
  221. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +0 -1
  222. package/templates/.qoder/learning/eval-history.jsonl +0 -28
  223. package/templates/data/index/wiki-index.json +0 -8
  224. package/templates/qoder/nul +0 -4
  225. package/templates/qoder/scripts/kg/extract.py +0 -398
  226. package/templates/qoder/scripts/kg/kg_semantic.py +0 -156
  227. package/templates/qoder/scripts/mcp/kg_mcp_server.py +0 -606
  228. package/templates/qoder/scripts/mcp/mcp_launcher.py +0 -442
  229. package/templates/qoder/scripts/mcp/zentao_mcp_server.py +0 -384
  230. package/templates/qoder/scripts/task/__init__.py +0 -11
  231. package/templates/qoder/scripts/test/__init__.py +0 -11
  232. package/templates/qoder/scripts/wlkj.py +0 -116
  233. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  234. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  235. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  236. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  237. /package/templates/qoder/scripts/{test → validation/test}/secure-ls.js +0 -0
@@ -1,239 +1,239 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """
4
- QODER Pipeline - 开发者管理工具
5
-
6
- 提供开发者身份的初始化和管理功能:
7
- - init_developer: 初始化开发者身份, 创建工作空间和日志
8
- - ensure_developer: 确保开发者已初始化 (未初始化则退出)
9
- - show_developer_info: 显示开发者信息
10
-
11
- 开发者身份存储在 .qoder/.developer 文件中 (gitignored)
12
- 工作空间在 workspace/members/<developer>/ 目录下 (与 workspace_init.py 一致)
13
- """
14
-
15
- from __future__ import annotations
16
-
17
- import sys
18
- from datetime import datetime
19
- from pathlib import Path
20
-
21
- # 将 scripts 目录加入路径以便导入 common 模块
22
- import os
23
- sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
24
-
25
- from common.paths import (
26
- DIR_WORKFLOW,
27
- FILE_DEVELOPER,
28
- MEMBERS_DIR,
29
- get_repo_root,
30
- get_developer,
31
- check_developer,
32
- )
33
-
34
-
35
- # =============================================================================
36
- # 开发者初始化
37
- # =============================================================================
38
-
39
- def write_developer_file(name: str, role: str | None = None,
40
- repo_root: Path | None = None) -> bool:
41
- """写入 .qoder/.developer (规范格式: name=<name>)。"""
42
- if repo_root is None:
43
- repo_root = get_repo_root()
44
- dev_file = repo_root / DIR_WORKFLOW / FILE_DEVELOPER
45
- lines = [f"name={name}"]
46
- if role:
47
- lines.append(f"role={role}")
48
- lines.append(f"initialized_at={datetime.now().isoformat()}")
49
- try:
50
- dev_file.write_text("\n".join(lines) + "\n", encoding="utf-8")
51
- return True
52
- except (OSError, IOError) as e:
53
- print(f"Error: Failed to create .developer file: {e}", file=sys.stderr)
54
- return False
55
-
56
-
57
- def _detect_git_author() -> str | None:
58
- """探测系统 git config 的 user.name <user.email>。git 未装或未配返回 None。"""
59
- import subprocess
60
- try:
61
- rn = subprocess.run(["git", "config", "user.name"],
62
- capture_output=True, text=True, timeout=5)
63
- re_ = subprocess.run(["git", "config", "user.email"],
64
- capture_output=True, text=True, timeout=5)
65
- if rn.returncode == 0 and re_.returncode == 0:
66
- gname = rn.stdout.strip()
67
- gemail = re_.stdout.strip()
68
- if gname and gemail:
69
- return f"{gname} <{gemail}>"
70
- except (FileNotFoundError, OSError, subprocess.SubprocessError):
71
- pass # git 未装
72
- return None
73
-
74
-
75
- def _ensure_git_config(name: str, repo_root: Path) -> None:
76
- """确认 git user.name/email 已配置。未配则提示 (绝不自动造假账号)。
77
-
78
- 旧逻辑会塞 name@local 假账号, 与零信任 push 门禁冲突, 已废弃。
79
- 真正的 git 配置由 setup.py configure_git_identity() 在 init 前完成。
80
- 这里只做兜底检测: 如果走到这还没配, 提示用户去配。
81
- """
82
- import subprocess
83
- # 先看 git 是否可用
84
- try:
85
- subprocess.run(["git", "--version"], capture_output=True, timeout=5)
86
- except (FileNotFoundError, OSError):
87
- print(" [INFO] git 未安装, 跳过 git 配置 (核心功能不依赖 git)")
88
- return
89
-
90
- author = _detect_git_author()
91
- if author:
92
- # 检测到疑似假账号也要提示 (虽然配了, 但 push 会被门禁拒)
93
- if "@local" in author:
94
- print(f" [WARN] git 作者疑似假账号: {author} (push 门禁会拒绝)")
95
- print(f" 请重跑 'wlkj init' 配置真实团队 git 账号")
96
- else:
97
- print(f" [OK] git 作者: {author}")
98
- return
99
-
100
- # git 未配: 不造假, 只提示
101
- print(f" [WARN] git 未配置 user.name/email")
102
- print(f" push/commit 会失败。请配置团队 git 账号:")
103
- print(f" git config --global user.name '你的名字'")
104
- print(f" git config --global user.email '你的团队邮箱'")
105
- print(f" 或重跑: wlkj init <你的名字>")
106
-
107
-
108
- def init_developer(name: str, role: str | None = None,
109
- repo_root: Path | None = None) -> bool:
110
- """初始化开发者身份。
111
-
112
- 创建以下内容:
113
- - .qoder/.developer 文件 (name= / role= / initialized_at=)
114
- - workspace/members/<name>/{journal,drafts,inbox}/ 目录
115
- - 初始日志文件 journal/journal-1.md
116
- - member.json + .signing_key (零信任身份注册, 用于 push 门禁)
117
- - git user.name/email 检测与配置
118
-
119
- Returns:
120
- 成功返回 True, 失败返回 False。
121
- """
122
- if not name:
123
- print("Error: developer name is required", file=sys.stderr)
124
- return False
125
-
126
- # 校验名称合法性 (允许字母数字、中文和部分符号)
127
- if not all(c.isalnum() or c in "-_" for c in name):
128
- print(f"Error: invalid developer name '{name}' (only alphanumeric, -, _ allowed)", file=sys.stderr)
129
- return False
130
-
131
- if repo_root is None:
132
- repo_root = get_repo_root()
133
-
134
- # 零信任: 切换身份时清除旧开发者的 current-task 指针
135
- # (防止 B 在 A 用过的机器上看到 A 的活跃任务, 误操作)
136
- try:
137
- from .paths import get_developer, set_current_task
138
- old_dev = get_developer(repo_root)
139
- if old_dev and old_dev != name:
140
- set_current_task(None, repo_root, developer=old_dev)
141
- print(f"Note: 切换开发者 {old_dev} -> {name}, 已清除 {old_dev} 的活跃任务指针")
142
- except Exception:
143
- pass # 清理失败不阻塞初始化
144
-
145
- # 1. 创建 .developer 文件
146
- if not write_developer_file(name, role, repo_root):
147
- return False
148
-
149
- # 2. 创建个人工作空间 workspace/members/<name>/
150
- # v3.0 M3: 个人目录 = member.json + drafts + outputs + journal + .private
151
- personal = repo_root / "workspace" / "members" / name
152
- try:
153
- for sub in ("journal", "drafts", "outputs", ".private", ".private/secrets"):
154
- (personal / sub).mkdir(parents=True, exist_ok=True)
155
- except (OSError, IOError) as e:
156
- print(f"Error: Failed to create workspace directory: {e}", file=sys.stderr)
157
- return False
158
-
159
- # 3. 创建初始日志文件
160
- journal_file = personal / "journal" / "journal-1.md"
161
- if not journal_file.exists():
162
- today = datetime.now().strftime("%Y-%m-%d")
163
- try:
164
- journal_file.write_text(
165
- f"# Journal - {name}\n\n> Started: {today}\n\n---\n\n",
166
- encoding="utf-8"
167
- )
168
- except (OSError, IOError) as e:
169
- print(f"Error: Failed to create journal file: {e}", file=sys.stderr)
170
- return False
171
-
172
- # 4. 零信任身份注册 (写 member.json + 签名密钥 + git_author)
173
- # 这是 push 门禁的前提: 没 member.json → syncgate 拒绝 push
174
- git_author = _detect_git_author()
175
- try:
176
- from common.identity import register_member, IdentityError, get_member
177
- # 修正: 旧 member.json 若是假账号(@local), 且现在 git 配了真账号 → 用真账号覆盖
178
- # register_member 已有"已注册则只更新 git_author, 密钥不动"的逻辑, 这里只加提示
179
- existing_member = get_member(name, repo_root)
180
- if existing_member:
181
- old_author = existing_member.get("git_author", "")
182
- if (old_author and "@local" in old_author
183
- and git_author and "@local" not in git_author):
184
- print(f" [修正] member.json git_author 从假账号更新为真账号: {git_author}")
185
- try:
186
- register_member(name, role or "pm", git_author, repo_root)
187
- print(f" [OK] 身份注册: member.json + 签名密钥已生成")
188
- except IdentityError as e:
189
- print(f" [WARN] 身份注册失败 (不阻塞): {e}")
190
- except ImportError:
191
- pass # identity 模块不可用, 跳过 (向后兼容)
192
-
193
- # 5. 确保 git 配置 (只检测+提示, 不造假; 真账号由 setup.py 在 init 前配好)
194
- _ensure_git_config(name, repo_root)
195
-
196
- print(f"Developer initialized: {name}" + (f" ({role})" if role else ""))
197
- print(f" Workspace: workspace/members/{name}/")
198
- print(f" Journal: workspace/members/{name}/journal/journal-1.md")
199
- return True
200
-
201
-
202
- # =============================================================================
203
- # 开发者校验
204
- # =============================================================================
205
-
206
- def ensure_developer(repo_root: Path | None = None) -> str:
207
- """确保开发者已初始化, 未初始化则打印提示并退出。"""
208
- developer = get_developer(repo_root)
209
- if not developer:
210
- print("Error: Developer not initialized.", file=sys.stderr)
211
- print("Run: python .qoder/scripts/workspace_init.py <your-name>", file=sys.stderr)
212
- sys.exit(1)
213
- return developer
214
-
215
-
216
- def show_developer_info(repo_root: Path | None = None) -> None:
217
- """显示当前开发者信息。"""
218
- from common.paths import get_developer_info, get_workspace_dir, get_active_journal_file
219
-
220
- info = get_developer_info(repo_root)
221
- if not info:
222
- print("Developer: not initialized")
223
- print("Run: python .qoder/scripts/workspace_init.py <your-name>")
224
- return
225
-
226
- print(f"Developer: {info.get('name', 'unknown')}")
227
- if info.get('role'):
228
- print(f"Role: {info['role']}")
229
- print(f"Initialized: {info.get('initialized_at', 'unknown')}")
230
-
231
- workspace = get_workspace_dir(repo_root)
232
- if workspace:
233
- print(f"Workspace: {workspace}")
234
-
235
- journal = get_active_journal_file(repo_root)
236
- if journal:
237
- from common.paths import count_lines
238
- lines = count_lines(journal)
239
- print(f"Active Journal: {journal.name} ({lines} lines)")
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ QODER Pipeline - 开发者管理工具
5
+
6
+ 提供开发者身份的初始化和管理功能:
7
+ - init_developer: 初始化开发者身份, 创建工作空间和日志
8
+ - ensure_developer: 确保开发者已初始化 (未初始化则退出)
9
+ - show_developer_info: 显示开发者信息
10
+
11
+ 开发者身份存储在 .qoder/.developer 文件中 (gitignored)
12
+ 工作空间在 workspace/members/<developer>/ 目录下
13
+ """
14
+
15
+ from __future__ import annotations
16
+
17
+ import sys
18
+ from datetime import datetime
19
+ from pathlib import Path
20
+
21
+ # 将 scripts 目录加入路径以便导入 common 模块
22
+ import os
23
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
24
+
25
+ from foundation.core.paths import (
26
+ DIR_WORKFLOW,
27
+ FILE_DEVELOPER,
28
+ MEMBERS_DIR,
29
+ get_repo_root,
30
+ get_developer,
31
+ check_developer,
32
+ )
33
+
34
+
35
+ # =============================================================================
36
+ # 开发者初始化
37
+ # =============================================================================
38
+
39
+ def write_developer_file(name: str, role: str | None = None,
40
+ repo_root: Path | None = None) -> bool:
41
+ """写入 .qoder/.developer (规范格式: name=<name>)。"""
42
+ if repo_root is None:
43
+ repo_root = get_repo_root()
44
+ dev_file = repo_root / DIR_WORKFLOW / FILE_DEVELOPER
45
+ lines = [f"name={name}"]
46
+ if role:
47
+ lines.append(f"role={role}")
48
+ lines.append(f"initialized_at={datetime.now().isoformat()}")
49
+ try:
50
+ dev_file.write_text("\n".join(lines) + "\n", encoding="utf-8")
51
+ return True
52
+ except (OSError, IOError) as e:
53
+ print(f"Error: Failed to create .developer file: {e}", file=sys.stderr)
54
+ return False
55
+
56
+
57
+ def _detect_git_author() -> str | None:
58
+ """探测系统 git config 的 user.name <user.email>。git 未装或未配返回 None。"""
59
+ import subprocess
60
+ try:
61
+ rn = subprocess.run(["git", "config", "user.name"],
62
+ capture_output=True, text=True, timeout=5)
63
+ re_ = subprocess.run(["git", "config", "user.email"],
64
+ capture_output=True, text=True, timeout=5)
65
+ if rn.returncode == 0 and re_.returncode == 0:
66
+ gname = rn.stdout.strip()
67
+ gemail = re_.stdout.strip()
68
+ if gname and gemail:
69
+ return f"{gname} <{gemail}>"
70
+ except (FileNotFoundError, OSError, subprocess.SubprocessError):
71
+ pass # git 未装
72
+ return None
73
+
74
+
75
+ def _ensure_git_config(name: str, repo_root: Path) -> None:
76
+ """确认 git user.name/email 已配置。未配则提示 (绝不自动造假账号)。
77
+
78
+ 旧逻辑会塞 name@local 假账号, 与零信任 push 门禁冲突, 已废弃。
79
+ 真正的 git 配置由 setup.py configure_git_identity() 在 init 前完成。
80
+ 这里只做兜底检测: 如果走到这还没配, 提示用户去配。
81
+ """
82
+ import subprocess
83
+ # 先看 git 是否可用
84
+ try:
85
+ subprocess.run(["git", "--version"], capture_output=True, timeout=5)
86
+ except (FileNotFoundError, OSError):
87
+ print(" [INFO] git 未安装, 跳过 git 配置 (核心功能不依赖 git)")
88
+ return
89
+
90
+ author = _detect_git_author()
91
+ if author:
92
+ # 检测到疑似假账号也要提示 (虽然配了, 但 push 会被门禁拒)
93
+ if "@local" in author:
94
+ print(f" [WARN] git 作者疑似假账号: {author} (push 门禁会拒绝)")
95
+ print(f" 请重跑 'wlkj init' 配置真实团队 git 账号")
96
+ else:
97
+ print(f" [OK] git 作者: {author}")
98
+ return
99
+
100
+ # git 未配: 不造假, 只提示
101
+ print(f" [WARN] git 未配置 user.name/email")
102
+ print(f" push/commit 会失败。请配置团队 git 账号:")
103
+ print(f" git config --global user.name '你的名字'")
104
+ print(f" git config --global user.email '你的团队邮箱'")
105
+ print(f" 或重跑: wlkj init <你的名字>")
106
+
107
+
108
+ def init_developer(name: str, role: str | None = None,
109
+ repo_root: Path | None = None) -> bool:
110
+ """初始化开发者身份。
111
+
112
+ 创建以下内容:
113
+ - .qoder/.developer 文件 (name= / role= / initialized_at=)
114
+ - workspace/members/<name>/{journal,drafts,inbox}/ 目录
115
+ - 初始日志文件 journal/journal-1.md
116
+ - member.json + .signing_key (零信任身份注册, 用于 push 门禁)
117
+ - git user.name/email 检测与配置
118
+
119
+ Returns:
120
+ 成功返回 True, 失败返回 False。
121
+ """
122
+ if not name:
123
+ print("Error: developer name is required", file=sys.stderr)
124
+ return False
125
+
126
+ # 校验名称合法性 (允许字母数字、中文和部分符号)
127
+ if not all(c.isalnum() or c in "-_" for c in name):
128
+ print(f"Error: invalid developer name '{name}' (only alphanumeric, -, _ allowed)", file=sys.stderr)
129
+ return False
130
+
131
+ if repo_root is None:
132
+ repo_root = get_repo_root()
133
+
134
+ # 零信任: 切换身份时清除旧开发者的 current-task 指针
135
+ # (防止 B 在 A 用过的机器上看到 A 的活跃任务, 误操作)
136
+ try:
137
+ from foundation.core.paths import get_developer, set_current_task
138
+ old_dev = get_developer(repo_root)
139
+ if old_dev and old_dev != name:
140
+ set_current_task(None, repo_root, developer=old_dev)
141
+ print(f"Note: 切换开发者 {old_dev} -> {name}, 已清除 {old_dev} 的活跃任务指针")
142
+ except Exception:
143
+ pass # 清理失败不阻塞初始化
144
+
145
+ # 1. 创建 .developer 文件
146
+ if not write_developer_file(name, role, repo_root):
147
+ return False
148
+
149
+ # 2. 创建个人工作空间 workspace/members/<name>/
150
+ # v3.0 M3: 个人目录 = member.json + drafts + outputs + journal + .private
151
+ personal = repo_root / "workspace" / "members" / name
152
+ try:
153
+ for sub in ("journal", "drafts", "outputs", ".private", ".private/secrets"):
154
+ (personal / sub).mkdir(parents=True, exist_ok=True)
155
+ except (OSError, IOError) as e:
156
+ print(f"Error: Failed to create workspace directory: {e}", file=sys.stderr)
157
+ return False
158
+
159
+ # 3. 创建初始日志文件
160
+ journal_file = personal / "journal" / "journal-1.md"
161
+ if not journal_file.exists():
162
+ today = datetime.now().strftime("%Y-%m-%d")
163
+ try:
164
+ journal_file.write_text(
165
+ f"# Journal - {name}\n\n> Started: {today}\n\n---\n\n",
166
+ encoding="utf-8"
167
+ )
168
+ except (OSError, IOError) as e:
169
+ print(f"Error: Failed to create journal file: {e}", file=sys.stderr)
170
+ return False
171
+
172
+ # 4. 零信任身份注册 (写 member.json + 签名密钥 + git_author)
173
+ # 这是 push 门禁的前提: 没 member.json → syncgate 拒绝 push
174
+ git_author = _detect_git_author()
175
+ try:
176
+ from foundation.identity.identity import register_member, IdentityError, get_member
177
+ # 修正: 旧 member.json 若是假账号(@local), 且现在 git 配了真账号 → 用真账号覆盖
178
+ # register_member 已有"已注册则只更新 git_author, 密钥不动"的逻辑, 这里只加提示
179
+ existing_member = get_member(name, repo_root)
180
+ if existing_member:
181
+ old_author = existing_member.get("git_author", "")
182
+ if (old_author and "@local" in old_author
183
+ and git_author and "@local" not in git_author):
184
+ print(f" [修正] member.json git_author 从假账号更新为真账号: {git_author}")
185
+ try:
186
+ register_member(name, role or "pm", git_author, repo_root)
187
+ print(f" [OK] 身份注册: member.json + 签名密钥已生成")
188
+ except IdentityError as e:
189
+ print(f" [WARN] 身份注册失败 (不阻塞): {e}")
190
+ except ImportError:
191
+ pass # identity 模块不可用, 跳过 (向后兼容)
192
+
193
+ # 5. 确保 git 配置 (只检测+提示, 不造假; 真账号由 setup.py 在 init 前配好)
194
+ _ensure_git_config(name, repo_root)
195
+
196
+ print(f"Developer initialized: {name}" + (f" ({role})" if role else ""))
197
+ print(f" Workspace: workspace/members/{name}/")
198
+ print(f" Journal: workspace/members/{name}/journal/journal-1.md")
199
+ return True
200
+
201
+
202
+ # =============================================================================
203
+ # 开发者校验
204
+ # =============================================================================
205
+
206
+ def ensure_developer(repo_root: Path | None = None) -> str:
207
+ """确保开发者已初始化, 未初始化则打印提示并退出。"""
208
+ developer = get_developer(repo_root)
209
+ if not developer:
210
+ print("Error: Developer not initialized.", file=sys.stderr)
211
+ print("Run: npx @hupan56/wlkj init <your-name>", file=sys.stderr)
212
+ sys.exit(1)
213
+ return developer
214
+
215
+
216
+ def show_developer_info(repo_root: Path | None = None) -> None:
217
+ """显示当前开发者信息。"""
218
+ from foundation.core.paths import get_developer_info, get_workspace_dir, get_active_journal_file
219
+
220
+ info = get_developer_info(repo_root)
221
+ if not info:
222
+ print("Developer: not initialized")
223
+ print("Run: npx @hupan56/wlkj init <your-name>")
224
+ return
225
+
226
+ print(f"Developer: {info.get('name', 'unknown')}")
227
+ if info.get('role'):
228
+ print(f"Role: {info['role']}")
229
+ print(f"Initialized: {info.get('initialized_at', 'unknown')}")
230
+
231
+ workspace = get_workspace_dir(repo_root)
232
+ if workspace:
233
+ print(f"Workspace: {workspace}")
234
+
235
+ journal = get_active_journal_file(repo_root)
236
+ if journal:
237
+ from foundation.core.paths import count_lines
238
+ lines = count_lines(journal)
239
+ print(f"Active Journal: {journal.name} ({lines} lines)")
@@ -22,7 +22,7 @@ guard.py - 角色能力边界守卫 (解耦的执行点)
22
22
  当前角色名 (identity.get_role 的便捷封装)
23
23
 
24
24
  Usage:
25
- from common.guard import check_produce
25
+ from foundation.identity.guard import check_produce
26
26
  r = check_produce('unit-test')
27
27
  if not r.ok:
28
28
  print(r.hint) # "你的角色 pm 不能产出 unit-test, 需 dev/test 角色"
@@ -34,7 +34,7 @@ import os
34
34
  import sys
35
35
 
36
36
  try:
37
- from .result import Result, CODE
37
+ from foundation.data.result import Result, CODE
38
38
  from .identity import get_role, can_produce, can_consume, get_role_config
39
39
  except ImportError:
40
40
  _COMMON_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -41,8 +41,8 @@ from typing import Optional, Dict, Any, Union
41
41
 
42
42
  # 相对导入兄弟模块
43
43
  try:
44
- from .atomicio import atomic_write_json, safe_read_json
45
- from .paths import get_repo_root, MEMBERS_DIR
44
+ from foundation.io.atomicio import atomic_write_json, safe_read_json
45
+ from foundation.core.paths import get_repo_root, MEMBERS_DIR
46
46
  except ImportError:
47
47
  _COMMON_DIR = os.path.dirname(os.path.abspath(__file__))
48
48
  if _COMMON_DIR not in sys.path:
@@ -52,7 +52,7 @@ except ImportError:
52
52
  _SCRIPTS_DIR = os.path.dirname(_COMMON_DIR)
53
53
  if _SCRIPTS_DIR not in sys.path:
54
54
  sys.path.insert(0, _SCRIPTS_DIR)
55
- from common.paths import get_repo_root, MEMBERS_DIR
55
+ from foundation.core.paths import get_repo_root, MEMBERS_DIR
56
56
 
57
57
  __all__ = [
58
58
  "IdentityError",
@@ -105,7 +105,7 @@ def _member_json(name: str, repo_root: Optional[Union[str, Path]] = None) -> Pat
105
105
  def _key_file(name: str, repo_root: Optional[Union[str, Path]] = None) -> Path:
106
106
  """签名密钥路径 (v3.0: 收进 .private/signing_key, 向后兼容老 .signing_key)。"""
107
107
  try:
108
- from .paths import get_private_file
108
+ from foundation.core.paths import get_private_file
109
109
  return get_private_file("signing_key", name)
110
110
  except Exception:
111
111
  return _member_dir(name, repo_root) / ".signing_key"
@@ -204,6 +204,10 @@ def register_member(
204
204
  or "%s <unknown@local>" % name
205
205
  ),
206
206
  "joined_at": joined_at,
207
+ # 禅道账号映射 (v3.1.3): 本地 developer 名(如 hupan56) ↔ 禅道 account(如 hupan)
208
+ # 不一致时, zentao_sync 靠此过滤归属 (见 contracts/isolation.md「禅道同步」)。
209
+ # 首次注册留空 (None), 成员后续填; 已注册的保留原值不覆盖。
210
+ "zentao_account": (existing.get("zentao_account") if existing else None),
207
211
  }
208
212
  atomic_write_json(mj, record)
209
213
  return record
@@ -272,11 +276,11 @@ def require_member(name: Optional[str] = None, repo_root: Optional[Union[str, Pa
272
276
  """
273
277
  if name is None:
274
278
  try:
275
- from .developer_paths import get_developer
279
+ from foundation.core.paths import get_developer
276
280
  except ImportError:
277
281
  _this = os.path.dirname(os.path.abspath(__file__))
278
282
  sys.path.insert(0, _this)
279
- from paths import get_developer # type: ignore
283
+ from foundation.core.paths import get_developer # type: ignore
280
284
  name = get_developer(repo_root)
281
285
  if not name:
282
286
  sys.stderr.write("[authz] 拒绝: 未设置开发者身份。先跑 /wl-init 注册。\n")
@@ -292,10 +296,10 @@ def require_member(name: Optional[str] = None, repo_root: Optional[Union[str, Pa
292
296
  def ensure_current_member(repo_root: Optional[Union[str, Path]] = None) -> Optional[str]:
293
297
  """软检查: 返回当前已验证的成员名, 或 None (不 exit)。给非破坏性命令用。"""
294
298
  try:
295
- from paths import get_developer
299
+ from foundation.core.paths import get_developer
296
300
  except ImportError:
297
301
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
298
- from paths import get_developer # type: ignore
302
+ from foundation.core.paths import get_developer # type: ignore
299
303
  name = get_developer(repo_root)
300
304
  if name and verify_member(name, repo_root):
301
305
  return name
@@ -341,10 +345,10 @@ def get_role(name: Optional[str] = None, repo_root: Optional[Union[str, Path]] =
341
345
  if not name:
342
346
  # 从 .developer 读
343
347
  try:
344
- from paths import get_developer, get_developer_info
348
+ from foundation.core.paths import get_developer, get_developer_info
345
349
  except ImportError:
346
350
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
347
- from paths import get_developer, get_developer_info # type: ignore
351
+ from foundation.core.paths import get_developer, get_developer_info # type: ignore
348
352
  info = get_developer_info(repo_root) if "get_developer_info" in dir() else None
349
353
  if isinstance(info, dict) and info.get("role"):
350
354
  return info["role"]
@@ -11,7 +11,7 @@ kg_mcp_server.py(:249-276) 逐字重复。改一处忘改另一处 → CLI 和 M
11
11
  让不同角色只看到与其职责相关的段落, 减少噪音。
12
12
 
13
13
  Usage:
14
- from common.roles import filter_by_role, ROLE_SECTIONS
14
+ from foundation.identity.roles import filter_by_role, ROLE_SECTIONS
15
15
  text = filter_by_role(context_pack_output, role='pm')
16
16
  """
17
17