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":"AAiFA,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,GAAG,UAAU,CAAC;IACrD,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;IAClB,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;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAmND,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":"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"}
|
package/dist/commands/analyze.js
CHANGED
|
@@ -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
|
-
|
|
1900
|
-
|
|
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(` ❌
|
|
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(`
|
|
1910
|
-
logger_1.logger.info(' 💡
|
|
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
|
-
|
|
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
|
-
|
|
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+)
|