sdd-flow-kit 1.3.15 → 1.3.21
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/dist/cli.js +16 -0
- package/dist/core/acAssertionBinding.js +180 -0
- package/dist/core/apiFieldContract.js +90 -0
- package/dist/core/apiFieldCoverage.js +335 -0
- package/dist/core/componentSubstance.js +172 -0
- package/dist/core/demoImplementationCoverage.js +244 -0
- package/dist/core/e2eAssertionDepth.js +237 -0
- package/dist/core/e2eDemoSignalClicks.js +90 -0
- package/dist/core/prdArtifacts.js +12 -1
- package/dist/core/prdCoverage.js +52 -36
- package/dist/core/prdSemanticDiff.js +7 -4
- package/dist/core/snakeCamel.js +93 -0
- package/dist/core/syncSourcePrd.js +181 -0
- package/dist/core/techDocQuality.js +91 -0
- package/dist/core/testAssertionAnalysis.js +213 -0
- package/dist/core/visualRegression.js +243 -0
- package/dist/core/writeNext.js +1 -1
- package/dist/index.js +6 -1
- package/dist/steps/runGate.js +49 -5
- package/dist/steps/runSyncSourcePrd.js +38 -0
- package/dist/steps/runValidate.js +4 -2
- package/dist/steps/setupProject.js +3 -0
- package/dist/steps/startFlow.js +9 -2
- package/package.json +2 -1
- package/scripts/assert-active-openspec-change.sh +114 -0
- package/scripts/assess-ac-assertion-binding.mjs +104 -0
- package/scripts/assess-api-field-contract.mjs +119 -0
- package/scripts/assess-api-field-coverage.mjs +88 -0
- package/scripts/assess-component-substance.mjs +87 -0
- package/scripts/assess-demo-implementation-coverage.mjs +188 -0
- package/scripts/assess-e2e-assertion-depth.mjs +162 -0
- package/scripts/assess-playwright-e2e-coverage.mjs +244 -0
- package/scripts/assess-tech-doc-quality.mjs +98 -0
- package/scripts/assess-visual-regression.mjs +92 -0
- package/scripts/install-git-hooks.sh +27 -0
- package/scripts/lib/ac-assertion-binding.mjs +119 -0
- package/scripts/lib/api-field-coverage.mjs +238 -0
- package/scripts/lib/component-substance.mjs +117 -0
- package/scripts/lib/demo-reference-parse.mjs +55 -0
- package/scripts/lib/e2e-demo-signal-clicks.mjs +43 -0
- package/scripts/lib/snake-camel.mjs +74 -0
- package/scripts/lib/test-assertion-analysis.mjs +148 -0
- package/scripts/lib/visual-regression.mjs +191 -0
- package/scripts/resolve-playwright-e2e-scope.mjs +248 -0
- package/src/templates/artifacts/01-adi-doc-skill-/346/214/207/345/274/225.template.md +6 -2
- 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
- package/src/templates/artifacts/04-/346/212/200/346/234/257/346/226/207/346/241/243.template.md +22 -0
- package/src/templates/artifacts/05-/351/252/214/346/224/266/346/270/205/345/215/225.template.md +4 -3
- package/src/templates/artifacts/06-openspec-/346/217/220/346/241/210/350/215/211/347/250/277.template.md +2 -2
- package/src/templates/artifacts/07-opsx-auto-chain.template.md +2 -2
- 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
- package/src/templates/artifacts/design-demo-reference.template.md +24 -0
- package/src/templates/artifacts/tests-fixtures-readme.template.md +19 -0
- package/src/templates/artifacts/visual-baseline-readme.template.md +28 -0
- package/src/templates/prompts/02-sdd-loop-prompt.md +25 -11
- package/src/templates/prompts/04-tech-doc-fill-prompt.md +76 -0
- package/src/templates/skills/confluence-doc.py.template +64 -25
- package/src/templates/skills/demo-reference-mandatory-workflow.md +79 -0
- package/src/templates/skills/doc-skill.SKILL.md.template +13 -6
- package/src/templates/skills/layered-testing-strategy.md +15 -6
package/src/templates/artifacts/04-/346/212/200/346/234/257/346/226/207/346/241/243.template.md
CHANGED
|
@@ -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)
|
|
@@ -144,6 +158,14 @@ type ExampleEntity = {
|
|
|
144
158
|
|
|
145
159
|
### 4.3 响应数据映射(API -> UI)
|
|
146
160
|
|
|
161
|
+
#### 4.3.1 响应字段映射表(门禁 SSOT,对接后端须逐字段登记)
|
|
162
|
+
|
|
163
|
+
| 后端字段 | 前端字段 | 展示位置 | 兜底值 |
|
|
164
|
+
| --- | --- | --- | --- |
|
|
165
|
+
| `subject_id` | `subjectId` | 列表第1列 | `-` |
|
|
166
|
+
| `subject_name` | `subjectName` | 列表项目名称 | `-` |
|
|
167
|
+
| (填写) | (填写) | (填写) | `-` |
|
|
168
|
+
|
|
147
169
|
- 展示字段组装规则:
|
|
148
170
|
- 兜底值处理:
|
|
149
171
|
- 时间/金额/百分比格式化规则:
|
package/src/templates/artifacts/05-/351/252/214/346/224/266/346/270/205/345/215/225.template.md
CHANGED
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
## 填写规则
|
|
12
12
|
|
|
13
13
|
1. **ID**:`AC-01`、`AC-02`… 全局唯一。
|
|
14
|
-
2. **验收标准**:必须可观测(DOM 顺序、完整 toast/tooltip 文案、E2E
|
|
15
|
-
3. **测试类型**:`unit` | `component` | `e2e` | `visual` | `manual`(可组合,如 `unit+e2e
|
|
14
|
+
2. **验收标准**:必须可观测(DOM 顺序、完整 toast/tooltip 文案、E2E 路径、**截图基线对比**等);含 PRD 原型图时须写 `source/.../image_N.png` 或 `visual-baseline/xxx.png` 与 `diff≤2%`。
|
|
15
|
+
3. **测试类型**:`unit` | `component` | `e2e` | `visual` | `manual`(可组合,如 `unit+e2e+visual`)。**PRD source 含 `.png` 原型图时,至少 1 条 P0/P1 `visual` AC**。
|
|
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
|
## 验收项
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|----|---------|-------------------|---------|--------|-------------------|---------|
|
|
24
24
|
| AC-01 | PRD §(填写) | (填写可观测断言,toast/tooltip 须一字不差) | unit | P0 | 待映射 | 待验收 |
|
|
25
25
|
| AC-02 | PRD §(填写) | (填写) | e2e | P1 | 待映射 | 待验收 |
|
|
26
|
+
| AC-02-V | PRD §(填写) | 列表页与基线 `source/.../image_1.png` 布局一致(diff≤2%) | visual+e2e | P1 | e2e/*.spec.ts | 待验收 |
|
|
26
27
|
|
|
27
28
|
## Intentional 偏差登记
|
|
28
29
|
|
|
@@ -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. `
|
|
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
|
|
|
@@ -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
|
+
| 演示模块 | 演示文件/组件 | 生产组件路径 | 关键交互信号(须在生产代码出现) | E2E 点击绑定(getByText/click) |
|
|
14
|
+
|---------|--------------|-------------|--------------------------------|--------------------------------|
|
|
15
|
+
| (示例)列表页 | FinancialOverview.vue | src/views/finance/index.vue | 请输入项目ID或名称、拉取欢聚最新数据 | getByPlaceholder('请输入项目ID或名称') |
|
|
16
|
+
| (示例)详情-BD预估 | ProjectDetail.vue | src/views/finance/components/BdEstimateSection.vue | 编辑预估、BD预计开票日期 | getByRole('button', { name: '编辑预估' }).click() |
|
|
17
|
+
| (示例)详情-红票 | ProjectDetail.vue | src/views/finance/components/RedInvoiceSection.vue | 红票及其他、添加记录 | getByText('添加记录').click() |
|
|
18
|
+
| (填写) | | | |
|
|
19
|
+
|
|
20
|
+
### 禁止的实现方式
|
|
21
|
+
|
|
22
|
+
- 禁止仅用单个 `*DetailDrawer.vue` 只读 `info-grid` 代替演示中的多区块/可编辑/弹窗。
|
|
23
|
+
- 禁止 tasks 只写「实现 DetailDrawer」而不拆演示模块。
|
|
24
|
+
- 禁止 08 报告证据仅写 `index.vue:1`。
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# API Fixture 样例(v1.3.20 门禁)
|
|
2
|
+
|
|
3
|
+
将**联调/抓包**得到的真实后端 JSON 放在此目录(保持 **snake_case** 键名)。
|
|
4
|
+
|
|
5
|
+
## 命名建议
|
|
6
|
+
|
|
7
|
+
- `finance-subject-page.json` — 列表分页响应
|
|
8
|
+
- `finance-subject-info.json` — 详情 subject-info
|
|
9
|
+
- `finance-subject-detail.json` — 详情 subject-detail
|
|
10
|
+
|
|
11
|
+
## 要求
|
|
12
|
+
|
|
13
|
+
1. 须含 `_` 分隔的后端字段(如 `subject_id`),禁止手写全 camelCase 空对象
|
|
14
|
+
2. 配套单测:`tests/**/caseTransform.test.ts` 加载本目录 JSON,`snakeToCamelDeep` 后 `expect` 关键 camelCase 字段
|
|
15
|
+
3. 04 技术文档 §4.3.1 字段映射表须与 fixture 字段一致
|
|
16
|
+
|
|
17
|
+
## 门禁
|
|
18
|
+
|
|
19
|
+
`assess-api-field-coverage.mjs` 在 deliver 阶段校验。
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# visual-baseline(L4 视觉回归基线)
|
|
2
|
+
|
|
3
|
+
> 由 `sdd-flow-kit` 在 PRD run 脚手架时创建。与 `source/` 下 PRD 原型图配合使用。
|
|
4
|
+
|
|
5
|
+
## 用途
|
|
6
|
+
|
|
7
|
+
- 存放 **裁剪后的 UI 基线截图**(可选;也可直接引用 `source/**/image_N.png`)
|
|
8
|
+
- `05-验收清单.md` 中 `visual` 类型 AC 须在「验收标准」写明基线路径,例如:
|
|
9
|
+
- `列表页与基线 source/adi-v234/image_1.png 布局一致(diff≤2%)`
|
|
10
|
+
- `详情抽屉与 visual-baseline/finance-detail.png 一致(diff≤2%)`
|
|
11
|
+
|
|
12
|
+
## E2E 要求(v1.3.21 门禁)
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
await expect(page).toHaveScreenshot("finance-report-list.png", {
|
|
16
|
+
maxDiffPixelRatio: 0.02,
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- 须与 `[AC-xx]` 同处一个 test 块
|
|
21
|
+
- **禁止**仅用 `page.screenshot()` 代替 `toHaveScreenshot`
|
|
22
|
+
- Playwright 快照目录默认:`e2e/finance/*.spec.ts-snapshots/` 或与基线名一致
|
|
23
|
+
|
|
24
|
+
## 门禁
|
|
25
|
+
|
|
26
|
+
`assess-visual-regression.mjs` 在 deliver 阶段校验。
|
|
27
|
+
|
|
28
|
+
豁免:`tasks.md` 写 `VISUAL_REGRESSION_EXEMPT: <原因>` 或 `OPSX_SKIP_VISUAL_REGRESSION=1`
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
|------|------|
|
|
47
47
|
| `01` | 业务概述、范围、风险(**不承担**完整验收) |
|
|
48
48
|
| `05` | **唯一验收 SSOT**(从 `source/PRD.md` 逐条抽 AC) |
|
|
49
|
-
| `04` |
|
|
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
|
|
104
|
-
3.
|
|
105
|
-
4.
|
|
106
|
-
5.
|
|
107
|
-
6.
|
|
108
|
-
7.
|
|
109
|
-
8.
|
|
110
|
-
9.
|
|
111
|
-
10.
|
|
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
|
-
|
|
129
|
+
12. **`strictCommands=true` 时**:禁止用等价命令替代 NEXT.md 中的 gate/phase 链路(可与 full-chain 组合,不强制每阶段暂停)
|
|
116
130
|
|
|
117
131
|
---
|
|
118
132
|
|
|
@@ -0,0 +1,76 @@
|
|
|
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** 写明 normalize 位置 + **4.3.1 字段映射表**(| 后端字段 | 前端字段 |);`tests/fixtures/<module>/*.json` 放联调抓包样例
|
|
45
|
+
- 提交 payload 示例(JSON)
|
|
46
|
+
|
|
47
|
+
### §5 表单与校验
|
|
48
|
+
- 关键弹窗/编辑字段校验矩阵(必填、格式、错误文案)
|
|
49
|
+
|
|
50
|
+
### §2.5 视觉基线(PRD 含原型图时必填)
|
|
51
|
+
|
|
52
|
+
- 基线图路径:`source/.../image_N.png` 或 `visual-baseline/xxx.png`
|
|
53
|
+
- 在 `05-验收清单.md` 增加 `visual` 类型 AC,写明 `diff≤2%`
|
|
54
|
+
- E2E 使用 `toHaveScreenshot`,禁止仅 `page.screenshot`
|
|
55
|
+
|
|
56
|
+
- 边界场景、文件级改造清单(**禁止**只写一个大组件名)、风险表、发布检查、测试要点与 05 AC 对应、待确认项(无则写「无」)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## 禁止的反模式(gate 会失败)
|
|
61
|
+
|
|
62
|
+
| 反模式 | 示例 |
|
|
63
|
+
|--------|------|
|
|
64
|
+
| 摘要替换 | 仅 7 条 `## N. xxx [AC-xx]` 列表 |
|
|
65
|
+
| 删章节 | 缺少 §3/§5/§6/§8/§9/§11 |
|
|
66
|
+
| 无接口表 | §4 只有一句话「封装 api/modules」 |
|
|
67
|
+
| 无演示映射 | UI 需求但 §2.4 为空 |
|
|
68
|
+
| 详情一笔带过 | 「FinanceDetailDrawer」不提子模块(BD预估、红票、可编辑金额) |
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 与下游衔接
|
|
73
|
+
|
|
74
|
+
- Propose 时:`design.md` **复制** §2.4 映射表 + §4 接口决策
|
|
75
|
+
- `tasks.md`:**一行映射表 → 至少一条**「演示模块迁移」任务
|
|
76
|
+
- 实现:**禁止**用单文件只读骨架代替映射表中的多个生产组件
|
|
@@ -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
|
-
"""
|
|
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 =
|
|
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="{
|
|
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
|
|
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,
|
|
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 =
|
|
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"📁
|
|
920
|
-
print(f"
|
|
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,
|
|
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 =
|
|
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,79 @@
|
|
|
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-component-substance.mjs`(v1.3.19):组件非空壳(≥40 有效行、template 含控件、API/emit);Section/Modal 须被父组件 import
|
|
61
|
+
- `assess-ac-assertion-binding.mjs`(v1.3.19):P0 AC 的 05 验收标准字面量须出现在 test expect 中;禁止纯 manual P0
|
|
62
|
+
- `assess-e2e-assertion-depth.mjs`:E2E 须数据/交互断言;**可点击信号**须在 spec 中有 click/getByText(v1.3.19)
|
|
63
|
+
- 08 报告证据须指向 **具体组件文件 + 行号 + 交互文案**
|
|
64
|
+
|
|
65
|
+
## 05 验收清单
|
|
66
|
+
|
|
67
|
+
详情类 AC 验收标准须写清演示模块,例如:
|
|
68
|
+
|
|
69
|
+
- `详情 Tab「财务明细」含金额与返点卡片、财务链路、红票及其他(对齐演示 ProjectDetail.vue)`
|
|
70
|
+
- `BD预估区含编辑预估按钮,保存 toast「BD预估已保存」`
|
|
71
|
+
|
|
72
|
+
## 豁免
|
|
73
|
+
|
|
74
|
+
| 场景 | 写法 |
|
|
75
|
+
|------|------|
|
|
76
|
+
| 纯 API/配置 | `DEMO_REFERENCE_EXEMPT: 无 UI` |
|
|
77
|
+
| 演示待补 | 禁止进入 impl;须先补演示或用户书面确认 |
|
|
78
|
+
|
|
79
|
+
环境变量(仅紧急):`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
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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}}
|