@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,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
+