sdd-flow-kit 1.3.14 → 1.3.18

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 (47) hide show
  1. package/dist/cli.js +97 -10
  2. package/dist/core/apiFieldContract.js +90 -0
  3. package/dist/core/demoImplementationCoverage.js +242 -0
  4. package/dist/core/e2eAssertionDepth.js +233 -0
  5. package/dist/core/prdArtifacts.js +12 -1
  6. package/dist/core/prdCoverage.js +46 -9
  7. package/dist/core/prdSemanticDiff.js +7 -4
  8. package/dist/core/syncSourcePrd.js +181 -0
  9. package/dist/core/techDocQuality.js +87 -0
  10. package/dist/core/testAssertionAnalysis.js +213 -0
  11. package/dist/core/versionIntent.js +65 -0
  12. package/dist/core/writeNext.js +1 -1
  13. package/dist/index.js +6 -1
  14. package/dist/steps/invokeFlow.js +5 -19
  15. package/dist/steps/runGate.js +49 -5
  16. package/dist/steps/runGuard.js +44 -0
  17. package/dist/steps/runSyncSourcePrd.js +38 -0
  18. package/dist/steps/runValidate.js +4 -2
  19. package/dist/steps/setupProject.js +31 -0
  20. package/dist/steps/startFlow.js +7 -2
  21. package/package.json +2 -1
  22. package/scripts/assert-active-openspec-change.sh +114 -0
  23. package/scripts/assess-api-field-contract.mjs +119 -0
  24. package/scripts/assess-demo-implementation-coverage.mjs +188 -0
  25. package/scripts/assess-e2e-assertion-depth.mjs +146 -0
  26. package/scripts/assess-playwright-e2e-coverage.mjs +244 -0
  27. package/scripts/assess-tech-doc-quality.mjs +91 -0
  28. package/scripts/install-git-hooks.sh +27 -0
  29. package/scripts/lib/test-assertion-analysis.mjs +134 -0
  30. package/scripts/resolve-playwright-e2e-scope.mjs +248 -0
  31. package/src/templates/artifacts/01-adi-doc-skill-/346/214/207/345/274/225.template.md +6 -2
  32. package/src/templates/artifacts/02-/351/234/200/346/261/202/345/210/206/346/236/220/346/217/220/347/244/272/350/257/215.template.md +5 -0
  33. package/src/templates/artifacts/04-/346/212/200/346/234/257/346/226/207/346/241/243.template.md +14 -0
  34. package/src/templates/artifacts/05-/351/252/214/346/224/266/346/270/205/345/215/225.template.md +2 -2
  35. package/src/templates/artifacts/06-agent-skill.template.md +3 -3
  36. package/src/templates/artifacts/06-openspec-/346/217/220/346/241/210/350/215/211/347/250/277.template.md +2 -2
  37. package/src/templates/artifacts/07-opsx-auto-chain.template.md +2 -2
  38. package/src/templates/artifacts/08-PRD/344/270/200/350/207/264/346/200/247/345/244/215/346/237/245/346/212/245/345/221/212.template.md +2 -0
  39. package/src/templates/artifacts/design-demo-reference.template.md +24 -0
  40. package/src/templates/prompts/02-sdd-loop-prompt.md +25 -11
  41. package/src/templates/prompts/04-tech-doc-fill-prompt.md +71 -0
  42. package/src/templates/rules/sdd-version-trigger.mdc.template +56 -0
  43. package/src/templates/skills/confluence-doc.py.template +64 -25
  44. package/src/templates/skills/demo-reference-mandatory-workflow.md +77 -0
  45. package/src/templates/skills/doc-skill.SKILL.md.template +13 -6
  46. package/src/templates/skills/layered-testing-strategy.md +13 -6
  47. package/src/templates/skills/version-trigger.SKILL.md.template +56 -0
@@ -5,6 +5,7 @@ import json
5
5
  import sys
6
6
  import os
7
7
  import re
