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
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * 根据 OpenSpec change / 显式模块名解析 Playwright 运行范围。
4
+ *
5
+ * scope 三级(见 e2e/e2e-scope.config.json defaultScope):
6
+ * - change(默认):优先 change 文档中的 e2e/*.spec.ts;未写明则按 changeScopeFallback 回退(默认 module)
7
+ * - module:解析到的 e2e/<module>/ 整个目录
8
+ * - full:输出 FULL,由调用方跑全量 e2e/**
9
+ */
10
+ import fs from "node:fs";
11
+ import path from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+
14
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
15
+ const CONFIG_PATH = path.join(ROOT, "e2e/e2e-scope.config.json");
16
+
17
+ const VALID_SCOPES = new Set(["change", "module", "full"]);
18
+
19
+ function loadConfig() {
20
+ return JSON.parse(fs.readFileSync(CONFIG_PATH, "utf8"));
21
+ }
22
+
23
+ function resolveDefaultScope(config) {
24
+ const fromEnv = process.env.OPSX_PLAYWRIGHT_SCOPE || process.env.POQUAN_PLAYWRIGHT_SCOPE;
25
+ if (fromEnv) return fromEnv;
26
+ return config.defaultScope || "change";
27
+ }
28
+
29
+ function parseArgs(argv) {
30
+ const config = loadConfig();
31
+ const out = {
32
+ change: "",
33
+ scope: resolveDefaultScope(config),
34
+ modules: "",
35
+ };
36
+ for (let i = 2; i < argv.length; i += 1) {
37
+ const a = argv[i];
38
+ if (a === "--change" && argv[i + 1]) {
39
+ out.change = argv[++i];
40
+ } else if (a === "--scope" && argv[i + 1]) {
41
+ out.scope = argv[++i];
42
+ } else if (a === "--modules" && argv[i + 1]) {
43
+ out.modules = argv[++i];
44
+ } else if (!a.startsWith("-") && !out.change) {
45
+ out.change = a;
46
+ }
47
+ }
48
+ const envModules = process.env.OPSX_E2E_MODULES || process.env.POQUAN_E2E_MODULES;
49
+ if (envModules) {
50
+ out.modules = envModules;
51
+ }
52
+ if (!VALID_SCOPES.has(out.scope)) {
53
+ console.error(
54
+ `[resolve-playwright-e2e-scope] 无效 scope="${out.scope}";允许: change | module | full`,
55
+ );
56
+ process.exit(2);
57
+ }
58
+ return out;
59
+ }
60
+
61
+ function findChangeDir(changeName) {
62
+ const active = path.join(ROOT, "openspec/changes", changeName);
63
+ if (fs.existsSync(active)) return active;
64
+ const archiveRoot = path.join(ROOT, "openspec/changes/archive");
65
+ if (!fs.existsSync(archiveRoot)) return null;
66
+ const hit = fs
67
+ .readdirSync(archiveRoot)
68
+ .filter((d) => d.endsWith(changeName) || d.includes(changeName))
69
+ .sort()
70
+ .pop();
71
+ return hit ? path.join(archiveRoot, hit) : null;
72
+ }
73
+
74
+ /** 从 change 文档中提取显式声明的 e2e spec 路径(tasks / proposal / design) */
75
+ function collectSpecPathsFromChangeDir(changeDir) {
76
+ const specs = new Set();
77
+ const specRe = /\be2e\/[\w/.-]+\.spec\.(?:ts|js)\b/g;
78
+ const files = ["tasks.md", "proposal.md", "design.md"];
79
+ for (const f of files) {
80
+ const fp = path.join(changeDir, f);
81
+ if (!fs.existsSync(fp)) continue;
82
+ const content = fs.readFileSync(fp, "utf8");
83
+ let m;
84
+ while ((m = specRe.exec(content)) !== null) {
85
+ const rel = m[0];
86
+ const abs = path.join(ROOT, rel);
87
+ if (fs.existsSync(abs)) specs.add(rel);
88
+ }
89
+ }
90
+ return [...specs].sort();
91
+ }
92
+
93
+ function resolveChangeSpecPaths(changeName, config) {
94
+ const paths = new Set();
95
+ const changeDir = findChangeDir(changeName);
96
+ if (changeDir) {
97
+ collectSpecPathsFromChangeDir(changeDir).forEach((p) => paths.add(p));
98
+ }
99
+ const overrides = config.changeNameToSpecs?.[changeName];
100
+ if (overrides) {
101
+ for (const raw of overrides) {
102
+ const rel = raw.startsWith("e2e/") ? raw : `e2e/${raw}`;
103
+ const abs = path.join(ROOT, rel);
104
+ if (fs.existsSync(abs)) paths.add(rel);
105
+ }
106
+ }
107
+ return [...paths].sort();
108
+ }
109
+
110
+ function collectCapabilities(changeDir) {
111
+ const caps = [];
112
+ const specsDir = path.join(changeDir, "specs");
113
+ if (!fs.existsSync(specsDir)) return caps;
114
+ for (const ent of fs.readdirSync(specsDir, { withFileTypes: true })) {
115
+ if (ent.isDirectory()) caps.push(ent.name);
116
+ }
117
+ return caps;
118
+ }
119
+
120
+ function scanFeatureDirs(text) {
121
+ const found = new Set();
122
+ const re = /src\/features\/([a-z0-9-]+)/gi;
123
+ let m;
124
+ while ((m = re.exec(text)) !== null) {
125
+ found.add(m[1]);
126
+ }
127
+ return [...found];
128
+ }
129
+
130
+ function matchChangeNameKeywords(changeName, config) {
131
+ const mods = new Set();
132
+ for (const { pattern, modules } of config.changeNameKeywords || []) {
133
+ if (new RegExp(pattern, "i").test(changeName)) {
134
+ modules.forEach((mod) => mods.add(mod));
135
+ }
136
+ }
137
+ return [...mods];
138
+ }
139
+
140
+ function modulesToPaths(moduleIds, config) {
141
+ const paths = new Set();
142
+ for (const id of moduleIds) {
143
+ const dirs = config.modules[id];
144
+ if (!dirs) continue;
145
+ dirs.forEach((p) => {
146
+ const abs = path.join(ROOT, p);
147
+ if (fs.existsSync(abs)) paths.add(p);
148
+ });
149
+ }
150
+ return [...paths].sort();
151
+ }
152
+
153
+ function resolveModules({ change, modules }, config) {
154
+ if (modules) {
155
+ return modules
156
+ .split(",")
157
+ .map((s) => s.trim())
158
+ .filter(Boolean);
159
+ }
160
+ const moduleSet = new Set();
161
+ if (change) {
162
+ const changeDir = findChangeDir(change);
163
+ if (changeDir) {
164
+ for (const cap of collectCapabilities(changeDir)) {
165
+ (config.capabilityToModules[cap] || []).forEach((m) => moduleSet.add(m));
166
+ }
167
+ const textFiles = ["proposal.md", "design.md", "tasks.md"];
168
+ let blob = "";
169
+ for (const f of textFiles) {
170
+ const fp = path.join(changeDir, f);
171
+ if (fs.existsSync(fp)) blob += `${fs.readFileSync(fp, "utf8")}\n`;
172
+ }
173
+ for (const feat of scanFeatureDirs(blob)) {
174
+ (config.featureDirToModules[feat] || []).forEach((m) => moduleSet.add(m));
175
+ }
176
+ }
177
+ matchChangeNameKeywords(change, config).forEach((m) => moduleSet.add(m));
178
+ }
179
+ return [...moduleSet];
180
+ }
181
+
182
+ /** 按 change / OPSX_E2E_MODULES / POQUAN_E2E_MODULES 解析模块 id 与 e2e 目录路径 */
183
+ function resolveModuleScope(args, config) {
184
+ const moduleIds = resolveModules(args, config);
185
+ const paths = modulesToPaths(moduleIds, config);
186
+ return { moduleIds, paths };
187
+ }
188
+
189
+ function emitModulePaths(args, config, logPrefix) {
190
+ const { moduleIds, paths } = resolveModuleScope(args, config);
191
+ if (paths.length === 0) {
192
+ console.error(
193
+ "[resolve-playwright-e2e-scope] 未能解析模块;请设置 OPSX_E2E_MODULES=auth,review / POQUAN_E2E_MODULES=auth,review 或 OPSX_PLAYWRIGHT_SCOPE=full",
194
+ );
195
+ process.exit(2);
196
+ }
197
+ process.stderr.write(
198
+ `${logPrefix} scope=module change=${args.change || "-"} modules=${moduleIds.join(",")} paths=${paths.join(" ")}\n`,
199
+ );
200
+ paths.forEach((p) => process.stdout.write(`${p}\n`));
201
+ }
202
+
203
+ function main() {
204
+ const config = loadConfig();
205
+ const args = parseArgs(process.argv);
206
+
207
+ if (args.scope === "full") {
208
+ process.stdout.write("FULL\n");
209
+ return;
210
+ }
211
+
212
+ if (args.scope === "change") {
213
+ if (!args.change) {
214
+ console.error(
215
+ "[resolve-playwright-e2e-scope] scope=change 需要 change 名;示例: node scripts/resolve-playwright-e2e-scope.mjs <change-name>",
216
+ );
217
+ process.exit(2);
218
+ }
219
+ const specPaths = resolveChangeSpecPaths(args.change, config);
220
+ if (specPaths.length > 0) {
221
+ process.stderr.write(
222
+ `[resolve-playwright-e2e-scope] scope=change(文档 spec) change=${args.change} specs=${specPaths.join(" ")}\n`,
223
+ );
224
+ specPaths.forEach((p) => process.stdout.write(`${p}\n`));
225
+ return;
226
+ }
227
+
228
+ const fallback = config.changeScopeFallback ?? "module";
229
+ if (fallback === "module") {
230
+ process.stderr.write(
231
+ `[resolve-playwright-e2e-scope] scope=change 未在 tasks/proposal/design 中找到 spec,` +
232
+ `已按 changeScopeFallback=module 回退模块目录(change=${args.change})\n`,
233
+ );
234
+ emitModulePaths(args, config, "[resolve-playwright-e2e-scope]");
235
+ return;
236
+ }
237
+
238
+ console.error(
239
+ `[resolve-playwright-e2e-scope] scope=change 未找到 e2e/*.spec.ts,且 changeScopeFallback=${fallback};` +
240
+ `可配置 changeNameToSpecs、将 changeScopeFallback 设为 module,或 OPSX_PLAYWRIGHT_SCOPE=module|full`,
241
+ );
242
+ process.exit(2);
243
+ }
244
+
245
+ emitModulePaths(args, config, "[resolve-playwright-e2e-scope]");
246
+ }
247
+
248
+ main();
@@ -7,9 +7,12 @@
7
7
  ```bash
8
8
  cd {{DOC_SKILL_REL}}
9
9
  export DOC_PRODUCT_PREFIX="{{PRODUCT_PREFIX}}"
10
+ export SDD_SYNC_SOURCE_DIR="{{SYNC_SOURCE_DIR_REL}}"
10
11
  python3 confluence-doc.py {{VERSION_EXAMPLE}}
11
12
  ```
