@hupan56/wlkj 3.1.31 → 3.2.0

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 (70) hide show
  1. package/package.json +1 -1
  2. package/templates/qoder/agents/insight-planning.md +67 -67
  3. package/templates/qoder/agents/prd-reference.md +47 -47
  4. package/templates/qoder/commands/optional/wl-insight.md +276 -276
  5. package/templates/qoder/commands/optional/wl-spec.md +10 -2
  6. package/templates/qoder/commands/wl-code.md +63 -4
  7. package/templates/qoder/commands/wl-design.md +1 -1
  8. package/templates/qoder/commands/wl-prd.md +87 -13
  9. package/templates/qoder/commands/wl-req.md +10 -3
  10. package/templates/qoder/commands/wl-task.md +613 -613
  11. package/templates/qoder/commands/wl-test.md +2 -2
  12. package/templates/qoder/contracts/CHANGELOG.md +418 -0
  13. package/templates/qoder/contracts/README.md +180 -0
  14. package/templates/qoder/contracts/code.md +82 -0
  15. package/templates/qoder/contracts/commit.md +86 -0
  16. package/templates/qoder/contracts/contract-header.md +76 -0
  17. package/templates/qoder/contracts/design.md +106 -0
  18. package/templates/qoder/contracts/fallback.md +126 -0
  19. package/templates/qoder/contracts/isolation.md +119 -0
  20. package/templates/qoder/contracts/prd.md +118 -0
  21. package/templates/qoder/contracts/schemas/design-spec.schema.json +46 -0
  22. package/templates/qoder/contracts/schemas/prd.schema.json +36 -0
  23. package/templates/qoder/contracts/schemas/test-cases.schema.json +40 -0
  24. package/templates/qoder/contracts/spec.md +112 -0
  25. package/templates/qoder/contracts/task.md +125 -0
  26. package/templates/qoder/contracts/test.md +112 -0
  27. package/templates/qoder/hooks/post-tool-use.py +20 -0
  28. package/templates/qoder/hooks/stop-eval.py +47 -0
  29. package/templates/qoder/rules/wl-pipeline.md +37 -0
  30. package/templates/qoder/scripts/deployment/setup/install_qoderwork.py +11 -0
  31. package/templates/qoder/scripts/deployment/setup/setup.py +70 -0
  32. package/templates/qoder/scripts/deployment/setup/wlkj_shim.py +104 -0
  33. package/templates/qoder/scripts/domain/deployment/deploy_to_test.py +298 -0
  34. package/templates/qoder/scripts/domain/kg/build/kg_build.py +241 -22
  35. package/templates/qoder/scripts/domain/kg/build/kg_incremental.py +108 -3
  36. package/templates/qoder/scripts/domain/kg/build/kg_signatures.py +169 -0
  37. package/templates/qoder/scripts/domain/kg/extract/ts_extract.py +111 -0
  38. package/templates/qoder/scripts/domain/kg/storage/kg_duckdb.py +43 -0
  39. package/templates/qoder/scripts/domain/requirement/req.py +134 -28
  40. package/templates/qoder/scripts/domain/task/zentao_panel.py +688 -53
  41. package/templates/qoder/scripts/foundation/core/paths.py +102 -0
  42. package/templates/qoder/scripts/protocol/mcp/zentao_mcp_server.py +23 -10
  43. package/templates/qoder/scripts/validation/eval/qwork_harness.py +1 -1
  44. package/templates/qoder/scripts/validation/eval/report-commands.md +2 -2
  45. package/templates/qoder/settings.json +27 -9
  46. package/templates/qoder/skills/design-import/SKILL.md +3 -3
  47. package/templates/qoder/skills/design-review/SKILL.md +1 -1
  48. package/templates/qoder/skills/prd-generator/SKILL.md +4 -4
  49. package/templates/qoder/skills/prd-review/SKILL.md +1 -1
  50. package/templates/qoder/skills/prototype-generator/SKILL.md +3 -3
  51. package/templates/qoder/skills/spec-coder/SKILL.md +1 -1
  52. package/templates/qoder/skills/spec-generator/SKILL.md +80 -23
  53. package/templates/qoder/skills/test-generator/SKILL.md +1 -1
  54. package/templates/qoder/skills/wl-code/SKILL.md +13 -1
  55. package/templates/qoder/skills/wl-commit/SKILL.md +1 -1
  56. package/templates/qoder/skills/wl-design/SKILL.md +6 -6
  57. package/templates/qoder/skills/wl-init/SKILL.md +2 -2
  58. package/templates/qoder/skills/wl-insight/SKILL.md +5 -5
  59. package/templates/qoder/skills/wl-prd/SKILL.md +60 -0
  60. package/templates/qoder/skills/wl-report/SKILL.md +2 -2
  61. package/templates/qoder/skills/wl-search/SKILL.md +1 -1
  62. package/templates/qoder/skills/wl-spec/SKILL.md +2 -2
  63. package/templates/qoder/skills/wl-status/SKILL.md +2 -2
  64. package/templates/qoder/skills/wl-task/SKILL.md +3 -3
  65. package/templates/qoder/skills/wl-test/SKILL.md +2 -2
  66. package/templates/qoder/templates/spec-template.md +124 -0
  67. package/templates/root/AGENTS.md +32 -4
  68. package/templates/qoder/skills/wl-prd-full/SKILL.md +0 -121
  69. package/templates/qoder/skills/wl-prd-quick/SKILL.md +0 -50
  70. package/templates/qoder/skills/wl-prd-review/SKILL.md +0 -47
