speccore 7.2.0 → 7.3.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/.agents/skills/spec-ask/SKILL.md +10 -5
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +102 -7
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/ask.d.ts +1 -1
- package/dist/commands/ask.d.ts.map +1 -1
- package/dist/commands/ask.js +2 -2
- package/dist/commands/ask.js.map +1 -1
- package/dist/commands/dev.js +1 -1
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/prompts.d.ts +7 -0
- package/dist/commands/prompts.d.ts.map +1 -1
- package/dist/commands/prompts.js +650 -52
- package/dist/commands/prompts.js.map +1 -1
- package/dist/core/ask-engine.d.ts.map +1 -1
- package/dist/core/ask-engine.js +58 -3
- package/dist/core/ask-engine.js.map +1 -1
- package/dist/core/intent-recognition.d.ts.map +1 -1
- package/dist/core/intent-recognition.js +21 -2
- package/dist/core/intent-recognition.js.map +1 -1
- package/package.json +1 -1
|
@@ -75,13 +75,18 @@ disable-model-invocation: false
|
|
|
75
75
|
- 步骤3-5: 同下
|
|
76
76
|
- **全局级分析**(用户明确说"全局""全量""项目分析""所有端"等):
|
|
77
77
|
- 步骤1: `speccore analyze --prompt --scope global --with-code` → 获取 SPECCORE_PROMPT
|
|
78
|
-
- 步骤2: **Read .speccore/CONSTITUTION.md
|
|
79
|
-
- 步骤3:
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
- 步骤2: **Read .speccore/CONSTITUTION.md 获取工程源码路径**,从源码路径读各端代码,**禁止读/写迭代目录**
|
|
79
|
+
- 步骤3: **严格按 prompt 中「当前执行层级 Layer N/4」执行,只做当前层**(v7.2.0+ 分层机制,禁止一次写全部):
|
|
80
|
+
- Layer 1 代码索引 → `platforms/{端}/_INDEX.md` + PATTERNS
|
|
81
|
+
- Layer 2 架构关联 → `platforms/_shared/_ASSOCIATION.md` + `_MODULES.md`
|
|
82
|
+
- Layer 3 业务深入 → 各端功能模块文档
|
|
83
|
+
- Layer 4 全局汇总 → `overview/`(REQUIREMENT/ANALYSIS/DEPS/FUNCTION_MAP/INTERACTION_MAP/API_CONTRACT) + `requirements/` + `platforms/`
|
|
84
|
+
- 步骤4: 每层产物用 `speccore analyze --apply '{"<相对路径>":"...",...}' --scope global` 写入 `.speccore/GLOBAL/`
|
|
85
|
+
- 步骤5: 看到 [SPECCORE_PIPELINE_NEXT] 或 prompt 提示的下一层命令时**自动继续,不询问用户**,直到 Layer 4 完成
|
|
82
86
|
- 步骤6: **用户提供参考文档时**: 如果用户附带了格式参考文档(如PDF/Word/截图),先按标准 Spec 模板生成默认文档,再按用户参考格式生成一份,**两边都要**
|
|
83
87
|
- ❌ 禁止: 跳过文档填充直接写代码、生成重复空壳、用 "API=0" 跳过
|
|
84
|
-
- ❌ 禁止: 全局分析时 fallback
|
|
88
|
+
- ❌ 禁止: 全局分析时 fallback 到迭代目录读取需求文档,或把全局产物写到迭代目录
|
|
89
|
+
- ❌ 禁止: 只生成单个 ANALYSIS.md 就收尾、用 outputs/ 临时报告代替落盘 —— 必须按层级完成全部文档并写入 `.speccore/GLOBAL/`
|
|
85
90
|
- ⚠️ 如果模板目录不存在或为空: 用你的专业知识自由撰写,绝不允许产出一行垃圾。你是一个专业的技术架构师和分析师,即使没有参考模板,也能产出高质量文档
|
|
86
91
|
6. **交互式文档编辑**: 分析完成后用户可以对任意文档的任意部分进行修改。支持:
|
|
87
92
|
- "修改 ANALYSIS.md 的接口清单部分,加上签到接口" → 只改指定章节,不改其他部分
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAgEA,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAC;IACxC,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAgEA,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAC;IACxC,KAAK,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAkpC3E"}
|
package/dist/commands/analyze.js
CHANGED
|
@@ -912,6 +912,8 @@ async function analyzeCommand(options) {
|
|
|
912
912
|
logger_1.logger.warn(`⚠️ 共跳过 ${skippedCount} 个非法目录的文档,请检查 AI 输出是否包含非端名目录`);
|
|
913
913
|
}
|
|
914
914
|
logger_1.logger.success(`✅ ${count} 个 Spec 文档已写入 020-specs/`);
|
|
915
|
+
// v6.90.0+: 事后校验——检测并清理 AI 绕过 --apply 创建的非法目录/文件
|
|
916
|
+
await sanitizeSpecDirectories(iterDir);
|
|
915
917
|
// v6.74.0+: 流式分析自动检查(回退检测 + 最终核对)
|
|
916
918
|
if (options.streamingPhase) {
|
|
917
919
|
const phase = options.streamingPhase;
|
|
@@ -1249,7 +1251,7 @@ async function preCreateSpecDirectories(iteration) {
|
|
|
1249
1251
|
const iterDir = await (0, context_1.getIterationDir)(iteration);
|
|
1250
1252
|
const specDir = (0, path_1.join)(iterDir, '020-specs');
|
|
1251
1253
|
await (0, fs_extra_1.ensureDir)(specDir);
|
|
1252
|
-
// 预创建 global/
|
|
1254
|
+
// 预创建 overview/ 子目录(v6.78.0+ 从 global/ 改名)
|
|
1253
1255
|
const globalDir = (0, path_1.join)(specDir, spec_paths_1.GLOBAL_SPECS_DIR);
|
|
1254
1256
|
await (0, fs_extra_1.ensureDir)(globalDir);
|
|
1255
1257
|
// 读取端列表并预创建各端目录
|
|
@@ -1258,10 +1260,103 @@ async function preCreateSpecDirectories(iteration) {
|
|
|
1258
1260
|
await (0, fs_extra_1.ensureDir)((0, path_1.join)(specDir, platform));
|
|
1259
1261
|
}
|
|
1260
1262
|
if (platforms.length > 0) {
|
|
1261
|
-
logger_1.logger.info(`📁 已预创建 020-specs/ 目录结构:
|
|
1263
|
+
logger_1.logger.info(`📁 已预创建 020-specs/ 目录结构: ${spec_paths_1.GLOBAL_SPECS_DIR}/ + ${platforms.length} 个端目录 (${platforms.join(', ')})`);
|
|
1262
1264
|
}
|
|
1263
1265
|
else {
|
|
1264
|
-
logger_1.logger.info(`📁 已预创建 020-specs/ 目录结构:
|
|
1266
|
+
logger_1.logger.info(`📁 已预创建 020-specs/ 目录结构: ${spec_paths_1.GLOBAL_SPECS_DIR}/`);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
/**
|
|
1270
|
+
* v6.90.0+: 事后校验——检测并清理 020-specs/ 下 AI 绕过 --apply 创建的非法目录和文件
|
|
1271
|
+
*
|
|
1272
|
+
* 解决的问题:AI 用 Write 工具直接写文件,绕过 CLI --apply,导致:
|
|
1273
|
+
* - 非法子目录(如 1001/、工程标识/、错误码/)
|
|
1274
|
+
* - 遗留的 global/ 旧目录(应迁移到 overview/)
|
|
1275
|
+
* - 根目录散落的 .md 文件(应在 overview/ 内)
|
|
1276
|
+
*/
|
|
1277
|
+
async function sanitizeSpecDirectories(iterDir) {
|
|
1278
|
+
const specDir = (0, path_1.join)(iterDir, '020-specs');
|
|
1279
|
+
if (!await (0, fs_extra_1.pathExists)(specDir))
|
|
1280
|
+
return;
|
|
1281
|
+
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
1282
|
+
const validDirs = new Set([spec_paths_1.GLOBAL_SPECS_DIR, ...platforms]);
|
|
1283
|
+
const globalSet = new Set(spec_paths_1.GLOBAL_SPEC_FILES);
|
|
1284
|
+
const entries = await (0, fs_extra_2.readdir)(specDir);
|
|
1285
|
+
let illegalDirCount = 0;
|
|
1286
|
+
let orphanFileCount = 0;
|
|
1287
|
+
let legacyGlobalMigrated = false;
|
|
1288
|
+
for (const entry of entries) {
|
|
1289
|
+
const entryPath = (0, path_1.join)(specDir, entry);
|
|
1290
|
+
const entryStat = await (0, fs_extra_1.stat)(entryPath);
|
|
1291
|
+
if (entryStat.isDirectory()) {
|
|
1292
|
+
// 检测遗留的 global/ 目录(v6.78.0+ 已改名为 overview/)
|
|
1293
|
+
if (entry === 'global') {
|
|
1294
|
+
logger_1.logger.warn(`⚠️ 检测到遗留 global/ 目录(v6.78.0+ 已改名为 ${spec_paths_1.GLOBAL_SPECS_DIR}/)`);
|
|
1295
|
+
// 将 global/ 中的文件迁移到 overview/
|
|
1296
|
+
const globalFiles = await (0, fs_extra_2.readdir)(entryPath);
|
|
1297
|
+
const overviewDir = (0, path_1.join)(specDir, spec_paths_1.GLOBAL_SPECS_DIR);
|
|
1298
|
+
await (0, fs_extra_1.ensureDir)(overviewDir);
|
|
1299
|
+
for (const f of globalFiles) {
|
|
1300
|
+
const src = (0, path_1.join)(entryPath, f);
|
|
1301
|
+
const dest = (0, path_1.join)(overviewDir, f);
|
|
1302
|
+
if (!await (0, fs_extra_1.pathExists)(dest)) {
|
|
1303
|
+
await (0, fs_extra_1.rename)(src, dest);
|
|
1304
|
+
logger_1.logger.info(` 📦 迁移: global/${f} → ${spec_paths_1.GLOBAL_SPECS_DIR}/${f}`);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
// 删除空的 global/ 目录
|
|
1308
|
+
const remaining = await (0, fs_extra_2.readdir)(entryPath);
|
|
1309
|
+
if (remaining.length === 0) {
|
|
1310
|
+
await (0, fs_extra_1.rename)(entryPath, (0, path_1.join)(specDir, `global.migrated-${Date.now()}`));
|
|
1311
|
+
logger_1.logger.info(` 🗑️ global/ 已迁移并归档`);
|
|
1312
|
+
}
|
|
1313
|
+
else {
|
|
1314
|
+
logger_1.logger.warn(` ⚠️ global/ 仍有 ${remaining.length} 个文件未迁移,已重命名归档`);
|
|
1315
|
+
await (0, fs_extra_1.rename)(entryPath, (0, path_1.join)(specDir, `global.archived-${Date.now()}`));
|
|
1316
|
+
}
|
|
1317
|
+
legacyGlobalMigrated = true;
|
|
1318
|
+
continue;
|
|
1319
|
+
}
|
|
1320
|
+
// 白名单校验:非 overview/ 且非端名的目录 → 非法
|
|
1321
|
+
if (!validDirs.has(entry)) {
|
|
1322
|
+
const archivedName = `${entry}.invalid-${Date.now()}`;
|
|
1323
|
+
await (0, fs_extra_1.rename)(entryPath, (0, path_1.join)(specDir, archivedName));
|
|
1324
|
+
logger_1.logger.warn(`⚠️ 非法目录已归档: 020-specs/${entry}/ → ${archivedName}/`);
|
|
1325
|
+
illegalDirCount++;
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
else if (entryStat.isFile()) {
|
|
1329
|
+
// 根目录散落的 .md 文件 → 检查是否应归入 overview/
|
|
1330
|
+
if (entry.endsWith('.md') && globalSet.has(entry)) {
|
|
1331
|
+
const overviewDir = (0, path_1.join)(specDir, spec_paths_1.GLOBAL_SPECS_DIR);
|
|
1332
|
+
await (0, fs_extra_1.ensureDir)(overviewDir);
|
|
1333
|
+
const dest = (0, path_1.join)(overviewDir, entry);
|
|
1334
|
+
if (!await (0, fs_extra_1.pathExists)(dest)) {
|
|
1335
|
+
await (0, fs_extra_1.rename)(entryPath, dest);
|
|
1336
|
+
logger_1.logger.warn(`⚠️ 散落文件已归位: 020-specs/${entry} → ${spec_paths_1.GLOBAL_SPECS_DIR}/${entry}`);
|
|
1337
|
+
orphanFileCount++;
|
|
1338
|
+
}
|
|
1339
|
+
else {
|
|
1340
|
+
// overview/ 中已有同名文件,归档根目录版本
|
|
1341
|
+
const archivedName = `${entry}.orphan-${Date.now()}`;
|
|
1342
|
+
await (0, fs_extra_1.rename)(entryPath, (0, path_1.join)(specDir, archivedName));
|
|
1343
|
+
logger_1.logger.warn(`⚠️ 重复散落文件已归档: 020-specs/${entry} → ${archivedName}`);
|
|
1344
|
+
orphanFileCount++;
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
// 汇总报告
|
|
1350
|
+
if (illegalDirCount > 0 || orphanFileCount > 0 || legacyGlobalMigrated) {
|
|
1351
|
+
logger_1.logger.info('');
|
|
1352
|
+
logger_1.logger.info(`🔍 020-specs/ 目录校验报告:`);
|
|
1353
|
+
if (illegalDirCount > 0)
|
|
1354
|
+
logger_1.logger.warn(` ⚠️ ${illegalDirCount} 个非法目录已归档(AI 绕过 --apply 创建)`);
|
|
1355
|
+
if (orphanFileCount > 0)
|
|
1356
|
+
logger_1.logger.warn(` ⚠️ ${orphanFileCount} 个散落文件已归位到 ${spec_paths_1.GLOBAL_SPECS_DIR}/`);
|
|
1357
|
+
if (legacyGlobalMigrated)
|
|
1358
|
+
logger_1.logger.info(` 📦 遗留 global/ 已迁移到 ${spec_paths_1.GLOBAL_SPECS_DIR}/`);
|
|
1359
|
+
logger_1.logger.info(` ✅ 当前合法目录: ${Array.from(validDirs).join(', ')}`);
|
|
1265
1360
|
}
|
|
1266
1361
|
}
|
|
1267
1362
|
/**
|
|
@@ -2974,7 +3069,7 @@ sequenceDiagram
|
|
|
2974
3069
|
prompt += `## 🚨 最高优先级警告(违反将导致分析失败)\n\n`;
|
|
2975
3070
|
prompt += `### ⛔ 绝对禁止创建任何额外目录\n`;
|
|
2976
3071
|
prompt += `- ❌ **错误行为**:创建 020-specs/1001/、020-specs/1002/、020-specs/错误码/、020-specs/工程标识/ 等垃圾目录\n`;
|
|
2977
|
-
prompt += `- ✅ **正确行为**:只使用 CLI 预创建的
|
|
3072
|
+
prompt += `- ✅ **正确行为**:只使用 CLI 预创建的 overview/ 和 {端名}/ 目录,不要手动 mkdir 或 Write 到不存在的目录\n`;
|
|
2978
3073
|
prompt += `- ⚠️ **后果**:如果创建额外目录,会导致后续 split/execute 命令找不到文件,整个工作流失败\n\n`;
|
|
2979
3074
|
prompt += `### 绝对禁止直接用 Write 工具写文件\n`;
|
|
2980
3075
|
prompt += `- ❌ **错误行为**:Write("020-specs/overview/ANALYSIS.md", content) 或直接 Write 到任何路径\n`;
|
|
@@ -2984,7 +3079,7 @@ sequenceDiagram
|
|
|
2984
3079
|
prompt += `### ✅ 正确的目录结构\n`;
|
|
2985
3080
|
prompt += `\`\`\`\n`;
|
|
2986
3081
|
prompt += `020-specs/\n`;
|
|
2987
|
-
prompt += `├──
|
|
3082
|
+
prompt += `├── overview/ ← REQUIREMENT.md, ANALYSIS.md, DEPS.md(跨端通用)\n`;
|
|
2988
3083
|
prompt += `├── admin-web/ ← TECH.md, TEST.md, UI_SPEC.md(Admin 端专属)\n`;
|
|
2989
3084
|
prompt += `├── booking-service/ ← TECH.md, TEST.md(后端服务专属)\n`;
|
|
2990
3085
|
prompt += `├── h5-mobile/ ← TECH.md, TEST.md, UI_SPEC.md(H5 端专属)\n`;
|
|
@@ -3229,7 +3324,7 @@ sequenceDiagram
|
|
|
3229
3324
|
prompt += ` - MONITOR.md(监控指标)\n`;
|
|
3230
3325
|
prompt += ` - **禁止**:不要创建 020-specs/ 下的任何额外子目录(如数字编号、中文名称等)\n`;
|
|
3231
3326
|
prompt += ` - **禁止直接用 Write 工具写文件到 020-specs/**:必须通过 \`speccore analyze --apply '{"文件名":"内容"}' -I ${iter}\` 写入\n`;
|
|
3232
|
-
prompt += ` - ⚠️ 直接 Write 会导致目录结构错误(所有文件扁平在根目录),必须走 --apply 让 CLI 自动路由到
|
|
3327
|
+
prompt += ` - ⚠️ 直接 Write 会导致目录结构错误(所有文件扁平在根目录),必须走 --apply 让 CLI 自动路由到 overview/ 或 {端名}/ 子目录\n`;
|
|
3233
3328
|
if (ctx.phase !== '1') {
|
|
3234
3329
|
// 端专业性约束只在默认模式(全量)中输出
|
|
3235
3330
|
prompt += `\n## ⚠️ 端专业性约束\n`;
|
|
@@ -3320,7 +3415,7 @@ sequenceDiagram
|
|
|
3320
3415
|
prompt += `\n## ⚠️ 重要:Phase 1 完成后的下一步\n\n`;
|
|
3321
3416
|
prompt += `当你通过 --apply 写入所有综合文档后,CLI 会检测到项目有多个端(≥2 个端)。\n`;
|
|
3322
3417
|
prompt += `**此时你需要主动询问用户**:\n\n`;
|
|
3323
|
-
prompt += `"✅ Phase 1 已完成,生成了
|
|
3418
|
+
prompt += `"✅ Phase 1 已完成,生成了 overview/ 的综合文档。\n`;
|
|
3324
3419
|
prompt += `检测到项目有 ${'{'}端列表{'}'} 个端,需要继续执行 Phase 2 生成各端专属文档吗?\n`;
|
|
3325
3420
|
prompt += `请确认:输入 '继续' 或 'yes' 以执行 Phase 2"\n\n`;
|
|
3326
3421
|
prompt += `**如果用户确认继续**,你需要执行:\n`;
|