speccore 8.3.232 → 8.3.234

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.
@@ -101,4 +101,9 @@ export declare function detectPendingUnits(iteration: string, allUnits: Iteratio
101
101
  export declare function consolidateUnitAnalyses(iteration: string, units: IterationUnit[], analyses: UnitAnalysis[]): Promise<string>;
102
102
  /** 构建单个功能单元的深度分析 Prompt */
103
103
  export declare function buildUnitAnalysisPrompt(iterDir: string, iteration: string, unit: IterationUnit, allUnits: IterationUnit[]): Promise<string>;
104
+ /**
105
+ * v8.3.234+: 生成并落盘「功能单元分析质量报告」——成功/失败清单 + 每单元产出物评分。
106
+ * 落盘到 020-specs/QUALITY_AUDIT.md;无可评单元时返回 null。
107
+ */
108
+ export declare function buildAndSaveQualityReport(iterDir: string, iter: string, units: IterationUnit[]): Promise<string | null>;
104
109
  //# sourceMappingURL=analyze.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"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"}
@@ -42,6 +42,7 @@ exports.loadUnitAnalyses = loadUnitAnalyses;
42
42
  exports.detectPendingUnits = detectPendingUnits;
43
43
  exports.consolidateUnitAnalyses = consolidateUnitAnalyses;
44
44
  exports.buildUnitAnalysisPrompt = buildUnitAnalysisPrompt;
45
+ exports.buildAndSaveQualityReport = buildAndSaveQualityReport;
45
46
  /**
46
47
  * analyze — 统一分析命令
47
48
  *
@@ -703,6 +704,8 @@ async function analyzeCommand(options) {
703
704
  logger_1.logger.success('🎉 所有功能单元分析已完成!');
704
705
  logger_1.logger.info(' 运行 --consolidate 汇总为统一报告');
705
706
  logger_1.logger.info(` speccore analyze --prompt -I ${iter} --consolidate`);
707
+ // v8.3.234+: 执行完成质量报告(成功/失败清单 + 产出物评分)
708
+ await buildAndSaveQualityReport(iterDir, iter, units);
706
709
  return;
707
710
  }
708
711
  targetUnitIds = pending.map(u => u.id);
@@ -715,6 +718,8 @@ async function analyzeCommand(options) {
715
718
  logger_1.logger.success('🎉 所有功能单元分析已完成!');
716
719
  logger_1.logger.info(' 运行 --consolidate 汇总为统一报告');
717
720
  logger_1.logger.info(` speccore analyze --prompt -I ${iter} --consolidate`);
721
+ // v8.3.234+: 执行完成质量报告(成功/失败清单 + 产出物评分)
722
+ await buildAndSaveQualityReport(iterDir, iter, units);
718
723
  return;
719
724
  }
720
725
  targetUnitIds = [pending[0].id];
@@ -726,7 +731,7 @@ async function analyzeCommand(options) {
726
731
  if (options.autoUnits || options.resumeUnits) {
727
732
  const loopResult = await runUnitDispatchLoop(iter, iterDir, units);
728
733
  if (loopResult.finished) {
729
- printUnitLoopSummary(iter, loopResult);
734
+ await printUnitLoopSummary(iter, iterDir, units, loopResult);
730
735
  return;
731
736
  }
732
737
  process.stdout.write(`[SPECCORE_PROMPT]\n${loopResult.prompt}\n\n## 完成后继续\n\n落盘后运行以下命令,CLI 将校验产出并自动推进到下一个单元:\n\n\`\`\`bash\nspeccore analyze --resume-units -I ${iter}\n\`\`\`\n`);
@@ -1895,19 +1900,26 @@ ${singlePrompt}`);
1895
1900
  }
1896
1901
  };
1897
1902
  await checkDir(specDir);
1898
- if (emptySkeletonDocs.length > 0) {
1899
- logger_1.logger.warn('');
1900
- logger_1.logger.warn(`⚠️ 检测到 ${emptySkeletonDocs.length} 个文档仍为骨架状态(含 <!-- SPEC-SKELETON -->):`);
1903
+ if (emptySkeletonDocs.length > 0 || emptyTableDocs.length > 0) {
1904
+ // v8.3.233+: 结构化报告 + 兜底指引——报告给用户,可对有问题单元再次分析直到干净
1905
+ const iterName = (0, path_1.basename)(iterDir);
1906
+ const problemUnits = new Set();
1907
+ const mapUnit = (d) => {
1908
+ const seg = d.split('/')[0];
1909
+ if (seg && seg !== 'overview')
1910
+ problemUnits.add(seg);
1911
+ };
1912
+ emptySkeletonDocs.forEach(mapUnit);
1913
+ emptyTableDocs.forEach(mapUnit);
1914
+ process.stdout.write('\n[SPECCORE_SKELETON_REPORT]\n');
1915
+ logger_1.logger.warn(`⚠️ 质量检查: ${emptySkeletonDocs.length} 个空骨架 / ${emptyTableDocs.length} 个空表格`);
1901
1916
  for (const d of emptySkeletonDocs)
1902
- logger_1.logger.warn(` ❌ ${d}`);
1903
- logger_1.logger.info(' 💡 建议重新执行 analyze 补充这些文档');
1904
- }
1905
- if (emptyTableDocs.length > 0) {
1906
- logger_1.logger.warn('');
1907
- logger_1.logger.warn(`⚠️ 检测到 ${emptyTableDocs.length} 个文档含空表格(只有表头无数据):`);
1917
+ logger_1.logger.warn(` ❌ 空骨架: 020-specs/${d}`);
1908
1918
  for (const d of emptyTableDocs)
1909
- logger_1.logger.warn(` ❌ ${d}`);
1910
- logger_1.logger.info(' 💡 建议重新执行 analyze 补充表格数据');
1919
+ logger_1.logger.warn(` ⚠️ 空表格: 020-specs/${d}`);
1920
+ logger_1.logger.info(' 💡 兜底修复(循环直到干净):');
1921
+ logger_1.logger.info(` speccore analyze --resume-units -I ${iterName.replace(/^Iteration-/, '')}`);
1922
+ logger_1.logger.info(' (仍为骨架的单元会被重新纳入分析;也可 --unit <单元名> 定向重析)');
1911
1923
  }
1912
1924
  }
1913
1925
  catch (e) {
@@ -6510,7 +6522,32 @@ async function loadUnitAnalyses(iteration) {
6510
6522
  async function detectPendingUnits(iteration, allUnits) {
6511
6523
  const completed = await loadUnitAnalyses(iteration);
6512
6524
  const completedIds = new Set(completed.map(a => a.id));
6513
- return allUnits.filter(u => !completedIds.has(u.id));
6525
+ const iterDir = `Iteration-${iteration.replace(/^Iteration-/, '')}`;
6526
+ const pending = [];
6527
+ for (const u of allUnits) {
6528
+ if (!completedIds.has(u.id)) {
6529
+ pending.push(u);
6530
+ continue;
6531
+ }
6532
+ // v8.3.233+: 完成记录存在但落盘内容仍为骨架 → 仍视为待分析(兜底:
6533
+ // 用户可对有问题的单元再次分析,直到无空骨架)
6534
+ if (await unitHasSkeletonOutput(iterDir, u))
6535
+ pending.push(u);
6536
+ }
6537
+ return pending;
6538
+ }
6539
+ /** v8.3.233+: 检查单元落盘规格是否仍为骨架/空内容(用于 pending 判定兜底,不写缓存) */
6540
+ async function unitHasSkeletonOutput(iterDir, unit) {
6541
+ const specDir = getUnitSpecDir(iterDir, unit);
6542
+ for (const f of ['REQUIREMENT.md', 'ANALYSIS.md', 'TECH.md']) {
6543
+ const fp = (0, path_1.join)(specDir, f);
6544
+ if (!(await (0, fs_extra_1.pathExists)(fp)))
6545
+ continue;
6546
+ const content = (await (0, fs_extra_2.readFile)(fp, 'utf-8')).trim();
6547
+ if (content && !content.includes('SPEC-SKELETON') && content.length >= 200)
6548
+ return false;
6549
+ }
6550
+ return true; // 三个候选全无效 → 视为骨架状态
6514
6551
  }
6515
6552
  /** 汇总所有单元分析为统一报告(带 [DOC:xxx] 标记) */
6516
6553
  async function consolidateUnitAnalyses(iteration, units, analyses) {
@@ -6881,11 +6918,12 @@ async function runUnitDispatchLoop(iter, iterDir, units) {
6881
6918
  return (0, dispatch_loop_1.runDispatchLoopRound)(steps, {
6882
6919
  projectRoot: (0, task_utils_1.findProjectRoot)() || process.cwd(),
6883
6920
  scope: `analyze-units:${iter}`,
6884
- maxRetries: 1,
6921
+ // v8.3.233+: 一轮内最多 3 次尝试(初始 + 2 重试);循环外 resume 还可无限续跑
6922
+ maxRetries: 2,
6885
6923
  });
6886
6924
  }
6887
6925
  /** 输出调度循环完成汇总 */
6888
- function printUnitLoopSummary(iter, result) {
6926
+ async function printUnitLoopSummary(iter, iterDir, units, result) {
6889
6927
  const s = result.summary;
6890
6928
  if (s.failed.length > 0) {
6891
6929
  logger_1.logger.warn(`⚠️ 功能单元分析循环完成: ${s.done.length} 完成 / ${s.failed.length} 失败`);
@@ -6898,6 +6936,77 @@ function printUnitLoopSummary(iter, result) {
6898
6936
  logger_1.logger.success(`🎉 所有 ${s.done.length} 个功能单元分析完成!`);
6899
6937
  }
6900
6938
  logger_1.logger.info(` 下一步: 汇总统一报告 speccore analyze --prompt -I ${iter} --consolidate`);
6939
+ // v8.3.234+: 执行完成质量报告(成功/失败清单 + 产出物评分)落盘 QUALITY_AUDIT.md
6940
+ await buildAndSaveQualityReport(iterDir, iter, units);
6941
+ }
6942
+ /**
6943
+ * v8.3.234+: 生成并落盘「功能单元分析质量报告」——成功/失败清单 + 每单元产出物评分。
6944
+ * 落盘到 020-specs/QUALITY_AUDIT.md;无可评单元时返回 null。
6945
+ */
6946
+ async function buildAndSaveQualityReport(iterDir, iter, units) {
6947
+ if (units.length === 0)
6948
+ return null;
6949
+ const { validateContentQuality } = await Promise.resolve().then(() => __importStar(require('../core/spec-skeleton')));
6950
+ const report = [];
6951
+ for (const u of units) {
6952
+ const specDir = getUnitSpecDir(iterDir, u);
6953
+ const rows = [];
6954
+ for (const f of ['REQUIREMENT.md', 'ANALYSIS.md', 'TECH.md']) {
6955
+ const fp = (0, path_1.join)(specDir, f);
6956
+ if (!(await (0, fs_extra_1.pathExists)(fp)))
6957
+ continue;
6958
+ const content = (await (0, fs_extra_2.readFile)(fp, 'utf-8')).trim();
6959
+ if (!content || content.includes('SPEC-SKELETON') || content.length < 200)
6960
+ continue;
6961
+ const q = await validateContentQuality(f, content, '');
6962
+ rows.push({ doc: f, score: q.score, issues: q.issues });
6963
+ }
6964
+ report.push({ unit: u.name, ok: rows.length > 0, rows });
6965
+ }
6966
+ const okCount = report.filter(r => r.ok).length;
6967
+ const failCount = report.length - okCount;
6968
+ const totalDocs = report.reduce((a, r) => a + r.rows.length, 0);
6969
+ const avgScore = totalDocs > 0 ? Math.round(report.reduce((a, r) => a + r.rows.reduce((b, row) => b + row.score, 0), 0) / totalDocs) : 0;
6970
+ const lines = [];
6971
+ lines.push('# 功能单元分析质量报告');
6972
+ lines.push('');
6973
+ lines.push(`> 生成时间: ${new Date().toISOString()}`);
6974
+ lines.push(`> 迭代: ${iter}`);
6975
+ lines.push(`> 结果: ${okCount} 成功 / ${failCount} 失败(共 ${units.length} 单元,评 ${totalDocs} 份文档,平均 ${avgScore} 分)`);
6976
+ lines.push('');
6977
+ lines.push('## 评分明细');
6978
+ lines.push('');
6979
+ lines.push('| 单元 | 状态 | 文档 | 评分 | 主要扣分项 |');
6980
+ lines.push('|:---|:---|:---|:---|:---|');
6981
+ for (const r of report) {
6982
+ if (r.ok) {
6983
+ for (const row of r.rows) {
6984
+ lines.push(`| ${r.unit} | ✅ | ${row.doc} | ${row.score} | ${row.issues.slice(0, 3).join(';') || '—'} |`);
6985
+ }
6986
+ }
6987
+ else {
6988
+ lines.push(`| ${r.unit} | ❌ 失败 | — | — | 缺少有效规格文档(REQUIREMENT/ANALYSIS/TECH 至少一份,内容 ≥200 字符且非骨架) |`);
6989
+ }
6990
+ }
6991
+ lines.push('');
6992
+ lines.push('## 失败单元修复');
6993
+ lines.push('');
6994
+ if (failCount === 0) {
6995
+ lines.push('无失败单元。');
6996
+ }
6997
+ else {
6998
+ lines.push('```bash');
6999
+ lines.push(`speccore analyze --resume-units -I ${iter}`);
7000
+ lines.push('```');
7001
+ lines.push('仍为骨架/空内容的单元会被重新纳入分析,循环直到干净。');
7002
+ }
7003
+ lines.push('');
7004
+ const specRoot = (0, path_1.join)(iterDir, '020-specs');
7005
+ await (0, fs_extra_1.ensureDir)(specRoot);
7006
+ const reportPath = (0, path_1.join)(specRoot, 'QUALITY_AUDIT.md');
7007
+ await (0, fs_extra_1.writeFile)(reportPath, lines.join('\n'));
7008
+ logger_1.logger.info(` 📊 质量报告已落盘: 020-specs/QUALITY_AUDIT.md(${okCount} 成功 / ${failCount} 失败,平均 ${avgScore} 分)`);
7009
+ return reportPath;
6901
7010
  }
6902
7011
  // ═══════════════════════════════════════════════════════════
6903
7012
  // 多子任务分析支持(v8.3.94+)