@@ -640,6 +640,108 @@ def get_module_spec_dir(module: Optional[str] = None) -> Path:
640
640
  return spec_dir
641
641
 
642
642
 
643
+ # ── spec 检测 (v3.x wl-code 门禁依据) ──────────────────────────
644
+ # 设计原则: 纯读函数, 不写文件不改状态, 任何调用都安全。
645
+ # spec 只存 2 处: workspace/specs/REQ-{ID}-*.spec.md (全局) + 当前任务目录 spec.md。
646
+ # status 从契约头读 (@contract spec v1 / status: draft|confirmed), 无头视同 draft。
647
+ # ─────────────────────────────────────────────────────────────
648
+
649
+ def get_spec_status(spec_path) -> str:
650
+ """读 spec 文件契约头的 status 字段。
651
+
652
+ 返回: 'draft' | 'confirmed' | None(文件不存在/无法解析)
653
+ - 无 status 字段 或 无契约头 → 视同 'draft' (wl-code 走确认环节, 不直接写码)
654
+ - 文件不存在 → None (wl-code 视为无 spec, 触发生成)
655
+ """
656
+ import re
657
+ try:
658
+ text = open(spec_path, encoding="utf-8").read()
659
+ except (OSError, IOError, TypeError):
660
+ return None
661
+ # 直接正则取 @contract spec 头里的 status (不依赖 contract.py, 避免循环 import)
662
+ m = re.search(r"<!--\s*@contract\s+spec(?:\s+v\d+)?\s*(.*?)-->", text, re.S)
663
+ if not m:
664
+ return "draft" # 无契约头 → 视同 draft (安全: 走确认环节)
665
+ body = m.group(1)
666
+ sm = re.search(r"^\s*status\s*:\s*(\S+)\s*$", body, re.M)
667
+ if not sm:
668
+ return "draft" # 有头但无 status 字段 → draft
669
+ val = sm.group(1).strip().lower()
670
+ return val if val in ("draft", "confirmed") else "draft"
671
+
672
+
673
+ def find_spec(req_id=None, developer_name=None, repo_root=None) -> list:
674
+ """按 REQ-ID 或当前任务找 spec 文件 (wl-code gate 的核心检测)。
675
+
676
+ 查 2 处 (spec 不存时间桶):
677
+ A. workspace/specs/REQ-{ID}-*.spec.md (全局 specs, glob 前缀匹配)
678
+ B. 当前任务目录的 spec.md (无 req_id 时, 读 .current-task)
679
+
680
+ Args:
681
+ req_id: REQ-YYYY-NNN 形式。传了就只查 A; 不传则查 B (当前任务)。
682
+ Returns:
683
+ [{path, status, source-req}, ...] 按优先级 (confirmed 优先)
684
+ status: 'draft' | 'confirmed' (从契约头读, 无头=draft)
685
+ """
686
+ import re
687
+ if repo_root is None:
688
+ repo_root = PROJECT_ROOT
689
+ results = []
690
+
691
+ def _inspect(p):
692
+ """读一个 spec 文件, 返回它的元信息 dict 或 None。"""
693
+ try:
694
+ text = open(p, encoding="utf-8").read()
695
+ except (OSError, IOError):
696
+ return None
697
+ m = re.search(r"<!--\s*@contract\s+spec(?:\s+v\d+)?\s*(.*?)-->", text, re.S)
698
+ body = m.group(1) if m else ""
699
+ status_m = re.search(r"^\s*status\s*:\s*(\S+)\s*$", body, re.M)
700
+ status = status_m.group(1).strip().lower() if status_m else "draft"
701
+ status = status if status in ("draft", "confirmed") else "draft"
702
+ sreq_m = re.search(r"^\s*source-req\s*:\s*(\S+)\s*$", body, re.M)
703
+ source_req = sreq_m.group(1).strip() if sreq_m else None
704
+ return {"path": str(p), "status": status, "source-req": source_req}
705
+
706
+ # A. 时间桶 REQ-ID 容器 (spec-generator 主写入位置, 优先查)
707
+ # 复用 find_req_dirs 跨桶找到容器, 再在容器里找 *.spec.md
708
+ if req_id:
709
+ clean_m = re.match(r"(REQ-\d{4}-\d{3,})", str(req_id))
710
+ clean = clean_m.group(1) if clean_m else str(req_id)
711
+ # A1. 时间桶容器 (members/{dev}/{drafts|outputs}/{桶}/{REQ-ID}/)
712
+ for hit in find_req_dirs(clean, developer_name=developer_name, repo_root=repo_root):
713
+ for f in sorted(Path(hit["path"]).glob("*.spec.md")):
714
+ info = _inspect(f)
715
+ if info:
716
+ results.append(info)
717
+ # A2. 兜底: 全局 .qoder/workspace/specs/ (老 spec 或不在桶里的)
718
+ specs_root = QODER_DIR / "workspace" / "specs"
719
+ if specs_root.is_dir():
720
+ for f in sorted(specs_root.glob("%s-*.spec.md" % clean)):
721
+ info = _inspect(f)
722
+ if info:
723
+ results.append(info)
724
+ for f in sorted(specs_root.glob("*.spec.md")):
725
+ info = _inspect(f)
726
+ if info and info not in results and info.get("source-req") == clean:
727
+ results.append(info)
728
+
729
+ # B. 当前任务目录的 spec.md (无 req_id 时主路径)
730
+ if not results:
731
+ ct = get_current_task()
732
+ if ct:
733
+ # ct 是相对 repo_root 的路径(如 workspace/tasks/xx), 但实际在 .qoder/ 下
734
+ task_spec = QODER_DIR / ct / "spec.md"
735
+ if task_spec.is_file():
736
+ info = _inspect(task_spec)
737
+ if info:
738
+ results.append(info)
739
+
740
+ # 排序: confirmed 优先 (让 wl-code gate 先看到可放行的)
741
+ results.sort(key=lambda x: 0 if x["status"] == "confirmed" else 1)
742
+ return results
743
+
744
+
643
745
  def get_task_dir(slug: str) -> Path:
