@hupan56/wlkj 3.0.0 → 3.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) 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 +55 -23
  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 +35 -12
  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/domain/task/__pycache__/syncgate.cpython-39.pyc +0 -0
  100. package/templates/qoder/scripts/{task → domain/task}/git_sync.py +40 -21
  101. package/templates/qoder/scripts/{task → domain/task}/syncgate.py +13 -8
  102. package/templates/qoder/scripts/{task → domain/task}/task.py +13 -5
  103. package/templates/qoder/scripts/{task → domain/task}/task_lifecycle.py +606 -596
  104. package/templates/qoder/scripts/{task → domain/task}/task_query.py +162 -161
  105. package/templates/qoder/scripts/{task → domain/task}/task_relations.py +425 -424
  106. package/templates/qoder/scripts/{task → domain/task}/team_sync.py +9 -4
  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/__pycache__/__init__.cpython-39.pyc +0 -0
  110. package/templates/qoder/scripts/foundation/__pycache__/bootstrap.cpython-39.pyc +0 -0
  111. package/templates/qoder/scripts/{common → foundation}/bootstrap.py +10 -10
  112. package/templates/qoder/scripts/foundation/core/__init__.py +0 -0
  113. package/templates/qoder/scripts/foundation/core/__pycache__/__init__.cpython-39.pyc +0 -0
  114. package/templates/qoder/scripts/foundation/core/__pycache__/paths.cpython-39.pyc +0 -0
  115. package/templates/qoder/scripts/{common → foundation/core}/cmd_registry.py +1 -1
  116. package/templates/qoder/scripts/{common → foundation/core}/config.py +1 -1
  117. package/templates/qoder/scripts/{common → foundation/core}/paths.py +706 -586
  118. package/templates/qoder/scripts/foundation/data/__init__.py +0 -0
  119. package/templates/qoder/scripts/{common → foundation/data}/contract.py +2 -2
  120. package/templates/qoder/scripts/{common → foundation/data}/events.py +2 -2
  121. package/templates/qoder/scripts/{common → foundation/data}/result.py +1 -1
  122. package/templates/qoder/scripts/{common → foundation/data}/task_utils.py +427 -404
  123. package/templates/qoder/scripts/foundation/identity/__init__.py +0 -0
  124. package/templates/qoder/scripts/foundation/identity/__pycache__/__init__.cpython-39.pyc +0 -0
  125. package/templates/qoder/scripts/foundation/identity/__pycache__/identity.cpython-39.pyc +0 -0
  126. package/templates/qoder/scripts/{common → foundation/identity}/check_publish.py +103 -98
  127. package/templates/qoder/scripts/{common → foundation/identity}/developer.py +239 -239
  128. package/templates/qoder/scripts/{common → foundation/identity}/guard.py +2 -2
  129. package/templates/qoder/scripts/{common → foundation/identity}/identity.py +14 -10
  130. package/templates/qoder/scripts/{common → foundation/identity}/roles.py +1 -1
  131. package/templates/qoder/scripts/foundation/integrations/__init__.py +0 -0
  132. package/templates/qoder/scripts/{common → foundation/integrations}/active_task.py +30 -15
  133. package/templates/qoder/scripts/{common → foundation/integrations}/feishu.py +2 -2
  134. package/templates/qoder/scripts/{common → foundation/integrations}/terms.py +3 -3
  135. package/templates/qoder/scripts/foundation/integrations/zentao_client.py +220 -0
  136. package/templates/qoder/scripts/foundation/io/__init__.py +0 -0
  137. package/templates/qoder/scripts/foundation/io/__pycache__/__init__.cpython-39.pyc +0 -0
  138. package/templates/qoder/scripts/foundation/io/__pycache__/atomicio.cpython-39.pyc +0 -0
  139. package/templates/qoder/scripts/foundation/io/__pycache__/filelock.cpython-39.pyc +0 -0
  140. package/templates/qoder/scripts/{common → foundation/io}/filelock.py +1 -1
  141. package/templates/qoder/scripts/{common → foundation/io}/reqid.py +1 -1
  142. package/templates/qoder/scripts/foundation/protocol/__init__.py +0 -0
  143. package/templates/qoder/scripts/foundation/protocol/duckdb_conn.py +39 -0
  144. package/templates/qoder/scripts/{common → foundation/protocol}/mcp_base.py +1 -1
  145. package/templates/qoder/scripts/foundation/utils/__init__.py +0 -0
  146. package/templates/qoder/scripts/{common → foundation/utils}/eval_api.py +12 -1
  147. package/templates/qoder/scripts/{common → foundation/utils}/pip_install.py +23 -6
  148. package/templates/qoder/scripts/{common → foundation/utils}/platform_guard.py +1 -1
  149. package/templates/qoder/scripts/orchestration/__init__.py +0 -0
  150. package/templates/qoder/scripts/orchestration/wlkj.py +185 -0
  151. package/templates/qoder/scripts/protocol/__init__.py +0 -0
  152. package/templates/qoder/scripts/protocol/browser/README.md +207 -0
  153. package/templates/qoder/scripts/protocol/browser/SKILL.md +265 -0
  154. package/templates/qoder/scripts/protocol/browser/config.env +9 -0
  155. package/templates/qoder/scripts/protocol/browser/references/cdp-api.md +110 -0
  156. package/templates/qoder/scripts/protocol/browser/references/migration-2.5.3.md +72 -0
  157. package/templates/qoder/scripts/protocol/browser/references/site-patterns/.gitkeep +0 -0
  158. package/templates/qoder/scripts/protocol/browser/scripts/browser-discovery.mjs +138 -0
  159. package/templates/qoder/scripts/protocol/browser/scripts/cdp-proxy.mjs +672 -0
  160. package/templates/qoder/scripts/protocol/browser/scripts/check-deps.mjs +206 -0
  161. package/templates/qoder/scripts/protocol/browser/scripts/find-url.mjs +253 -0
  162. package/templates/qoder/scripts/protocol/browser/scripts/match-site.mjs +46 -0
  163. package/templates/qoder/scripts/protocol/browser/templates/config.env.template +9 -0
  164. package/templates/qoder/scripts/protocol/mcp/__init__.py +11 -0
  165. package/templates/qoder/scripts/protocol/mcp/kg_mcp_server.py +478 -0
  166. package/templates/qoder/scripts/{mcp → protocol/mcp}/lanhu_stdio_wrapper.py +11 -5
  167. package/templates/qoder/scripts/{mcp → protocol/mcp}/mcp_doctor.py +47 -14
  168. package/templates/qoder/scripts/protocol/mcp/mcp_launcher.py +600 -0
  169. package/templates/qoder/scripts/{mcp → protocol/mcp}/mysql_mcp_server.py +181 -67
  170. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +1920 -0
  171. package/templates/qoder/scripts/protocol/transports/__init__.py +56 -0
  172. package/templates/qoder/scripts/protocol/transports/base.py +87 -0
  173. package/templates/qoder/scripts/protocol/transports/cli.py +132 -0
  174. package/templates/qoder/scripts/protocol/transports/http.py +141 -0
  175. package/templates/qoder/scripts/protocol/transports/stdio.py +293 -0
  176. package/templates/qoder/scripts/run_weekly_update.bat +27 -18
  177. package/templates/qoder/scripts/run_weekly_update.sh +22 -13
  178. package/templates/qoder/scripts/validation/__init__.py +0 -0
  179. package/templates/qoder/scripts/validation/eval/__init__.py +0 -0
  180. package/templates/qoder/scripts/validation/eval/perf-report-2026-06-24.md +139 -0
  181. package/templates/qoder/scripts/validation/eval/qwork_harness.py +617 -0
  182. package/templates/qoder/scripts/validation/eval/report-commands.md +220 -0
  183. package/templates/qoder/scripts/validation/eval/transcript_timing.py +386 -0
  184. package/templates/qoder/scripts/validation/metrics/__init__.py +0 -0
  185. package/templates/qoder/scripts/{report → validation/metrics}/eval_prd.py +17 -10
  186. package/templates/qoder/scripts/validation/metrics/usability_score.py +750 -0
  187. package/templates/qoder/scripts/validation/test/__init__.py +11 -0
  188. package/templates/qoder/scripts/validation/test/assertion_gen.py +551 -0
  189. package/templates/qoder/scripts/{test → validation/test}/autotest.py +64 -4
  190. package/templates/qoder/scripts/{common → validation/test}/autotest_auth.py +1 -1
  191. package/templates/qoder/scripts/{test → validation/test}/autotest_batch.py +16 -3
  192. package/templates/qoder/scripts/{test → validation/test}/autotest_data.py +17 -12
  193. package/templates/qoder/scripts/validation/test/autotest_opencli.py +646 -0
  194. package/templates/qoder/scripts/{test → validation/test}/autotest_run.py +17 -3
  195. package/templates/qoder/scripts/validation/test/autotest_webaccess.py +571 -0
  196. package/templates/qoder/scripts/{test → validation/test}/benchmark.py +12 -6
  197. package/templates/qoder/scripts/{test → validation/test}/kg_auto_login.py +8 -2
  198. package/templates/qoder/scripts/{test → validation/test}/kg_test_runner.py +7 -2
  199. package/templates/qoder/scripts/{test → validation/test}/page_probe.py +8 -3
  200. package/templates/qoder/scripts/validation/test/smoke_all_commands.py +170 -0
  201. package/templates/qoder/settings.json +30 -0
  202. package/templates/qoder/skills/design-import/SKILL.md +22 -13
  203. package/templates/qoder/skills/design-review/SKILL.md +19 -10
  204. package/templates/qoder/skills/prd-generator/SKILL.md +22 -18
  205. package/templates/qoder/skills/prd-review/SKILL.md +6 -4
  206. package/templates/qoder/skills/prototype-generator/SKILL.md +63 -14
  207. package/templates/qoder/skills/spec-coder/SKILL.md +22 -13
  208. package/templates/qoder/skills/spec-generator/SKILL.md +22 -10
  209. package/templates/qoder/skills/test-generator/SKILL.md +7 -5
  210. package/templates/qoder/skills/wl-code/SKILL.md +23 -11
  211. package/templates/qoder/skills/wl-commit/SKILL.md +9 -8
  212. package/templates/qoder/skills/wl-design/SKILL.md +5 -3
  213. package/templates/qoder/skills/wl-init/SKILL.md +6 -6
  214. package/templates/qoder/skills/wl-insight/SKILL.md +23 -10
  215. package/templates/qoder/skills/wl-prd-full/SKILL.md +57 -6
  216. package/templates/qoder/skills/wl-prd-quick/SKILL.md +3 -3
  217. package/templates/qoder/skills/wl-prd-review/SKILL.md +16 -4
  218. package/templates/qoder/skills/wl-report/SKILL.md +25 -23
  219. package/templates/qoder/skills/wl-search/SKILL.md +149 -78
  220. package/templates/qoder/skills/wl-spec/SKILL.md +7 -5
  221. package/templates/qoder/skills/wl-status/SKILL.md +48 -16
  222. package/templates/qoder/skills/wl-task/SKILL.md +92 -10
  223. package/templates/qoder/skills/wl-test/SKILL.md +75 -29
  224. package/templates/qoder/templates/prd-full-template.md +7 -0
  225. package/templates/root/AGENTS.md +275 -236
  226. package/templates/root/requirements.txt +3 -0
  227. package/templates/root//344/275/277/347/224/250/350/257/264/346/230/216.md +3 -3
  228. package/templates/root//346/226/260/346/211/213/346/214/207/345/215/227.md +2 -2
  229. package/templates/.qoder/.runtime/ctx-cache-5660152f1d6dd819.md +0 -23
  230. package/templates/.qoder/.runtime/ctx-cache-afdce0dac06b25b0.md +0 -23
  231. package/templates/.qoder/.runtime/search-cache-eae7644e7b122f35.txt +0 -1
  232. package/templates/.qoder/learning/eval-history.jsonl +0 -28
  233. package/templates/data/index/wiki-index.json +0 -8
  234. package/templates/qoder/nul +0 -4
  235. package/templates/qoder/scripts/kg/extract.py +0 -398
  236. package/templates/qoder/scripts/kg/kg_semantic.py +0 -156
  237. package/templates/qoder/scripts/mcp/kg_mcp_server.py +0 -606
  238. package/templates/qoder/scripts/mcp/mcp_launcher.py +0 -442
  239. package/templates/qoder/scripts/mcp/zentao_mcp_server.py +0 -384
  240. package/templates/qoder/scripts/task/__init__.py +0 -11
  241. package/templates/qoder/scripts/test/__init__.py +0 -11
  242. package/templates/qoder/scripts/wlkj.py +0 -116
  243. /package/templates/qoder/scripts/{common → deployment}/__init__.py +0 -0
  244. /package/templates/qoder/scripts/{common → domain/kg/graph}/graph_traverse.py +0 -0
  245. /package/templates/qoder/scripts/{common → domain/kg/server}/repowiki.py +0 -0
  246. /package/templates/qoder/scripts/{common → foundation/io}/atomicio.py +0 -0
  247. /package/templates/qoder/scripts/{test → validation/test}/secure-ls.js +0 -0