8
+ import shutil
8
9
  from pathlib import Path
9
10
  from urllib.parse import quote, urlencode, urljoin, urlparse, unquote
10
11
  from urllib.request import Request, urlopen
@@ -66,6 +67,10 @@ def version_slug(prefix: str, version: str) -> str:
66
67
  return prefix.lower() + "-v" + version.replace(".", "")
67
68
 
68
69
 
70
+ # 图片统一放在版本目录下的 image/ 子目录,与 PRD Markdown 同级
71
+ IMAGE_SUBDIR = "image"
72
+
73
+
69
74
  def dedupe_keywords(items: list[str]) -> list[str]:
70
75
  """去重并保持顺序。"""
71
76
  seen: set[str] = set()
@@ -564,10 +569,11 @@ def download_images_http(
564
569
  token: str,
565
570
  content_html: str,
566
571
  version_dir: Path,
567
- slug: str,
568
572
  request_get=None,
569
573
  ) -> str:
570
- """下载正文图片并改写相对路径;request_get 可注入 Playwright page.request.get。"""
574
+ """下载正文图片到版本目录下的 image/ 并改写相对路径;request_get 可注入 Playwright page.request.get。"""
575
+ image_dir = version_dir / IMAGE_SUBDIR
576
+ image_dir.mkdir(parents=True, exist_ok=True)
571
577
  img_urls = re.findall(r'<img[^>]*src="([^"]+)"', content_html)
572
578
  for i, img_url in enumerate(img_urls):
573
579
  original_url = img_url