644
746
  """Get task directory by slug."""
645
747
  from datetime import datetime
@@ -691,13 +691,23 @@ class ZentaoMCPServer(BaseMCPServer):
691
691
  pid = args.get('product_id', 1)
692
692
  path = '/products/%s/builds' % pid
693
693
  scope = '产品 %s' % pid
694
- return self._safe_get(
695
- path, None,
696
- '%s 的版本 (%%d ):' % scope,
697
- lambda b: ' [%s] %s (date=%s)' % (
698
- b.get('id'), str(b.get('name', ''))[:20], b.get('date', '')),
699
- empty_msg='%s 暂无版本(build)。' % scope,
700
- )
694
+ r = _api('GET', path, None)
695
+ # 禅道部分维度可能不支持 builds 端点(404 not found) → 给明确引导而非裸"查询失败"
696
+ if r.status_code == 404 and not (args.get('project_id') or args.get('execution_id') or args.get('product_id')):
697
+ return ('⚠️ 查版本需要指定维度(禅道无"全量版本"端点)。\n'
698
+ ' 常用: list_builds(project_id=N) 看项目级按周版本\n'
699
+ ' 或: list_builds(product_id=N) / list_builds(execution_id=N)')
700
+ if r.status_code not in (200, 201):
701
+ return '查询失败: %s (该维度可能无版本)' % r.status_code
702
+ data = r.json()
703
+ items = data.get('builds') if isinstance(data, dict) else None
704
+ if not isinstance(items, list) or not items:
705
+ return '%s 暂无版本(build)。' % scope
706
+ lines = ['%s 的版本 (%d 个):' % (scope, len(items))]
707
+ for b in items:
708
+ lines.append(' [%s] %s (date=%s)' % (
709
+ b.get('id'), str(b.get('name', ''))[:20], b.get('date', '')))
710
+ return '\n'.join(lines)
701
711
 
702
712
  @tool("get_build",
703
713
  "查版本/构建详情。例: get_build(build_id=8)",
@@ -1288,7 +1298,9 @@ class ZentaoMCPServer(BaseMCPServer):
1288
1298
  '可能权限不足或字段缺失')
1289
1299
 
1290
1300
  @tool("update_task",
1291
- "修改任务(名称/指派/工时/截止等)。权限不足返回提示不报错。例: update_task(task_id=301, name='导出PDF接口(改)', left=3)",
1301
+ "修改任务(名称/指派/工时/截止/描述等)。权限不足返回提示不报错。"
1302
+ "★spec 回填: 确认后的 spec 摘要可通过 desc 写入任务描述, 让禅道里能看到开发规格要点。"
1303
+ "例: update_task(task_id=301, name='导出PDF接口(改)', left=3, desc='spec摘要...')",
1292
1304
  {"type": "object", "properties": {
1293
1305
  "task_id": {"type": "integer", "description": "任务ID"},
1294
1306
  "name": {"type": "string", "description": "新名称(可选)"},
@@ -1296,6 +1308,7 @@ class ZentaoMCPServer(BaseMCPServer):
1296
1308
  "estimate": {"type": "number", "description": "预计工时(可选)"},
1297
1309
  "left": {"type": "number", "description": "剩余工时(可选)"},
1298
1310
  "deadline": {"type": "string", "description": "截止日期(可选)"},
1311
+ "desc": {"type": "string", "description": "任务描述(可选)。spec 回填用: 写 spec 摘要(接口清单/关键表/异常/AC映射) + 本地 spec 路径"},
1299
1312
  }, "required": ["task_id"]})
1300
1313
  def _t_update_task(self, args):
1301
1314
  tid = args.get('task_id', 0)
@@ -1303,11 +1316,11 @@ class ZentaoMCPServer(BaseMCPServer):
1303
1316
  if guard:
1304
1317
  return guard
1305
1318
  payload = {}
1306
- for k in ('name', 'assignedTo', 'estimate', 'left', 'deadline'):
1319
+ for k in ('name', 'assignedTo', 'estimate', 'left', 'deadline', 'desc'):
1307
1320
  if args.get(k) is not None:
1308
1321
  payload[k] = args[k]
1309
1322
  if not payload:
