speccore 6.76.0 → 6.77.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.
Files changed (52) hide show
  1. package/.agents/skills/spec-analyze/SKILL.md +174 -4
  2. package/.agents/skills/spec-change/SKILL.md +156 -20
  3. package/.agents/skills/spec-doc2spec/SKILL.md +121 -4
  4. package/.agents/skills/spec-execute/SKILL.md +148 -5
  5. package/.agents/skills/spec-iteration-create/SKILL.md +128 -9
  6. package/.agents/skills/spec-plan/SKILL.md +123 -4
  7. package/.agents/skills/spec-spec2doc/SKILL.md +126 -4
  8. package/.agents/skills/spec-split/SKILL.md +214 -4
  9. package/.agents/skills/spec-task-create/SKILL.md +156 -9
  10. package/.agents/skills/speccore-router/SKILL.md +21 -1
  11. package/dist/cli.js +22 -0
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/analyze.d.ts +2 -0
  14. package/dist/commands/analyze.d.ts.map +1 -1
  15. package/dist/commands/analyze.js +241 -14
  16. package/dist/commands/analyze.js.map +1 -1
  17. package/dist/commands/clarify.d.ts +11 -0
  18. package/dist/commands/clarify.d.ts.map +1 -0
  19. package/dist/commands/clarify.js +138 -0
  20. package/dist/commands/clarify.js.map +1 -0
  21. package/dist/commands/execute.d.ts +1 -0
  22. package/dist/commands/execute.d.ts.map +1 -1
  23. package/dist/commands/execute.js +15 -0
  24. package/dist/commands/execute.js.map +1 -1
  25. package/dist/commands/init.d.ts.map +1 -1
  26. package/dist/commands/init.js +4 -8
  27. package/dist/commands/init.js.map +1 -1
  28. package/dist/commands/iteration/split.d.ts +3 -1
  29. package/dist/commands/iteration/split.d.ts.map +1 -1
  30. package/dist/commands/iteration/split.js +125 -153
  31. package/dist/commands/iteration/split.js.map +1 -1
  32. package/dist/commands/update.js +0 -1
  33. package/dist/commands/update.js.map +1 -1
  34. package/dist/core/analyze-context-guard.js +2 -2
  35. package/dist/core/analyze-context-guard.js.map +1 -1
  36. package/dist/core/ask-engine.d.ts.map +1 -1
  37. package/dist/core/ask-engine.js +3 -2
  38. package/dist/core/ask-engine.js.map +1 -1
  39. package/dist/core/change-detector.d.ts +25 -0
  40. package/dist/core/change-detector.d.ts.map +1 -0
  41. package/dist/core/change-detector.js +170 -0
  42. package/dist/core/change-detector.js.map +1 -0
  43. package/dist/core/requirement-clarifier.d.ts +41 -0
  44. package/dist/core/requirement-clarifier.d.ts.map +1 -0
  45. package/dist/core/requirement-clarifier.js +181 -0
  46. package/dist/core/requirement-clarifier.js.map +1 -0
  47. package/dist/core/streaming-analyzer.d.ts.map +1 -1
  48. package/dist/core/streaming-analyzer.js +17 -4
  49. package/dist/core/streaming-analyzer.js.map +1 -1
  50. package/package.json +1 -1
  51. package/.agents/skills/spec-dev/SKILL.md +0 -10
  52. package/.agents/skills/spec-synthesize/SKILL.md +0 -10
@@ -459,6 +459,28 @@ async function analyzeCommand(options) {
459
459
  logger_1.logger.warn('未找到需求文档,请先导入: speccore doc2spec');
460
460
  return;
461
461
  }