12
13
 
14
+ 脚本成功后会自动将 `docs/<版本目录>/*.md` 与 `image/` 同步到本 run 的 `source/PRD.md` 与 `source/image/`(也可手动执行 `npx sdd-flow-kit sync-source-prd --run-id <runId>`)。
15
+
13
16
  版本号可传:`2.3.2`、`V2.3.2`、`ADI_V2.3.2`、`ADI-V2.3.2`(脚本会归一化)。
14
17
 
15
18
  2. 脚本会依次用关键词打开 **Confluence 专用搜索页** `dosearchsite.action?queryString=<关键词>`(非首页顶栏搜索),并依次尝试:`ADI_V*` → `ADI-V*` → `ADI_*` → `ADI-*` → `ADI_v*` → `ADI-v*` → `ADI V*` → `ADI_V*结算` → `V*` 等。
@@ -24,8 +27,9 @@ python3 confluence-doc.py {{VERSION_EXAMPLE}}
24
27
 
25
28
  5. **禁止**在 Confluence 脚本未跑完或未确认失败前,用本地 Word/原型替代 `source/PRD.md`。
26
29
 
27
- 6. 成功后把生成的 `docs/*.md` **主文档**复制/回填到本 run 目录:
28
- - `source/PRD.md`
30
+ 6. 同步结果(自动,无需手抄):
31
+ - `source/PRD.md`(含 `> 原型图片目录: image/` 元数据行)
32
+ - `source/image/`(正文图片,与 docs 版本目录一致)
29
33
 