1310
- return '⚠️ 没有要更新的字段(可选: name/assignedTo/estimate/left/deadline)。'
1323
+ return '⚠️ 没有要更新的字段(可选: name/assignedTo/estimate/left/deadline/desc)。'
1311
1324
  return self._safe_write(
1312
1325
  'PUT', '/tasks/%s' % tid, payload,
1313
1326
  '✅ 任务 #%s 已更新' % tid,
@@ -15,7 +15,7 @@ qwork_harness.py — QoderWork 命令自动化测试框架 (P2)
15
15
  python qwork_harness.py "/wl-search 考勤"
16
16
  python qwork_harness.py "/wl-search 考勤" --auto-answer=0 # 选第1个
17
17
  python qwork_harness.py "/wl-search 考勤" --no-answer # 只跑不等答
18
- python qwork_harness.py "/wl-prd-full 用户管理" --auto-answer=1
18
+ python qwork_harness.py "/wl-prd 用户管理" --auto-answer=1
19
19
 
20
20
  依赖: websocket-client (pip install websocket-client)
21
21
  """
@@ -143,7 +143,7 @@ AskUserQuestion 在 transcript 里的真实生命周期:
143
143
  python qwork_harness.py "/wl-search 考勤"
144
144
 
145
145
  # 强制选项序号(0-based)
146
- python qwork_harness.py "/wl-prd-full 用户管理" --auto-answer=0
146
+ python qwork_harness.py "/wl-prd 用户管理" --auto-answer=0
147
147
 
148
148
  # 只跑不代答(遇到提问就停)
149
149
  python qwork_harness.py "/wl-search 考勤" --no-answer
@@ -214,7 +214,7 @@ python qwork_harness.py "/wl-search 考勤" --json
214
214
  # 或直接 python qwork_harness.py "/wl-search 考勤" (注意 / 在 bash 下的转义)
215
215
 
216
216
  python qwork_harness.py "/wl-search 考勤"
217
- python qwork_harness.py "/wl-prd-full 用户管理" --auto-answer=0 # 强制选项序号
217
+ python qwork_harness.py "/wl-prd 用户管理" --auto-answer=0 # 强制选项序号
218
218
  python qwork_harness.py "/wl-search 考勤" --no-answer # 不代答
219
219
  python qwork_harness.py "/wl-search 考勤" --json # JSON 输出
220
220
  ```
@@ -1,15 +1,33 @@
1
1
  {
2
2
  "permissions": {
3
+ "defaultMode": "acceptEdits",
3
4
  "allow": [
4
- "Bash(*)",
5
- "Read(*)",
6
- "Write(*)",
7
- "Edit(*)",
8
- "Glob(*)",
9
- "Grep(*)",
10
- "WebFetch(*)",
11
- "WebSearch(*)",
12
- "mcp__*"
5
+ "Read",
6
+ "Write",
7
+ "Edit",
8
+ "Glob",
9
+ "Grep",
10
+ "WebFetch",
11
+ "WebSearch",
12
+ "mcp__*",
13
+ "Bash(python:*)",
14
+ "Bash(python3:*)",
15
+ "Bash(py:*)",
16
+ "Bash(git:*)",
17
+ "Bash(npm:*)",
18
+ "Bash(npx:*)",
19
+ "Bash(node:*)",
20
+ "Bash(ls:*)",
21
+ "Bash(cat:*)",
22
+ "Bash(echo:*)",
23
+ "Bash(test:*)",
24
+ "Bash(mkdir:*)",
25
+ "Bash(cp:*)",
26
+ "Bash(mv:*)",
27
+ "Bash(find:*)",
28
+ "Bash(grep:*)",
29
+ "Bash(sed:*)",
30
+ "Bash(cd:*)"
13
31
  ],
14
32
  "deny": []
15
33
  },
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: design-import
3
- description: "把设计师的 Figma/Axure 设计稿录入工作流,生成设计规范 spec.json 并存入知识图谱。Import designer's Figma/Axure design into the pipeline as a style spec. "
4
- trigger: "user invokes /wl-* command explicitly"
3
+ description: "把设计师的设计稿录入工作流,生成设计规范 spec.json 并存入知识图谱。蓝湖链接直读为主(精确提取颜色/尺寸/字体/切图),无蓝湖可截图口述降级。/wl-design 预览模式走这里。"
4
+ trigger: " /wl-design 预览模式内部调用(实现层)"
5
5
  ---
6
6
 
7
7
 
@@ -48,7 +48,7 @@ ls "$R/data/style/"*-design-spec.json 2>/dev/null # 列所有 spec
48
48
 
49
49
  ## Step 0: 确认平台
50
50
 
51
- 跟 /wl-prd-full 一样,先问:Web 管理端 / APP 移动端 / 两端都要?
51
+ 跟 /wl-prd 一样,先问:Web 管理端 / APP 移动端 / 两端都要?
52
52
  **问了就停,等设计师回答。**
53
53
 
54
54
  ## Step 1: 收集设计信息
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: design-review
3
3
  description: "评审设计交付物的完整性。Review design artifacts for completeness. "
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: " /wl-design 评审模式内部调用(实现层)"
5
5
  ---
6
6
 
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: prd-generator
3
- description: "生成 PRD + 平台匹配的原型。Generate PRD with platform-aware prototype. "
4
- trigger: "user invokes /wl-* command explicitly"
3
+ description: "/wl-prd 完整档/快速档的实现层。生成 PRD + 平台匹配的原型,带 EVA 质量门禁。"
4
+ trigger: " /wl-prd 完整/快速模式内部调用(实现层,不直接响应自然语言)"
5
5
  ---
6
6
 
7
7
 
@@ -16,8 +16,8 @@ PY=$(python --version >/dev/null 2>&1 && echo python || echo python3)
16
16
 
17
17
  # PRD Generator Skill
18
18
 
19
- > 📌 **主入口:`/wl-prd-full`(正经需求)/ `/wl-prd-quick`(小改动)命令。** 本 skill 是它们的实现层 + Quest/QoderWork 自然语言路由。
20
- > 两者功能等价,优先用 `/wl-prd-full` 或 `/wl-prd-quick`(参数提示更全、更稳定)。
19
+ > 📌 **主入口:`/wl-prd` 命令(完整档 / 快速档 / 评审 三模式)。** 本 skill 是完整/快速模式的实现层 + Quest/QoderWork 自然语言路由。
20
+ > 命令见 `.qoder/commands/wl-prd.md`(参数提示更全、更稳定)。
21
21
  > **模块契约**(输入/输出/校验):`.qoder/contracts/prd.md`
22
22
  > **第一性原理:又快又准**(快=并行+砍模式,准=语义归档+质量锁)
23
23
  > **定位:专注"已确定需求"的落地。** 探索/调研/规划/对标已移交 `/wl-insight`,
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: prd-review
3
3
  description: "评审 PRD 完整性与质量。Review PRD for completeness and quality. "
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: " /wl-prd 评审模式内部调用(实现层)"
5
5
  ---
6
6
 
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: prototype-generator
3
3
  description: "生成匹配项目 UI 风格的交互式 HTML 原型(Web 端 fywl-ui 用 Vben Admin + Ant Design Vue;APP 端 Carmg-H5 用 Vant 3)。Generate interactive HTML prototypes matching project UI style. "
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: " /wl-prd /wl-design 原型生成内部调用(实现层)"
5
5
  ---
6
6
 
7
7
 
@@ -37,7 +37,7 @@ Generate production-ready HTML prototypes that match the project's actual UI sty
37
37
 
38
38
  本 skill **只在用户明确选择"画原型"后才进入**。
39
39
 
40
- - 如果上游 `/wl-prd-full` 或 `/wl-prd` 在「批量确认」环节已决定**不画**(PRD 第 1 行
40
+ - 如果上游 `/wl-prd` 在「批量确认」环节已决定**不画**(PRD 第 1 行
41
41
  `@contract` 头标记 `prototype: none`),**立即退出本 skill**,不生成任何 HTML。
42
42
  - 如果上游没有 contract 头(独立调用本 skill),**先问用户**:
43
43
  `这个需求要画原型吗?(画 / 不画)`
@@ -50,7 +50,7 @@ Generate production-ready HTML prototypes that match the project's actual UI sty
50
50
  ---
51
51
  ## Step 0: Know the Platform
52
52
 
53
- The platform MUST already be decided (asked by /wl-prd-full Step 0).
53
+ The platform MUST already be decided (asked by /wl-prd Step 0).
54
54
  If you don't know it, STOP and ask the user (Web 管理端 / APP 移动端 / 两端都要).
55
55
 
56
56
  | Platform | Project | Template | Design Tokens |
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: spec-coder
3
3
  description: "严格按开发 Spec 实现代码。Implement code strictly following development Spec. 需用户确认(DANGEROUS)。"
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: " /wl-code 内部调用(实现层)"
5
5
  ---
6
6
 
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: spec-generator
3
3
  description: "从已确认的 PRD 自动生成开发 Spec 文档(技术规格说明)。Auto-generate development Spec documents from confirmed PRDs. "
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: " /wl-spec 内部调用(实现层)"
5
5
  ---
6
6
 
7
7
 
@@ -28,21 +28,46 @@ PY=$(python --version >/dev/null 2>&1 && echo python || echo python3)
28
28
  再 `$PY "$R/.qoder/scripts/foundation/core/paths.py" whoami`(输出开发者名;空=未初始化)。
29
29
  ⚠️ 勿用裸相对路径 `.qoder/.developer`(QoderWork 桌面端 cwd 不在仓库根,会读不到而误报未初始化)。
30
30
  - **活动任务**:当前任务(决定 spec 存到哪个 task 目录)。读法 `$PY "$R/.qoder/scripts/foundation/core/paths.py" current-task`(输出任务路径;空=无活动任务)。
31
- - 扫描 PRD 来源目录:`data/docs/prd/`(已发布)+ `workspace/members/{dev}/drafts/REQ-*.md`(草稿)
31
+ - 扫描 PRD 来源目录:`data/docs/prd/`(已发布)+ PRD 所在的 REQ-ID 容器
32
+ (`workspace/members/{dev}/{drafts|outputs}/{YYYY}/{MM}/{Ww}/{REQ-ID}/`,用 `find_req_dirs` 跨桶查找)
32
33
  找出还没有对应 Spec 的 PRD
33
34
  - 风格/字段参考:`$PY "$R/.qoder/scripts/orchestration/wlkj.py" search --field <字段名>` 查现有字段命名约定
34
35
  - 团队 Java 约定(MyBatis Plus + RESTful + BigDecimal 金额)写在本 skill 的 Step 3
35
36
 
36
- ## Step 1: 定位 PRD
37
+ ## Step 1: 定位 PRD(优先禅道 task,本地兜底)
38
+
39
+ **核心:1 禅道 task ↔ 1 spec。PRD 真源是 task 关联的 story**(本地找不到别人提的 PRD 时,从禅道 story 读)。
40
+
41
+ ### 优先级 1:从禅道 task 读(解决"别人提的 PRD 本地没有")
37
42
 
38
43
  ```bash
39
- # 列出已发布的 PRD
40
- ls data/docs/prd/REQ-*.md
41
- # 列出当前开发者的草稿 PRD
42
- ls workspace/members/{developer}/drafts/REQ-*.md
44
+ # 当前活动任务(panel / /wl-task 指向的禅道 task)
45
+ TASK=$($PY "$R/.qoder/scripts/foundation/core/paths.py" current-task) # 或直接给 task_id
46
+ ```
47
+
48
+ 走 MCP 读 task → story:
49
+ ```python
50
+ cap.mcp.call("get_task", {"task_id": 1453}) # 拿 task 详情,取 story 字段
51
+ cap.mcp.call("get_story_detail", {"story_id": 761}) # 读 story.spec 字段 = PRD 数据源
43
52
  ```
53
+ story.spec 即 PRD 正文(验收标准/字段/操作)。**本地无该 PRD 文件也能生成 spec。**
44
54
 
45
- 找出"有 PRD 但无 Spec"的需求。如果有多份,问用户先做哪个。
55
+ ### 优先级 2:本地 PRD 兜底
56
+
57
+ ```bash
58
+ # task 无 story 关联,或禅道不可达 → 扫本地
59
+ ls data/docs/prd/REQ-*.md # 已发布
60
+ $PY "$R/.qoder/scripts/foundation/core/paths.py" whoami # 取开发者
61
+ # 草稿在 REQ-ID 容器: workspace/members/{DEV}/{drafts|outputs}/{桶}/{REQ-ID}/
62
+ ```
63
+ 跨桶找某 REQ:复用 `paths.find_req_dirs(req_id, DEV)`。
64
+
65
+ ### 决定
66
+
67
+ 找出"要生成 spec 的目标"后:
68
+ - **禅道 task 来的**:spec 主标识用 `task_id`,契约头写 `zentao: task=X story=Y`,第 0 章"禅道关联"填实。
69
+ - **本地 PRD 来的**:用 REQ-ID,`zentao:` 留空(后续 panel 回填 task 时补)。
70
+ - 多份候选时问用户先做哪个。
46
71
 
47
72
  ## Step 2: 读取上下文
48
73
 
@@ -57,41 +82,73 @@ cap.mcp.call("context_pack", {"keyword": "..."}) <PRD里的模块关键词> --pl
57
82
 
58
83
  ### 同时并发补这几项(与 context_pack 无依赖,同回合并发)
59
84
 
60
- 1. **PRD 文件**(必需):需求源
61
- 2. **历史 Spec**(推荐):扫 `workspace/specs/` 看同类需求的写法,照着写
62
- 3. **真实表结构**(强烈推荐):context_pack 不含 DB schema,写 API 字段前单独查
85
+ 1. **PRD 数据源**(必需):禅道 task 来的 = Step 1 读到的 story.spec;本地来的 = PRD 文件
86
+ 2. **spec 模板**(必需):`$R/.qoder/templates/spec-template.md` —— **必须读它,照它的 6 章骨架逐节填,不自由发挥结构**
87
+ 3. **历史 Spec**(推荐):扫 PRD 同容器或历史 REQ-ID 容器看同类需求的写法,照着写
88
+ 4. **真实表结构**(强烈推荐):context_pack 不含 DB schema,写 API 字段前单独查
63
89
  - 先 `cap.mcp.call("list_envs", {})` 问环境,再 `query_schema(table='quality_case', db='fywl_ics_quality')`
64
90
  - 拿到真实列名/类型/注释(注释里常含枚举定义,如"0=小时,1=工作日")
65
91
 
66
92
  > 数据字典 `data/docs/constitution/` 如存在顺手读,不存在跳过。
67
- > 以上 PRD/历史Spec/query_schema 三项相互独立 → **同一条消息并发发**,不要逐个等。
93
+ > 以上 PRD源/模板/历史Spec/query_schema 四项相互独立 → **同一条消息并发发**,不要逐个等。
94
+
95
+ ## Step 3: 照模板分析(不自由发挥结构)
68
96
 
69
- ## Step 3: 分析并生成
97
+ **核心:读 `templates/spec-template.md` 6 章骨架,逐章节填空。** 不是从零生成结构。
70
98
 
71
- 从 PRD 提取:
72
- - 每个用户故事 → 一个或多个 API 接口
73
- - 验收标准 → 接口入参/出参/错误场景
74
- - 数据需求 → 数据库表设计
75
- - 非功能性需求 约束章节
99
+ 从 PRD 提取并填入对应章节:
100
+ - 每个用户故事 → 1 章一个或多个 API 接口
101
+ - 验收标准 → 第 1 章入参/出参 + 第 3 章异常场景 + 第 5 章测试用例
102
+ - 数据需求 → 第 2 章表设计(表名 `t_{module}_{entity}`,金额 BigDecimal)
103
+ - **第 3 章异常矩阵 ★强制**:每个操作**系统性枚举所有失败场景**(参数/业务/权限/并发/外部依赖/数据不存在/边界值),这是写代码前必须想清楚的,不可遗漏
104
+ - **第 4 章 AI 边界 ★强制**:明确划分 ✅可自动 / ⚠️必须人工确认 / 🚫禁止AI做
105
+ - **第 5 章测试用例 ★强制**:每条 PRD 验收标准 ≥1 个用例,输入/预期/断言齐全
106
+ - 第 6 章映射表:每条 PRD acceptance → 对应接口/数据/异常/用例,保证可追溯不漏
107
+
108
+ ★强制章节不适用时写"无"并附原因(例:纯查询页异常章写"无(仅查询,校验由前端处理)")。
76
109
 
77
110
  ## Step 4: 输出
78
111
 
79
- 写到 `workspace/specs/REQ-{ID}-{module}.spec.md`(或 task 目录 `workspace/tasks/{task-id}/spec.md`)
112
+ **存储位置(按来源二选一)**:
113
+
114
+ - **禅道 task 来的**(1 task ↔ 1 spec):`workspace/tasks/{task_id}/spec.md`(复用现有 task 目录,task_id 即禅道 task id)
115
+ - **本地 PRD 来的**:跟着 PRD 同容器,`workspace/members/{dev}/{drafts|outputs}/{YYYY}/{MM}/{Ww}/{REQ-ID}/REQ-{ID}-{module}.spec.md`
116
+ (复用 `paths.get_req_dir` / `find_req_dirs`,跨时间桶可查)
117
+
118
+ **契约头**(status 初始为 draft;禅道来的带 zentao 字段):
119
+ ```markdown
120
+ <!-- @contract spec v1
121
+ source-req: REQ-2025-0042
122
+ platform: web
123
+ module: policy
124
+ endpoints: [POST /api/policy/amend, GET /api/policy/amend/{id}]
125
+ status: draft
126
+ zentao: task=1453 story=761
127
+ -->
128
+ ```
129
+ > `zentao:` 字段:禅道 task 来的必须填(task+story);本地来的留空,待 panel 回填 task 时补。
130
+
131
+ > 兜底:若本地 PRD 不在时间桶容器(老 PRD 在 `data/docs/prd/`),spec 写到 `workspace/specs/REQ-{ID}-{module}.spec.md`(向后兼容)。
80
132
 
81
- 规则:
82
- - 每条 PRD 验收标准都映射到一个 Spec 测试用例
133
+ 规则(模板已固化,这里只强调重点):
134
+ - 每条 PRD 验收标准都映射到一个 Spec 测试用例(第 6 章)
83
135
  - API 路径遵循 RESTful 约定
84
136
  - 表名遵循 `t_{module}_{entity}`
85
137
  - 金额字段必须用 `BigDecimal`
86
138
  - 不写 PRD 未定义的功能
87
139
  - Entity → Mapper → Service → Controller 全栈结构
88
140
 
89
- ## Step 5: 通知
141
+ ## Step 5: 通知并提交确认
90
142
 
91
- 报告给被分配的开发者评审。
143
+ 生成后 `status: draft`。报告给被分配的开发者评审:
144
+ 1. 展示 spec 全文 + 列出关键决策点(接口设计 / 表结构 / 异常枚举 / AI 边界)
145
+ 2. 提示:可直接修改 spec 文件(路径见输出),改完告知
146
+ 3. **⚠️ status 保持 draft,不要自动改 confirmed** —— 用户在 `/wl-code` 的 spec gate 确认后才升级
147
+ 4. **不在此回填禅道** —— spec 回填禅道 task 的 `desc` 由 `/wl-code` 在用户确认后做(见 wl-code Step 1),本 skill 只负责生成
92
148
 
93
149
  ## 触发条件
94
150
 
95
151
  - 手动:用户说"生成 Spec"、"写技术规格"、"/wl-spec"
96
152
  - 任务驱动:PRD 评审通过后,下一步通常就是生成 Spec
153
+ - `/wl-code` gate:无 spec 或 status≠confirmed 时,`/wl-code` 自动调本 skill 生成 draft
97
154
  - 子 agent:可被 prd-generator 在 PRD 确认后调度
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: test-generator
3
3
  description: "从已实现代码和 Spec 自动生成单元测试。Auto-generate unit tests from implemented code and Spec. 需用户确认(DANGEROUS)。"
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: " /wl-test quick模式内部调用(实现层)"
5
5
  ---
6
6
 
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: wl-code
3
3
  description: "按开发 Spec 严格实现代码(/wl-code 命令入口)。Implement code following a Spec strictly. 需用户确认(DANGEROUS)。"
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: "用户显式打 /wl-code; 或自然语言"写代码""实现这个功能""按spec开发"。需确认"
5
5
  ---
6
6
 
7
7
 
@@ -53,6 +53,18 @@ cap.mcp.call("context_pack", {"keyword": "..."}) <模块关键词> --platform <w
53
53
  - 拿真实列名/类型/注释(含枚举定义),别靠推断。
54
54
  - [QAS环境] 表结构与生产一致可放心用。
55
55
 
56
+ ### 排查/修 bug 类先对齐链路(kg 取证,1-2 步定位,禁止空转假设)
57
+
58
+ > 遵守 wl-pipeline 规则 2.6:取证优先用 kg(`cap.mcp.call`),**不许"假设A→假设B→假设C"连环空转**。
59
+
60
+ | 场景 | 对齐链路 | kg 先取证 | 最常见根因 |
61
+ |------|---------|----------|-----------|
62
+ | 后端报错/类型异常 | 前端格式→BO→Entity→DB列 | `query_schema`(DB列类型) + `context_pack`(BO/Entity文件) | String/Date/Long 不一致 |
63
+ | 接口不通/400 | 路由→Controller→Service→Mapper→SQL | `code-api`(路由/参数) + `table_impact`(影响面) | 参数名不匹配/缺@RequestBody |
64
+ | 前端白屏/NaN | 组件→API→响应→字段映射 | `context_pack`(组件/API) + `field_map`(字段映射) | null未处理/字段名拼错 |
65
+
66
+ kg 取证后 Read 命中文件找**不一致点**,定位即动手,**别发散推理**。
67
+
56
68
  ## 执行
57
69
 
58
70
  1. **加载 Spec**:按 REQ-ID 找 spec;没参数就读 `.qoder/.current-task`
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: wl-commit
3
3
  description: "代码提交 + push + 同步,带质量门禁。Git commit + push + sync with pre-commit quality gate. 需用户确认(DANGEROUS)。"
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: "用户显式打 /wl-commit; 或自然语言"提交代码""commit"。需确认"
5
5
  ---
6
6
 
7
7
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: wl-design
3
- description: "设计工序入口: import 录入设计稿→spec.json(默认) / generate 按设计spec出原型 / review 评审原型。"
4
- trigger: "user invokes /wl-* command explicitly"
3
+ description: "设计工序站: 预览(蓝湖稿→HTML预览,默认) / 扫描(看现有系统页面组件风格) / 评审(检查原型是否用系统真源)。"
4
+ trigger: "用户显式打 /wl-design; 或自然语言"出原型""设计稿""预览设计""扫描页面风格""
5
5
  ---
6
6
 
7
7
 
@@ -28,12 +28,12 @@ PY=$(python --version >/dev/null 2>&1 && echo python || echo python3)
28
28
 
29
29
  | 用户说 | 模式 | 走哪个 skill |
30
30
  |--------|------|-------------|
31
- | "录入设计稿""Figma稿录入""把这个设计录入" | **import**(默认) | design-import |
32
- | "按设计出原型""按设计师规范出原型" | **generate** | prototype-generator |
33
- | "评审原型""设计稿看一下""检查交互稿" | **review** | design-review |
31
+ | "预览""出预览""蓝湖链接""看看设计稿" 或 含 lanhuapp.com | **预览**(默认) | design-import |
32
+ | "扫描""看系统""有哪些页面""什么风格" | **扫描** | 看现有系统页面/组件/风格 |
33
+ | "评审""检查""合规""颜色对不对" | **评审** | design-review |
34
34
  | 模糊 | 先问意图 | — |
35
35
 
36
- 默认 import(最常见入口)。
36
+ 默认 预览(最常见入口)。
37
37
 
38
38
  ## ⚙️ 自取上下文(Quest / QoderWork 无 hook 注入,必须自读)
39
39
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: wl-init
3
3
  description: "初始化/切换开发者身份 + 环境体检。Initialize/switch developer identity + environment health check. "
4
- trigger: "user invokes /wl-* command explicitly"
4
+ trigger: "用户显式打 /wl-init; 身份初始化"
5
5
  ---
6
6
 
7
7
 
@@ -63,7 +63,7 @@ $PY "$R/.qoder/scripts/orchestration/wlkj.py" doctor --fix
63
63
 
64
64
  ## 输出规则
65
65
 
66
- - 体检完打印一句总结:「环境健康,可以开始工作:/wl-prd-full <需求>」或「N 个问题待修,加 --fix 自愈」
66
+ - 体检完打印一句总结:「环境健康,可以开始工作:/wl-prd <需求>」或「N 个问题待修,加 --fix 自愈」
67
67
  - 如果用户没给名字但 `.developer` 不存在:先问"你叫什么名字?角色是 pm/dev/design?"
68
68
  - 如果 git user.name 与开发者名不一致:在体检里 `[WARN]` 提示,`--fix` 会自动改
69
69
 
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: wl-insight
3
- description: "需求探索 + 外部调研 + 未来规划。流水线的'上游探索站',负责发现需求、对标竞品、做 Gap 分析和 roadmap。把'该做什么、为什么做'想清楚,结论交给 /wl-prd-full 落地。"
4
- trigger: "user invokes /wl-* command explicitly"
3
+ description: "需求上游探索站。默认澄清(产品听不懂时对焦,必要时出原型帮理解); discover(发现机会) / research(调研竞品) / plan(规划roadmap)。说'转PRD'落地。"
4
+ trigger: "用户显式打 /wl-insight; 或自然语言需求澄清(产品听不懂时)"
5
5
  ---
6
6
 
7
7
 
@@ -38,7 +38,7 @@ insight(探索/调研/规划)→ [用户确认转PRD] → prd(落地)→
38
38
  ```
39
39
 
40
40
  **insight 不产 PRD,不画原型,不分配 REQ-ID。** insight 的产出是**洞察报告**(.md)。
41
- 报告写完,提示用户"要把某个机会转成 PRD 吗?" → 是 → 自动进 `/wl-prd-full` 参考模式(mode: reference)。
41
+ 报告写完,提示用户"要把某个机会转成 PRD 吗?" → 是 → 自动进 `/wl-prd` 参考模式(mode: reference)。
42
42
 
43
43
  ---
44
44
 
@@ -154,12 +154,12 @@ OST ├─ Opportunity(用户机会/痛点)─ discover ──┤ → i
154
154
  insight 报告末尾**永远**给一句:
155
155
 
156
156
  ```
157
- 要把握住哪个机会?说"转 PRD"我把它作为现状输入,进 /wl-prd-full 参考模式落地成可执行 PRD。
157
+ 要把握住哪个机会?说"转 PRD"我把它作为现状输入,进 /wl-prd 参考模式落地成可执行 PRD。
158
158
  ```
159
159
 
160
160
  用户说"转 PRD"或指定某个机会 → 触发:
161
161
  ```
162
- /wl-prd-full 参考:{报告路径}#{机会编号}
162
+ /wl-prd 参考:{报告路径}#{机会编号}
163
163
  ```
164
164
  prd 以 reference 模式(mode: reference)承接,读取 insight 报告作为现状背景,走"轻反思+批量确认"流程落地。
165
165