@gordon.gan/specflow 1.4.3-beta → 1.4.4-beta
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 +1 -1
- package/dist/core/project-config.d.ts +4 -0
- package/dist/core/project-config.js +49 -0
- package/dist/core/project-conventions.d.ts +15 -0
- package/dist/core/project-conventions.js +66 -0
- package/package.json +1 -1
- package/prompts/approval/database-guidance.md +10 -8
- package/prompts/approval/frontend-guidance.md +249 -0
- package/prompts/approval/generate.md +291 -88
- package/prompts/approval/project-conventions-guidance.md +171 -0
- package/skills/GUIDANCE_PACKS.md +45 -24
- package/skills/database/README.md +11 -10
- package/skills/specflow-approval/SKILL.md +172 -82
- package/templates/approval.md +81 -310
package/README.md
CHANGED
|
@@ -126,7 +126,7 @@ npm install -g @gordon.gan/specflow
|
|
|
126
126
|
npm install -g github:Gordon-Gan-Jiang/specflow
|
|
127
127
|
|
|
128
128
|
# 验证
|
|
129
|
-
specflow --version # 以 npm / package.json 为准(当前 1.4.
|
|
129
|
+
specflow --version # 以 npm / package.json 为准(当前 1.4.4-beta)
|
|
130
130
|
specflow --help
|
|
131
131
|
```
|
|
132
132
|
|
|
@@ -6,6 +6,9 @@ export interface NormalizedReference {
|
|
|
6
6
|
readonly id: string;
|
|
7
7
|
readonly remote?: string;
|
|
8
8
|
}
|
|
9
|
+
export declare const CONVENTION_TOPICS: readonly ["architecture", "api", "database", "frontend"];
|
|
10
|
+
export type ConventionTopic = (typeof CONVENTION_TOPICS)[number];
|
|
11
|
+
export type ProjectConventions = Readonly<Partial<Record<ConventionTopic, readonly string[]>>>;
|
|
9
12
|
export interface ParsedProjectConfig {
|
|
10
13
|
readonly schema: string;
|
|
11
14
|
readonly context?: string;
|
|
@@ -14,6 +17,7 @@ export interface ParsedProjectConfig {
|
|
|
14
17
|
readonly workflowUpstream?: string;
|
|
15
18
|
readonly store?: string;
|
|
16
19
|
readonly references: readonly NormalizedReference[];
|
|
20
|
+
readonly conventions: ProjectConventions;
|
|
17
21
|
readonly diagnostics: readonly Diagnostic[];
|
|
18
22
|
}
|
|
19
23
|
export declare function parseProjectConfig(raw: unknown): ParsedProjectConfig;
|
|
@@ -12,6 +12,12 @@ const ReferenceObjectSchema = z
|
|
|
12
12
|
remote: z.string().url().optional(),
|
|
13
13
|
})
|
|
14
14
|
.strict();
|
|
15
|
+
export const CONVENTION_TOPICS = [
|
|
16
|
+
'architecture',
|
|
17
|
+
'api',
|
|
18
|
+
'database',
|
|
19
|
+
'frontend',
|
|
20
|
+
];
|
|
15
21
|
function referenceDiagnostic(message, target) {
|
|
16
22
|
return {
|
|
17
23
|
severity: 'warning',
|
|
@@ -155,6 +161,48 @@ export function parseProjectConfig(raw) {
|
|
|
155
161
|
fix: `Add '${workflowUpstream}' to specflow/config.yaml references.`,
|
|
156
162
|
});
|
|
157
163
|
}
|
|
164
|
+
const conventions = {};
|
|
165
|
+
if (record.conventions !== undefined) {
|
|
166
|
+
const conventionsRaw = typeof record.conventions === 'object' &&
|
|
167
|
+
record.conventions !== null &&
|
|
168
|
+
!Array.isArray(record.conventions)
|
|
169
|
+
? record.conventions
|
|
170
|
+
: undefined;
|
|
171
|
+
if (!conventionsRaw) {
|
|
172
|
+
diagnostics.push({
|
|
173
|
+
severity: 'error',
|
|
174
|
+
code: 'invalid_conventions_config',
|
|
175
|
+
message: 'Project conventions must be an object of topic → path arrays.',
|
|
176
|
+
target: 'config.conventions',
|
|
177
|
+
fix: 'Use conventions.architecture|api|database|frontend: [relative/path.md].',
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
for (const topic of CONVENTION_TOPICS) {
|
|
182
|
+
const value = conventionsRaw[topic];
|
|
183
|
+
if (value === undefined) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (!Array.isArray(value) || !value.every((item) => typeof item === 'string')) {
|
|
187
|
+
diagnostics.push({
|
|
188
|
+
severity: 'error',
|
|
189
|
+
code: 'invalid_conventions_topic',
|
|
190
|
+
message: `conventions.${topic} must be an array of relative file path strings.`,
|
|
191
|
+
target: `config.conventions.${topic}`,
|
|
192
|
+
fix: `Set conventions.${topic} to e.g. ['docs/engineering/${topic}.md'].`,
|
|
193
|
+
});
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
const paths = value
|
|
197
|
+
.map((item) => item.trim())
|
|
198
|
+
.filter((item) => item.length > 0)
|
|
199
|
+
.slice(0, 3);
|
|
200
|
+
if (paths.length > 0) {
|
|
201
|
+
conventions[topic] = paths;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
158
206
|
return {
|
|
159
207
|
schema,
|
|
160
208
|
context,
|
|
@@ -163,6 +211,7 @@ export function parseProjectConfig(raw) {
|
|
|
163
211
|
workflowUpstream,
|
|
164
212
|
store,
|
|
165
213
|
references,
|
|
214
|
+
conventions,
|
|
166
215
|
diagnostics,
|
|
167
216
|
};
|
|
168
217
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ConventionTopic, type ProjectConventions } from './project-config.js';
|
|
2
|
+
export type IdeFlavor = 'cursor' | 'claude' | 'codex';
|
|
3
|
+
/**
|
|
4
|
+
* Resolves project convention files for an approval topic.
|
|
5
|
+
* Priority: config conventions.<topic> → repo-neutral docs.
|
|
6
|
+
* IDE-specific rule/skill globs are documented for the agent to scan; this helper
|
|
7
|
+
* covers the deterministic, config + neutral paths used in tests and tooling.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveProjectConventionPaths(input: {
|
|
10
|
+
readonly projectRoot: string;
|
|
11
|
+
readonly topic: ConventionTopic;
|
|
12
|
+
readonly conventions?: ProjectConventions;
|
|
13
|
+
}): readonly string[];
|
|
14
|
+
export declare function listConventionTopics(): readonly ConventionTopic[];
|
|
15
|
+
export declare function neutralCandidatesFor(topic: ConventionTopic): readonly string[];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { CONVENTION_TOPICS, } from './project-config.js';
|
|
4
|
+
const NEUTRAL_CANDIDATES = {
|
|
5
|
+
architecture: [
|
|
6
|
+
'docs/engineering/architecture.md',
|
|
7
|
+
'.specflow/conventions/architecture.md',
|
|
8
|
+
'ARCHITECTURE.md',
|
|
9
|
+
],
|
|
10
|
+
api: [
|
|
11
|
+
'docs/api/guidelines.md',
|
|
12
|
+
'docs/engineering/api.md',
|
|
13
|
+
'.specflow/conventions/api.md',
|
|
14
|
+
],
|
|
15
|
+
database: [
|
|
16
|
+
'docs/db/conventions.md',
|
|
17
|
+
'docs/engineering/database.md',
|
|
18
|
+
'.specflow/conventions/database.md',
|
|
19
|
+
],
|
|
20
|
+
frontend: [
|
|
21
|
+
'docs/frontend/conventions.md',
|
|
22
|
+
'docs/frontend/patterns.md',
|
|
23
|
+
'docs/frontend/testing.md',
|
|
24
|
+
'docs/engineering/frontend.md',
|
|
25
|
+
'.specflow/conventions/frontend.md',
|
|
26
|
+
'agent_docs/tech_stack.md',
|
|
27
|
+
'agent_docs/code_patterns.md',
|
|
28
|
+
'agent_docs/testing.md',
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
const MAX_FILES_PER_TOPIC = 3;
|
|
32
|
+
function existingRelative(projectRoot, relativePaths) {
|
|
33
|
+
const found = [];
|
|
34
|
+
for (const relative of relativePaths) {
|
|
35
|
+
const normalized = relative.replace(/^\.\//, '').replace(/\\/g, '/');
|
|
36
|
+
if (!normalized || normalized.includes('..')) {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (existsSync(join(projectRoot, ...normalized.split('/')))) {
|
|
40
|
+
found.push(normalized);
|
|
41
|
+
}
|
|
42
|
+
if (found.length >= MAX_FILES_PER_TOPIC) {
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return found;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolves project convention files for an approval topic.
|
|
50
|
+
* Priority: config conventions.<topic> → repo-neutral docs.
|
|
51
|
+
* IDE-specific rule/skill globs are documented for the agent to scan; this helper
|
|
52
|
+
* covers the deterministic, config + neutral paths used in tests and tooling.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveProjectConventionPaths(input) {
|
|
55
|
+
const configured = input.conventions?.[input.topic];
|
|
56
|
+
if (configured && configured.length > 0) {
|
|
57
|
+
return existingRelative(input.projectRoot, configured.slice(0, MAX_FILES_PER_TOPIC));
|
|
58
|
+
}
|
|
59
|
+
return existingRelative(input.projectRoot, NEUTRAL_CANDIDATES[input.topic]);
|
|
60
|
+
}
|
|
61
|
+
export function listConventionTopics() {
|
|
62
|
+
return CONVENTION_TOPICS;
|
|
63
|
+
}
|
|
64
|
+
export function neutralCandidatesFor(topic) {
|
|
65
|
+
return NEUTRAL_CANDIDATES[topic];
|
|
66
|
+
}
|
package/package.json
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
# Approval · Database Guidance Router
|
|
2
2
|
|
|
3
|
-
>
|
|
4
|
-
>
|
|
5
|
-
>
|
|
6
|
-
> **禁止**依赖远程 skill
|
|
7
|
-
> **Not** an MCP tool — on hit, `Read` local matched skill files; on miss, LLM-only §4.4.
|
|
8
|
-
> **禁止**写成「invoke `/mysql` skill」——一律 `Read` 路径。
|
|
3
|
+
> **本地技能**: SpecFlow pack 在 `{ide}/specflow/guidance/database/`(见 `skills/guidance-packs.yaml`)。
|
|
4
|
+
> **项目约定**: 写 §4.4 **之前**还须执行 `prompts/approval/project-conventions-guidance.md`(`topic=database`)。
|
|
5
|
+
> **优先级**: 项目约定 + 现网 DDL **>** 本文件 SpecFlow guidance **>** LLM-fallback。
|
|
6
|
+
> **禁止**依赖远程 skill 仓库; **Not** an MCP tool; 禁止「invoke `/mysql` skill」。
|
|
9
7
|
|
|
10
8
|
---
|
|
11
9
|
|
|
@@ -58,6 +56,9 @@ Guidance: <.cursor|claude|agents>/specflow/guidance/database/<stack>/SKILL.md
|
|
|
58
56
|
|
|
59
57
|
## 3. On hit — load **local** guidance (Read, do not invent, do not fetch)
|
|
60
58
|
|
|
59
|
+
> 先完成 `project-conventions-guidance.md` 的 `topic=database` 解析并 Read 项目约定(若有)。
|
|
60
|
+
> 本表仅加载 **SpecFlow** guidance pack,用于补强 DDL 写法;不得覆盖项目禁令。
|
|
61
|
+
|
|
61
62
|
Base = resolved `guidanceRoot` above. From that directory:
|
|
62
63
|
|
|
63
64
|
| Stack | Must Read | Also Read when §4.4 needs it |
|
|
@@ -76,8 +77,9 @@ Apply guidance to §4.4 output:
|
|
|
76
77
|
2. Prefer type/index gotchas from the skill (e.g. DECIMAL for money, no FLOAT amounts).
|
|
77
78
|
3. Keep SpecFlow hard rules (ER, full CREATE TABLE, 本迭代用法, G3/G4) — skill **supplements**, does not replace.
|
|
78
79
|
|
|
79
|
-
Cite in §4.4 总则 the **actual**
|
|
80
|
-
|
|
80
|
+
Cite in §4.4 总则 the **actual** paths used:
|
|
81
|
+
- `项目约定: <path…> | 未发现`
|
|
82
|
+
- `DB 技能: .cursor/specflow/guidance/database/mysql` 或 `skills/database/mysql (package fallback)` 或 `LLM-fallback`
|
|
81
83
|
|
|
82
84
|
---
|
|
83
85
|
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
# Approval · Frontend Guidance Router
|
|
2
|
+
|
|
3
|
+
> Used by `/specflow:approval` when the change touches **UI / 控制台 / 页面 / 组件**.
|
|
4
|
+
> **项目约定**: 写 **§4.6** 前必须执行 `project-conventions-guidance.md`(`topic=frontend`),
|
|
5
|
+
> **并**按本文件 §3 补扫 IDE skills / rules / 落地规约(组件、样式、表单、测试等)。
|
|
6
|
+
> **优先级**: 项目约定 + IDE skills/rules + 现网页面/组件/路由 **>** 本文件结构硬门槛 **>** LLM。
|
|
7
|
+
> **Not** an MCP tool; **禁止** `invoke /react` 之类 IDE skill 口号 —— 一律解析路径后 `Read`。
|
|
8
|
+
> 灵感对齐 vibe-coding Part3 Frontend(栈五元组 / 目录分层 / Visual Loop),**不**搬 MVP 访谈问卷。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 1. Detect `uiInScope`
|
|
13
|
+
|
|
14
|
+
Scan proposal / design / tasks / specs (and Tech Stack Intake answers) for UI signals:
|
|
15
|
+
|
|
16
|
+
| Signal (any) | Meaning |
|
|
17
|
+
|--------------|---------|
|
|
18
|
+
| 控制台 / 前端 / UI / 页面 / 路由 / 组件 / 表单 / 弹窗 | UI work in scope |
|
|
19
|
+
| `*.tsx` / `*.vue` / `*.svelte` / `pages/` / `app/` router paths in tasks | UI work in scope |
|
|
20
|
+
| §2.2 前端行非「不涉及」 | UI work in scope |
|
|
21
|
+
| Explicit「不涉及前端」+ no UI paths | `uiInScope=false` |
|
|
22
|
+
|
|
23
|
+
**Announce**:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
UI in scope for approval: yes | no
|
|
27
|
+
FE stack: <detected or user-confirmed or unknown>
|
|
28
|
+
Project conventions (frontend): <paths…> | none
|
|
29
|
+
IDE FE skills/rules: <paths…> | none
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
If `uiInScope=no` → omit entire §4.6 from `approval.md`(write one line under detailed design
|
|
33
|
+
optional checklist only if needed: `不涉及前端/UI 变更`). Do **not** invent pages.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 2. Detect frontend stack (signals)
|
|
38
|
+
|
|
39
|
+
Project root / common app dirs (non-recursive first; optional `apps/*` / `web/` / `frontend/` one level):
|
|
40
|
+
|
|
41
|
+
| Signal | Suggested FE |
|
|
42
|
+
|--------|--------------|
|
|
43
|
+
| `next` / `next.config.*` | Next.js |
|
|
44
|
+
| `vite` + `react` | React + Vite |
|
|
45
|
+
| `vue` / `nuxt` | Vue / Nuxt |
|
|
46
|
+
| `svelte` / `@sveltejs/kit` | Svelte / SvelteKit |
|
|
47
|
+
| `@angular/core` | Angular |
|
|
48
|
+
| `react-native` / `expo` | React Native |
|
|
49
|
+
| `tailwindcss` | Styling: Tailwind |
|
|
50
|
+
| `zustand` / `@reduxjs/toolkit` / `pinia` / `jotai` | State hint |
|
|
51
|
+
| `shadcn` / `@mui` / `antd` / `element-plus` | UI kit hint |
|
|
52
|
+
|
|
53
|
+
Record a **五元组** for §2.2 / §4.6.1 (fill unknowns via Intake, never invent):
|
|
54
|
+
|
|
55
|
+
1. **Framework** — e.g. React+TS / Next.js / Vue3
|
|
56
|
+
2. **Styling** — Tailwind / CSS Modules / 现网设计系统
|
|
57
|
+
3. **State** — Zustand / Redux / Pinia / 仅服务端状态 …
|
|
58
|
+
4. **UI kit** — shadcn / Ant Design / 公司组件库 / Custom
|
|
59
|
+
5. **FE testing** — Vitest+RTL / Playwright / Cypress / 项目现网命令
|
|
60
|
+
|
|
61
|
+
If `uiInScope=yes` and any of Framework / Styling / State is still unknown after artifacts +
|
|
62
|
+
signals → **STOP** and ask (merge into Tech Stack Intake; do not invent):
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
本变更含前端/UI,请补全前端技术选型(可写「沿用现网」):
|
|
66
|
+
1. Framework / 语言
|
|
67
|
+
2. Styling / 设计系统
|
|
68
|
+
3. 状态管理(client vs server state 偏好)
|
|
69
|
+
4. UI 组件库(或公司内部库)
|
|
70
|
+
5. 前端验证方式(单测 / 组件测 / E2E / browser 手测命令)
|
|
71
|
+
6.(可选)若用 v0/Lovable 等 AI builder 起稿:导出与本地可构建计划
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
## 3. Load implementation conventions (项目约定 + IDE skills/rules + 落地文档)
|
|
77
|
+
|
|
78
|
+
> **目的**:§4.6 不是只选栈,还要让 apply 阶段能按**本仓真实落地规约**写页面/组件。
|
|
79
|
+
> **硬规则**:`uiInScope=yes` 时,起草 §4.6 **之前**必须完成本节;禁止跳过 IDE skills/rules 扫描。
|
|
80
|
+
> **预算**:合计最多 **Read 5 个文件**(配置路径优先占满预算;细节 reference 仅入口点名后再读,禁止链式跳转)。
|
|
81
|
+
|
|
82
|
+
### 3.1 加载顺序(固定)
|
|
83
|
+
|
|
84
|
+
1. **`project-conventions-guidance.md` `topic=frontend`**
|
|
85
|
+
- 先 `specflow/config.yaml` → `conventions.frontend`
|
|
86
|
+
- 再仓根中立 docs(见该路由 §2.2)
|
|
87
|
+
2. **IDE skills / rules / 记忆文件**(本会话 `activeIde` 优先,再 cursor → claude → agents 回退)
|
|
88
|
+
3. **落地向 agent/工程文档**(若尚未纳入预算)
|
|
89
|
+
4. **现网锚点**(Pass 6:路由/布局/API client,**仅读 design/tasks 点名的文件**)
|
|
90
|
+
|
|
91
|
+
**Priority**: ① 项目约定 + IDE skills/rules + 现网 UI **>** ② §4.6 骨架 **>** ③ LLM。
|
|
92
|
+
|
|
93
|
+
### 3.2 必须覆盖的「开发落地」主题(按需匹配文件)
|
|
94
|
+
|
|
95
|
+
扫描/选取文件时,优先覆盖下列维度(有则 Read,无则在 §4.6.1 写「未发现」——**禁止臆造**):
|
|
96
|
+
|
|
97
|
+
| 落地维度 | 写入 §4.6 何处 | 典型关键词 / 文件名线索 |
|
|
98
|
+
|----------|----------------|-------------------------|
|
|
99
|
+
| 目录与命名(components/features/pages) | 4.6.1 / 4.6.3 | `structure`, `folder`, `naming`, `feature-based` |
|
|
100
|
+
| 组件边界与复用(ui vs features) | 4.6.3 | `component`, `design.?system`, `shadcn`, `storybook` |
|
|
101
|
+
| 路由 / 信息架构 | 4.6.2 | `router`, `routing`, `app.?router`, `pages` |
|
|
102
|
+
| 状态与数据获取 | 4.6.4 | `state`, `zustand`, `redux`, `react.?query`, `swr`, `pinia` |
|
|
103
|
+
| 表单与校验 | 4.6.3 / 4.6.4 | `form`, `zod`, `yup`, `validation`, `rhf` |
|
|
104
|
+
| API client / 错误呈现(Toast/Alert) | 4.6.3 / 4.6.4 + 挂 §4.5 | `api.?client`, `fetch`, `axios`, `toast`, `error.?boundary` |
|
|
105
|
+
| 样式 / Token / 主题 | 4.6.1 / 4.6.5 | `tailwind`, `css`, `theme`, `token`, `styled` |
|
|
106
|
+
| 无障碍 / 响应式 | 4.6.5 | `a11y`, `accessibility`, `responsive`, `breakpoint` |
|
|
107
|
+
| i18n | 4.6.1 备注 / 4.6.3 | `i18n`, `locale`, `intl` |
|
|
108
|
+
| 测试与 Visual Loop 命令 | 4.6.5 + §6 | `vitest`, `playwright`, `cypress`, `rtl`, `testing`, `e2e` |
|
|
109
|
+
| Lint / format 禁令 | §2.1 约束 + 4.6.1 | `eslint`, `prettier`, `stylelint`, `biome` |
|
|
110
|
+
|
|
111
|
+
### 3.3 IDE 扫描清单(解析路径后 Read,禁止 invoke)
|
|
112
|
+
|
|
113
|
+
对每个命中路径:**先看文件名/frontmatter `name`/`description`/首段标题**,与上表关键词匹配再纳入预算。
|
|
114
|
+
|
|
115
|
+
**Cursor**
|
|
116
|
+
|
|
117
|
+
| 类型 | 路径模式 |
|
|
118
|
+
|------|----------|
|
|
119
|
+
| Rules | `.cursor/rules/**/*.mdc`(及 `.md`) |
|
|
120
|
+
| Skills | `.cursor/skills/**/SKILL.md` |
|
|
121
|
+
| 其它 | `.cursor/rules` 下与 FE 相关的聚合 rule |
|
|
122
|
+
|
|
123
|
+
**Claude**
|
|
124
|
+
|
|
125
|
+
| 类型 | 路径模式 |
|
|
126
|
+
|------|----------|
|
|
127
|
+
| Skills | `.claude/skills/**/SKILL.md` |
|
|
128
|
+
| Rules | `.claude/rules/**/*` |
|
|
129
|
+
| 记忆 | `CLAUDE.md` / `.claude/CLAUDE.md`(只抽取 FE 相关章节,勿整文件灌入上下文) |
|
|
130
|
+
|
|
131
|
+
**Codex**
|
|
132
|
+
|
|
133
|
+
| 类型 | 路径模式 |
|
|
134
|
+
|------|----------|
|
|
135
|
+
| Skills | `.agents/skills/**/SKILL.md` |
|
|
136
|
+
| 记忆 | `AGENTS.md`(只抽取 FE 相关段落) |
|
|
137
|
+
|
|
138
|
+
**仓根 / 中立落地文档(补充候选,与 conventions 路由合并去重)**
|
|
139
|
+
|
|
140
|
+
| 路径 |
|
|
141
|
+
|------|
|
|
142
|
+
| `docs/frontend/**/*.md`(优先 `conventions.md` / `patterns.md` / `testing.md`) |
|
|
143
|
+
| `docs/engineering/frontend.md` |
|
|
144
|
+
| `.specflow/conventions/frontend.md` |
|
|
145
|
+
| `agent_docs/tech_stack.md` |
|
|
146
|
+
| `agent_docs/code_patterns.md` |
|
|
147
|
+
| `agent_docs/testing.md` |
|
|
148
|
+
| `REVIEW-CHECKLIST.md`(仅 UI/前端相关条目) |
|
|
149
|
+
|
|
150
|
+
**关键词**(文件名 + 标题 + skill description,大小写不敏感):
|
|
151
|
+
|
|
152
|
+
```text
|
|
153
|
+
frontend|front-end|ui|ux|react|vue|next|nuxt|svelte|angular|
|
|
154
|
+
tailwind|component|design-system|design system|css|style|
|
|
155
|
+
router|routing|form|zod|state|zustand|redux|pinia|query|
|
|
156
|
+
playwright|vitest|cypress|testing-library|a11y|accessibility|
|
|
157
|
+
i18n|控制台|前端|页面|组件|样式|表单|路由
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### 3.4 选取与冲突
|
|
161
|
+
|
|
162
|
+
1. `conventions.frontend` 配置路径 **最先占用预算**。
|
|
163
|
+
2. 其次 activeIde 命中的 skill/rule(每类优先 1–2 个最相关)。
|
|
164
|
+
3. 再补仓根 `agent_docs/*` / `docs/frontend/*`。
|
|
165
|
+
4. 同主题多文件内容冲突 → **以 config / 仓根中立 docs 为准**,IDE skill 仅作补充;在 §4.6.1 注明。
|
|
166
|
+
5. 发现硬禁令(例:「禁止新建全局 CSS」「必须用公司 Button」)→ 写入 §2.1 与 §4.6,违反则 chat/`§8` WARNING。
|
|
167
|
+
|
|
168
|
+
### 3.5 写入总则
|
|
169
|
+
|
|
170
|
+
Cite in §4.6.1:
|
|
171
|
+
|
|
172
|
+
| 项 | 填法 |
|
|
173
|
+
|----|------|
|
|
174
|
+
| 项目约定 | config + 中立 docs 路径,`; ` 分隔 / **未发现** |
|
|
175
|
+
| IDE skills/rules | 实际 Read 的 skill/rule 路径 / **未发现** |
|
|
176
|
+
| FE 栈 | 五元组摘要 \| 用户确认 \| 沿用现网 |
|
|
177
|
+
|
|
178
|
+
Announce 示例:
|
|
179
|
+
|
|
180
|
+
```text
|
|
181
|
+
Project conventions (frontend): docs/frontend/conventions.md
|
|
182
|
+
IDE FE skills/rules: .cursor/rules/frontend.mdc; .cursor/skills/ui-patterns/SKILL.md
|
|
183
|
+
Conflict policy: project > IDE conventions > SpecFlow §4.6 skeleton > LLM
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 4. §4.6 output contract (when `uiInScope=yes`)
|
|
189
|
+
|
|
190
|
+
Follow `generate.md` §4.6 exactly. Outline hygiene:
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
### 4.6 前端 / UI 设计
|
|
194
|
+
├── #### 4.6.1 总则与本迭代结论
|
|
195
|
+
├── #### 4.6.2 信息架构与路由
|
|
196
|
+
├── #### 4.6.3 关键页面 / 组件详设
|
|
197
|
+
│ └── ##### Page · <短名> ← 每页仅此一级标题
|
|
198
|
+
├── #### 4.6.4 状态与数据获取
|
|
199
|
+
└── #### 4.6.5 视觉与验证回路
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Labels such as「空态」「加载」「错误」「依赖接口」are `**bold**`, never extra headings.
|
|
203
|
+
|
|
204
|
+
Apply loaded conventions into the body:
|
|
205
|
+
|
|
206
|
+
- 目录/命名禁令 → 4.6.1「本迭代不涉及」与 4.6.3 组件边界
|
|
207
|
+
- 状态/表单/API client 模式 → 4.6.4(写「采用项目约定:<path>」)
|
|
208
|
+
- a11y/响应式/测试命令 → 4.6.5
|
|
209
|
+
- **禁止**把 skill 原文整段粘贴进 approval;用可读中文转述硬约束
|
|
210
|
+
|
|
211
|
+
**Quality gates (UI path)**:
|
|
212
|
+
|
|
213
|
+
| ID | Rule |
|
|
214
|
+
|----|------|
|
|
215
|
+
| **G5** | 必须有本迭代**页面/路由清单**(禁止只写「用 React」) |
|
|
216
|
+
| **G6** | 每个关键 `Page · …` 至少覆盖 **空态 / 加载 / 错误** 之一,并标明依赖的 §4.5 `In` |
|
|
217
|
+
|
|
218
|
+
**Visual Verification Loop** (write into §4.6.5 + feed §6 when useful):
|
|
219
|
+
|
|
220
|
+
1. **Generate** — AI/人产出组件
|
|
221
|
+
2. **Render** — dev server 或 headless browser
|
|
222
|
+
3. **Inspect** — 截图 / 设计原则 / a11y 抽查
|
|
223
|
+
4. **Refine** — 修视觉与交互回归后再合入
|
|
224
|
+
|
|
225
|
+
Record exact `dev` / `test` / `browser` commands when known (from conventions / IDE skills / Intake).
|
|
226
|
+
|
|
227
|
+
**Builder exit** (only if AI builder used): source ownership + local install/dev/test + secrets
|
|
228
|
+
handling + exit plan — put under §4.6.1 备注 or §2.5 风险; do not pad marketing lists.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 5. Cross-links
|
|
233
|
+
|
|
234
|
+
- Pages that call APIs **must** reference §4.5 interface numbers (`I1…`).
|
|
235
|
+
- User journeys in §1.3 / Happy Path §4.2 should name the same pages.
|
|
236
|
+
- §3 architecture may show「控制台 / Web」box; details live in §4.6, not duplicated as
|
|
237
|
+
code-dump trees in §2.1.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 6. On miss / fallback
|
|
242
|
+
|
|
243
|
+
| Case | Action |
|
|
244
|
+
|------|--------|
|
|
245
|
+
| `uiInScope=no` | Omit §4.6 |
|
|
246
|
+
| `uiInScope=yes`, no conventions / no IDE FE skills | Draft §4.6 with skeleton + Intake;`项目约定: 未发现`;`IDE skills/rules: 未发现`; chat 可 WARNING 建议补 `docs/frontend/conventions.md` 或 Cursor rule |
|
|
247
|
+
| User refuses FE selection while UI required | `[待 refine 澄清: 前端技术选型]`; do not fabricate page trees |
|
|
248
|
+
| Only API change, no UI | §4.5 only; §4.6 omitted |
|
|
249
|
+
| IDE skill 与仓根约定冲突 | 仓根/config 优先;记 WARNING |
|