462
+ // v6.76.0+: --clarify 模式下检测需求文档专业度
463
+ if (options.clarify) {
464
+ const { detectProfessionalLevel } = await Promise.resolve().then(() => __importStar(require('../core/requirement-clarifier')));
465
+ let lowQualityCount = 0;
466
+ for (const reqPath of requirements) {
467
+ const reqContent = await (0, fs_extra_2.readFile)(reqPath, 'utf-8');
468
+ const level = detectProfessionalLevel(reqContent);
469
+ if (level !== 'high') {
470
+ lowQualityCount++;
471
+ logger_1.logger.warn(` ⚠️ 需求文档质量${level.toUpperCase()}: ${reqPath.replace(iterDir + '/', '')}`);
472
+ logger_1.logger.info(` 💡 建议: speccore clarify --from "${reqPath}" --to ${iter}`);
473
+ }
474
+ }
475
+ if (lowQualityCount > 0) {
476
+ logger_1.logger.info('');
477
+ logger_1.logger.info(`📋 ${lowQualityCount}/${requirements.length} 个需求文档需要澄清整理`);
478
+ logger_1.logger.info(' 选项 1: 先执行 clarify 整理需求,再重新 analyze');
479
+ logger_1.logger.info(' 选项 2: 继续使用当前文档分析(加 --force 跳过检测)');
480
+ logger_1.logger.info('');
481
+ // 不阻断,但在 prompt 中注入澄清指令
482
+ }
483
+ }
462
484
  // 【v6.40.2 修复】--auto 不再跳过 AI,而是自动生成 prompt 让宿主 AI 执行专业分析
463
485
  logger_1.logger.info(` Auto 分析: ${iter} (${requirements.length} 个需求文档 → AI 专业分析)`);
464
486
  // 设置 prompt 模式,fall through 到下面的 prompt 生成逻辑
@@ -466,9 +488,18 @@ async function analyzeCommand(options) {
466
488
  }
467
489
  // ── v6.49.13+: 预创建 020-specs/ 目录结构(CLI 控制目录,AI 只填内容)──