@@ -583,7 +589,7 @@ def download_images_http(
583
589
  parsed = urlparse(img_url)
584
590
  ext = os.path.splitext(parsed.path)[1] or ".png"
585
591
  filename = f"image_{i + 1}{ext}"
586
- filepath = version_dir / filename
592
+ filepath = image_dir / filename
587
593
  try:
588
594
  if request_get:
589
595
  resp = request_get(img_url)
@@ -600,7 +606,7 @@ def download_images_http(
600
606
  if ok and body:
601
607
  filepath.write_bytes(body)
602
608
  content_html = content_html.replace(
603
- f'src="{original_url}"', f'src="{slug}/{filename}"'
609
+ f'src="{original_url}"', f'src="{IMAGE_SUBDIR}/{filename}"'
604
610
  )
605
611
  except Exception:
606
612
  pass
@@ -608,7 +614,6 @@ def download_images_http(
608
614
 
609
615
 
610
616
  def write_prd_markdown(
611
- docs_root: Path,
612
617
  title: str,
613
618
  matched_keyword: str,
614
619
  target_url: str,
@@ -617,12 +622,12 @@ def write_prd_markdown(
617
622
  base_url: str,
618
623
  token: str,
619
624
  version_dir: Path,
620
- slug: str,
621
625
  request_get=None,
622
626
  ) -> Path:
623
- """将 HTML 转 Markdown 并写入 docs 目录。"""
627
+ """将 HTML 转 Markdown 并写入版本目录(与 image/ 同级)。"""
628
+ version_dir.mkdir(parents=True, exist_ok=True)
624
629
  html = clean_confluence_storage_html(content_html)
625
- html = download_images_http(base_url, token, html, version_dir, slug, request_get)
630
+ html = download_images_http(base_url, token, html, version_dir, request_get)
626
631
  content_md = parse_html_to_markdown(html)
627
632
  md_content = f"""# {title}
628
633
 
@@ -636,19 +641,57 @@ def write_prd_markdown(
636
641
  md_filename = sanitize_filename(title) + ".md"
637
642
  if not re.search(rf"{prefix}[-_]?V", md_filename, flags=re.IGNORECASE):
638
643
  md_filename = f"{matched_keyword}-{md_filename}"
639
- md_path = docs_root / md_filename
644
+ md_path = version_dir / md_filename
640
645
  md_path.write_text(md_content, encoding="utf-8")
641
646
  return md_path
642
647
 
643
648
 
649
+ def ensure_prd_image_dir_metadata(content: str) -> str:
650
+ """在 PRD 头部写入原型图片相对路径,供 OPSX UI 解析。"""
651
+ if "原型图片目录" in content:
652
+ return content
653
+ lines = content.split("\n")
654
+ title_idx = next(
655
+ (i for i, line in enumerate(lines) if line.strip().startswith("# ")),
656
+ -1,
657
+ )
658
+ insert_at = title_idx + 1 if title_idx >= 0 else 0
659
+ lines.insert(insert_at, "")
660
+ lines.insert(insert_at + 1, f"> 原型图片目录: {IMAGE_SUBDIR}/")
661
+ return "\n".join(lines)
662
+
663
+
664
+ def sync_to_openspec_source(md_path: Path, version_dir: Path) -> Path | None:
665
+ """将 PRD 与 image/ 同步到 openspec source/(需设置环境变量 SDD_SYNC_SOURCE_DIR)。"""
666
+ raw = env("SDD_SYNC_SOURCE_DIR")
667
+ if not raw:
668
+ return None
669
+ source_dir = Path(raw).expanduser()
670
+ if not source_dir.is_absolute():
671
+ source_dir = (Path.cwd() / source_dir).resolve()
672
+ source_dir.mkdir(parents=True, exist_ok=True)
673
+ content = ensure_prd_image_dir_metadata(md_path.read_text(encoding="utf-8"))
674
+ dest_md = source_dir / "PRD.md"
675
+ dest_md.write_text(content, encoding="utf-8")
676
+ src_image = version_dir / IMAGE_SUBDIR
677
+ dest_image = source_dir / IMAGE_SUBDIR
678
+ if src_image.is_dir():
679
+ if dest_image.exists():
680
+ shutil.rmtree(dest_image)
681
+ shutil.copytree(src_image, dest_image)
682
+ print(f"📋 已同步到 openspec source: {dest_md}")
683
+ print(f"🖼️ 已同步图片目录: {dest_image}")
684
+ else:
685
+ print(f"📋 已同步到 openspec source: {dest_md}")
686
+ return dest_md
687
+
688
+
644
689
  def try_rest_download(
645
690
  base_url: str,
646
691
  prefix: str,
647
692
  version: str,
648
693
  keywords: list[str],
649
- docs_root: Path,
650
694
  version_dir: Path,
651
- slug: str,
652
695
  ) -> bool:
653
696
  """REST API 主路径:Bearer Token 拉取 PRD,不依赖 Playwright 登录。"""
654
697
  token = get_api_token()
@@ -664,7 +707,6 @@ def try_rest_download(
664
707
  print(f"✅ [REST] 命中: {matched_keyword} | {title[:80]}")
665
708
  page = rest_fetch_page(base_url, token, page_id)
666
709
  md_path = write_prd_markdown(
667
- docs_root,
668
710
  page["title"],
669
711
  matched_keyword,
670
712
  target_url,
@@ -673,13 +715,13 @@ def try_rest_download(
673
715
  base_url,
674
716
  token,
675
717
  version_dir,
676
- slug,
677
718
  )
678
719
  if md_path.stat().st_size < 80:
679
720
  raise RuntimeError("生成的 Markdown 过短")
721
+ sync_to_openspec_source(md_path, version_dir)
680
722
  print("\n✅ 获取完成(REST API)!")
681
723
  print(f"📄 主文档: {md_path}")
682
- print(f"🖼️ 图片目录: {version_dir}")
724
+ print(f"🖼️ 图片目录: {version_dir / IMAGE_SUBDIR}")
683
725
  return True
684
726
  except Exception as e:
685
727
  print(f" REST 拉取失败: {e}")
@@ -916,8 +958,9 @@ def main():
916
958
 
917
959
  print(f"\n📥 开始获取 {prefix} {keywords[0]} 需求文档")
918
960
  print(f"🔍 将依次尝试: {', '.join(keywords)}")
919
- print(f"📁 输出目录: {docs_root}")
920
- print(f"🖼️ 图片目录: {version_dir}")
961
+ print(f"📁 输出根目录: {docs_root}")
962
+ print(f"📁 版本目录: {version_dir}")
963
+ print(f"🖼️ 图片目录: {version_dir / IMAGE_SUBDIR}")
921
964
 
922
965
  headed = env_bool("CONFLUENCE_HEADED") or env("CONFLUENCE_HEADLESS", "1").lower() in (
923
966
  "0",
@@ -944,9 +987,7 @@ def main():
944
987
  prefix=prefix,
945
988
  version=version,
946
989
  keywords=keywords,
947
- docs_root=docs_root,
948
990
  version_dir=version_dir,
949
- slug=slug,
950
991
  headless=headless,
951
992
  slow_mo=slow_mo,
952
993
  )
@@ -958,7 +999,7 @@ def main():
958
999
 
959
1000
  if use_rest:
960
1001
  print("\n🌐 Playwright 未成功,回退 REST API(Bearer Token)...")
961
- if try_rest_download(base_url, prefix, version, keywords, docs_root, version_dir, slug):
1002
+ if try_rest_download(base_url, prefix, version, keywords, version_dir):
962
1003
  return
963
1004
 
964
1005
  print("\n❌ PRD 拉取失败:Playwright 与 REST 均未成功。")
@@ -978,9 +1019,7 @@ def _download_via_playwright(
978
1019
  prefix: str,
979
1020
  version: str,
980
1021
  keywords: list[str],
981
- docs_root: Path,
982
1022
  version_dir: Path,
983
- slug: str,
984
1023
  headless: bool,
985
1024
  slow_mo: int,
986
1025
  ) -> bool:
@@ -1017,7 +1056,7 @@ def _download_via_playwright(
1017
1056
  )
1018
1057
 
1019
1058
  if not target_url or not matched_keyword:
1020
- debug_path = docs_root / "confluence-search-debug.png"
1059
+ debug_path = version_dir / "confluence-search-debug.png"
1021
1060
  try:
1022
1061
  page.screenshot(path=str(debug_path), full_page=True)
1023
1062
  print(f" 已保存调试截图: {debug_path}")
@@ -1075,7 +1114,6 @@ def _download_via_playwright(
1075
1114
 
1076
1115
  token = get_api_token()
1077
1116
  md_path = write_prd_markdown(
1078
- docs_root,
1079
1117
  title,
1080
1118
  matched_keyword,
1081
1119
  target_url,
@@ -1084,13 +1122,14 @@ def _download_via_playwright(
1084
1122
  base_url,
1085
1123
  token,
1086
1124
  version_dir,
1087
- slug,
1088
1125
  request_get=page.request.get,
1089
1126
  )
1090
1127
 
1128
+ sync_to_openspec_source(md_path, version_dir)
1129
+
1091
1130
  print("\n✅ 获取完成(Playwright)!")
1092
1131
  print(f"📄 主文档: {md_path}")
1093
- print(f"🖼️ 图片目录: {version_dir}")
1132
+ print(f"🖼️ 图片目录: {version_dir / IMAGE_SUBDIR}")
1094
1133
  return True
1095
1134
  except Exception as e:
1096
1135
  print(f"\n❌ Playwright 获取失败: {e}")
@@ -0,0 +1,77 @@
1
+ # 演示代码强制迁移工作流(SDD / OpenSpec 通用)
2
+
3
+ > 适用于 **Vue / React / 其他** 演示仓库。验收标准不是「技术栈一致」,而是 **交互与功能与演示代码等价**。
4
+
5
+ ## 原则
6
+
7
+ 1. **演示代码是 UI/交互 SSOT**(高于 PRD 文字摘要、高于 AI 自拟骨架)。
8
+ 2. **禁止** 用「一个 FinanceDetailDrawer 读接口」代替「按演示拆分的多子模块」。
9
+ 3. **禁止** 在 08 报告用 `index.vue:1` 或注释登记冒充实现。
10
+ 4. 演示可为 React、生产为 Vue(或反之)——须在映射表注明技术栈,迁移的是 **模块边界 + 交互信号**,不是复制粘贴 DOM 库。
11
+
12
+ ## 阶段 B — 04 技术文档
13
+
14
+ 在 `04-技术文档草稿.md` 增加 **§2.4 演示代码参照**(propose 时迁入 `design.md`):
15
+
16
+ ```markdown
17
+ ## 2.4 演示代码参照
18
+
19
+ - 演示代码根路径:`/path/to/demo` 或相对路径
20
+ - 技术栈:vue | react | 其他
21
+ - 说明:(可选)Element Plus 演示 → 生产 Naive UI
22
+
23
+ | 演示模块 | 演示文件/组件 | 计划生产组件路径 | 关键交互信号 |
24
+ |---------|--------------|-----------------|-------------|
25
+ | BD预估 | ProjectDetail.vue §BD预估 | src/views/.../BdEstimateSection.vue | 编辑预估、BD预计开票日期、距今天数 |
26
+ | 红票及其他 | ProjectDetail.vue §红票 | src/views/.../RedInvoiceSection.vue | 红票及其他、添加记录、红票 |
27
+ ```
28
+
29
+ 纯后端 / 无 UI 演示时,在 `design.md` 首行写:`DEMO_REFERENCE_EXEMPT: <原因>`
30
+
31
+ ## 阶段 C — Propose
32
+
33
+ `design.md` **必须**含 `## 演示代码参照` 与上表(可从 04 复制并细化路径)。
34
+
35
+ `tasks.md` **必须**含:
36
+
37
+ ```markdown
38
+ ## 演示模块迁移(强制,对齐 design 映射表)
39
+
40
+ ### Red
41
+ - [ ] D.1 为每个映射行编写失败测试(组件存在 / 交互文案 / API mock)
42
+ ### Green
43
+ - [ ] D.2 按演示结构实现生产组件(禁止合并为单文件只读骨架)
44
+ ```
45
+
46
+ **门禁**:`gate propose-ready` / `gate ac-ready` 执行 `checkDemoReferenceArtifacts`。
47
+
48
+ ## 阶段 D — Apply
49
+
50
+ 实现顺序:
51
+
52
+ 1. 读演示文件对应段落(无关技术栈)
53
+ 2. 拆分为生产 `components/*.vue`(或 tsx)
54
+ 3. 接已有 API(`config/api/modules`)
55
+ 4. 每完成一行映射,勾选 tasks 并跑该行单测
56
+
57
+ ## 阶段 E — Validate / Deliver
58
+
59
+ - `assess-demo-implementation-coverage.mjs`:映射表中的生产文件存在,且含「关键交互信号」
60
+ - `assess-e2e-assertion-depth.mjs`:E2E 须点到演示中的主按钮/区块(非 placeholder-only)
61
+ - 08 报告证据须指向 **具体组件文件 + 行号 + 交互文案**
62
+
63
+ ## 05 验收清单
64
+
65
+ 详情类 AC 验收标准须写清演示模块,例如:
66
+
67
+ - `详情 Tab「财务明细」含金额与返点卡片、财务链路、红票及其他(对齐演示 ProjectDetail.vue)`
68
+ - `BD预估区含编辑预估按钮,保存 toast「BD预估已保存」`
69
+
70
+ ## 豁免
71
+
72
+ | 场景 | 写法 |
73
+ |------|------|
74
+ | 纯 API/配置 | `DEMO_REFERENCE_EXEMPT: 无 UI` |
75
+ | 演示待补 | 禁止进入 impl;须先补演示或用户书面确认 |
76
+
77
+ 环境变量(仅紧急):`OPSX_SKIP_DEMO_REFERENCE=1`
@@ -2,7 +2,7 @@
2
2
  name: {{SKILL_NAME}}
3
3
  description: |
4
4
  当用户说「获取 {{PRODUCT}} Vx.y.z 需求文档」「下载 {{PRODUCT}}-Vx.y.z PRD」「查询 {{PRODUCT}} x.y.z 版本需求」时触发。
5
- 自动从 Confluence 搜索对应版本 PRD 页面;`技术文档`、`后端`、`详细设计` 类页面会被拒绝,避免误下载为 PRD;下载图片并生成 Markdown 到本仓库 `docs/`。
5
+ 自动从 Confluence 搜索对应版本 PRD 页面;`技术文档`、`后端`、`详细设计` 类页面会被拒绝,避免误下载为 PRD;下载图片并生成 Markdown 到本仓库 `docs/<版本目录>/`。
6
6
  ---
7
7
 
8
8
  # {{PRODUCT}} 需求文档获取(docs/{{SKILL_DIR}})
@@ -80,14 +80,21 @@ CONFLUENCE_PAGE_URL="https://confluence.huan.tv/spaces/yyzcpt/pages/109609740/..
80
80
 
81
81
  ## 输出结构
82
82
 
83
+ 每个版本独占一个目录(目录名由产品前缀 + 版本号自动生成,如 `adi-v234`):
84
+
83
85
  ```
84
- <repo>/docs/
85
- ├── {{PRODUCT_PREFIX}}-V1.2.3-xxx.md
86
- └── {{PRODUCT_PREFIX_LOWER}}-v123/
87
- ├── image_1.png
88
- └── image_2.png
86
+ <docs根目录>/
87
+ └── {{PRODUCT_PREFIX_LOWER}}-v123/ # 版本目录(相对脚本所在 docs/ 或 DOC_DOWNLOAD_DIR)
88
+ ├── {{PRODUCT_PREFIX}}_V1.2.3-xxx.md # PRD 主文档
89
+ └── image/ # 正文图片
90
+ ├── image_1.png
91
+ └── image_2.png
89
92
  ```
90
93
 
94
+ - **docs 根目录**:默认为脚本上级目录(`docs/` 或 monorepo 下的 `frontend/docs/`);可用环境变量 `DOC_DOWNLOAD_DIR` 覆盖为任意绝对/相对路径。
95
+ - **版本目录**:`<docs根目录>/<prefix>-v<版本号去点>`,便于多版本并存、按目录定位 PRD。
96
+ - **openspec 同步**:在 SDD run 中执行脚本时设置 `SDD_SYNC_SOURCE_DIR`(由 `01-获取需求文档指引.md` 自动注入),下载成功后自动写入 `source/PRD.md` 与 `source/image/`;亦可 `npx sdd-flow-kit sync-source-prd --run-id <runId>`。
97
+
91
98
  ## 注意事项
92
99
 
93
100
  {{CONFLUENCE_SPACE_NOTE}}
@@ -4,12 +4,19 @@
4
4
 
5
5
  ## 四层模型
6
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 与原型偏差 |
7
+ | 层级 | 覆盖范围 | 典型断言 | 缺失风险 | 门禁 |
8
+ |------|---------|---------|---------|------|
9
+ | **L1 能力** | API、状态机、mapper、脏数据 | 接口封装、枚举映射、mutation 参数、**snake/camel normalize** | 主流程不通、列表空数据 | `assess-api-field-contract.mjs` + unit |
10
+ | **L2 交互契约** | 列序、disabled、toast、tooltip、placeholder | **完整字符串**(禁止 `toContain('成功')`) | PRD 细节漏项 | AC 映射须 test 块内 `expect` |
11
+ | **L3 路径** | 每页面/每主链路一条 E2E | 登录 → 列表有数据点详情 → **演示映射中的按钮/区块** | 只 smoke placeholder | `assess-e2e-assertion-depth.mjs` |
12
+ | **L3.5 演示迁移** | 演示模块 生产组件 1:1 | design 映射表每行在生产代码有「关键交互信号」 | 单文件只读骨架代替演示 | `assess-demo-implementation-coverage.mjs` |
13
+ | **L4 视觉** | 原型图 / Figma / `playwright-pic` | 列位置、紫色摘要、布局两行限制 | UI 与原型偏差 | 人工 + 截图 |
14
+
15
+ ## 禁止伪覆盖
16
+
17
+ - **禁止** `prd-atoms-coverage.spec.ts` 等仅 `toBeGreaterThan(0)` 或注释登记 PRD-ID 的文件计入 semantic/e2e 覆盖。
18
+ - **禁止** 仅 `getByPlaceholder` 可见即宣布列表类 AC 通过;须 `waitForResponse` / `getByRole('cell')` / `toContainText` 等数据断言。
19
+ - **禁止** 用单个 DetailDrawer 只读骨架代替演示中的 BD预估/红票/可编辑金额等子模块;须遵循 `demo-reference-mandatory-workflow` skill。
13
20
 
14
21
  ## 与 05-验收清单的绑定
15
22
 
@@ -0,0 +1,56 @@
1
+ ---
2
+ name: 00-sdd-flow-kit-version-trigger
3
+ description: 最高优先级触发。凡用户表达“开发/进行/实现 <产品> <版本> 需求/版本”,例如 ADI_V2.3.4、OMS V1.24.5、BreakX 1.0.2、欢盟 V2.1.0,必须第一步执行 `npx sdd-flow-kit guard "<用户原话>" -y --agent {{AGENT_NAME}}`。禁止先执行 openspec new change、OPSX Propose 或修改 src/e2e。
4
+ ---
5
+
6
+ # SDD Flow Kit 版本开发强制入口
7
+
8
+ ## 适用范围
9
+
10
+ 当用户输入匹配以下任一意图时,本 skill 优先于普通 OpenSpec / OPSX 流程:
11
+
12
+ - `开发 <产品> <版本>`
13
+ - `进行 <产品> <版本> 需求`
14
+ - `实现 <产品> <版本> 版本`
15
+ - `<产品>_V<版本>` / `<产品>-V<版本>`
16
+ - 示例:`开发 ADI_V2.3.4版本`、`开发 OMS V1.24.5`、`进行 BreakX 1.0.2 需求`、`欢盟 V2.1.0 版本开发`
17
+
18
+ ## 第一动作(必须)
19
+
20
+ 在项目根目录立即执行:
21
+
22
+ ```bash
23
+ npx sdd-flow-kit guard "<用户原话>" -y --agent {{AGENT_NAME}}
24
+ ```
25
+
26
+ 若 `guard` 不可用,退化为:
27
+
28
+ ```bash
29
+ npx sdd-flow-kit invoke "开发 <产品> <版本> 需求" -y --agent {{AGENT_NAME}}
30
+ ```
31
+
32
+ ## 严格禁止
33
+
34
+ 在 `guard/invoke` 成功前,禁止:
35
+
36
+ - 创建 `openspec/changes/**`
37
+ - 执行 `openspec new change`
38
+ - 执行 OPSX / OpenSpec Propose
39
+ - 修改 `src/**`、`frontend/src/**`、`e2e/**`
40
+ - 用自然语言计划替代脚本入口
41
+
42
+ ## 成功后继续
43
+
44
+ `guard/invoke` 成功后,必须读取并遵循:
45
+
46
+ - `openspec/PRD/<runId>/NEXT.md`
47
+ - `openspec/PRD/<runId>/.session-state.json`
48
+
49
+ 若 `.session-state.json` 中 `docModeOnly=true`,仍然禁止修改业务代码,直到 `gate docs-closed`、`gate ac-ready`、`phase impl` 与 `gate impl-allowed` 全部通过。
50
+
51
+ ## 优先级
52
+
53
+ ```text
54
+ 版本开发意图 → sdd-flow-kit guard/invoke → NEXT.md
55
+ 普通代码需求 → OPSX/OpenSpec
56
+ ```