30
34
  ## 直链兜底(可选,非默认)
31
35
 
@@ -23,6 +23,11 @@
23
23
  - `01-需求分析报告.md`
24
24
  - `02-改动点清单.md`
25
25
  - `03-待确认问题清单.md`
26
+ - 阶段 B 交付模式另产出:`05-验收清单.md`、**填写完成的** `04-技术文档草稿.md`(须符合 `04-技术文档生成指引.md`,禁止摘要版)
27
+
28
+ ## 04 技术文档(阶段 B 必读)
29
+ - 同 run 目录:`04-技术文档生成指引.md`
30
+ - 脚手架已生成完整模板 `04-技术文档草稿.md` → **在原文件上填内容,勿删章节**
26
31
 
27
32
  ## 输出话术(建议固定)
28
33
  - 提问模式:`SDD 模式:提问模式;矛盾点池状态:未闭合;仅更新 03,等待人工确认。`
@@ -92,6 +92,20 @@
92
92
  - 错误态提示口径(toast/inline):
93
93
  - 权限不足提示:
94
94
 
95
+ ### 2.4 演示代码参照(UI 类必填)
96
+
97
+ > 演示可为 **Vue / React / 其他**;生产实现须达到 **相同交互与功能**。Propose 时整段迁入 `design.md` 的 `## 演示代码参照`。
98
+
99
+ - 演示代码根路径:
100
+ - 技术栈:vue | react | 其他
101
+ - 生产 UI 库:
102
+
103
+ | 演示模块 | 演示文件/组件 | 计划生产组件路径 | 关键交互信号(验收时须在代码中出现) |
104
+ |---------|--------------|-----------------|-------------------------------------|
105
+ | | | | |
106
+
107
+ 纯后端/无 UI 演示:在 design 写 `DEMO_REFERENCE_EXEMPT: <原因>`
108
+
95
109
  ## 3. 前端状态与数据模型设计