@@ -1,161 +1,162 @@
1
- #!/usr/bin/env python3
2
- # -*- coding: utf-8 -*-
3
- """task_query.py - task 查询层 (v3.0 f6 从 task.py 拆出)"""
4
- # v3.0 路径自举
5
- import os as _o, sys as _s, argparse
6
- from pathlib import Path
7
- from datetime import datetime
8
- _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'common')
9
- if _cp not in _s.path: _s.path.insert(0, _cp)
10
- from bootstrap import setup; setup()
11
-
12
- import os, sys, json, shutil
13
- from datetime import datetime
14
- from pathlib import Path
15
- from common.paths import (
16
- DIR_TASKS, DIR_ARCHIVE, FILE_TASK_JSON,
17
- get_repo_root, get_developer, get_tasks_dir,
18
- )
19
- from common.active_task import (
20
- clear_active_task, resolve_active_task, resolve_context_key, set_active_task,
21
- )
22
- from common.task_utils import (
23
- resolve_task_dir, run_task_hooks, load_task_json, write_task_json,
24
- modify_task_json, assert_can_modify_task,
25
- )
26
- from common.atomicio import atomic_write_json, safe_read_json, atomic_write_text
27
-
28
-
29
- def cmd_list(args: argparse.Namespace) -> int:
30
- """列出活跃任务。支持 --mine / --status / --ready / --blocked 过滤。"""
31
- repo_root = get_repo_root()
32
- tasks_dir = get_tasks_dir(repo_root)
33
- developer = get_developer(repo_root)
34
- active = resolve_active_task(repo_root)
35
-
36
- filter_mine = args.mine
37
- filter_status = args.status
38
- filter_ready = getattr(args, "ready", False)
39
- filter_blocked = getattr(args, "blocked", False)
40
-
41
- if not tasks_dir.is_dir():
42
- print("No tasks directory found")
43
- return 0
44
-
45
- # 预加载所有任务 (用于 --ready/--blocked 判断依赖是否完成)
46
- all_tasks = {}
47
- for d in sorted(tasks_dir.iterdir()):
48
- if d.is_dir():
49
- data = load_task_json(d)
50
- if data:
51
- all_tasks[d.name] = data
52
-
53
- def is_dep_completed(dep_name: str) -> bool:
54
- dep = all_tasks.get(dep_name)
55
- return bool(dep and dep.get("status") == "completed")
56
-
57
- tasks = []
58
- for name, task_data in all_tasks.items():
59
- d = tasks_dir / name
60
-
61
- # 过滤: --mine
62
- if filter_mine and developer not in (
63
- task_data.get("assignee"), task_data.get("creator")
64
- ):
65
- continue
66
- if filter_status and task_data.get("status") != filter_status:
67
- continue
68
-
69
- # --ready: 未完成 且 所有 blocked_by 已完成
70
- if filter_ready:
71
- if task_data.get("status") == "completed":
72
- continue
73
- blocked_by = task_data.get("blocked_by") or []
74
- if any(not is_dep_completed(dep) for dep in blocked_by):
75
- continue
76
-
77
- # --blocked: 有未完成的 blocked_by
78
- if filter_blocked:
79
- blocked_by = task_data.get("blocked_by") or []
80
- open_blocks = [dep for dep in blocked_by if not is_dep_completed(dep)]
81
- if not open_blocks:
82
- continue
83
-
84
- tasks.append((name, task_data))
85
-
86
- if not tasks:
87
- print("No tasks found" + (
88
- " (no tasks ready to start)" if filter_ready else
89
- " (no blocked tasks)" if filter_blocked else ""
90
- ))
91
- return 0
92
-
93
- print(f"Tasks ({len(tasks)}):")
94
- for name, data in tasks:
95
- is_current = active.task_path and name in active.task_path
96
- marker = " *" if is_current else " "
97
- assignee = data.get("assignee", "?")
98
- status = data.get("status", "?")
99
- priority = data.get("priority", "?")
100
- title = data.get("title", name)
101
- extras = []
102
- due = data.get("due_date")
103
- if due:
104
- extras.append(f"due:{due}")
105
- blocked_by = data.get("blocked_by") or []
106
- open_blocks = [dep for dep in blocked_by if not is_dep_completed(dep)]
107
- if open_blocks:
108
- extras.append(f"blocked:{','.join(open_blocks)}")
109
- extra_str = f" [{', '.join(extras)}]" if extras else ""
110
- print(f"{marker} [{priority}] [{status}] {name} ({assignee}) - {title}{extra_str}")
111
-
112
- return 0
113
-
114
-
115
- # =============================================================================
116
- # 命令: show
117
- # =============================================================================
118
-
119
- def cmd_show(args: argparse.Namespace) -> int:
120
- """显示任务详情。"""
121
- repo_root = get_repo_root()
122
- full_path = resolve_task_dir(args.dir, repo_root)
123
-
124
- if not full_path.is_dir():
125
- print(f"Error: Task not found: {args.dir}", file=sys.stderr)
126
- return 1
127
-
128
- task_data = load_task_json(full_path)
129
- if not task_data:
130
- print(f"Error: Missing task.json in {full_path.name}", file=sys.stderr)
131
- return 1
132
-
133
- print(f"Task: {full_path.name}")
134
- for key in ("title", "status", "priority", "rice", "assignee", "creator",
135
- "created_at", "updated_at", "parent", "tags",
136
- "due_date", "start_date", "estimate_hours"):
137
- val = task_data.get(key)
138
- if val not in (None, [], ""):
139
- print(f" {key}: {val}")
140
- children = task_data.get("children") or []
141
- if children:
142
- print(f" children: {', '.join(children)}")
143
- blocked_by = task_data.get("blocked_by") or []
144
- if blocked_by:
145
- print(f" blocked_by: {', '.join(blocked_by)}")
146
- blocks = task_data.get("blocks") or []
147
- if blocks:
148
- print(f" blocks: {', '.join(blocks)}")
149
- stage_ts = task_data.get("stage_ts") or {}
150
- if any(stage_ts.values()):
151
- print(f" stage_ts: {stage_ts}")
152
- prd_file = full_path / "prd.md"
153
- if prd_file.is_file():
154
- print(f" prd: workspace/tasks/{full_path.name}/prd.md")
155
- return 0
156
-
157
-
158
- # =============================================================================
159
- # 命令: add-subtask / remove-subtask
160
- # =============================================================================
161
-
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """task_query.py - task 查询层 (v3.0 f6 从 task.py 拆出)"""
4
+ # v3.0 路径自举
5
+ import os as _o, sys as _s, argparse
6
+ from pathlib import Path
7
+ from datetime import datetime
8
+ _cp = _o.path.join(_o.path.dirname(_o.path.dirname(_o.path.abspath(__file__))), 'foundation')
9
+ if _cp not in _s.path: _s.path.insert(0, _cp)
10
+ from bootstrap import setup; setup()
11
+ from foundation.core.paths import get_repo_root
12
+
13
+ import os, sys, json, shutil
14
+ from datetime import datetime
15
+ from pathlib import Path
16
+ from foundation.core.paths import (
17
+ DIR_TASKS, DIR_ARCHIVE, FILE_TASK_JSON,
18
+ get_repo_root, get_developer, get_tasks_dir,
19
+ )
20
+ from foundation.integrations.active_task import (
21
+ clear_active_task, resolve_active_task, resolve_context_key, set_active_task,
22
+ )
23
+ from foundation.data.task_utils import (
24
+ resolve_task_dir, run_task_hooks, load_task_json, write_task_json,
25
+ modify_task_json, assert_can_modify_task,
26
+ )
27
+ from foundation.io.atomicio import atomic_write_json, safe_read_json, atomic_write_text
28
+
29
+
30
+ def cmd_list(args: argparse.Namespace) -> int:
31
+ """列出活跃任务。支持 --mine / --status / --ready / --blocked 过滤。"""
32
+ repo_root = get_repo_root()
33
+ tasks_dir = get_tasks_dir(repo_root)
34
+ developer = get_developer(repo_root)
35
+ active = resolve_active_task(repo_root)
36
+
37
+ filter_mine = args.mine
38
+ filter_status = args.status
39
+ filter_ready = getattr(args, "ready", False)
40
+ filter_blocked = getattr(args, "blocked", False)
41
+
42
+ if not tasks_dir.is_dir():
43
+ print("No tasks directory found")
44
+ return 0
45
+
46
+ # 预加载所有任务 (用于 --ready/--blocked 判断依赖是否完成)
47
+ all_tasks = {}
48
+ for d in sorted(tasks_dir.iterdir()):
49
+ if d.is_dir():
50
+ data = load_task_json(d)
51
+ if data:
52
+ all_tasks[d.name] = data
53
+
54
+ def is_dep_completed(dep_name: str) -> bool:
55
+ dep = all_tasks.get(dep_name)
56
+ return bool(dep and dep.get("status") == "completed")
57
+
58
+ tasks = []
59
+ for name, task_data in all_tasks.items():
60
+ d = tasks_dir / name
61
+
62
+ # 过滤: --mine
63
+ if filter_mine and developer not in (
64
+ task_data.get("assignee"), task_data.get("creator")
65
+ ):
66
+ continue
67
+ if filter_status and task_data.get("status") != filter_status:
68
+ continue
69
+
70
+ # --ready: 未完成 且 所有 blocked_by 已完成
71
+ if filter_ready:
72
+ if task_data.get("status") == "completed":
73
+ continue
74
+ blocked_by = task_data.get("blocked_by") or []
75
+ if any(not is_dep_completed(dep) for dep in blocked_by):
76
+ continue
77
+
78
+ # --blocked: 有未完成的 blocked_by
79
+ if filter_blocked:
80
+ blocked_by = task_data.get("blocked_by") or []
81
+ open_blocks = [dep for dep in blocked_by if not is_dep_completed(dep)]
82
+ if not open_blocks:
83
+ continue
84
+
85
+ tasks.append((name, task_data))
86
+
87
+ if not tasks:
88
+ print("No tasks found" + (
89
+ " (no tasks ready to start)" if filter_ready else
90
+ " (no blocked tasks)" if filter_blocked else ""
91
+ ))
92
+ return 0
93
+
94
+ print(f"Tasks ({len(tasks)}):")
95
+ for name, data in tasks:
96
+ is_current = active.task_path and name in active.task_path
97
+ marker = " *" if is_current else " "
98
+ assignee = data.get("assignee", "?")
99
+ status = data.get("status", "?")
100
+ priority = data.get("priority", "?")
101
+ title = data.get("title", name)
102
+ extras = []
103
+ due = data.get("due_date")
104
+ if due:
105
+ extras.append(f"due:{due}")
106
+ blocked_by = data.get("blocked_by") or []
107
+ open_blocks = [dep for dep in blocked_by if not is_dep_completed(dep)]
108
+ if open_blocks:
109
+ extras.append(f"blocked:{','.join(open_blocks)}")
110
+ extra_str = f" [{', '.join(extras)}]" if extras else ""
111
+ print(f"{marker} [{priority}] [{status}] {name} ({assignee}) - {title}{extra_str}")
112
+
113
+ return 0
114
+
115
+
116
+ # =============================================================================
117
+ # 命令: show
118
+ # =============================================================================
119
+
120
+ def cmd_show(args: argparse.Namespace) -> int:
121
+ """显示任务详情。"""
122
+ repo_root = get_repo_root()
123
+ full_path = resolve_task_dir(args.dir, repo_root)
124
+
125
+ if not full_path.is_dir():
126
+ print(f"Error: Task not found: {args.dir}", file=sys.stderr)
127
+ return 1
128
+
129
+ task_data = load_task_json(full_path)
130
+ if not task_data:
131
+ print(f"Error: Missing task.json in {full_path.name}", file=sys.stderr)
132
+ return 1
133
+
134
+ print(f"Task: {full_path.name}")
135
+ for key in ("title", "status", "priority", "rice", "assignee", "creator",
136
+ "created_at", "updated_at", "parent", "tags",
137
+ "due_date", "start_date", "estimate_hours"):
138
+ val = task_data.get(key)
139
+ if val not in (None, [], ""):
140
+ print(f" {key}: {val}")
141
+ children = task_data.get("children") or []
142
+ if children:
143
+ print(f" children: {', '.join(children)}")
144
+ blocked_by = task_data.get("blocked_by") or []
145
+ if blocked_by:
146
+ print(f" blocked_by: {', '.join(blocked_by)}")
147
+ blocks = task_data.get("blocks") or []
148
+ if blocks:
149
+ print(f" blocks: {', '.join(blocks)}")
150
+ stage_ts = task_data.get("stage_ts") or {}
151
+ if any(stage_ts.values()):
152
+ print(f" stage_ts: {stage_ts}")
153
+ prd_file = full_path / "prd.md"
154
+ if prd_file.is_file():
155
+ print(f" prd: workspace/tasks/{full_path.name}/prd.md")
156
+ return 0
157
+
158
+
159
+ # =============================================================================
160
+ # 命令: add-subtask / remove-subtask
161
+ # =============================================================================
162
+