@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.
Files changed (253) hide show
  1. package/bin/cli.js +1435 -1107
  2. package/package.json +29 -29
  3. package/templates/qoder/agents/insight-planning.md +1 -1
  4. package/templates/qoder/agents/insight-research.md +28 -15
  5. package/templates/qoder/commands/optional/wl-insight.md +161 -161
  6. package/templates/qoder/commands/optional/wl-report.md +20 -39
  7. package/templates/qoder/commands/optional/wl-status.md +4 -4
  8. package/templates/qoder/commands/wl-code.md +2 -2
  9. package/templates/qoder/commands/wl-design.md +6 -6
  10. package/templates/qoder/commands/wl-init.md +3 -3
  11. package/templates/qoder/commands/wl-prd.md +26 -13
  12. package/templates/qoder/commands/wl-req.md +43 -0
  13. package/templates/qoder/commands/wl-search.md +78 -47
  14. package/templates/qoder/commands/wl-task.md +343 -40
  15. package/templates/qoder/commands/wl-test.md +43 -17
  16. package/templates/qoder/config.yaml +52 -14
  17. package/templates/qoder/hooks/post-tool-use.py +181 -0
  18. package/templates/qoder/hooks/session-start.py +94 -23
  19. package/templates/qoder/hooks/stop-eval.py +207 -0
  20. package/templates/qoder/hooks/user-prompt-submit.py +139 -0
  21. package/templates/qoder/rules/wl-pipeline.md +85 -49
  22. package/templates/qoder/scripts/README.md +102 -0
  23. package/templates/qoder/scripts/capability/__init__.py +26 -0
  24. package/templates/qoder/scripts/capability/__main__.py +72 -0
  25. package/templates/qoder/scripts/capability/adapters/__init__.py +29 -0
  26. package/templates/qoder/scripts/capability/adapters/cli.py +316 -0
  27. package/templates/qoder/scripts/capability/adapters/mcp.py +334 -0
  28. package/templates/qoder/scripts/capability/adapters/qw.py +271 -0
  29. package/templates/qoder/scripts/capability/caps/__init__.py +27 -0
  30. package/templates/qoder/scripts/capability/caps/context.py +36 -0
  31. package/templates/qoder/scripts/capability/caps/cron.py +50 -0
  32. package/templates/qoder/scripts/capability/caps/identity.py +43 -0
  33. package/templates/qoder/scripts/capability/caps/memory.py +71 -0
  34. package/templates/qoder/scripts/capability/caps/notify.py +41 -0
  35. package/templates/qoder/scripts/capability/caps/present.py +48 -0
  36. package/templates/qoder/scripts/capability/caps/repo.py +31 -0
  37. package/templates/qoder/scripts/capability/caps/sandbox.py +43 -0
  38. package/templates/qoder/scripts/capability/chain.py +92 -0
  39. package/templates/qoder/scripts/capability/memory_chain.py +41 -0
  40. package/templates/qoder/scripts/capability/registry.py +246 -0
  41. package/templates/qoder/scripts/capability/registry_mcp.py +250 -0
  42. package/templates/qoder/scripts/capability/smoke_test.py +211 -0
  43. package/templates/qoder/scripts/capability/smoke_test_report.json +94 -0
  44. package/templates/qoder/scripts/deployment/setup/__init__.py +11 -0
  45. package/templates/qoder/scripts/deployment/setup/carriers.py +669 -0
  46. package/templates/qoder/scripts/deployment/setup/carriers_verify.py +148 -0
  47. package/templates/qoder/scripts/{init_doctor.py → deployment/setup/init_doctor.py} +100 -39
  48. package/templates/qoder/scripts/{install_qoderwork.py → deployment/setup/install_qoderwork.py} +48 -30
  49. package/templates/qoder/scripts/{platform_doctor.py → deployment/setup/platform_doctor.py} +271 -259
  50. package/templates/qoder/scripts/{repo_root.py → deployment/setup/repo_root.py} +9 -2
  51. package/templates/qoder/scripts/{setup.py → deployment/setup/setup.py} +143 -14
  52. package/templates/qoder/scripts/{setup_lanhu.py → deployment/setup/setup_lanhu.py} +979 -963
  53. package/templates/qoder/scripts/domain/design/__init__.py +0 -0
  54. package/templates/qoder/scripts/{fill_prototype.py → domain/design/fill_prototype.py} +17 -5
  55. package/templates/qoder/scripts/{gen_design_doc.py → domain/design/gen_design_doc.py} +406 -394
  56. package/templates/qoder/scripts/domain/kg/__init__.py +11 -0
  57. package/templates/qoder/scripts/domain/kg/build/__init__.py +0 -0
  58. package/templates/qoder/scripts/domain/kg/build/build_entity_registry.py +201 -0
  59. package/templates/qoder/scripts/domain/kg/build/build_relations.py +132 -0
  60. package/templates/qoder/scripts/{build_style_index.py → domain/kg/build/build_style_index.py} +50 -15
  61. package/templates/qoder/scripts/domain/kg/build/build_workflows.py +149 -0
  62. package/templates/qoder/scripts/{kg_build.py → domain/kg/build/kg_build.py} +685 -612
  63. package/templates/qoder/scripts/{kg_build_db.py → domain/kg/build/kg_build_db.py} +338 -327
  64. package/templates/qoder/scripts/{kg_incremental.py → domain/kg/build/kg_incremental.py} +425 -393
  65. package/templates/qoder/scripts/{learn_aggregate.py → domain/kg/build/learn_aggregate.py} +212 -201
  66. package/templates/qoder/scripts/domain/kg/extract/__init__.py +0 -0
  67. package/templates/qoder/scripts/{common → domain/kg/extract}/extract.py +430 -419
  68. package/templates/qoder/scripts/domain/kg/extract/test_extract.py +115 -0
  69. package/templates/qoder/scripts/{common → domain/kg/extract}/ts_extract.py +614 -536
  70. package/templates/qoder/scripts/domain/kg/graph/__init__.py +0 -0
  71. package/templates/qoder/scripts/{kg_link_db.py → domain/kg/graph/kg_link_db.py} +235 -224
  72. package/templates/qoder/scripts/domain/kg/graph/kg_semantic.py +683 -0
  73. package/templates/qoder/scripts/{kg.py → domain/kg/kg.py} +871 -708
  74. package/templates/qoder/scripts/domain/kg/kg_capabilities.py +182 -0
  75. package/templates/qoder/scripts/domain/kg/search/__init__.py +0 -0
  76. package/templates/qoder/scripts/{context_pack.py → domain/kg/search/context_pack.py} +45 -17
  77. package/templates/qoder/scripts/{enrich_prompt.py → domain/kg/search/enrich_prompt.py} +238 -226
  78. package/templates/qoder/scripts/domain/kg/search/prefetch.py +384 -0
  79. package/templates/qoder/scripts/{common → domain/kg/search}/search_engine.py +207 -205
  80. package/templates/qoder/scripts/{search_index.py → domain/kg/search/search_index.py} +210 -88
  81. package/templates/qoder/scripts/domain/kg/server/__init__.py +0 -0
  82. package/templates/qoder/scripts/domain/kg/server/kgd.py +549 -0
  83. package/templates/qoder/scripts/domain/kg/server/perf_bench.py +197 -0
  84. package/templates/qoder/scripts/domain/kg/storage/__init__.py +0 -0
  85. package/templates/qoder/scripts/{kg_duckdb.py → domain/kg/storage/kg_duckdb.py} +70 -45
  86. package/templates/qoder/scripts/domain/learning/__init__.py +0 -0
  87. package/templates/qoder/scripts/{learn.py → domain/learning/learn.py} +157 -146
  88. package/templates/qoder/scripts/domain/report/__init__.py +11 -0
  89. package/templates/qoder/scripts/{add_session.py → domain/report/add_session.py} +256 -244
  90. package/templates/qoder/scripts/{export.py → domain/report/export.py} +72 -4
  91. package/templates/qoder/scripts/{report.py → domain/report/report.py} +292 -281
  92. package/templates/qoder/scripts/domain/report/report_snapshot.py +261 -0
  93. package/templates/qoder/scripts/domain/report/role.py +39 -0
  94. package/templates/qoder/scripts/{status.py → domain/report/status.py} +737 -628
  95. package/templates/qoder/scripts/domain/report/status_snapshot.py +191 -0
  96. package/templates/qoder/scripts/domain/requirement/__init__.py +0 -0
  97. package/templates/qoder/scripts/{archive_prd.py → domain/requirement/archive_prd.py} +389 -377
  98. package/templates/qoder/scripts/domain/requirement/req.py +228 -0
  99. package/templates/qoder/scripts/domain/task/__init__.py +11 -0
  100. package/templates/qoder/scripts/{git_sync.py → domain/task/git_sync.py} +90 -50
  101. package/templates/qoder/scripts/{syncgate.py → domain/task/syncgate.py} +18 -7
  102. package/templates/qoder/scripts/domain/task/task.py +229 -0
  103. package/templates/qoder/scripts/domain/task/task_lifecycle.py +606 -0
  104. package/templates/qoder/scripts/domain/task/task_query.py +162 -0
  105. package/templates/qoder/scripts/domain/task/task_relations.py +425 -0
  106. package/templates/qoder/scripts/{team_sync.py → domain/task/team_sync.py} +101 -23
  107. package/templates/qoder/scripts/domain/task/zentao_sync.py +370 -0
  108. package/templates/qoder/scripts/foundation/__init__.py +0 -0
  109. package/templates/qoder/scripts/foundation/bootstrap.py +145 -0
  110. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  111. package/templates/qoder/scripts/foundation/core/cmd_registry.py +112 -0
  112. package/templates/qoder/scripts/foundation/core/config.py +187 -0
  113. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -400
  114. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  115. package/templates/qoder/scripts/foundation/data/contract.py +317 -0
  116. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  117. package/templates/qoder/scripts/foundation/data/result.py +223 -0
  118. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -392
  119. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  120. package/templates/qoder/scripts/foundation/identity/check_publish.py +103 -0
  121. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -238
  122. package/templates/qoder/scripts/foundation/identity/guard.py +159 -0
  123. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +132 -9
  124. package/templates/qoder/scripts/foundation/identity/roles.py +60 -0
  125. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  126. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  127. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +11 -10
  128. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  129. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  130. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  131. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  132. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  133. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  134. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  135. package/templates/qoder/scripts/foundation/protocol/mcp_base.py +268 -0
  136. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  137. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  138. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  139. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  140. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  141. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  142. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  143. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  144. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  145. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  146. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  147. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  148. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  149. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  150. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  151. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  152. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  153. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  154. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  155. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  156. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  157. package/templates/qoder/scripts/{lanhu_stdio_wrapper.py → protocol/mcp/lanhu_stdio_wrapper.py} +131 -119
  158. package/templates/qoder/scripts/protocol/mcp/mcp_doctor.py +548 -0
  159. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  160. package/templates/qoder/scripts/protocol/mcp/mysql_mcp_server.py +461 -0
  161. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  162. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  163. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  164. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  165. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  166. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  167. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  168. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  169. package/templates/qoder/scripts/validation/__init__.py +0 -0
  170. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  171. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  172. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  173. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  174. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  175. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  176. package/templates/qoder/scripts/{eval_prd.py → validation/metrics/eval_prd.py} +84 -15
  177. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  178. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  179. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  180. package/templates/qoder/scripts/{autotest.py → validation/test/autotest.py} +1234 -1751
  181. package/templates/qoder/scripts/validation/test/autotest_auth.py +109 -0
  182. package/templates/qoder/scripts/{autotest_batch.py → validation/test/autotest_batch.py} +255 -224
  183. package/templates/qoder/scripts/validation/test/autotest_data.py +680 -0
  184. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  185. package/templates/qoder/scripts/{autotest_run.py → validation/test/autotest_run.py} +323 -297
  186. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  187. package/templates/qoder/scripts/{benchmark.py → validation/test/benchmark.py} +17 -5
  188. package/templates/qoder/scripts/{kg_auto_login.py → validation/test/kg_auto_login.py} +208 -196
  189. package/templates/qoder/scripts/{kg_test_runner.py → validation/test/kg_test_runner.py} +13 -2
  190. package/templates/qoder/scripts/{page_probe.py → validation/test/page_probe.py} +470 -459
  191. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  192. package/templates/qoder/settings.json +23 -2
  193. package/templates/qoder/skills/design-import/SKILL.md +235 -226
  194. package/templates/qoder/skills/design-review/SKILL.md +91 -82
  195. package/templates/qoder/skills/prd-generator/SKILL.md +38 -24
  196. package/templates/qoder/skills/prd-review/SKILL.md +8 -6
  197. package/templates/qoder/skills/prototype-generator/SKILL.md +296 -247
  198. package/templates/qoder/skills/spec-coder/SKILL.md +24 -15
  199. package/templates/qoder/skills/spec-generator/SKILL.md +24 -12
  200. package/templates/qoder/skills/test-generator/SKILL.md +9 -7
  201. package/templates/qoder/skills/wl-code/SKILL.md +25 -13
  202. package/templates/qoder/skills/wl-commit/SKILL.md +10 -9
  203. package/templates/qoder/skills/wl-design/SKILL.md +7 -5
  204. package/templates/qoder/skills/wl-init/SKILL.md +8 -8
  205. package/templates/qoder/skills/wl-insight/SKILL.md +25 -12
  206. package/templates/qoder/skills/wl-prd-full/SKILL.md +59 -8
  207. package/templates/qoder/skills/wl-prd-quick/SKILL.md +7 -7
  208. package/templates/qoder/skills/wl-prd-review/SKILL.md +18 -6
  209. package/templates/qoder/skills/wl-report/SKILL.md +27 -25
  210. package/templates/qoder/skills/wl-search/SKILL.md +151 -80
  211. package/templates/qoder/skills/wl-spec/SKILL.md +9 -7
  212. package/templates/qoder/skills/wl-status/SKILL.md +50 -18
  213. package/templates/qoder/skills/wl-task/SKILL.md +94 -12
  214. package/templates/qoder/skills/wl-test/SKILL.md +154 -45
  215. package/templates/qoder/templates/prd-full-template.md +7 -0
  216. package/templates/root/AGENTS.md +275 -237
  217. package/templates/root/requirements.txt +3 -0
  218. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  219. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  220. package/templates/qoder/hooks/inject-workflow-state.py +0 -169
  221. package/templates/qoder/scripts/__pycache__/check_mcp_launch.cpython-39.pyc +0 -0
  222. package/templates/qoder/scripts/__pycache__/install_qoderwork.cpython-39.pyc +0 -0
  223. package/templates/qoder/scripts/__pycache__/mcp_launcher.cpython-39.pyc +0 -0
  224. package/templates/qoder/scripts/__pycache__/platform_doctor.cpython-39.pyc +0 -0
  225. package/templates/qoder/scripts/check_carriers.py +0 -238
  226. package/templates/qoder/scripts/check_mcp.py +0 -298
  227. package/templates/qoder/scripts/check_mcp_launch.py +0 -183
  228. package/templates/qoder/scripts/check_qoderwork_consistency.py +0 -166
  229. package/templates/qoder/scripts/collect_prds.py +0 -31
  230. package/templates/qoder/scripts/common/mentions.py +0 -134
  231. package/templates/qoder/scripts/common/utf8.py +0 -38
  232. package/templates/qoder/scripts/extract_api_params.py +0 -246
  233. package/templates/qoder/scripts/extract_routes.py +0 -54
  234. package/templates/qoder/scripts/extract_routes_tree.py +0 -78
  235. package/templates/qoder/scripts/handoff.py +0 -22
  236. package/templates/qoder/scripts/init_developer.py +0 -76
  237. package/templates/qoder/scripts/kg_mcp_server.py +0 -801
  238. package/templates/qoder/scripts/kg_semantic.py +0 -150
  239. package/templates/qoder/scripts/mcp_launcher.py +0 -414
  240. package/templates/qoder/scripts/mysql_mcp_server.py +0 -396
  241. package/templates/qoder/scripts/parse_prds.py +0 -33
  242. package/templates/qoder/scripts/role.py +0 -51
  243. package/templates/qoder/scripts/sync_carriers.py +0 -259
  244. package/templates/qoder/scripts/task.py +0 -1261
  245. package/templates/qoder/scripts/workspace_init.py +0 -102
  246. package/templates/qoder/scripts/zentao_mcp_server.py +0 -424
  247. package/templates/qoder/skills/prompt-enrich/SKILL.md +0 -90
  248. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  249. /package/templates/qoder/{skills/prototype-generator/SKILL.md.zcode-79180-2af4721f-f9a6-412c-88db-c0af680d211b.tmp → scripts/domain/__init__.py} +0 -0
  250. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  251. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  252. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  253. /package/templates/qoder/scripts/{secure-ls.js → validation/test/secure-ls.js} +0 -0
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+ # v3.0 路径自举
3
+ import os as _o, sys as _s
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
10
+ if _cp not in _s.path: _s.path.insert(0, _cp)
11
+ from bootstrap import setup; setup()
12
+
13
+ """
14
+ check_publish.py - 统一发布前置检查 (guard + contract 双门)
15
+
16
+ 把"造了没接"的两个基建真正接入执行链路:
17
+ - guard.py (角色边界): 当前角色能否产出该契约? 越权 → 软提示
18
+ - contract.py (契约校验): 产出文件带不带 @contract 头? 带了是否合规?
19
+
20
+ 设计原则 (与 guard/contract 一致):
21
+ - 降级不阻塞: 越权/无契约头/校验警告 → 打印提示但 exit 0 (让用户决定)
22
+ - 只有"硬错误"(契约校验 FAIL) → exit 1, 阻止发布
23
+ - 统一入口: 所有产出型 skill 发布前调这一个脚本, 不用各自接 guard/contract
24
+
25
+ 用法:
26
+ python .qoder/scripts/common/check_publish.py <契约类型> <产出文件路径>
27
+ python .qoder/scripts/common/check_publish.py prd workspace/.../REQ-2026-001-xxx.md
28
+ python .qoder/scripts/common/check_publish.py design-spec workspace/.../xxx-design-spec.json
29
+ python .qoder/scripts/common/check_publish.py test-cases workspace/.../xxx-cases.json
30
+
31
+ 退出码:
32
+ 0 = 通过 (含软警告, 可发布)
33
+ 1 = 硬失败 (契约校验 FAIL, 建议不发布)
34
+ 2 = 参数错误 / 内部异常
35
+
36
+ 输出: 人类可读的检查报告 (角色 + 契约两段)
37
+ """
38
+
39
+ import sys
40
+
41
+
42
+ def run(contract_type, artifact_path):
43
+ """跑 guard + contract 双门检查。返回 exit code。"""
44
+ # ============ 门 1: 角色边界 (guard) ============
45
+ # 越权只软提示, 不阻塞 (ensure=False)
46
+ print('--- 角色边界检查 ---')
47
+ try:
48
+ from foundation.identity.guard import check_produce
49
+ gr = check_produce(contract_type)
50
+ if gr.ok and not gr.is_warn:
51
+ print('✓', gr.msg)
52
+ else:
53
+ # 越权 (WARN): 提示但仍可继续
54
+ print(gr.msg)
55
+ if gr.hint:
56
+ print(' →', gr.hint)
57
+ print(' (软提示, 不阻塞发布。若需切换角色: /wl-init)')
58
+ except Exception as e:
59
+ print('⚠️ 角色检查不可用 ({}), 跳过'.format(str(e)[:60]))
60
+
61
+ # ============ 门 2: 契约校验 (contract) ============
62
+ print()
63
+ print('--- 契约校验 ---')
64
+ import os
65
+ if not os.path.isfile(artifact_path):
66
+ print('⚠️ 产出文件不存在: {}'.format(artifact_path))
67
+ print(' (跳过契约校验)')
68
+ return 0
69
+ try:
70
+ from foundation.data.contract import validate_contract
71
+ cr = validate_contract(artifact_path)
72
+ if cr.ok and not cr.is_warn:
73
+ print('✓', cr.msg)
74
+ return 0
75
+ elif cr.is_warn:
76
+ # 警告 (无契约头/字段警告/无schema): 软门禁, 可继续
77
+ print(cr.msg)
78
+ if cr.hint:
79
+ print(' →', cr.hint)
80
+ return 0
81
+ else:
82
+ # FAIL (硬错误): 缺必填/类型错/枚举越界 → 阻止
83
+ print('[FAIL]', cr.msg)
84
+ if cr.hint:
85
+ print(' →', cr.hint)
86
+ print(' (硬失败, 建议修正后再发布)')
87
+ return 1
88
+ except Exception as e:
89
+ print('⚠️ 契约校验异常 ({}), 跳过'.format(str(e)[:60]))
90
+ return 0
91
+
92
+
93
+ def main():
94
+ if len(sys.argv) < 3:
95
+ print(__doc__)
96
+ return 2
97
+ contract_type = sys.argv[1]
98
+ artifact_path = sys.argv[2]
99
+ return run(contract_type, artifact_path)
100
+
101
+
102
+ if __name__ == '__main__':
103
+ sys.exit(main())
@@ -1,238 +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
- personal = repo_root / "workspace" / "members" / name
151
- try:
152
- for sub in ("journal", "drafts", "inbox"):
153
- (personal / sub).mkdir(parents=True, exist_ok=True)
154
- except (OSError, IOError) as e:
155
- print(f"Error: Failed to create workspace directory: {e}", file=sys.stderr)
156
- return False
157
-
158
- # 3. 创建初始日志文件
159
- journal_file = personal / "journal" / "journal-1.md"
160
- if not journal_file.exists():
161
- today = datetime.now().strftime("%Y-%m-%d")
162
- try:
163
- journal_file.write_text(
164
- f"# Journal - {name}\n\n> Started: {today}\n\n---\n\n",
165
- encoding="utf-8"
166
- )
167
- except (OSError, IOError) as e:
168
- print(f"Error: Failed to create journal file: {e}", file=sys.stderr)
169
- return False
170
-
171
- # 4. 零信任身份注册 (写 member.json + 签名密钥 + git_author)
172
- # 这是 push 门禁的前提: member.json syncgate 拒绝 push
173
- git_author = _detect_git_author()
174
- try:
175
- from common.identity import register_member, IdentityError, get_member
176
- # 修正: member.json 若是假账号(@local), 且现在 git 配了真账号 → 用真账号覆盖
177
- # register_member 已有"已注册则只更新 git_author, 密钥不动"的逻辑, 这里只加提示
178
- existing_member = get_member(name, repo_root)
179
- if existing_member:
180
- old_author = existing_member.get("git_author", "")
181
- if (old_author and "@local" in old_author
182
- and git_author and "@local" not in git_author):
183
- print(f" [修正] member.json git_author 从假账号更新为真账号: {git_author}")
184
- try:
185
- register_member(name, role or "pm", git_author, repo_root)
186
- print(f" [OK] 身份注册: member.json + 签名密钥已生成")
187
- except IdentityError as e:
188
- print(f" [WARN] 身份注册失败 (不阻塞): {e}")
189
- except ImportError:
190
- pass # identity 模块不可用, 跳过 (向后兼容)
191
-
192
- # 5. 确保 git 配置 (只检测+提示, 不造假; 真账号由 setup.py 在 init 前配好)
193
- _ensure_git_config(name, repo_root)
194
-
195
- print(f"Developer initialized: {name}" + (f" ({role})" if role else ""))
196
- print(f" Workspace: workspace/members/{name}/")
197
- print(f" Journal: workspace/members/{name}/journal/journal-1.md")
198
- return True
199
-
200
-
201
- # =============================================================================
202
- # 开发者校验
203
- # =============================================================================
204
-
205
- def ensure_developer(repo_root: Path | None = None) -> str:
206
- """确保开发者已初始化, 未初始化则打印提示并退出。"""
207
- developer = get_developer(repo_root)
208
- if not developer:
209
- print("Error: Developer not initialized.", file=sys.stderr)
210
- print("Run: python .qoder/scripts/workspace_init.py <your-name>", file=sys.stderr)
211
- sys.exit(1)
212
- return developer
213
-
214
-
215
- def show_developer_info(repo_root: Path | None = None) -> None:
216
- """显示当前开发者信息。"""
217
- from common.paths import get_developer_info, get_workspace_dir, get_active_journal_file
218
-
219
- info = get_developer_info(repo_root)
220
- if not info:
221
- print("Developer: not initialized")
222
- print("Run: python .qoder/scripts/workspace_init.py <your-name>")
223
- return
224
-
225
- print(f"Developer: {info.get('name', 'unknown')}")
226
- if info.get('role'):
227
- print(f"Role: {info['role']}")
228
- print(f"Initialized: {info.get('initialized_at', 'unknown')}")
229
-
230
- workspace = get_workspace_dir(repo_root)
231
- if workspace:
232
- print(f"Workspace: {workspace}")
233
-
234
- journal = get_active_journal_file(repo_root)
235
- if journal:
236
- from common.paths import count_lines
237
- lines = count_lines(journal)
238
- 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)")