sdd-flow-kit 1.2.3 → 1.3.1

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 (32) hide show
  1. package/README.md +71 -45
  2. package/dist/adapters/index.js +6 -6
  3. package/dist/cli.js +45 -9
  4. package/dist/core/acMatrix.js +116 -0
  5. package/dist/core/bootstrap.js +14 -6
  6. package/dist/core/inferProject.js +9 -2
  7. package/dist/core/openspecGate.js +45 -0
  8. package/dist/core/prdArtifacts.js +26 -0
  9. package/dist/core/projectRoots.js +79 -2
  10. package/dist/core/sessionState.js +2 -0
  11. package/dist/core/writeNext.js +19 -2
  12. package/dist/postinstall.js +22 -8
  13. package/dist/steps/runDeliver.js +18 -6
  14. package/dist/steps/runGate.js +97 -0
  15. package/dist/steps/runPhaseAdvance.js +53 -6
  16. package/dist/steps/runPropose.js +3 -1
  17. package/dist/steps/runValidate.js +204 -0
  18. package/dist/steps/setupProject.js +65 -2
  19. package/dist/steps/startFlow.js +14 -11
  20. package/package.json +1 -1
  21. package/src/templates/artifacts/01-adi-doc-skill-/346/214/207/345/274/225.template.md +4 -2
  22. package/src/templates/artifacts/01-/351/234/200/346/261/202/345/210/206/346/236/220/346/212/245/345/221/212.template.md +6 -1
  23. package/src/templates/artifacts/04-/346/212/200/346/234/257/346/226/207/346/241/243.template.md +272 -11
  24. package/src/templates/artifacts/05-/351/252/214/346/224/266/346/270/205/345/215/225.template.md +38 -0
  25. package/src/templates/artifacts/06-agent-skill.template.md +23 -9
  26. package/src/templates/artifacts/{05-openspec- → 06-openspec-}/346/217/220/346/241/210/350/215/211/347/250/277.template.md +16 -4
  27. package/src/templates/artifacts/{06-opsx-auto-chain.template.md → 07-opsx-auto-chain.template.md} +23 -9
  28. package/src/templates/prompts/02-sdd-loop-prompt.md +26 -9
  29. package/src/templates/rules/sdd-no-implement-until-apply.mdc.template +27 -8
  30. package/src/templates/skills/confluence-doc.py.template +65 -11
  31. package/src/templates/skills/doc-skill.SKILL.md.template +2 -0
  32. package/src/templates/skills/layered-testing-strategy.md +35 -0
@@ -61,14 +61,52 @@ def version_slug(prefix: str, version: str) -> str:
61
61
  return prefix.lower() + "-v" + version.replace(".", "")
62
62
 
63
63
 
64
- def search_keywords(prefix: str, version: str) -> list[str]:
65
- """固定顺序(与用户 Confluence 全局搜索习惯一致)。无论用户输入 ADI 2.3.2 还是 ADI_V2.3.2 都走这一套。"""
66
- return [
67
- f"{prefix}_V{version}",
68
- f"{prefix}-V{version}",
69
- f"{prefix}_{version}",
70
- f"{prefix}-{version}",
71
- ]
64
+ def dedupe_keywords(items: list[str]) -> list[str]:
65
+ """去重并保持顺序。"""
66
+ seen: set[str] = set()
67
+ out: list[str] = []
68
+ for item in items:
69
+ key = item.strip()
70
+ if not key or key in seen:
71
+ continue
72
+ seen.add(key)
73
+ out.append(key)
74
+ return out
75
+
76
+
77
+ def search_keywords(prefix: str, version: str, raw_input: str | None = None) -> list[str]:
78
+ """固定顺序(与用户 Confluence 全局搜索习惯一致)。
79
+
80
+ ADI 等产品的典型降级链:
81
+ 用户原样输入 → ADI_V2.3.4 → ADI-V2.3.4 → ADI_2.3.4 → ADI-2.3.4
82
+ → ADI_v2.3.4 → ADI-v2.3.4 → ADI V2.3.4 → V2.3.4
83
+ """
84
+ p = prefix.strip()
85
+ # BreakX(破圈引擎)PRD 在 xhs 空间,页面标题多为 V1.0.2 xxx,而非 BreakX_V1.0.2
86
+ if p.upper() in ("BREAKX", "BX"):
87
+ return dedupe_keywords(
88
+ [
89
+ *( [raw_input.strip()] if raw_input and raw_input.strip() else [] ),
90
+ f"V{version}",
91
+ f"BreakX V{version}",
92
+ f"BreakX_V{version}",
93
+ f"BreakX-V{version}",
94
+ f"xhs V{version}",
95
+ ]
96
+ )
97
+ return dedupe_keywords(
98
+ [
99
+ *( [raw_input.strip()] if raw_input and raw_input.strip() else [] ),
100
+ f"{prefix}_V{version}",
101
+ f"{prefix}-V{version}",
102
+ f"{prefix}_{version}",
103
+ f"{prefix}-{version}",
104
+ f"{prefix}_v{version}",
105
+ f"{prefix}-v{version}",
106
+ f"{prefix} V{version}",
107
+ f"V{version}",
108
+ ]
109
+ )
72
110
 