468
490
  if (options.prompt) {
469
- const iterForDirs = options.iteration || await (0, context_1.getDefaultIteration)();
470
- if (iterForDirs) {
471
- await preCreateSpecDirectories(iterForDirs);
491
+ if (options.scope === 'global') {
492
+ // 全局分析:预创建 .speccore/GLOBAL/ 目录结构,不写迭代目录
493
+ const globalDir = (0, path_1.join)(process.cwd(), '.speccore', 'GLOBAL');
494
+ await (0, fs_extra_1.ensureDir)(globalDir);
495
+ await (0, fs_extra_1.ensureDir)((0, path_1.join)(globalDir, 'platforms'));
496
+ logger_1.logger.info(`📁 已预创建 .speccore/GLOBAL/ 目录结构`);
497
+ }
498
+ else {
499
+ const iterForDirs = options.iteration || await (0, context_1.getDefaultIteration)();
500
+ if (iterForDirs) {
501
+ await preCreateSpecDirectories(iterForDirs);
502
+ }
472
503
  }
473
504
  }
474
505
  // ── 非 prompt/apply 模式 → 全部转 AI prompt,不再走代码模板分析 ──
@@ -615,7 +646,7 @@ async function analyzeCommand(options) {
615
646
  }
616
647
  // ── Prompt 模式 ──
617
648
  if (options.prompt) {
618
- const iter = options.iteration || await (0, context_1.getDefaultIteration)();
649
+ const iter = options.scope === 'global' ? 'GLOBAL' : (options.iteration || await (0, context_1.getDefaultIteration)());
619
650
  const prompt = await buildMultiDocPrompt('analyze', { iteration: iter, task: options.task, type: options.type, scope: options.scope, withCode: options.withCode, platform: options.platform, phase: options.phase, autoMode: options.auto }, options);
620
651
  process.stdout.write(`[SPECCORE_PROMPT]\n${prompt}`);
621
652
  process.exitCode = 10;
@@ -624,12 +655,26 @@ async function analyzeCommand(options) {
624
655
  // ── Apply 模式 ──
625
656
  // 两层解耦:迭代级分析写 020-specs/,任务级分析只写 Task 目录(不覆盖迭代级基线)
626
657
  if (options.apply) {
627
- if (!options.iteration) {
658
+ // v6.76.0+: 支持 --apply @file.json 从文件读取(解决 Windows 下 JSON 转义问题)
659
+ if (options.apply.startsWith('@')) {
660
+ const filePath = options.apply.slice(1).trim();
661
+ try {
662
+ const fileContent = await (0, fs_extra_2.readFile)(filePath, 'utf-8');
663
+ options.apply = fileContent;
664
+ logger_1.logger.info(` 📄 已从文件读取 apply 内容: ${filePath}`);
665
+ }
666
+ catch (e) {
667
+ logger_1.logger.error(`无法读取 apply 文件: ${filePath}`);
668
+ return;
669
+ }
670
+ }
671
+ const isGlobalScope = options.scope === 'global';
672
+ if (!isGlobalScope && !options.iteration) {
628
673
  logger_1.logger.error('--apply 需要 --iteration');
629
674
  return;
630
675
  }
631
- const iterDir = await (0, context_1.getIterationDir)(options.iteration);
632
- const isTaskLevel = !!options.task;
676
+ const iterDir = isGlobalScope ? undefined : await (0, context_1.getIterationDir)(options.iteration);
677
+ const isTaskLevel = !isGlobalScope && !!options.task;
633
678
  let taskDir = null;
634
679
  if (isTaskLevel) {
635
680
  const taskId = options.task.startsWith('Task-') ? options.task : `Task-${options.task}`;
@@ -666,6 +711,66 @@ async function analyzeCommand(options) {
666
711
  const platformLabel = options.platform ? `/${options.platform}` : '';
667
712
  logger_1.logger.success(`✅ ${count} 个 Spec 文档已写入 ${options.task}${platformLabel}/(任务级,迭代基线不变)`);
668
713
  }
714
+ else if (isGlobalScope) {
715
+ // 全局级:写入 .speccore/GLOBAL/(与 platforms/ 同级,非迭代目录)
716
+ const globalBaseDir = (0, path_1.join)(process.cwd(), '.speccore', 'GLOBAL');
717
+ await (0, fs_extra_1.ensureDir)(globalBaseDir);
718
+ const globalSet = new Set(spec_paths_1.GLOBAL_SPEC_FILES);
719
+ for (const [filename, content] of Object.entries(docs)) {
720
+ // PATTERNS/ 文件特殊处理 → 写入 .speccore/PATTERNS/
721
+ if (filename.startsWith('PATTERNS/')) {
722
+ const patternsDir = (0, path_1.join)(process.cwd(), '.speccore', 'PATTERNS');
723
+ await (0, fs_extra_1.ensureDir)(patternsDir);
724
+ const patternFile = filename.slice('PATTERNS/'.length);
725
+ const fp = (0, path_1.join)(patternsDir, patternFile);
726
+ let existing = '';
727
+ if (await (0, fs_extra_1.pathExists)(fp))
728
+ existing = await (0, fs_extra_2.readFile)(fp, 'utf-8');
729
+ const merged = existing ? `${existing}\n\n---\n\n${content}` : content;
730
+ await (0, fs_extra_1.writeFile)(fp, merged);
731
+ logger_1.logger.info(` 🧩 PATTERN 已追加: ${patternFile}`);
732
+ count++;
733
+ continue;
734
+ }
735
+ let targetDir;
736
+ let targetFilename;
737
+ if (filename.includes('/')) {
738
+ const parts = filename.split('/');
739
+ if (parts[0] === 'platforms') {
740
+ // platforms/admin-web/_INDEX.md → .speccore/GLOBAL/platforms/admin-web/
741
+ targetDir = (0, path_1.join)(globalBaseDir, ...parts.slice(0, -1));
742
+ targetFilename = parts[parts.length - 1];
743
+ }
744
+ else {
745
+ // admin-web/FEATURES.md → .speccore/GLOBAL/platforms/admin-web/
746
+ targetDir = (0, path_1.join)(globalBaseDir, 'platforms', parts[0]);
747
+ targetFilename = parts[parts.length - 1];
748
+ }
749
+ }
750
+ else if (globalSet.has(filename)) {
751
+ targetDir = globalBaseDir;
752
+ targetFilename = filename;
753
+ }
754
+ else {
755
+ targetDir = globalBaseDir;
756
+ targetFilename = filename;
757
+ }
758
+ await (0, fs_extra_1.ensureDir)(targetDir);
759
+ const fp = (0, path_1.join)(targetDir, targetFilename);
760
+ if (!(await (0, task_utils_1.shouldOverwrite)(fp, !!options.interactive))) {
761
+ logger_1.logger.info(` ⏭️ 跳过: ${filename}`);
762
+ continue;
763
+ }
764
+ const bk = await (0, task_utils_1.backupWithTimestamp)(fp);
765
+ if (bk) {
766
+ backups.push(bk);
767
+ logger_1.logger.info(` 📦 ${filename} 旧版已备份: ${bk.split('/').pop()}`);
768
+ }
769
+ await (0, fs_extra_1.writeFile)(fp, content);
770
+ count++;
771
+ }
772
+ logger_1.logger.success(`✅ ${count} 个全局文档已写入 .speccore/GLOBAL/`);
773
+ }
669
774
  else {
670
775
  // 迭代级:写 020-specs/(全局文档写入 global/ 子目录,v6.41.0+)
671
776
  // v6.69.2+: 增加端名白名单校验,防止 AI 创建非法目录
@@ -723,6 +828,49 @@ async function analyzeCommand(options) {
723
828
  logger_1.logger.warn(`⚠️ 共跳过 ${skippedCount} 个非法目录的文档,请检查 AI 输出是否包含非端名目录`);
724
829
  }
725
830
  logger_1.logger.success(`✅ ${count} 个 Spec 文档已写入 020-specs/`);
831
+ // v6.74.0+: 流式分析自动检查(回退检测 + 最终核对)
832
+ if (options.streamingPhase) {
833
+ const phase = options.streamingPhase;
834
+ if (phase === 'phase1-backend' || phase === 'phase3-frontend') {
835
+ logger_1.logger.info('');
836
+ logger_1.logger.info('🔍 流式分析回退检测...');
837
+ const bt = await (0, streaming_analyzer_1.detectBacktrackingNeeds)(iterDir, phase);
838
+ if (bt.needed) {
839
+ logger_1.logger.warn(` ⚠️ 检测到 ${bt.targets.length} 个文档需要回退修正:`);
840
+ for (let i = 0; i < bt.targets.length; i++) {
841
+ logger_1.logger.warn(` - ${bt.targets[i]}: ${bt.reasons[i]}`);
842
+ }
843
+ logger_1.logger.info(' 💡 请在下一 Phase 前先修正上述文档');
844
+ }
845
+ else {
846
+ logger_1.logger.info(' ✅ 无回退需求,继续下一 Phase');
847
+ }
848
+ }
849
+ if (phase === 'phase6-final-audit') {
850
+ logger_1.logger.info('');
851
+ logger_1.logger.info('🔍 执行最终核对检查...');
852
+ const auditIssues = await (0, streaming_analyzer_1.runFinalAudit)(iterDir);
853
+ if (auditIssues.length > 0) {
854
+ const errors = auditIssues.filter(i => i.severity === 'error');
855
+ const warnings = auditIssues.filter(i => i.severity === 'warning');
856
+ if (errors.length > 0) {
857
+ logger_1.logger.error(` ❌ 发现 ${errors.length} 个错误:`);
858
+ for (const e of errors) {
859
+ logger_1.logger.error(` - ${e.description}`);
860
+ }
861
+ }
862
+ if (warnings.length > 0) {
863
+ logger_1.logger.warn(` ⚠️ 发现 ${warnings.length} 个警告:`);
864
+ for (const w of warnings) {
865
+ logger_1.logger.warn(` - ${w.description}`);
866
+ }
867
+ }
868
+ }
869
+ else {
870
+ logger_1.logger.info(' ✅ 最终核对通过,所有文档完整一致');
871
+ }
872
+ }
873
+ }
726
874
  // v6.72.0+: FUNCTION_MAP.md 自检
727
875
  const fmContent = docs['FUNCTION_MAP.md'] || docs['global/FUNCTION_MAP.md'];
728
876
  if (fmContent) {
@@ -774,6 +922,24 @@ async function analyzeCommand(options) {
774
922
  logger_1.logger.info(` ⏭️ 用户取消覆盖`);
775
923
  }
776
924
  }
925
+ else if (isGlobalScope) {
926
+ // 全局级:写 .speccore/GLOBAL/ANALYSIS.md
927
+ const globalDir = (0, path_1.join)(process.cwd(), '.speccore', 'GLOBAL');
928
+ await (0, fs_extra_1.ensureDir)(globalDir);
929
+ const globalAnalysisPath = (0, path_1.join)(globalDir, 'ANALYSIS.md');
930
+ if (await (0, task_utils_1.shouldOverwrite)(globalAnalysisPath, !!options.interactive)) {
931
+ const globalBackup = await (0, task_utils_1.backupWithTimestamp)(globalAnalysisPath);
932
+ if (globalBackup) {
933
+ backups.push(globalBackup);
934
+ logger_1.logger.info(` 📦 旧版已备份: ${globalBackup.split('/').pop()}`);
935
+ }
936
+ await (0, fs_extra_1.writeFile)(globalAnalysisPath, options.apply);
937
+ logger_1.logger.success(`✅ ANALYSIS.md 已写入 .speccore/GLOBAL/`);
938
+ }
939
+ else {
940
+ logger_1.logger.info(` ⏭️ 用户取消覆盖`);
941
+ }
942
+ }
777
943
  else {
778
944
  // 迭代级:写 020-specs/global/(全局文档,v6.41.0+)
779
945
  const specDir = (0, path_1.join)(iterDir, '020-specs');
@@ -1375,9 +1541,10 @@ async function buildMultiDocPrompt(command, ctx, options) {
1375
1541
  prompt += ` - 「## 端列表」章节 → 全局权威端名列表(如 backend/h5/admin)\n`;
1376
1542
  prompt += ` - 每个工程独立分析,文档输出到: .speccore/GLOBAL/platforms/{端名}/\n`;
1377
1543
  prompt += `2. Read .speccore/GLOBAL/ 下所有文档了解跨项目需求\n`;
1544
+ prompt += `3. **禁止行为(重要)**: 不要打开浏览器、不要模拟用户操作、不要访问 URL。所有分析必须基于直接 Read 源码文件完成。如果文件不存在,跳过即可,不要尝试其他方式获取。\n`;
1378
1545
  if (ctx.withCode) {
1379
1546
  // v6.71.2+: 双层扫描 + 功能模块驱动(替代原来的按端顺序分析)
1380
- prompt += `3. 从 CONSTITUTION.md 的「源码路径」列读取所有工程目录\n`;
1547
+ prompt += `4. 从 CONSTITUTION.md 的「源码路径」列读取所有工程目录\n`;
1381
1548
  prompt += `\n## 📊 Layer 1: 快速扫描所有端(并行,只提取索引)\n\n`;
1382
1549
  prompt += `对每个端,只读取关键索引文件(不深入代码逻辑):\n\n`;
1383
1550
  prompt += `**后端端**:\n`;
@@ -1449,7 +1616,7 @@ async function buildMultiDocPrompt(command, ctx, options) {
1449
1616
  prompt += `5. 以上文档输出到 .speccore/GLOBAL/ 和 .speccore/PATTERNS/,使用 Write 工具写入\n`;
1450
1617
  }
1451
1618
  else {
1452
- prompt += `3. 读取 .speccore/GLOBAL/ 下各项目需求文档,生成跨项目索引和需求目录\n`;
1619
+ prompt += `4. 读取 .speccore/GLOBAL/ 下各项目需求文档,生成跨项目索引和需求目录\n`;
1453
1620
  }
1454
1621
  prompt += `\n## 输出文档\n`;
1455
1622
  if (ctx.withCode) {
@@ -1514,6 +1681,7 @@ async function buildMultiDocPrompt(command, ctx, options) {
1514
1681
  `# 需求规格说明书
1515
1682
 
1516
1683
  > ${iter} | ${now}
1684
+ > ⚠️ 迭代名称仅为目录标识,不代表需求内容。以下分析严格基于需求文档,严禁臆造文档中未提及的功能。
1517
1685
 
1518
1686
  ## 写作要求
1519
1687
  将原始需求文档综合整理为一份结构化的需求规格说明书,不是简单复制原文,而是:
@@ -1534,6 +1702,7 @@ async function buildMultiDocPrompt(command, ctx, options) {
1534
1702
  `# 需求分析报告
1535
1703
 
1536
1704
  > ${iter} | ${now}
1705
+ > ⚠️ 迭代名称仅为目录标识,不代表需求内容。以下分析严格基于需求文档,严禁臆造文档中未提及的功能。
1537
1706
 
1538
1707
  ## 写作要求
1539
1708
  这是一份完整的需求分析报告,不是填空表。请根据 READ 的需求文档,用自然段落、表格、列表自由组织内容,涵盖以下要点:
@@ -1743,6 +1912,46 @@ sequenceDiagram
1743
1912
  BS-->>H5: 409 Conflict
1744
1913
  end
1745
1914
  \`\`\`
1915
+ `],
1916
+ ['DEV_GUIDE.md',
1917
+ `# 开发者实现指南
1918
+
1919
+ > ${iter} | ${now}
1920
+ > 本文档面向开发者,提供具体实现步骤、代码模式和最佳实践。
1921
+
1922
+ ## 写作要求
1923
+
1924
+ ### 全局级 DEV_GUIDE.md(020-specs/global/)
1925
+ - **技术栈与选型决策**:每个技术点的选型理由、替代方案对比
1926
+ - **代码分层规范**:目录结构、各层职责、代码组织方式
1927
+ - **通用设计模式**:Repository 模式、Service 模式、策略模式等具体实现
1928
+ - **跨端数据流**:请求从入口到数据库的完整链路、数据转换规则
1929
+ - **错误处理策略**:全局错误码、异常分类、降级策略
1930
+ - **性能优化基线**:缓存策略、数据库优化、并发控制
1931
+ - **安全基线**:鉴权流程、数据校验、敏感信息处理
1932
+
1933
+ ### 端级 DEV_GUIDE.md(020-specs/{端}/)
1934
+ - **端技术栈**:框架、库、工具链及选型理由
1935
+ - **目录结构规范**:该端的代码组织方式
1936
+ - **核心流程实现**:关键业务流程的伪代码/示例代码
1937
+ - **API 调用模式**:请求封装、错误处理、重试策略
1938
+ - **状态管理**:全局状态设计、与后端同步策略
1939
+ - **端特定最佳实践**:该端特有的性能优化、安全策略
1940
+
1941
+ ### 任务级 DEV_GUIDE.md(Task/00-specs/)
1942
+ - **任务概述**:该任务在整体功能中的位置和职责
1943
+ - **实现步骤**:Step-by-step 的开发步骤
1944
+ - **关键代码示例**:核心逻辑的伪代码或代码片段
1945
+ - **与存量功能的集成**:如何与已有代码交互、复用哪些模块
1946
+ - **测试策略**:单元测试、集成测试的具体写法
1947
+ - **注意事项**:常见坑点、边界条件、调试技巧
1948
+
1949
+ ## 质量要求
1950
+ - 必须是**可执行的实现指导**,不是抽象概念
1951
+ - 包含具体的代码示例(伪代码或关键代码片段)
1952
+ - 基于 020-specs/ 中已有的分析文档,不做重复分析
1953
+ - 补充技术文档中未涉及的实现细节
1954
+ - 如果涉及存量功能,说明复用方式和集成点
1746
1955
  `],
1747
1956
  ];
1748
1957
  // 任务类型 × 文档矩阵: 每种类型生成哪些文档
@@ -1758,7 +1967,11 @@ sequenceDiagram
1758
1967
  security: ['ANALYSIS.md', 'TEST.md', 'REVIEW.md', 'RISK.md'],
1759
1968
  performance: ['ANALYSIS.md', 'TECH.md', 'TEST.md', 'MONITOR.md'],
1760
1969
  };
1761
- const includeDocs = isTask ? (DOC_MATRIX[taskType] || DOC_MATRIX['feature']) : DOC_MATRIX['feature'];
1970
+ let includeDocs = isTask ? (DOC_MATRIX[taskType] || DOC_MATRIX['feature']) : DOC_MATRIX['feature'];
1971
+ // v6.76.0+: --dev-guide 模式下增加 DEV_GUIDE.md
1972
+ if (options?.devGuide) {
1973
+ includeDocs = [...includeDocs, 'DEV_GUIDE.md'];
1974
+ }
1762
1975
  // ── v6.61.0+: 恢复 Phase 1/Phase 2 分步逻辑,但 CLI 自动触发 Phase 2 ──
1763
1976
  // Phase 1: 生成全局文档(global/REQUIREMENT.md、ANALYSIS.md、DEPS.md 等)
1764
1977
  // Phase 2: 生成各端专属文档({端}/TECH.md、TEST.md、UI_SPEC.md 等)
@@ -1860,6 +2073,7 @@ sequenceDiagram
1860
2073
  prompt += `### 绝对禁止直接用 Write 工具写文件\n`;
1861
2074
  prompt += `- ❌ **错误行为**:Write("020-specs/global/ANALYSIS.md", content) 或直接 Write 到任何路径\n`;
1862
2075
  prompt += `- ✅ **正确行为**:必须通过 \`speccore analyze --apply '{"global/ANALYSIS.md":"...","admin-web/TECH.md":"..."}' -I ${iter}\` 写入\n`;
2076
+ prompt += `- 💡 **Windows 兼容**:如果 JSON 在命令行中转义困难,先将 JSON 写入文件(如 result.json),然后执行 \`speccore analyze --apply @result.json -I ${iter}\`\n`;
1863
2077
  prompt += `- ⚠️ **原因**:--apply 会让 CLI 自动路由文件到正确的子目录,直接 Write 会绕过这个机制,导致所有文件扁平在根目录\n\n`;
1864
2078
  prompt += `### ✅ 正确的目录结构\n`;
1865
2079
  prompt += `\`\`\`\n`;
@@ -1872,6 +2086,13 @@ sequenceDiagram
1872
2086
  prompt += `\`\`\`\n`;
1873
2087
  prompt += `- 每个端目录下只有该端的专属文档,不要混放\n`;
1874
2088
  prompt += `- 不要创建上述之外的任何子目录\n\n`;
2089
+ prompt += `## ⚠️ 迭代名称仅为目录标识(重要)\n\n`;
2090
+ prompt += `- 迭代名称("${iter}")仅为目录标识符,**不代表需求内容**\n`;
2091
+ prompt += `- **需求文档是唯一事实来源**:所有分析必须 100% 基于 010-requirements/ 下的文档内容\n`;
2092
+ prompt += `- 如果迭代名称与文档内容不一致(如迭代名叫"功能A"但文档描述"功能B"),**严格以文档内容为准**,完全忽略迭代名称\n`;
2093
+ prompt += `- **严禁基于迭代名称臆造功能**:不要补充文档中未提及的功能、接口、页面、字段、业务规则\n`;
2094
+ prompt += `- 如果文档内容不完整,标注"文档未提及",不要自行脑补\n`;
2095
+ prompt += `- 分析过程中,始终把迭代名称当作透明信息处理,不做任何功能推断\n\n`;
1875
2096
  prompt += `## 分析范围说明\n`;
1876
2097
  if (isTask) {
1877
2098
  prompt += `- 当前是**任务级分析**,类型为 \`${taskType}\`,只需产出 ${taskDocs.length} 个文档:${taskDocs.map(([n]) => n).join('、')}\n`;
@@ -1985,15 +2206,21 @@ sequenceDiagram
1985
2206
  prompt += ` e. 如用户指定了特定文档,优先读取指定文件;如要求全部,再读 sources/ 原始文档\n`;
1986
2207
  prompt += ` f. **文档长度自适应**:如果单个需求文档超过 5000 字,先快速扫描目录和章节标题,标记关键章节,再深入阅读。不要在非关键章节上花费过多 tokens\n`;
1987
2208
  prompt += `4. 读懂需求文档后,按专业模板标准自由撰写每个文档(不是填空表)\n`;
1988
- prompt += `5. 每个文档都要具体内容(禁止"待填充")\n`;
1989
- prompt += `6. **端发现(重要)**:先确定项目有哪些端,再按端组织文档\n`;
2209
+ prompt += `5. **文档忠实度约束(最高优先级)**:\n`;
2210
+ prompt += ` - **严禁臆造**:只能写需求文档中明确提及的功能、接口、页面、字段、业务规则\n`;
2211
+ prompt += ` - **严禁扩展**:不要基于迭代名称或你的知识补充文档中未提及的内容\n`;
2212
+ prompt += ` - **严禁推断**:不要从一句话推断出整个功能模块,只写文档中明确描述的内容\n`;
2213
+ prompt += ` - **边界处理**:如果文档对某功能描述不完整,标注"文档未充分描述",不要自行脑补完整方案\n`;
2214
+ prompt += ` - **交叉验证**:每写一个功能点,回头检查需求文档中是否有对应描述,没有则删除\n`;
2215
+ prompt += `6. 每个文档都要具体内容(禁止"待填充")\n`;
2216
+ prompt += `7. **端发现(重要)**:先确定项目有哪些端,再按端组织文档\n`;
1990
2217
  prompt += ` - 第 1 步:Read .speccore/CONSTITUTION.md\n`;
1991
2218
  prompt += ` - 第 2 步:从「## 端列表」章节提取端名(这是全局权威来源)\n`;
1992
2219
  prompt += ` - 第 3 步:如果没有「端列表」章节,从「对应端」列提取\n`;
1993
2220
  prompt += ` - 第 4 步:如果以上都无法确定,根据需求文档内容判断\n`;
1994
2221
  prompt += ` - 第 5 步:将发现的端列表写入 020-specs/PLATFORMS.md\n`;
1995
2222
  // v6.70.0+: REQUIREMENT.md 以产品视角撰写(不按端分章节)
1996
- prompt += `6b. **REQUIREMENT.md 写作风格(重要)**:全局需求文档必须以产品/用户视角撰写\n`;
2223
+ prompt += `8. **REQUIREMENT.md 写作风格(重要)**:全局需求文档必须以产品/用户视角撰写\n`;
1997
2224
  prompt += ` - **按业务场景/用户旅程组织章节**,不按端分章节(如"H5端需求"、"后端需求")\n`;
1998
2225
  prompt += ` - 每个场景描述:用户操作 → 系统响应 → 业务规则 → 边界条件\n`;
1999
2226
  prompt += ` - 系统响应中自然包含前后端交互,但不刻意标注技术实现细节\n`;
@@ -2003,7 +2230,7 @@ sequenceDiagram
2003
2230
  prompt += ` - 端的信息只在「功能模块清单」表格中标注,正文不区分端\n`;
2004
2231
  // v6.49.14+: 功能模块清单必须含涉及端列 + 来源链接
2005
2232
  // v6.71.3+: 增加「与全局层对比」列
2006
- prompt += `7. **功能模块清单(重要)**:写入 global/REQUIREMENT.md 时,功能模块清单表格必须包含以下列\n`;
2233
+ prompt += `9. **功能模块清单(重要)**:写入 global/REQUIREMENT.md 时,功能模块清单表格必须包含以下列\n`;
2007
2234
  prompt += ` - 表格格式:| # | 功能模块 | 涉及端 | 全局对比 | 来源 | 说明 |\n`;
2008
2235
  prompt += ` - 「涉及端」:每个模块标注需要**新开发工作**的端(标准端名,逗号分隔)\n`;
2009
2236
  prompt += ` - 「涉及」= 该端需要写新接口/新页面/新逻辑\n`;