96
110
 
97
111
  ### 3.1 领域模型(TypeScript)
@@ -11,10 +11,10 @@
11
11
  ## 填写规则
12
12
 
13
13
  1. **ID**:`AC-01`、`AC-02`… 全局唯一。
14
- 2. **验收标准**:必须可观测(DOM 顺序、完整 toast/tooltip 文案、E2E 路径、截图对比等)。
14
+ 2. **验收标准**:必须可观测(DOM 顺序、完整 toast/tooltip 文案、E2E 路径、截图对比等);**详情/弹窗类须写明演示模块名**(如「对齐演示 ProjectDetail §红票及其他」)。
15
15
  3. **测试类型**:`unit` | `component` | `e2e` | `visual` | `manual`(可组合,如 `unit+e2e`)。
16
16
  4. **优先级**:`P0`(交付阻断)/ `P1` / `P2`。
17
- 5. **映射**:propose 后在 `openspec/changes/<change>/tasks.md` 或 `spec.md` 中引用 `[AC-XX]`。
17
+ 5. **映射**:propose 后在 `openspec/changes/<change>/tasks.md` 或 `spec.md` 中引用 `[AC-XX]`;**tasks 须有「演示模块迁移」段,与 design 映射表一行一任务**。
18
18
  6. **Intentional 偏差**:与 PRD 有意不一致时,必须同步记入 `03-待确认问题清单.md` 并在下文登记。
19
19
 
20
20
  ## 验收项
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: sdd-flow-kit
3
- description: 用户说「开发/进行 {{DEFAULT_PRODUCT}} x.x.x 版本/需求」「ADI_2.3.2」等时触发。**禁止**未过 gate 直接改 src。必须先 invoke/run,确认点闭合后走 OpenSpec+Superpowers(gate→05 AC→propose→ac-ready→apply→ac-signed→deliver)。
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}}` 或 invoke/run。禁止先执行 openspec new change、OPSX Propose 或修改 src/e2e;成功后必须读取 NEXT.md 与 .session-state.json。
4
4
  ---
5
5
 
6
6
  # SDD Flow Kit({{PROJECT_KIND}} — 脚本门禁)
@@ -10,10 +10,10 @@ description: 用户说「开发/进行 {{DEFAULT_PRODUCT}} x.x.x 版本/需求
10
10
  用户一旦表达版本开发意图,**在本回合终端执行**(项目根 = 安装 sdd-flow-kit 的目录,如 `frontend/`):
11
11
 
12
12
  ```bash
13
- npx sdd-flow-kit invoke "开发 {{DEFAULT_PRODUCT}} <版本号> 需求" -y --agent {{AGENT_NAME}}
13
+ npx sdd-flow-kit guard "<用户原话>" -y --agent {{AGENT_NAME}}
14
14
  ```
15
15
 
16
- 或:
16
+ 若 `guard` 不可用,再退化为:
17
17
 
18
18
  ```bash
19
19
  npx sdd-flow-kit run --product {{DEFAULT_PRODUCT}} --version <版本号> -y --agent {{AGENT_NAME}}
@@ -8,7 +8,7 @@
8
8
  - [ ] `03-待确认问题清单.md` 已标注 **矛盾点池状态:已闭合**
9
9
  - [ ] `05-验收清单.md` 已标注 **定义状态:已定义**,且 P0 项齐全
10
10
  - [ ] `01-需求分析报告.md`、`02-改动点清单.md`、`04-技术文档草稿.md` 已生成(04 须引用 AC-ID)
