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.
- package/README.md +71 -45
- package/dist/adapters/index.js +6 -6
- package/dist/cli.js +45 -9
- package/dist/core/acMatrix.js +116 -0
- package/dist/core/bootstrap.js +14 -6
- package/dist/core/inferProject.js +9 -2
- package/dist/core/openspecGate.js +45 -0
- package/dist/core/prdArtifacts.js +26 -0
- package/dist/core/projectRoots.js +79 -2
- package/dist/core/sessionState.js +2 -0
- package/dist/core/writeNext.js +19 -2
- package/dist/postinstall.js +22 -8
- package/dist/steps/runDeliver.js +18 -6
- package/dist/steps/runGate.js +97 -0
- package/dist/steps/runPhaseAdvance.js +53 -6
- package/dist/steps/runPropose.js +3 -1
- package/dist/steps/runValidate.js +204 -0
- package/dist/steps/setupProject.js +65 -2
- package/dist/steps/startFlow.js +14 -11
- package/package.json +1 -1
- package/src/templates/artifacts/01-adi-doc-skill-/346/214/207/345/274/225.template.md +4 -2
- 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
- package/src/templates/artifacts/04-/346/212/200/346/234/257/346/226/207/346/241/243.template.md +272 -11
- package/src/templates/artifacts/05-/351/252/214/346/224/266/346/270/205/345/215/225.template.md +38 -0
- package/src/templates/artifacts/06-agent-skill.template.md +23 -9
- package/src/templates/artifacts/{05-openspec- → 06-openspec-}/346/217/220/346/241/210/350/215/211/347/250/277.template.md +16 -4
- package/src/templates/artifacts/{06-opsx-auto-chain.template.md → 07-opsx-auto-chain.template.md} +23 -9
- package/src/templates/prompts/02-sdd-loop-prompt.md +26 -9
- package/src/templates/rules/sdd-no-implement-until-apply.mdc.template +27 -8
- package/src/templates/skills/confluence-doc.py.template +65 -11
- package/src/templates/skills/doc-skill.SKILL.md.template +2 -0
- 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
|
|
65
|
-
"""
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
378
|
-
|
|
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) 依次尝试
|
|
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)
|
|
@@ -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」。
|