73
111
 
74
112
  def sanitize_filename(name: str) -> str:
@@ -147,6 +185,12 @@ def score_link_match(text: str, href: str, prefix: str, version: str, keyword: s
147
185
  slug = f"{p}v{v_compact}"
148
186
  if slug in path_compact or f"{p}-v{v_compact}" in path or f"{p}_v{v_compact}" in path:
149
187
  score += 4
188
+ # BreakX:标题以 V1.0.2 开头时加分
189
+ if p in ("breakx", "bx") and (t.startswith(f"v{version}") or f"v{version}" in t[:12]):
190
+ score += 5
191
+ space = env("CONFLUENCE_SPACE", "").lower()
192
+ if space and f"/spaces/{space}/" in href.lower():
193
+ score += 5
150
194
  return score
151
195
 
152
196
 
@@ -215,6 +259,12 @@ def is_prd_page(page, page_url: str) -> bool:
215
259
 
216
260
  crumbs = read_breadcrumb_text(page)
217
261
  crumbs_upper = crumbs.upper()
262
+ prefix = env("DOC_PRODUCT_PREFIX", "").upper()
263
+ # BreakX:xhs 空间 PRD 挂在「产品设计」下,不一定有 PRD 字样
264
+ if prefix in ("BREAKX", "BX") and "/spaces/xhs/" in page_url.lower():
265
+ if "产品设计" in crumbs or "BREAKX" in crumbs_upper or "破圈" in crumbs:
266
+ print(f" ✓ BreakX/xhs 产品设计命中: {crumbs[:120]}")
267
+ return True
218
268
  if re.search(r"\bPRD\b", crumbs_upper) or "需求" in crumbs or "PRD" in crumbs_upper:
219
269
  print(f" ✓ PRD 父级命中: {crumbs[:120]}")
220
270
  return True
@@ -374,8 +424,11 @@ def main():
374
424
  or DEFAULT_CONFLUENCE_PASSWORD
375
425
  )
376
426
  prefix = os.environ.get("DOC_PRODUCT_PREFIX", "{{DOC_PRODUCT_PREFIX}}").strip() or "{{DOC_PRODUCT_PREFIX}}"
377
- version = normalize_version(sys.argv[1])
378
- keywords = search_keywords(prefix, version)
427
+ if prefix.upper() in ("BREAKX", "BX") and not os.environ.get("CONFLUENCE_SPACE"):
428
+ os.environ["CONFLUENCE_SPACE"] = "xhs"
429
+ raw_arg = sys.argv[1].strip()
430
+ version = normalize_version(raw_arg)
431
+ keywords = search_keywords(prefix, version, raw_input=raw_arg)
379
432
 
380
433
  # 输出目录默认为仓库 docs/ 下
381
434
  default_download = os.environ.get("DOC_DOWNLOAD_DIR")