11
- - [ ] `gate ac-ready` 通过(P0 已映射到 spec/tasks
11
+ - [ ] `gate ac-ready` 通过(P0 已映射到 spec/tasks,且 **design 含演示模块映射表**)
12
12
  - [ ] 用户已确认可进入提案阶段(阶段 B 闭环)
13
13
  - [ ] `autoChainOpsx` 为 true(默认)→ 与用户确认后**同一回合**自动 propose,无需再等「继续」
14
14
 
@@ -18,7 +18,7 @@
18
18
  - **验收 SSOT**:`05-验收清单.md`(**必须**)
19
19
  - 改动清单:`02-改动点清单.md`
20
20
  - 技术方案:`04-技术文档草稿.md`(引用 AC-ID)
21
- - UI/交互参考:(填写用户提供的路径,例如原型页面或设计稿目录)
21
+ - UI/交互参考:(**必填**)演示代码根路径 + 技术栈(vue/react);propose 时写入 `design.md` → `## 演示代码参照` 映射表(见 `design-demo-reference.template.md`)
22
22
 
23
23
  ## 执行命令(在 AI 工具中)
24
24
 
@@ -38,8 +38,8 @@
38
38
  ## UI 路径解析(按优先级)
39
39
 
40
40
  1. 用户本条消息给出的路径
41
- 2. `source/PRD.md` 中的「原型图片目录」行(如 `docs/adi-v232/`)
42
- 3. `docs/<product>-v<version无点>/` 或 `docs/<product>-<version>/` 目录(只读扫描)
41
+ 2. `source/PRD.md` 中的「原型图片目录」行(如 `source/image/` 或 `docs/adi-v232/image/`)
42
+ 3. `source/image/` 或 `docs/<product>-v<version无点>/image/`(只读扫描)
43
43
 
44
44
  缺失 UI 时:**仍继续** propose,在 `proposal.md` / `design.md` 注明「UI 待补」。
45
45
 
@@ -66,6 +66,8 @@
66
66
  - 「先沿用旧版,后续再改」— 兜底措辞
67
67
  - 「组件里应该有处理」— 无路径/行号/断言
68
68
  - 「基本满足」— 结论不在三选一内
69
+ - `src/views/foo/index.vue:1` — **仅文件首行,无具体组件/交互证据**
70
+ - `tests/.../prd-atoms-coverage.test.ts` — **注释登记 PRD-ID,非真实实现**
69
71
 
70
72
  ## 逐条对比(PRD 原子 × 代码)
71
73
 
@@ -0,0 +1,24 @@
1
+ ## 演示代码参照
2
+
3
+ > **UI 类 change 必填**。演示可为 Vue/React;生产实现须达到相同交互与功能,允许换 UI 库。
4
+ > 纯后端/无 UI 时在 change 文档首行写:`DEMO_REFERENCE_EXEMPT: <原因>`
5
+
6
+ - **演示代码根路径**:`(填写绝对或相对路径,如 /path/to/demo 或 docs/demo-v234)`
7
+ - **技术栈**:`vue` | `react` | `其他`
8
+ - **生产 UI 库**:`(如 Naive UI / Ant Design)`
9
+ - **迁移说明**:(可选)演示 Element Plus → 生产 Naive UI,布局与交互 SSOT 仍以演示为准
10
+
11
+ ### 演示模块 → 生产组件映射(门禁 SSOT)
12
+
13
+ | 演示模块 | 演示文件/组件 | 生产组件路径 | 关键交互信号(须在生产代码出现) |
14
+ |---------|--------------|-------------|--------------------------------|
15
+ | (示例)列表页 | FinancialOverview.vue | src/views/finance/index.vue | 请输入项目ID或名称、拉取欢聚最新数据 |
16
+ | (示例)详情-BD预估 | ProjectDetail.vue | src/views/finance/components/BdEstimateSection.vue | 编辑预估、BD预计开票日期、距BD预计 |
17
+ | (示例)详情-红票 | ProjectDetail.vue | src/views/finance/components/RedInvoiceSection.vue | 红票及其他、添加记录、红票 |
18
+ | (填写) | | | |
19
+
20
+ ### 禁止的实现方式
21
+
22
+ - 禁止仅用单个 `*DetailDrawer.vue` 只读 `info-grid` 代替演示中的多区块/可编辑/弹窗。
23
+ - 禁止 tasks 只写「实现 DetailDrawer」而不拆演示模块。
24
+ - 禁止 08 报告证据仅写 `index.vue:1`。
@@ -46,7 +46,7 @@
46
46
  |------|------|
47
47
  | `01` | 业务概述、范围、风险(**不承担**完整验收) |
48
48
  | `05` | **唯一验收 SSOT**(从 `source/PRD.md` 逐条抽 AC) |
49
- | `04` | 技术方案(引用 AC-ID) |
49
+ | `04` | **可开发级**前端技术方案(**保留模板全部 11 章**,引用 AC-ID) |
50
50
  | `02` | 代码改动计划表 |
51
51
 
52
52
  #### 3. 文档模板要求
@@ -73,6 +73,19 @@
73
73
  * **格式**:表格形式(仅在“提问模式”下生成或更新)。
74
74
  * **字段**:问题类型 (断点/起点缺失/推测缺口) | 问题描述 | 代码位置 (如有) | 建议/待确认项。
75
75
 
76
+ **📄 04-技术文档草稿.md(与 `04-技术文档.template.md` 同结构,强制)**
77
+
78
+ > **必读**:同 run 目录下 `04-技术文档生成指引.md`。
79
+ > **禁止**用 bullet 摘要替换整份文件;**禁止**删减 `##` / `###` 章节标题。
80
+
81
+ * **填写方式**:Read 现有 `04-技术文档草稿.md`(脚手架已写入完整模板)→ **在原文件内逐节替换占位**,不得新建简化版。
82
+ * **输入**:`source/PRD.md`、`source/接口文档.md`、用户演示代码路径(Vue/React)、`05-验收清单.md`、仓库代码扫描结果。
83
+ * **必备章节**(标题须保留):文档元信息 → §1 改造范围(含 1.1–1.4)→ §2 页面与交互(含 **2.4 演示代码参照与映射表**)→ §3 状态模型 → §4 接口(含 **4.1 接口清单表**、4.3 字段映射/normalize)→ §5 表单校验 → §6 边界 → §7 **文件级**改造清单 → §8 风险表 → §9 发布回滚 → §10 测试验收 → §11 待确认。
84
+ * **篇幅**:填完后通常 **≥150 行**;§4.1 至少 5 条接口;UI 类 §2.4 至少 3 行演示映射。
85
+ * **AC 标注**:`[AC-XX]` 分散在各章节,勿只在文首堆叠。
86
+ * **详情/抽屉类**:须按演示代码拆子模块写入 §2.2 / §2.4 / §7(如 BD预估编辑、红票及其他、可编辑金额),**禁止**仅写单个 `*DetailDrawer`。
87
+ * **gate**:`docs-closed` 会校验 `tech-doc-structure`,不合格不得 propose。
88
+
76
89
  ---
77
90
 
78
91
  ### 🚦 核心指令 (Execution Logic)
@@ -100,19 +113,20 @@
100
113
 
101
114
  **任务(阶段 B 文档产出;`full-chain` 模式下不得在本路径结束回合)**:
102
115
  1. 更新 `03-待确认问题清单.md`,标注“**矛盾点池状态:已闭合**”,写入用户确认结论。
103
- 2. **从 `source/PRD.md` 生成 `05-验收清单.md`**(标注「定义状态:已定义」),再生成 `04-技术文档草稿.md`(引用 AC-ID)。
104
- 3. 生成最终版 `01-需求分析报告.md` `02-改动点清单.md`(清单中的路径是**计划**,不得在本回合修改这些文件)。
105
- 4. 确认 `02-改动点清单.md` 中仅包含代码文件改动,不涉及 `openspec/spec/` 内容。
106
- 5. **禁止** 在阶段 B 内修改 `src/` 等业务代码。
107
- 6. 更新 `.session-state.json`:`status: ready_for_propose`;若用户口令含执行模式,同步 `executionMode` / `strictCommands`。
108
- 7. 执行 `gate docs-closed` `phase advance --to docs-done`(exit 0 才继续)。
109
- 8. **若 `autoChainOpsx !== false` `executionMode !== staged-confirm`(默认 full-chain)**:**不得结束回合**,同一回合继续读 `07-opsx-自动串联指引.md`,执行 C→D→E 直至 `deliver` exit 0;**不要**要求用户再说「继续」。
110
- 9. 仅当 `autoChainOpsx === false` 时输出:`05/01/02/03/04 已更新。回复「继续」进入提案。`
111
- 10. **`executionMode=staged-confirm` 时**(含兼容口令「严格SOP,不可替代」):
116
+ 2. **从 `source/PRD.md` 生成 `05-验收清单.md`**(标注「定义状态:已定义」)。
117
+ 3. **填写 `04-技术文档草稿.md`**:先 Read 已有模板文件 + `04-技术文档生成指引.md`,**保留全部章节标题**,逐节填入 PRD/接口/演示/代码扫描内容;**禁止**重写为摘要版。
118
+ 4. 生成最终版 `01-需求分析报告.md` `02-改动点清单.md`(清单中的路径是**计划**,不得在本回合修改这些文件)。
119
+ 5. 确认 `02-改动点清单.md` 中仅包含代码文件改动,不涉及 `openspec/spec/` 内容。
120
+ 6. **禁止** 在阶段 B 内修改 `src/` 等业务代码。
121
+ 7. 更新 `.session-state.json`:`status: ready_for_propose`;若用户口令含执行模式,同步 `executionMode` / `strictCommands`。
122
+ 8. 执行 `gate docs-closed` `phase advance --to docs-done`(exit 0 才继续;失败则继续补全 04 直至 `tech-doc-structure` 通过)。
123
+ 9. **若 `autoChainOpsx !== false` `executionMode !== staged-confirm`(默认 full-chain)**:**不得结束回合**,同一回合继续读 `07-opsx-自动串联指引.md`,执行 C→D→E 直至 `deliver` exit 0;**不要**要求用户再说「继续」。
124
+ 10. 仅当 `autoChainOpsx === false` 时输出:`05/01/02/03/04 已更新。回复「继续」进入提案。`
125
+ 11. **`executionMode=staged-confirm` 时**(含兼容口令「严格SOP,不可替代」):
112
126
  - 每阶段执行前先输出:`本次计划命令清单(逐条)`
113
127
  - 每阶段执行后输出:`门禁结果 + 证据文件路径 + 下一步命令`
114
128
  - 等待用户确认后再进入下一阶段
115
- 11. **`strictCommands=true` 时**:禁止用等价命令替代 NEXT.md 中的 gate/phase 链路(可与 full-chain 组合,不强制每阶段暂停)
129
+ 12. **`strictCommands=true` 时**:禁止用等价命令替代 NEXT.md 中的 gate/phase 链路(可与 full-chain 组合,不强制每阶段暂停)
116
130
 
117
131
  ---
118
132
 
@@ -0,0 +1,71 @@
1
+ # 04-技术文档填写规范(阶段 B 强制)
2
+
3
+ > **SSOT 模板**:同目录 run 下已由脚手架生成的 `04-技术文档草稿.md`(来自 `04-技术文档.template.md`)。
4
+ > **禁止**用几行 bullet + `[AC-xx]` 替换整份文件;**必须保留模板全部章节标题**,仅在各节内填入真实内容。
5
+
6
+ ---
7
+
8
+ ## 填写方式(必须遵守)
9
+
10
+ 1. **先 Read** 当前 `04-技术文档草稿.md`(已是完整模板,约 11 章)。
11
+ 2. **在原文件上逐节替换**占位内容(`(填写)`、空表格行、示例行),**不得删除**任何 `##` / `###` 标题。
12
+ 3. 输入来源(按优先级):
13
+ - `source/PRD.md`(业务规则、交互、文案)
14
+ - `source/接口文档.md`(§4 接口清单、字段映射)
15
+ - 用户提供的**演示代码**路径(Vue/React 均可 → §2.4 映射表)
16
+ - `05-验收清单.md`(在各章标注 `[AC-XX]`,勿只在文首堆叠)
17
+ - 仓库现有代码(§1 现状、§7 改造清单)
18
+ 4. 填完后自检:行数建议 **≥150**;§4.1 至少 **5 行**接口表;§2.4 至少 **3 行**演示映射(UI 类需求)。
19
+ 5. 运行 `npx sdd-flow-kit gate --expect docs-closed`;若 `tech-doc-structure` 失败,继续补全缺失章节。
20
+
21
+ ---
22
+
23
+ ## 各章最低填写要求
24
+
25
+ ### 文档元信息
26
+ - 需求名称、版本、业务域、分支、关联 PRD/接口/演示路径/自测
27
+
28
+ ### §1 改造范围
29
+ - **1.1** 量化成功标准;**1.2** 列出全部页面/路由/弹窗;**1.3** Out of Scope(含 mock、后续迭代)
30
+ - 每条 In Scope 能力标注 `[AC-XX]`
31
+
32
+ ### §2 页面与交互设计
33
+ - **2.1** 权限/场景矩阵(有权限/无权限/只读等)
34
+ - **2.2** 至少 2 条用户路径(列表、详情、导入、编辑…)写清 Step 与成功/失败 toast **完整文案**
35
+ - **2.3** loading、空态、防重复提交
36
+ - **2.4 演示代码参照(UI 必填)**:根路径、技术栈、**映射表**(演示模块 → 计划生产组件 → 关键交互信号)
37
+
38
+ ### §3 状态与数据模型
39
+ - 核心 TypeScript 类型(列表行、详情 VO、表单草稿)
40
+ - remote / ui / 派生状态划分;详情打开/关闭清理
41
+
42
+ ### §4 接口与数据交互
43
+ - **4.1 表格**:接口路径 | Method | 用途 | 请求字段 | 响应字段 | 异常处理
44
+ - **4.3** 写明后端 SNAKE_CASE → 前端 camelCase normalize 位置(如 `config/api/modules/*/caseTransform`)
45
+ - 提交 payload 示例(JSON)
46
+
47
+ ### §5 表单与校验
48
+ - 关键弹窗/编辑字段校验矩阵(必填、格式、错误文案)
49
+
50
+ ### §6–§11
51
+ - 边界场景、文件级改造清单(**禁止**只写一个大组件名)、风险表、发布检查、测试要点与 05 AC 对应、待确认项(无则写「无」)
52
+
53
+ ---
54
+
55
+ ## 禁止的反模式(gate 会失败)
56
+
57
+ | 反模式 | 示例 |
58
+ |--------|------|
59
+ | 摘要替换 | 仅 7 条 `## N. xxx [AC-xx]` 列表 |
60
+ | 删章节 | 缺少 §3/§5/§6/§8/§9/§11 |
61
+ | 无接口表 | §4 只有一句话「封装 api/modules」 |
62
+ | 无演示映射 | UI 需求但 §2.4 为空 |
63
+ | 详情一笔带过 | 「FinanceDetailDrawer」不提子模块(BD预估、红票、可编辑金额) |
64
+
65
+ ---
66
+
67
+ ## 与下游衔接
68
+
69
+ - Propose 时:`design.md` **复制** §2.4 映射表 + §4 接口决策
70
+ - `tasks.md`:**一行映射表 → 至少一条**「演示模块迁移」任务
71
+ - 实现:**禁止**用单文件只读骨架代替映射表中的多个生产组件
@@ -0,0 +1,56 @@
1
+ ---
2
+ description: 最高优先级:识别“开发/进行/实现 产品 版本”时必须先执行 sdd-flow-kit guard/invoke,禁止先走 OpenSpec/OPSX 或修改业务代码
3
+ alwaysApply: true
4
+ ---
5
+
6
+ # SDD Flow Kit 版本开发强制入口(最高优先级)
7
+
8
+ 当用户输入匹配以下任一意图时:
9
+
10
+ - `开发 <产品> <版本>`
11
+ - `进行 <产品> <版本> 需求`
12
+ - `实现 <产品> <版本> 版本`
13
+ - `<产品>_V<版本>` / `<产品>-V<版本>`
14
+ - 示例:`开发 ADI_V2.3.4版本`、`开发 OMS V1.24.5`、`进行 BreakX 1.0.2 需求`、`欢盟 V2.1.0 版本开发`
15
+
16
+ ## 第一动作(必须)
17
+
18
+ 必须先执行:
19
+
20
+ ```bash
21
+ npx sdd-flow-kit guard "<用户原话>" -y --agent {{AGENT_NAME}}
22
+ ```
23
+
24
+ 若无法使用 `guard`,退化为:
25
+
26
+ ```bash
27
+ npx sdd-flow-kit invoke "开发 <产品> <版本> 需求" -y --agent {{AGENT_NAME}}
28
+ ```
29
+
30
+ ## 严格禁止
31
+
32
+ 在 `guard/invoke` 成功前,禁止:
33
+
34
+ - 创建 `openspec/changes/**`
35
+ - 执行 `openspec new change`
36
+ - 执行 OPSX / OpenSpec Propose
37
+ - 修改 `src/**`、`frontend/src/**`、`e2e/**`
38
+ - 用自然语言计划替代脚本入口
39
+
40
+ ## 成功后继续
41
+
42
+ `guard/invoke` 成功后,必须读取并遵循:
43
+
44
+ - `openspec/PRD/<runId>/NEXT.md`
45
+ - `openspec/PRD/<runId>/.session-state.json`
46
+
47
+ 若 `.session-state.json` 中 `docModeOnly=true`,仍然禁止修改业务代码,直到 `gate docs-closed`、`gate ac-ready`、`phase impl` 与 `gate impl-allowed` 全部通过。
48
+
49
+ ## 优先级
50
+
51
+ 本规则优先于普通 OpenSpec/OPSX 自然语言需求入口:
52
+
53
+ ```text
54
+ 版本开发意图 → sdd-flow-kit guard/invoke → NEXT.md
55
+ 普通代码需求 → OPSX/OpenSpec
56
+ ```