speccore 6.72.0 → 6.74.0
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 +12 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts +2 -0
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +118 -9
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/change.d.ts +10 -0
- package/dist/commands/change.d.ts.map +1 -1
- package/dist/commands/change.js +532 -205
- package/dist/commands/change.js.map +1 -1
- package/dist/core/ai-impact-analyzer.d.ts +127 -0
- package/dist/core/ai-impact-analyzer.d.ts.map +1 -0
- package/dist/core/ai-impact-analyzer.js +531 -0
- package/dist/core/ai-impact-analyzer.js.map +1 -0
- package/dist/core/change-inbox.d.ts +80 -0
- package/dist/core/change-inbox.d.ts.map +1 -0
- package/dist/core/change-inbox.js +352 -0
- package/dist/core/change-inbox.js.map +1 -0
- package/dist/core/change-parser.d.ts +27 -0
- package/dist/core/change-parser.d.ts.map +1 -0
- package/dist/core/change-parser.js +248 -0
- package/dist/core/change-parser.js.map +1 -0
- package/dist/core/streaming-analyzer.d.ts +72 -0
- package/dist/core/streaming-analyzer.d.ts.map +1 -0
- package/dist/core/streaming-analyzer.js +658 -0
- package/dist/core/streaming-analyzer.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* streaming-analyzer — 流式全局分析引擎(v6.74.0)
|
|
4
|
+
*
|
|
5
|
+
* 把"四层批处理"升级为"七阶段流处理":
|
|
6
|
+
* Phase 0: 快速全局扫描(所有端并行索引)
|
|
7
|
+
* Phase 1: 后端拓扑排序分析(从依赖源头开始,逐模块深入)
|
|
8
|
+
* Phase 2: 后端完成后全局实时更新
|
|
9
|
+
* Phase 3: 前端逐个分析
|
|
10
|
+
* Phase 4: 横向关联检查(前后端字段/接口一致性)
|
|
11
|
+
* Phase 5: 纵向关联检查(功能模块跨端完整性)
|
|
12
|
+
* Phase 6: 最终核对检查(完整性 + 一致性 + 遗漏检测)
|
|
13
|
+
*
|
|
14
|
+
* 核心机制:
|
|
15
|
+
* - 每 Phase 产出写入文件,作为后续 Phase 的输入
|
|
16
|
+
* - 实时关联调整:当前 Phase 发现与前期文档冲突时,提示回退修正
|
|
17
|
+
* - 知识图谱实时刷新:每 Phase 完成后刷新图谱
|
|
18
|
+
*/
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
exports.DEFAULT_STREAMING_CONFIG = void 0;
|
|
21
|
+
exports.buildPhasePrompt = buildPhasePrompt;
|
|
22
|
+
exports.detectBacktrackingNeeds = detectBacktrackingNeeds;
|
|
23
|
+
exports.runFinalAudit = runFinalAudit;
|
|
24
|
+
exports.getPhaseSequence = getPhaseSequence;
|
|
25
|
+
exports.getPhaseDisplayName = getPhaseDisplayName;
|
|
26
|
+
exports.detectBackendDependencyOrder = detectBackendDependencyOrder;
|
|
27
|
+
const path_1 = require("path");
|
|
28
|
+
const fs_extra_1 = require("fs-extra");
|
|
29
|
+
const spec_paths_1 = require("./spec-paths");
|
|
30
|
+
exports.DEFAULT_STREAMING_CONFIG = {
|
|
31
|
+
enableRealtimeUpdate: true,
|
|
32
|
+
enableBacktrack: true,
|
|
33
|
+
enableFinalAudit: true,
|
|
34
|
+
backendFirst: true,
|
|
35
|
+
};
|
|
36
|
+
// ── Phase Prompt 生成 ──
|
|
37
|
+
/**
|
|
38
|
+
* 生成指定 Phase 的 Prompt
|
|
39
|
+
*/
|
|
40
|
+
async function buildPhasePrompt(ctx) {
|
|
41
|
+
switch (ctx.phase) {
|
|
42
|
+
case 'phase0-scan':
|
|
43
|
+
return buildPhase0Prompt(ctx);
|
|
44
|
+
case 'phase1-backend':
|
|
45
|
+
return buildPhase1Prompt(ctx);
|
|
46
|
+
case 'phase2-global-update':
|
|
47
|
+
return buildPhase2Prompt(ctx);
|
|
48
|
+
case 'phase3-frontend':
|
|
49
|
+
return buildPhase3Prompt(ctx);
|
|
50
|
+
case 'phase4-cross-check':
|
|
51
|
+
return buildPhase4Prompt(ctx);
|
|
52
|
+
case 'phase5-vertical-check':
|
|
53
|
+
return buildPhase5Prompt(ctx);
|
|
54
|
+
case 'phase6-final-audit':
|
|
55
|
+
return buildPhase6Prompt(ctx);
|
|
56
|
+
default:
|
|
57
|
+
return '';
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** Phase 0: 快速全局扫描 — 所有端并行,只提取索引 */
|
|
61
|
+
function buildPhase0Prompt(ctx) {
|
|
62
|
+
const { platforms, platformTypes } = ctx;
|
|
63
|
+
let prompt = `\n# Phase 0: 快速全局扫描(建立全局视野)\n\n`;
|
|
64
|
+
prompt += `## 目标\n`;
|
|
65
|
+
prompt += `快速扫描所有端,建立全局索引,不深入代码逻辑。产出各端 \_INDEX.md。\n\n`;
|
|
66
|
+
prompt += `## 扫描范围\n`;
|
|
67
|
+
prompt += `项目共有 ${platforms.length} 个端: ${platforms.join(', ')}\n\n`;
|
|
68
|
+
for (const platform of platforms) {
|
|
69
|
+
const pType = platformTypes.get(platform) || 'unknown';
|
|
70
|
+
const isBackend = pType.includes('service') || pType.includes('Java') || pType.includes('Node') || pType.includes('Go') || pType.includes('Python');
|
|
71
|
+
const isFrontend = !isBackend;
|
|
72
|
+
prompt += `### ${platform} (${pType})\n`;
|
|
73
|
+
if (isBackend) {
|
|
74
|
+
prompt += `- 读取 Controller/Handler/Resource 目录文件列表 → 提取接口类名、接口路径\n`;
|
|
75
|
+
prompt += `- 读取 Entity/Model/Schema 目录文件列表 → 提取实体名称、表名\n`;
|
|
76
|
+
prompt += `- 读取 Service/UseCase 目录文件列表 → 提取服务类名\n`;
|
|
77
|
+
prompt += `- 读取依赖配置文件 → 提取技术栈和外部依赖\n`;
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
prompt += `- 读取 router/routes 配置文件 → 提取页面路径、页面名称\n`;
|
|
81
|
+
prompt += `- 读取 pages/views 目录文件列表 → 提取页面名称、主要功能\n`;
|
|
82
|
+
prompt += `- 搜索 API 调用模式 → 提取调用的接口路径列表\n`;
|
|
83
|
+
prompt += `- 读取状态管理目录 → 提取全局状态名称\n`;
|
|
84
|
+
}
|
|
85
|
+
prompt += `\n`;
|
|
86
|
+
}
|
|
87
|
+
prompt += `## 输出要求\n`;
|
|
88
|
+
prompt += `每个端一个 \_INDEX.md,只含名称和路径列表:\n`;
|
|
89
|
+
prompt += `- 后端端:接口列表、实体列表、服务列表、依赖列表\n`;
|
|
90
|
+
prompt += `- 前端端:页面列表、API调用列表、状态列表、组件列表\n`;
|
|
91
|
+
prompt += `**存放**: \`.speccore/GLOBAL/platforms/{端名}/_INDEX.md\`\n\n`;
|
|
92
|
+
prompt += `## 回写命令\n`;
|
|
93
|
+
prompt += `\`\`\`bash\n`;
|
|
94
|
+
for (const platform of platforms) {
|
|
95
|
+
prompt += `speccore analyze --apply '{"${platform}/_INDEX.md":"..."}' -I ${ctx.iteration} --global\n`;
|
|
96
|
+
}
|
|
97
|
+
prompt += `\`\`\`\n\n`;
|
|
98
|
+
prompt += `> ⚠️ 注意:Phase 0 只提取索引,不写详细逻辑。详细分析在后续 Phase 中进行。\n`;
|
|
99
|
+
return prompt;
|
|
100
|
+
}
|
|
101
|
+
/** Phase 1: 后端拓扑排序分析 — 从依赖源头开始,逐模块深入 */
|
|
102
|
+
function buildPhase1Prompt(ctx) {
|
|
103
|
+
const { platforms, platformTypes, iteration } = ctx;
|
|
104
|
+
const backendPlatforms = platforms.filter(p => {
|
|
105
|
+
const t = platformTypes.get(p) || '';
|
|
106
|
+
return t.includes('service') || t.includes('Java') || t.includes('Node') || t.includes('Go') || t.includes('Python') || t.includes('后端');
|
|
107
|
+
});
|
|
108
|
+
let prompt = `\n# Phase 1: 后端深度分析(拓扑排序,从依赖源头开始)\n\n`;
|
|
109
|
+
prompt += `## 目标\n`;
|
|
110
|
+
prompt += `深入分析每个后端端,从依赖关系最源头的服务开始,逐个模块分析。\n\n`;
|
|
111
|
+
if (backendPlatforms.length === 0) {
|
|
112
|
+
prompt += `> 未检测到后端端,跳过 Phase 1,直接进入 Phase 3(前端分析)。\n`;
|
|
113
|
+
return prompt;
|
|
114
|
+
}
|
|
115
|
+
prompt += `## 后端端列表(${backendPlatforms.length} 个)\n`;
|
|
116
|
+
for (const p of backendPlatforms) {
|
|
117
|
+
prompt += `- ${p} (${platformTypes.get(p) || 'unknown'})\n`;
|
|
118
|
+
}
|
|
119
|
+
prompt += `\n`;
|
|
120
|
+
prompt += `## 分析顺序原则\n`;
|
|
121
|
+
prompt += `1. **先分析不依赖其他后端服务的端**(最源头的服务,如 user-service、auth-service)\n`;
|
|
122
|
+
prompt += `2. **再分析依赖已分析服务的端**(如 booking-service 依赖 room-service,则 room-service 先分析)\n`;
|
|
123
|
+
prompt += `3. **最后分析网关/聚合层**(如 api-gateway、BFF 层)\n`;
|
|
124
|
+
prompt += `4. 如果无法确定依赖关系,按字母顺序分析\n\n`;
|
|
125
|
+
prompt += `## 每个后端端的分析内容(必须深入)\n`;
|
|
126
|
+
prompt += `基于 Phase 0 的 \_INDEX.md,逐个端深入分析:\n\n`;
|
|
127
|
+
prompt += `### 1. API 详细设计\n`;
|
|
128
|
+
prompt += `- 每个接口:路径、HTTP方法、请求参数(名称/类型/必填/校验规则)、响应结构\n`;
|
|
129
|
+
prompt += `- 状态码定义(200/400/401/403/404/409/500 等场景)\n`;
|
|
130
|
+
prompt += `- 错误码定义(统一格式,跨端一致)\n`;
|
|
131
|
+
prompt += `- 鉴权要求(哪些接口需要登录/权限)\n\n`;
|
|
132
|
+
prompt += `### 2. 数据模型设计\n`;
|
|
133
|
+
prompt += `- 每个实体:表名、字段(名称/类型/长度/约束/默认值/注释)\n`;
|
|
134
|
+
prompt += `- 索引设计(主键、唯一索引、普通索引、联合索引及理由)\n`;
|
|
135
|
+
prompt += `- 实体关系(一对一/一对多/多对多,外键约束)\n`;
|
|
136
|
+
prompt += `- 与全局层已有数据模型的对比(新增/扩展/重构/复用)\n\n`;
|
|
137
|
+
prompt += `### 3. 业务规则实现\n`;
|
|
138
|
+
prompt += `- 核心业务流程的伪代码或流程图\n`;
|
|
139
|
+
prompt += `- 边界条件处理(空值、越界、并发、超时)\n`;
|
|
140
|
+
prompt += `- 状态机定义(如订单状态流转)\n`;
|
|
141
|
+
prompt += `- 事务边界(哪些操作需要原子性)\n\n`;
|
|
142
|
+
prompt += `### 4. 技术专项(按端类型选择)\n`;
|
|
143
|
+
for (const p of backendPlatforms) {
|
|
144
|
+
const t = platformTypes.get(p) || '';
|
|
145
|
+
prompt += `- **${p} (${t})**: `;
|
|
146
|
+
if (t.includes('Java')) {
|
|
147
|
+
prompt += `Spring Boot 版本、JPA/MyBatis 选型、缓存策略(Redis/Caffeine)、消息队列(Kafka/RabbitMQ)、线程池配置、JVM 参数\n`;
|
|
148
|
+
}
|
|
149
|
+
else if (t.includes('Node')) {
|
|
150
|
+
prompt += `NestJS/Express 选型、TypeORM/Prisma 选型、异步处理(Bull/议程)、内存管理、集群模式\n`;
|
|
151
|
+
}
|
|
152
|
+
else if (t.includes('Go')) {
|
|
153
|
+
prompt += `Gin/Echo 选型、GORM 选型、协程模式、微服务框架(go-micro/gRPC)、性能优化\n`;
|
|
154
|
+
}
|
|
155
|
+
else if (t.includes('Python')) {
|
|
156
|
+
prompt += `FastAPI/Django 选型、SQLAlchemy 选型、Celery 任务队列、GIL 影响、AI/ML 集成\n`;
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
prompt += `API 框架、ORM 选型、缓存、消息队列、并发处理\n`;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
prompt += `\n`;
|
|
163
|
+
prompt += `## 输出文档\n`;
|
|
164
|
+
for (const p of backendPlatforms) {
|
|
165
|
+
prompt += `- \`${p}/API_INVENTORY.md\`:完整接口清单\n`;
|
|
166
|
+
prompt += `- \`${p}/DATA_MODEL.md\`:数据模型设计\n`;
|
|
167
|
+
prompt += `- \`${p}/BUSINESS_RULES.md\`:业务规则与状态机\n`;
|
|
168
|
+
prompt += `- \`${p}/TECH_STACK.md\`:技术栈与架构说明\n`;
|
|
169
|
+
}
|
|
170
|
+
prompt += `\n**存放**: \`.speccore/GLOBAL/platforms/{端名}/\`\n\n`;
|
|
171
|
+
prompt += `## 实时关联调整机制(重要)\n`;
|
|
172
|
+
prompt += `分析当前后端端时,如果发现以下情况,**必须回退修正已分析的端**:\n`;
|
|
173
|
+
prompt += `- 当前端的数据模型字段与已分析端冲突(如 user-service 和 auth-service 都定义了 User 表但字段不一致)\n`;
|
|
174
|
+
prompt += `- 当前端的接口与已分析端重复(如两个服务都提供了 /api/users 接口)\n`;
|
|
175
|
+
prompt += `- 当前端依赖的已分析端接口不存在或参数不匹配\n`;
|
|
176
|
+
prompt += `- 已分析端的技术选型影响当前端(如缓存策略、消息格式)\n\n`;
|
|
177
|
+
prompt += `**回退操作**:\n`;
|
|
178
|
+
prompt += `1. 在 BUSINESS_RULES.md 或 DATA_MODEL.md 中标注冲突点和修正方案\n`;
|
|
179
|
+
prompt += `2. 输出需要修正的已分析端列表和具体修正内容\n`;
|
|
180
|
+
prompt += `3. 执行修正:\`speccore analyze --apply '{"{端名}/DATA_MODEL.md":"修正后的内容"}' -I ${iteration} --global\`\n\n`;
|
|
181
|
+
prompt += `## 回写命令示例\n`;
|
|
182
|
+
prompt += `\`\`\`bash\n`;
|
|
183
|
+
for (const p of backendPlatforms) {
|
|
184
|
+
prompt += `speccore analyze --apply '{"${p}/API_INVENTORY.md":"...","${p}/DATA_MODEL.md":"...","${p}/BUSINESS_RULES.md":"...","${p}/TECH_STACK.md":"..."}' -I ${iteration} --global\n`;
|
|
185
|
+
}
|
|
186
|
+
prompt += `\`\`\`\n`;
|
|
187
|
+
return prompt;
|
|
188
|
+
}
|
|
189
|
+
/** Phase 2: 后端完成后全局实时更新 */
|
|
190
|
+
function buildPhase2Prompt(ctx) {
|
|
191
|
+
const { iteration } = ctx;
|
|
192
|
+
let prompt = `\n# Phase 2: 全局实时更新(后端分析完成后)\n\n`;
|
|
193
|
+
prompt += `## 目标\n`;
|
|
194
|
+
prompt += `所有后端端分析完成后,汇总后端分析成果,更新全局文档。\n\n`;
|
|
195
|
+
prompt += `## 读取输入\n`;
|
|
196
|
+
prompt += `1. Read 所有后端端的 API_INVENTORY.md、DATA_MODEL.md、BUSINESS_RULES.md\n`;
|
|
197
|
+
prompt += `2. Read Phase 0 的 _ASSOCIATION.md(如有)\n`;
|
|
198
|
+
prompt += `3. Read 已有的全局层文档(如有)\n\n`;
|
|
199
|
+
prompt += `## 更新内容\n`;
|
|
200
|
+
prompt += `### 1. 更新 global/API_CONTRACT.yaml\n`;
|
|
201
|
+
prompt += `汇总所有后端端的接口,生成统一契约:\n`;
|
|
202
|
+
prompt += `- 接口路径、方法、消费者端、提供者端\n`;
|
|
203
|
+
prompt += `- 请求/响应参数定义\n`;
|
|
204
|
+
prompt += `- 枚举定义(前后端共享)\n`;
|
|
205
|
+
prompt += `- 事件/消息契约\n\n`;
|
|
206
|
+
prompt += `### 2. 更新 global/ARCHITECTURE.md\n`;
|
|
207
|
+
prompt += `基于后端分析结果,更新全局架构:\n`;
|
|
208
|
+
prompt += `- 服务拓扑图(哪些服务依赖哪些服务)\n`;
|
|
209
|
+
prompt += `- 数据流图(请求从入口到各服务的流转)\n`;
|
|
210
|
+
prompt += `- 数据库分布(每个服务对应哪些表)\n`;
|
|
211
|
+
prompt += `- 中间件使用(缓存、消息队列、网关等)\n\n`;
|
|
212
|
+
prompt += `### 3. 更新 global/FUNCTION_MAP.md\n`;
|
|
213
|
+
prompt += `基于后端分析的功能模块,更新功能映射表:\n`;
|
|
214
|
+
prompt += `- 功能单元 × 后端端映射\n`;
|
|
215
|
+
prompt += `- 标注每个功能的数据模型依赖\n`;
|
|
216
|
+
prompt += `- 标注服务间调用关系\n\n`;
|
|
217
|
+
prompt += `### 4. 一致性校验\n`;
|
|
218
|
+
prompt += `- 检查所有后端端的枚举定义是否一致\n`;
|
|
219
|
+
prompt += `- 检查跨服务的实体字段是否冲突\n`;
|
|
220
|
+
prompt += `- 检查接口路径是否重复\n`;
|
|
221
|
+
prompt += `- 输出 CONSISTENCY_CHECK.md 记录发现的问题\n\n`;
|
|
222
|
+
prompt += `## 回写命令\n`;
|
|
223
|
+
prompt += `\`\`\`bash\n`;
|
|
224
|
+
prompt += `speccore analyze --apply '{"global/API_CONTRACT.yaml":"...","global/ARCHITECTURE.md":"...","global/FUNCTION_MAP.md":"...","global/CONSISTENCY_CHECK.md":"..."}' -I ${iteration} --global\n`;
|
|
225
|
+
prompt += `\`\`\`\n`;
|
|
226
|
+
return prompt;
|
|
227
|
+
}
|
|
228
|
+
/** Phase 3: 前端逐个分析 */
|
|
229
|
+
function buildPhase3Prompt(ctx) {
|
|
230
|
+
const { platforms, platformTypes, iteration } = ctx;
|
|
231
|
+
const frontendPlatforms = platforms.filter(p => {
|
|
232
|
+
const t = platformTypes.get(p) || '';
|
|
233
|
+
return t.includes('H5') || t.includes('Web') || t.includes('小程序') || t.includes('Android') || t.includes('iOS') || t.includes('前端') || t.includes('桌面');
|
|
234
|
+
});
|
|
235
|
+
let prompt = `\n# Phase 3: 前端深度分析(逐个端分析,对齐后端契约)\n\n`;
|
|
236
|
+
prompt += `## 目标\n`;
|
|
237
|
+
prompt += `深入分析每个前端端,基于 Phase 2 的全局 API 契约,生成前端专属文档。\n\n`;
|
|
238
|
+
if (frontendPlatforms.length === 0) {
|
|
239
|
+
prompt += `> 未检测到前端端,跳过 Phase 3,直接进入 Phase 4(横向关联检查)。\n`;
|
|
240
|
+
return prompt;
|
|
241
|
+
}
|
|
242
|
+
prompt += `## 前端端列表(${frontendPlatforms.length} 个)\n`;
|
|
243
|
+
for (const p of frontendPlatforms) {
|
|
244
|
+
prompt += `- ${p} (${platformTypes.get(p) || 'unknown'})\n`;
|
|
245
|
+
}
|
|
246
|
+
prompt += `\n`;
|
|
247
|
+
prompt += `## 分析前提(必须读取)\n`;
|
|
248
|
+
prompt += `在开始前端分析前,必须先读取:\n`;
|
|
249
|
+
prompt += `1. \`global/API_CONTRACT.yaml\` → 后端接口契约(字段名、类型、枚举值)\n`;
|
|
250
|
+
prompt += `2. \`global/ARCHITECTURE.md\` → 全局架构(服务拓扑)\n`;
|
|
251
|
+
prompt += `3. 相关后端端的 \`API_INVENTORY.md\` → 该前端调用的后端接口详情\n`;
|
|
252
|
+
prompt += `4. Phase 0 的该前端端 \`_INDEX.md\` → 页面和组件索引\n\n`;
|
|
253
|
+
prompt += `## 每个前端端的分析内容(必须深入)\n`;
|
|
254
|
+
prompt += `### 1. 页面详细设计\n`;
|
|
255
|
+
prompt += `- 每个页面的:路径、名称、核心功能、入口位置\n`;
|
|
256
|
+
prompt += `- 页面组件拆分(列表页/表单页/详情页/仪表盘等)\n`;
|
|
257
|
+
prompt += `- 页面间跳转关系(路由配置)\n`;
|
|
258
|
+
prompt += `- 权限控制(哪些页面/按钮需要权限)\n\n`;
|
|
259
|
+
prompt += `### 2. 字段映射设计(前后端契约对齐)\n`;
|
|
260
|
+
prompt += `- 每个页面展示哪些字段\n`;
|
|
261
|
+
prompt += `- 字段来源(后端哪个接口的哪个字段)\n`;
|
|
262
|
+
prompt += `- 字段展示格式(日期格式、金额格式、枚举转标签)\n`;
|
|
263
|
+
prompt += `- 字段校验规则(前端校验 + 后端校验对照)\n\n`;
|
|
264
|
+
prompt += `### 3. 交互流程设计\n`;
|
|
265
|
+
prompt += `- 用户操作流程(步骤流程图)\n`;
|
|
266
|
+
prompt += `- 状态变化(加载中/成功/失败/空状态)\n`;
|
|
267
|
+
prompt += `- 异常提示方式(toast/modal/inline)\n`;
|
|
268
|
+
prompt += `- 与后端状态枚举的映射关系\n\n`;
|
|
269
|
+
prompt += `### 4. API 调用清单\n`;
|
|
270
|
+
prompt += `- 每个页面调用的后端接口(路径+方法+用途)\n`;
|
|
271
|
+
prompt += `- 请求参数映射(前端表单字段 → 后端接口参数)\n`;
|
|
272
|
+
prompt += `- 响应数据处理(字段提取、错误处理、缓存策略)\n\n`;
|
|
273
|
+
prompt += `### 5. 技术专项(按端类型选择)\n`;
|
|
274
|
+
for (const p of frontendPlatforms) {
|
|
275
|
+
const t = platformTypes.get(p) || '';
|
|
276
|
+
prompt += `- **${p} (${t})**: `;
|
|
277
|
+
if (t.includes('微信') || t.includes('公众号')) {
|
|
278
|
+
prompt += `微信 JS-SDK 集成、OAuth 授权流程、分享配置、微信支付、模板消息、JSSDK 权限验证\n`;
|
|
279
|
+
}
|
|
280
|
+
else if (t.includes('H5') && !t.includes('微信')) {
|
|
281
|
+
prompt += `响应式布局、viewport 适配、触摸交互优化、弱网处理、首屏性能优化(FCP/LCP)、PWA 支持\n`;
|
|
282
|
+
}
|
|
283
|
+
else if (t.includes('Android')) {
|
|
284
|
+
prompt += `Activity/Fragment 生命周期、权限管理、推送集成、屏幕适配、内存优化、电量优化\n`;
|
|
285
|
+
}
|
|
286
|
+
else if (t.includes('iOS')) {
|
|
287
|
+
prompt += `Swift/SwiftUI 选型、App Store 审核规范、推送通知、性能优化、内存管理\n`;
|
|
288
|
+
}
|
|
289
|
+
else if (t.includes('小程序')) {
|
|
290
|
+
prompt += `包体积控制(2MB 限制)、平台 API 使用、setData 优化、页面栈管理、分包加载\n`;
|
|
291
|
+
}
|
|
292
|
+
else if (t.includes('Web') || t.includes('管理')) {
|
|
293
|
+
prompt += `复杂表单设计、数据表格优化、权限 UI 设计、状态管理(Pinia/Vuex/Redux)、路由守卫\n`;
|
|
294
|
+
}
|
|
295
|
+
else if (t.includes('桌面')) {
|
|
296
|
+
prompt += `本地存储方案、系统 API 调用、自动更新机制、离线支持、多窗口管理\n`;
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
prompt += `前端框架选型、状态管理、路由设计、组件库、构建优化\n`;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
prompt += `\n`;
|
|
303
|
+
prompt += `## 输出文档\n`;
|
|
304
|
+
for (const p of frontendPlatforms) {
|
|
305
|
+
prompt += `- \`${p}/FEATURES.md\`:产品视角功能清单(页面+交互+API调用链)\n`;
|
|
306
|
+
prompt += `- \`${p}/UI_FLOW.md\`:页面流转图、用户操作流程\n`;
|
|
307
|
+
prompt += `- \`${p}/API_CALL_MAP.md\`:页面 → 接口 → 后端服务 映射表\n`;
|
|
308
|
+
prompt += `- \`${p}/UI_SPEC.md\`:UI 规格(字段映射必须与后端 API 字段一一对应)\n`;
|
|
309
|
+
prompt += `- \`${p}/TECH_STACK.md\`:前端技术栈\n`;
|
|
310
|
+
}
|
|
311
|
+
prompt += `\n**存放**: \`.speccore/GLOBAL/platforms/{端名}/\`\n\n`;
|
|
312
|
+
prompt += `## 实时关联调整机制(重要)\n`;
|
|
313
|
+
prompt += `分析前端端时,如果发现以下情况,**必须回退修正后端或全局文档**:\n`;
|
|
314
|
+
prompt += `- 前端需要的接口在后端 API_INVENTORY.md 中不存在 → 需要后端补充接口\n`;
|
|
315
|
+
prompt += `- 前端字段映射与后端 API_CONTRACT.yaml 字段不一致(名称/类型/枚举值)\n`;
|
|
316
|
+
prompt += `- 前端状态枚举与后端状态枚举不匹配\n`;
|
|
317
|
+
prompt += `- 前端需要的权限在后端接口中未定义\n\n`;
|
|
318
|
+
prompt += `**回退操作**:\n`;
|
|
319
|
+
prompt += `1. 在前端文档中标注缺失/不一致点\n`;
|
|
320
|
+
prompt += `2. 输出需要修正的后后端端列表和具体修正内容\n`;
|
|
321
|
+
prompt += `3. 执行修正:\`speccore analyze --apply '{"{后端端}/API_INVENTORY.md":"补充后的内容"}' -I ${iteration} --global\`\n\n`;
|
|
322
|
+
prompt += `## 回写命令示例\n`;
|
|
323
|
+
prompt += `\`\`\`bash\n`;
|
|
324
|
+
for (const p of frontendPlatforms) {
|
|
325
|
+
prompt += `speccore analyze --apply '{"${p}/FEATURES.md":"...","${p}/UI_FLOW.md":"...","${p}/API_CALL_MAP.md":"...","${p}/UI_SPEC.md":"...","${p}/TECH_STACK.md":"..."}' -I ${iteration} --global\n`;
|
|
326
|
+
}
|
|
327
|
+
prompt += `\`\`\`\n`;
|
|
328
|
+
return prompt;
|
|
329
|
+
}
|
|
330
|
+
/** Phase 4: 横向关联检查(前后端字段/接口一致性) */
|
|
331
|
+
function buildPhase4Prompt(ctx) {
|
|
332
|
+
const { iteration } = ctx;
|
|
333
|
+
let prompt = `\n# Phase 4: 横向关联检查(前后端一致性)\n\n`;
|
|
334
|
+
prompt += `## 目标\n`;
|
|
335
|
+
prompt += `检查所有前端端与后端端之间的一致性,确保前后端契约对齐。\n\n`;
|
|
336
|
+
prompt += `## 读取输入\n`;
|
|
337
|
+
prompt += `1. 所有后端端的 \`API_INVENTORY.md\` 和 \`DATA_MODEL.md\`\n`;
|
|
338
|
+
prompt += `2. 所有前端端的 \`UI_SPEC.md\` 和 \`API_CALL_MAP.md\`\n`;
|
|
339
|
+
prompt += `3. \`global/API_CONTRACT.yaml\`\n\n`;
|
|
340
|
+
prompt += `## 检查项\n`;
|
|
341
|
+
prompt += `### 1. 字段一致性\n`;
|
|
342
|
+
prompt += `- [ ] 前端 UI_SPEC.md 中的字段名与后端 API 响应字段名完全一致(大小写敏感)\n`;
|
|
343
|
+
prompt += `- [ ] 前端字段类型与后端字段类型兼容(如后端 int → 前端 number)\n`;
|
|
344
|
+
prompt += `- [ ] 前端必填校验与后端必填校验一致\n`;
|
|
345
|
+
prompt += `- [ ] 前端枚举值与后端枚举值完全一致(数值和含义)\n\n`;
|
|
346
|
+
prompt += `### 2. 接口一致性\n`;
|
|
347
|
+
prompt += `- [ ] 前端 API_CALL_MAP.md 中的接口在后端 API_INVENTORY.md 中存在\n`;
|
|
348
|
+
prompt += `- [ ] 接口路径完全一致(包括前缀,如 /api/ vs /api/v1/)\n`;
|
|
349
|
+
prompt += `- [ ] HTTP 方法一致(GET/POST/PUT/DELETE)\n`;
|
|
350
|
+
prompt += `- [ ] 请求参数名称和类型一致\n\n`;
|
|
351
|
+
prompt += `### 3. 状态一致性\n`;
|
|
352
|
+
prompt += `- [ ] 前端状态枚举与后端状态枚举定义一致\n`;
|
|
353
|
+
prompt += `- [ ] 状态流转逻辑一致(前端展示的状态变化 = 后端实体的状态变化)\n\n`;
|
|
354
|
+
prompt += `## 输出\n`;
|
|
355
|
+
prompt += `- \`global/CROSS_CHECK.md\`:横向关联检查报告\n`;
|
|
356
|
+
prompt += ` - 列出所有不一致项(字段/接口/状态)\n`;
|
|
357
|
+
prompt += ` - 标注严重程度(致命/严重/警告)\n`;
|
|
358
|
+
prompt += ` - 给出修正建议\n\n`;
|
|
359
|
+
prompt += `## 回写命令\n`;
|
|
360
|
+
prompt += `\`\`\`bash\n`;
|
|
361
|
+
prompt += `speccore analyze --apply '{"global/CROSS_CHECK.md":"..."}' -I ${iteration} --global\n`;
|
|
362
|
+
prompt += `\`\`\`\n`;
|
|
363
|
+
return prompt;
|
|
364
|
+
}
|
|
365
|
+
/** Phase 5: 纵向关联检查(功能模块跨端完整性) */
|
|
366
|
+
function buildPhase5Prompt(ctx) {
|
|
367
|
+
const { iteration } = ctx;
|
|
368
|
+
let prompt = `\n# Phase 5: 纵向关联检查(功能模块跨端完整性)\n\n`;
|
|
369
|
+
prompt += `## 目标\n`;
|
|
370
|
+
prompt += `按功能模块维度检查跨端完整性,确保每个功能在各端的实现都齐全。\n\n`;
|
|
371
|
+
prompt += `## 读取输入\n`;
|
|
372
|
+
prompt += `1. \`global/FUNCTION_MAP.md\` → 功能单元列表\n`;
|
|
373
|
+
prompt += `2. 各端的 \`FEATURES.md\` 或 \`API_INVENTORY.md\`\n`;
|
|
374
|
+
prompt += `3. \`global/INTERACTION_MAP.md\`(如有)\n\n`;
|
|
375
|
+
prompt += `## 检查项\n`;
|
|
376
|
+
prompt += `### 1. 功能覆盖完整性\n`;
|
|
377
|
+
prompt += `对每个功能单元,检查:\n`;
|
|
378
|
+
prompt += `- [ ] 该功能涉及的所有端都有对应实现文档\n`;
|
|
379
|
+
prompt += `- [ ] 后端端有对应的 API 接口\n`;
|
|
380
|
+
prompt += `- [ ] 前端端有对应的页面/组件\n`;
|
|
381
|
+
prompt += `- [ ] 功能单元间的依赖关系已标注\n\n`;
|
|
382
|
+
prompt += `### 2. 交互链路完整性\n`;
|
|
383
|
+
prompt += `- [ ] 用户操作流程完整(从入口到结果)\n`;
|
|
384
|
+
prompt += `- [ ] 每个用户操作都有对应的后端接口\n`;
|
|
385
|
+
prompt += `- [ ] 后端处理结果都能正确反馈到前端\n`;
|
|
386
|
+
prompt += `- [ ] 异常场景有处理(错误提示、重试、降级)\n\n`;
|
|
387
|
+
prompt += `### 3. 数据流完整性\n`;
|
|
388
|
+
prompt += `- [ ] 数据从前端提交 → 后端处理 → 数据库存储 的链路完整\n`;
|
|
389
|
+
prompt += `- [ ] 数据从数据库读取 → 后端组装 → 前端展示 的链路完整\n`;
|
|
390
|
+
prompt += `- [ ] 跨服务调用的数据传递格式一致\n\n`;
|
|
391
|
+
prompt += `## 输出\n`;
|
|
392
|
+
prompt += `- \`global/VERTICAL_CHECK.md\`:纵向关联检查报告\n`;
|
|
393
|
+
prompt += ` - 列出功能覆盖缺口(哪些功能在哪些端缺失)\n`;
|
|
394
|
+
prompt += ` - 列出交互链路断裂点\n`;
|
|
395
|
+
prompt += ` - 列出数据流不一致点\n\n`;
|
|
396
|
+
prompt += `## 回写命令\n`;
|
|
397
|
+
prompt += `\`\`\`bash\n`;
|
|
398
|
+
prompt += `speccore analyze --apply '{"global/VERTICAL_CHECK.md":"..."}' -I ${iteration} --global\n`;
|
|
399
|
+
prompt += `\`\`\`\n`;
|
|
400
|
+
return prompt;
|
|
401
|
+
}
|
|
402
|
+
/** Phase 6: 最终核对检查 */
|
|
403
|
+
function buildPhase6Prompt(ctx) {
|
|
404
|
+
const { iteration } = ctx;
|
|
405
|
+
let prompt = `\n# Phase 6: 最终核对检查(完整性 + 一致性 + 遗漏检测)\n\n`;
|
|
406
|
+
prompt += `## 目标\n`;
|
|
407
|
+
prompt += `全面检查所有分析产出,确保没有遗漏和不一致。\n\n`;
|
|
408
|
+
prompt += `## 读取输入\n`;
|
|
409
|
+
prompt += `1. 所有全局文档(global/ 下的所有 .md 和 .yaml)\n`;
|
|
410
|
+
prompt += `2. 所有端专属文档(platforms/{端名}/ 下的所有 .md)\n`;
|
|
411
|
+
prompt += `3. \`global/CROSS_CHECK.md\` 和 \`global/VERTICAL_CHECK.md\`\n\n`;
|
|
412
|
+
prompt += `## 核对清单(必须逐条检查)\n\n`;
|
|
413
|
+
prompt += `### A. 文档完整性检查\n`;
|
|
414
|
+
prompt += `- [ ] 每个后端端都有 API_INVENTORY.md、DATA_MODEL.md、BUSINESS_RULES.md、TECH_STACK.md\n`;
|
|
415
|
+
prompt += `- [ ] 每个前端端都有 FEATURES.md、UI_FLOW.md、API_CALL_MAP.md、UI_SPEC.md\n`;
|
|
416
|
+
prompt += `- [ ] 全局文档齐全:API_CONTRACT.yaml、ARCHITECTURE.md、FUNCTION_MAP.md、CONSISTENCY_CHECK.md\n`;
|
|
417
|
+
prompt += `- [ ] 检查报告齐全:CROSS_CHECK.md、VERTICAL_CHECK.md\n\n`;
|
|
418
|
+
prompt += `### B. 内容完整性检查\n`;
|
|
419
|
+
prompt += `- [ ] 所有文档都没有"待填充"、"_待定_"、"TBD"等占位符\n`;
|
|
420
|
+
prompt += `- [ ] 所有接口都有完整的参数定义和响应定义\n`;
|
|
421
|
+
prompt += `- [ ] 所有数据模型都有完整的字段定义\n`;
|
|
422
|
+
prompt += `- [ ] 所有页面都有字段映射和交互流程\n`;
|
|
423
|
+
prompt += `- [ ] 所有枚举值都有前后端一致的定义\n\n`;
|
|
424
|
+
prompt += `### C. 一致性检查\n`;
|
|
425
|
+
prompt += `- [ ] API_CONTRACT.yaml 中的接口与后端 API_INVENTORY.md 完全一致\n`;
|
|
426
|
+
prompt += `- [ ] API_CONTRACT.yaml 中的枚举与前端 UI_SPEC.md 完全一致\n`;
|
|
427
|
+
prompt += `- [ ] FUNCTION_MAP.md 中的功能单元与 REQUIREMENT.md 的功能模块一一对应\n`;
|
|
428
|
+
prompt += `- [ ] 各端 TECH_STACK.md 的技术选型与 global/ARCHITECTURE.md 一致\n\n`;
|
|
429
|
+
prompt += `### D. 遗漏检测\n`;
|
|
430
|
+
prompt += `- [ ] 需求文档中的每个功能模块都有对应的分析文档\n`;
|
|
431
|
+
prompt += `- [ ] 需求文档中的每个接口需求都有对应的 API 定义\n`;
|
|
432
|
+
prompt += `- [ ] 需求文档中的每个页面需求都有对应的页面设计\n`;
|
|
433
|
+
prompt += `- [ ] 需求文档中的每个业务规则都有对应的实现说明\n`;
|
|
434
|
+
prompt += `- [ ] 没有"孤儿代码"(后端有接口但前端没调用,或前端有页面但后端没接口)\n\n`;
|
|
435
|
+
prompt += `## 输出\n`;
|
|
436
|
+
prompt += `- \`global/FINAL_AUDIT.md\`:最终核对报告\n`;
|
|
437
|
+
prompt += ` - 检查项总数、通过数、失败数\n`;
|
|
438
|
+
prompt += ` - 每个失败项的详细说明、影响、修正建议\n`;
|
|
439
|
+
prompt += ` - 按严重程度排序(致命 > 严重 > 警告)\n\n`;
|
|
440
|
+
prompt += `## 回写命令\n`;
|
|
441
|
+
prompt += `\`\`\`bash\n`;
|
|
442
|
+
prompt += `speccore analyze --apply '{"global/FINAL_AUDIT.md":"..."}' -I ${iteration} --global\n`;
|
|
443
|
+
prompt += `\`\`\`\n`;
|
|
444
|
+
prompt += `> ⚠️ 如果 FINAL_AUDIT.md 中有"致命"或"严重"级别的问题,必须回退到对应 Phase 修正后再重新执行 Phase 6。\n`;
|
|
445
|
+
return prompt;
|
|
446
|
+
}
|
|
447
|
+
// ── 实时关联调整检测 ──
|
|
448
|
+
/**
|
|
449
|
+
* 检测当前分析结果是否需要回退修正已分析的文档
|
|
450
|
+
*/
|
|
451
|
+
async function detectBacktrackingNeeds(iterDir, currentPhase) {
|
|
452
|
+
const targets = [];
|
|
453
|
+
const reasons = [];
|
|
454
|
+
const globalDir = (0, path_1.join)(iterDir, '.speccore', 'GLOBAL');
|
|
455
|
+
const platformsDir = (0, path_1.join)(globalDir, 'platforms');
|
|
456
|
+
// Phase 1 (后端分析) 完成后,检查是否需要调整 Phase 0 的 _INDEX.md
|
|
457
|
+
if (currentPhase === 'phase1-backend') {
|
|
458
|
+
// 检查:后端深入分析发现的接口/实体是否在 _INDEX.md 中缺失
|
|
459
|
+
// 简化实现:检查文件存在性
|
|
460
|
+
try {
|
|
461
|
+
const platformEntries = await (0, fs_extra_1.readdir)(platformsDir, { withFileTypes: true });
|
|
462
|
+
for (const entry of platformEntries) {
|
|
463
|
+
if (!entry.isDirectory())
|
|
464
|
+
continue;
|
|
465
|
+
const platformDir = (0, path_1.join)(platformsDir, entry.name);
|
|
466
|
+
const indexPath = (0, path_1.join)(platformDir, '_INDEX.md');
|
|
467
|
+
const apiInventoryPath = (0, path_1.join)(platformDir, 'API_INVENTORY.md');
|
|
468
|
+
if (await (0, fs_extra_1.pathExists)(apiInventoryPath) && await (0, fs_extra_1.pathExists)(indexPath)) {
|
|
469
|
+
const indexContent = await (0, fs_extra_1.readFile)(indexPath, 'utf-8');
|
|
470
|
+
const apiContent = await (0, fs_extra_1.readFile)(apiInventoryPath, 'utf-8');
|
|
471
|
+
// 简单检查:API_INVENTORY 中的接口路径是否在 _INDEX 中
|
|
472
|
+
const apiPaths = apiContent.match(/\/api\/[a-zA-Z0-9\/\-_]+/g) || [];
|
|
473
|
+
const missingInIndex = apiPaths.filter(p => !indexContent.includes(p));
|
|
474
|
+
if (missingInIndex.length > 0) {
|
|
475
|
+
targets.push(`${entry.name}/_INDEX.md`);
|
|
476
|
+
reasons.push(`${entry.name} 的 API_INVENTORY.md 中有 ${missingInIndex.length} 个接口未在 _INDEX.md 中收录`);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
catch { /* ignore */ }
|
|
482
|
+
}
|
|
483
|
+
// Phase 3 (前端分析) 完成后,检查是否需要调整后端 API
|
|
484
|
+
if (currentPhase === 'phase3-frontend') {
|
|
485
|
+
try {
|
|
486
|
+
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
487
|
+
const backendPlatforms = platforms.filter(async (p) => {
|
|
488
|
+
const types = await (0, spec_paths_1.parsePlatformTypes)();
|
|
489
|
+
const t = types.get(p) || '';
|
|
490
|
+
return t.includes('service') || t.includes('后端');
|
|
491
|
+
});
|
|
492
|
+
const frontendPlatforms = platforms.filter(p => !backendPlatforms.includes(p));
|
|
493
|
+
for (const fp of frontendPlatforms) {
|
|
494
|
+
const apiCallMapPath = (0, path_1.join)(platformsDir, fp, 'API_CALL_MAP.md');
|
|
495
|
+
if (!(await (0, fs_extra_1.pathExists)(apiCallMapPath)))
|
|
496
|
+
continue;
|
|
497
|
+
const apiCallContent = await (0, fs_extra_1.readFile)(apiCallMapPath, 'utf-8');
|
|
498
|
+
const frontendApis = apiCallContent.match(/\/api\/[a-zA-Z0-9\/\-_]+/g) || [];
|
|
499
|
+
for (const apiPath of [...new Set(frontendApis)]) {
|
|
500
|
+
let found = false;
|
|
501
|
+
for (const bp of backendPlatforms) {
|
|
502
|
+
const apiInventoryPath = (0, path_1.join)(platformsDir, bp, 'API_INVENTORY.md');
|
|
503
|
+
if (await (0, fs_extra_1.pathExists)(apiInventoryPath)) {
|
|
504
|
+
const invContent = await (0, fs_extra_1.readFile)(apiInventoryPath, 'utf-8');
|
|
505
|
+
if (invContent.includes(apiPath)) {
|
|
506
|
+
found = true;
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
if (!found) {
|
|
512
|
+
targets.push(`${fp}/API_CALL_MAP.md`);
|
|
513
|
+
reasons.push(`前端 ${fp} 调用的接口 ${apiPath} 在所有后端端中都未找到定义`);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
catch { /* ignore */ }
|
|
519
|
+
}
|
|
520
|
+
return { needed: targets.length > 0, targets, reasons };
|
|
521
|
+
}
|
|
522
|
+
// ── 最终核对检查 ──
|
|
523
|
+
/**
|
|
524
|
+
* 执行最终核对检查,返回发现的问题列表
|
|
525
|
+
*/
|
|
526
|
+
async function runFinalAudit(iterDir) {
|
|
527
|
+
const issues = [];
|
|
528
|
+
const globalDir = (0, path_1.join)(iterDir, '.speccore', 'GLOBAL');
|
|
529
|
+
const platformsDir = (0, path_1.join)(globalDir, 'platforms');
|
|
530
|
+
// 1. 检查全局文档完整性
|
|
531
|
+
const requiredGlobalDocs = ['API_CONTRACT.yaml', 'ARCHITECTURE.md', 'FUNCTION_MAP.md'];
|
|
532
|
+
for (const doc of requiredGlobalDocs) {
|
|
533
|
+
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(globalDir, doc)))) {
|
|
534
|
+
issues.push({
|
|
535
|
+
severity: 'error',
|
|
536
|
+
category: 'missing-doc',
|
|
537
|
+
description: `全局文档缺失: ${doc}`,
|
|
538
|
+
affectedFiles: [(0, path_1.join)(globalDir, doc)],
|
|
539
|
+
suggestion: `执行对应 Phase 生成 ${doc}`,
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
// 2. 检查端文档完整性
|
|
544
|
+
try {
|
|
545
|
+
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
546
|
+
const types = await (0, spec_paths_1.parsePlatformTypes)();
|
|
547
|
+
for (const p of platforms) {
|
|
548
|
+
const pDir = (0, path_1.join)(platformsDir, p);
|
|
549
|
+
const t = types.get(p) || '';
|
|
550
|
+
const isBackend = t.includes('service') || t.includes('后端');
|
|
551
|
+
if (isBackend) {
|
|
552
|
+
for (const doc of ['API_INVENTORY.md', 'DATA_MODEL.md', 'BUSINESS_RULES.md']) {
|
|
553
|
+
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(pDir, doc)))) {
|
|
554
|
+
issues.push({
|
|
555
|
+
severity: 'error',
|
|
556
|
+
category: 'missing-doc',
|
|
557
|
+
description: `后端端 ${p} 缺失文档: ${doc}`,
|
|
558
|
+
affectedFiles: [(0, path_1.join)(pDir, doc)],
|
|
559
|
+
suggestion: `执行 Phase 1 生成 ${p}/${doc}`,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
for (const doc of ['FEATURES.md', 'UI_FLOW.md', 'API_CALL_MAP.md', 'UI_SPEC.md']) {
|
|
566
|
+
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(pDir, doc)))) {
|
|
567
|
+
issues.push({
|
|
568
|
+
severity: 'error',
|
|
569
|
+
category: 'missing-doc',
|
|
570
|
+
description: `前端端 ${p} 缺失文档: ${doc}`,
|
|
571
|
+
affectedFiles: [(0, path_1.join)(pDir, doc)],
|
|
572
|
+
suggestion: `执行 Phase 3 生成 ${p}/${doc}`,
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
catch { /* ignore */ }
|
|
580
|
+
// 3. 检查内容占位符
|
|
581
|
+
try {
|
|
582
|
+
const allMdFiles = await findAllMarkdownFiles(globalDir);
|
|
583
|
+
for (const file of allMdFiles) {
|
|
584
|
+
const content = await (0, fs_extra_1.readFile)(file, 'utf-8');
|
|
585
|
+
const placeholders = ['待填充', '_待定_', 'TBD', 'TODO', 'FIXME'];
|
|
586
|
+
for (const ph of placeholders) {
|
|
587
|
+
if (content.includes(ph)) {
|
|
588
|
+
issues.push({
|
|
589
|
+
severity: 'warning',
|
|
590
|
+
category: 'missing-doc',
|
|
591
|
+
description: `文档中包含占位符 "${ph}"`,
|
|
592
|
+
affectedFiles: [file],
|
|
593
|
+
suggestion: '补充具体内容后移除占位符',
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
catch { /* ignore */ }
|
|
600
|
+
return issues;
|
|
601
|
+
}
|
|
602
|
+
/** 递归查找所有 markdown 文件 */
|
|
603
|
+
async function findAllMarkdownFiles(dir) {
|
|
604
|
+
const result = [];
|
|
605
|
+
try {
|
|
606
|
+
const entries = await (0, fs_extra_1.readdir)(dir, { withFileTypes: true });
|
|
607
|
+
for (const entry of entries) {
|
|
608
|
+
const fullPath = (0, path_1.join)(dir, entry.name);
|
|
609
|
+
if (entry.isDirectory()) {
|
|
610
|
+
result.push(...await findAllMarkdownFiles(fullPath));
|
|
611
|
+
}
|
|
612
|
+
else if (entry.name.endsWith('.md')) {
|
|
613
|
+
result.push(fullPath);
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
catch { /* ignore */ }
|
|
618
|
+
return result;
|
|
619
|
+
}
|
|
620
|
+
// ── 辅助函数 ──
|
|
621
|
+
/**
|
|
622
|
+
* 获取 Phase 顺序
|
|
623
|
+
*/
|
|
624
|
+
function getPhaseSequence() {
|
|
625
|
+
return [
|
|
626
|
+
'phase0-scan',
|
|
627
|
+
'phase1-backend',
|
|
628
|
+
'phase2-global-update',
|
|
629
|
+
'phase3-frontend',
|
|
630
|
+
'phase4-cross-check',
|
|
631
|
+
'phase5-vertical-check',
|
|
632
|
+
'phase6-final-audit',
|
|
633
|
+
];
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* 获取 Phase 的中文名称
|
|
637
|
+
*/
|
|
638
|
+
function getPhaseDisplayName(phase) {
|
|
639
|
+
const names = {
|
|
640
|
+
'phase0-scan': 'Phase 0: 快速全局扫描',
|
|
641
|
+
'phase1-backend': 'Phase 1: 后端深度分析',
|
|
642
|
+
'phase2-global-update': 'Phase 2: 全局实时更新',
|
|
643
|
+
'phase3-frontend': 'Phase 3: 前端深度分析',
|
|
644
|
+
'phase4-cross-check': 'Phase 4: 横向关联检查',
|
|
645
|
+
'phase5-vertical-check': 'Phase 5: 纵向关联检查',
|
|
646
|
+
'phase6-final-audit': 'Phase 6: 最终核对检查',
|
|
647
|
+
};
|
|
648
|
+
return names[phase] || phase;
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
* 检测后端端之间的依赖拓扑顺序
|
|
652
|
+
* 简化版:基于 FUNCTION_MAP.md 中的依赖关系排序
|
|
653
|
+
*/
|
|
654
|
+
async function detectBackendDependencyOrder(iterDir, backendPlatforms) {
|
|
655
|
+
// 默认返回字母序,实际实现可以读取 FUNCTION_MAP.md 或 DEPS.md 解析依赖关系
|
|
656
|
+
return [...backendPlatforms].sort();
|
|
657
|
+
}
|
|
658
|
+
//# sourceMappingURL=streaming-analyzer.js.map
|