@@ -439,7 +492,8 @@ def main():
439
492
  pass
440
493
  print(f"❌ 未找到 {prefix} {version} 的需求文档。")
441
494
  print(
442
- " 排查:1) 是否存在 PRD 父级页面 2) 依次尝试 ADI_V2.3.2 / ADI-V2.3.2 / ADI_2.3.2 / ADI-2.3.2"
495
+ " 排查:1) 是否存在 PRD 父级页面 2) 依次尝试 "
496
+ "ADI_V2.3.4 / ADI-V2.3.4 / ADI_2.3.4 / ADI-2.3.4 / ADI_v2.3.4 / V2.3.4"
443
497
  )
444
498
  print(" 3) 或设置 CONFLUENCE_PAGE_URL=<页面完整URL> 直接下载")
445
499
  sys.exit(1)
@@ -63,6 +63,8 @@ python3 confluence-doc.py {{PRODUCT_PREFIX}}_V1.2.3
63
63
 
64
64
  ## 注意事项
65
65
 
66
+ {{CONFLUENCE_SPACE_NOTE}}
67
+
66
68
  - 依赖 Playwright:`pip install playwright && playwright install chromium`
67
69
  - 脚本:`docs/{{SKILL_DIR}}/confluence-doc.py`
68
70
  - 脚本已内置默认账号密码;如需使用其他账号可用环境变量覆盖
@@ -0,0 +1,35 @@
1
+ # 分层测试策略(SDD / OpenSpec 强制)
2
+
3
+ > 由 `sdd-flow-kit` 安装到目标项目时,应合并进 `tdd-script` 与 `playwright-e2e-dev-server` skill 的「验收层级」章节。
4
+
5
+ ## 四层模型
6
+
7
+ | 层级 | 覆盖范围 | 典型断言 | 缺失风险 |
8
+ |------|---------|---------|---------|
9
+ | **L1 能力** | API、状态机、mapper、脏数据 | 接口封装、枚举映射、mutation 参数 | 主流程不通 |
10
+ | **L2 交互契约** | 列序、disabled、toast、tooltip、placeholder | **完整字符串**(禁止 `toContain('成功')`) | PRD 细节漏项 |
11
+ | **L3 路径** | 每页面/每主链路一条 E2E | 登录 → 设规则 → 结果页重审 | 只 smoke 一条路径 |
12
+ | **L4 视觉** | 原型图 / Figma / `playwright-pic` | 列位置、紫色摘要、布局两行限制 | UI 与原型偏差 |
13
+
14
+ ## 与 05-验收清单的绑定
15
+
16
+ 1. 每条 AC 的「测试类型」列决定最低层级(`unit`→L1/L2,`e2e`→L3,`visual`→L4)。
17
+ 2. `tasks.md` 的 Red task 标题须含 `[AC-XX]`,断言文案从 05「验收标准」列复制。
18
+ 3. P0 AC 至少一条自动化测试(unit/component/e2e);纯 `manual` 的 P0 须在 deliver 前在 05 标 `已验收` 并注明证据路径。
19
+
20
+ ## UI 类 change 强制规则
21
+
22
+ - **每个受影响页面**至少 **1 条 E2E**(非单点 smoke)。
23
+ - **列表/表格类**:断言列顺序(`nth-child`、`data-column-index` 或表头文案顺序)。
24
+ - **文案类**:断言 PRD/05 中的**完整** toast、tooltip、placeholder。
25
+ - **弹窗类**:单条/批量模式、保存成功/失败分支均须有 L2 或 L3 覆盖。
26
+
27
+ ## Playwright
28
+
29
+ - 默认无头;每用例结束截图到 `playwright-pic/<module>/<change>/`。
30
+ - change 级 scope 须覆盖 05 中所有 `e2e` 类型 AC。
31
+
32
+ ## TDD Red 阶段
33
+
34
+ - 先写失败测试,断言来自 `05-验收清单.md`,再写实现。
35
+ - 禁止「规则列展示」类模糊断言;须写清「第 N 列」「文案为 XXX」。