speccore 8.3.21 → 8.3.26
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/README.md +7 -4
- package/dist/cli.js +19 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +24 -8
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/config.d.ts +3 -1
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +206 -90
- package/dist/commands/config.js.map +1 -1
- package/dist/commands/context-output.d.ts.map +1 -1
- package/dist/commands/context-output.js +0 -10
- package/dist/commands/context-output.js.map +1 -1
- package/dist/commands/dev.js +6 -7
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +140 -0
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/done.js +51 -20
- package/dist/commands/done.js.map +1 -1
- package/dist/commands/execute.d.ts.map +1 -1
- package/dist/commands/execute.js +147 -45
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/help.js +5 -0
- package/dist/commands/help.js.map +1 -1
- package/dist/commands/init.d.ts +0 -2
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +9 -51
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/iteration/split.js +29 -17
- package/dist/commands/iteration/split.js.map +1 -1
- package/dist/commands/status-panel.d.ts.map +1 -1
- package/dist/commands/status-panel.js +13 -48
- package/dist/commands/status-panel.js.map +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +32 -0
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +206 -8
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/verdict.d.ts +16 -0
- package/dist/commands/verdict.d.ts.map +1 -0
- package/dist/commands/verdict.js +189 -0
- package/dist/commands/verdict.js.map +1 -0
- package/dist/commands/verify.d.ts.map +1 -1
- package/dist/commands/verify.js +3 -2
- package/dist/commands/verify.js.map +1 -1
- package/dist/core/analyze-engine.d.ts.map +1 -1
- package/dist/core/analyze-engine.js +3 -4
- package/dist/core/analyze-engine.js.map +1 -1
- package/dist/core/arbitration/arbitration-engine.d.ts +36 -0
- package/dist/core/arbitration/arbitration-engine.d.ts.map +1 -0
- package/dist/core/arbitration/arbitration-engine.js +142 -0
- package/dist/core/arbitration/arbitration-engine.js.map +1 -0
- package/dist/core/arbitration/conflict-detector.d.ts +15 -0
- package/dist/core/arbitration/conflict-detector.d.ts.map +1 -0
- package/dist/core/arbitration/conflict-detector.js +78 -0
- package/dist/core/arbitration/conflict-detector.js.map +1 -0
- package/dist/core/arbitration/conflict-types.d.ts +34 -0
- package/dist/core/arbitration/conflict-types.d.ts.map +1 -0
- package/dist/core/arbitration/conflict-types.js +8 -0
- package/dist/core/arbitration/conflict-types.js.map +1 -0
- package/dist/core/arbitration/contract-registry.d.ts +15 -0
- package/dist/core/arbitration/contract-registry.d.ts.map +1 -0
- package/dist/core/arbitration/contract-registry.js +185 -0
- package/dist/core/arbitration/contract-registry.js.map +1 -0
- package/dist/core/arbitration/contract-types.d.ts +33 -0
- package/dist/core/arbitration/contract-types.d.ts.map +1 -0
- package/dist/core/arbitration/contract-types.js +8 -0
- package/dist/core/arbitration/contract-types.js.map +1 -0
- package/dist/core/arbitration/index.d.ts +16 -0
- package/dist/core/arbitration/index.d.ts.map +1 -0
- package/dist/core/arbitration/index.js +32 -0
- package/dist/core/arbitration/index.js.map +1 -0
- package/dist/core/arbitration/l1-auto-arbiter.d.ts +19 -0
- package/dist/core/arbitration/l1-auto-arbiter.d.ts.map +1 -0
- package/dist/core/arbitration/l1-auto-arbiter.js +41 -0
- package/dist/core/arbitration/l1-auto-arbiter.js.map +1 -0
- package/dist/core/arbitration/l2-ai-arbiter.d.ts +19 -0
- package/dist/core/arbitration/l2-ai-arbiter.d.ts.map +1 -0
- package/dist/core/arbitration/l2-ai-arbiter.js +57 -0
- package/dist/core/arbitration/l2-ai-arbiter.js.map +1 -0
- package/dist/core/arbitration/l3-human-arbiter.d.ts +24 -0
- package/dist/core/arbitration/l3-human-arbiter.d.ts.map +1 -0
- package/dist/core/arbitration/l3-human-arbiter.js +65 -0
- package/dist/core/arbitration/l3-human-arbiter.js.map +1 -0
- package/dist/core/arbitration/verdict-generator.d.ts +16 -0
- package/dist/core/arbitration/verdict-generator.d.ts.map +1 -0
- package/dist/core/arbitration/verdict-generator.js +166 -0
- package/dist/core/arbitration/verdict-generator.js.map +1 -0
- package/dist/core/arbitration/verdict-types.d.ts +49 -0
- package/dist/core/arbitration/verdict-types.d.ts.map +1 -0
- package/dist/core/arbitration/verdict-types.js +8 -0
- package/dist/core/arbitration/verdict-types.js.map +1 -0
- package/dist/core/ask-config.d.ts +4 -3
- package/dist/core/ask-config.d.ts.map +1 -1
- package/dist/core/ask-config.js +79 -1
- package/dist/core/ask-config.js.map +1 -1
- package/dist/core/ask-engine.d.ts.map +1 -1
- package/dist/core/ask-engine.js +7 -0
- package/dist/core/ask-engine.js.map +1 -1
- package/dist/core/intent-recognition.d.ts +1 -1
- package/dist/core/intent-recognition.d.ts.map +1 -1
- package/dist/core/intent-recognition.js +10 -0
- package/dist/core/intent-recognition.js.map +1 -1
- package/dist/core/pattern-detector.d.ts +24 -0
- package/dist/core/pattern-detector.d.ts.map +1 -1
- package/dist/core/pattern-detector.js +172 -3
- package/dist/core/pattern-detector.js.map +1 -1
- package/dist/core/quality-audit.d.ts.map +1 -1
- package/dist/core/quality-audit.js +23 -15
- package/dist/core/quality-audit.js.map +1 -1
- package/dist/core/spec-skeleton.d.ts.map +1 -1
- package/dist/core/spec-skeleton.js +35 -12
- package/dist/core/spec-skeleton.js.map +1 -1
- package/dist/core/unified-config.d.ts +161 -27
- package/dist/core/unified-config.d.ts.map +1 -1
- package/dist/core/unified-config.js +856 -82
- package/dist/core/unified-config.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/execute.js
CHANGED
|
@@ -63,6 +63,8 @@ const execution_state_1 = require("../core/execution-state");
|
|
|
63
63
|
const git_integration_1 = require("../core/git-integration");
|
|
64
64
|
const prompt_builder_1 = require("../core/prompt-builder");
|
|
65
65
|
const verify_engine_1 = require("../core/verify-engine");
|
|
66
|
+
const arbitration_engine_1 = require("../core/arbitration/arbitration-engine");
|
|
67
|
+
const verdict_generator_1 = require("../core/arbitration/verdict-generator");
|
|
66
68
|
const unified_config_1 = require("../core/unified-config");
|
|
67
69
|
const pipeline_engine_1 = require("../core/pipeline-engine");
|
|
68
70
|
const index_guard_1 = require("../core/index-guard");
|
|
@@ -1171,13 +1173,7 @@ async function preFlightCheck(tasks, iteration, options) {
|
|
|
1171
1173
|
}
|
|
1172
1174
|
}
|
|
1173
1175
|
if (!testFound) {
|
|
1174
|
-
|
|
1175
|
-
const testPath = (0, path_1.join)(taskDir, '99-artifacts', 'TEST.md');
|
|
1176
|
-
if (await (0, fs_extra_1.pathExists)(testPath)) {
|
|
1177
|
-
const test = await (0, fs_extra_1.readFile)(testPath, 'utf-8');
|
|
1178
|
-
const n = (test.match(/⬜|✅|❌/g) || []).length;
|
|
1179
|
-
logger_1.logger.info(` 3. 测试: ${n} 用例`);
|
|
1180
|
-
}
|
|
1176
|
+
logger_1.logger.info(` 3. 测试: 未找到`);
|
|
1181
1177
|
}
|
|
1182
1178
|
// 4. Review(v6.49.9+: 扫描平铺的端目录)
|
|
1183
1179
|
let reviewFound = false;
|
|
@@ -1188,7 +1184,7 @@ async function preFlightCheck(tasks, iteration, options) {
|
|
|
1188
1184
|
}
|
|
1189
1185
|
}
|
|
1190
1186
|
if (!reviewFound) {
|
|
1191
|
-
logger_1.logger.info(` 4. 审查:
|
|
1187
|
+
logger_1.logger.info(` 4. 审查: ❌`);
|
|
1192
1188
|
}
|
|
1193
1189
|
// 5. API(00-specs/ 优先,_shared/ 回退)
|
|
1194
1190
|
const hasApiContract = await (0, fs_extra_1.pathExists)((0, path_1.join)(taskDir, '00-specs', 'API_CONTRACT.yaml')) || await (0, fs_extra_1.pathExists)((0, path_1.join)(taskDir, '_shared', 'API_CONTRACT.yaml'));
|
|
@@ -1533,7 +1529,8 @@ async function executionVerifyLoop(tasks, iteration, options) {
|
|
|
1533
1529
|
const maxRounds = 3;
|
|
1534
1530
|
const iterDir = await (0, context_1.getIterationDir)(iteration);
|
|
1535
1531
|
const config = await (0, unified_config_1.loadConfig)();
|
|
1536
|
-
const
|
|
1532
|
+
const projectConfig = await (0, unified_config_1.loadProjectConfig)();
|
|
1533
|
+
const codePath = projectConfig.code_scope?.[0] || process.cwd();
|
|
1537
1534
|
const absCodePath = codePath.startsWith('/') ? codePath : (0, path_1.join)(process.cwd(), codePath);
|
|
1538
1535
|
for (const task of tasks) {
|
|
1539
1536
|
logger_1.logger.info(`\n🔍 验证 ${task.id}...`);
|
|
@@ -1544,27 +1541,100 @@ async function executionVerifyLoop(tasks, iteration, options) {
|
|
|
1544
1541
|
if (round > 1)
|
|
1545
1542
|
logger_1.logger.info(` 🔄 第 ${round} 轮修复...`);
|
|
1546
1543
|
allPassed = true;
|
|
1547
|
-
// ── Step 1:
|
|
1548
|
-
const
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
});
|
|
1544
|
+
// ── Step 1: 契约冲突裁决 / 传统质量门禁 ──
|
|
1545
|
+
const arbConfig = await (0, arbitration_engine_1.getArbitrationConfig)();
|
|
1546
|
+
let testPassed = true;
|
|
1547
|
+
if (!arbConfig.enabled) {
|
|
1548
|
+
// 仲裁已禁用:回退到传统质量门禁
|
|
1549
|
+
const gate = await (0, verify_engine_1.runQualityGate)(task.id, taskCodePath, taskDir);
|
|
1550
|
+
await (0, verify_engine_1.writeVerifyReport)(gate.report, taskDir);
|
|
1551
|
+
if (options.auto) {
|
|
1552
|
+
logger_1.logger.info(` 🚧 质量门禁: ${gate.passed ? '✅ 通过' : '❌ 失败'} (arbitration=off)`);
|
|
1553
|
+
}
|
|
1554
|
+
else {
|
|
1555
|
+
logger_1.logger.info('');
|
|
1556
|
+
logger_1.logger.info(`🚧 传统质量门禁 — ${task.id}`);
|
|
1557
|
+
logger_1.logger.info(` ${gate.passed ? '✅ 全部通过' : `❌ ${gate.blockingFailed.length} 项阻塞性检查失败`}`);
|
|
1560
1558
|
}
|
|
1559
|
+
if (!gate.passed) {
|
|
1560
|
+
allPassed = false;
|
|
1561
|
+
}
|
|
1562
|
+
const testCheck = gate.report.checks.find(c => c.name === '单元测试');
|
|
1563
|
+
testPassed = !testCheck || testCheck.status !== 'fail';
|
|
1561
1564
|
}
|
|
1562
1565
|
else {
|
|
1563
|
-
|
|
1566
|
+
// 仲裁已启用:执行三级裁决
|
|
1567
|
+
const arbResult = await (0, arbitration_engine_1.runArbitration)(task.id, taskCodePath, taskDir, { mode: arbConfig.mode });
|
|
1568
|
+
await (0, verdict_generator_1.writeArbitrationReport)(arbResult.report, taskDir);
|
|
1569
|
+
if (options.auto) {
|
|
1570
|
+
// auto 模式:极简输出
|
|
1571
|
+
const totalFailed = arbResult.report.L1.failed + arbResult.report.L2.failed + arbResult.report.L3.failed;
|
|
1572
|
+
const modeLabel = arbConfig.mode === 'full' ? '' : ` [${arbConfig.mode}]`;
|
|
1573
|
+
if (totalFailed === 0) {
|
|
1574
|
+
logger_1.logger.info(` ⚖️ 契约裁决${modeLabel}: ✅ 全部通过`);
|
|
1575
|
+
}
|
|
1576
|
+
else {
|
|
1577
|
+
logger_1.logger.info(` ⚖️ 契约裁决${modeLabel}: ❌ L1=${arbResult.report.L1.failed} L2=${arbResult.report.L2.pending} L3=${arbResult.report.L3.pending}`);
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1580
|
+
else {
|
|
1581
|
+
// 正常模式:完整输出
|
|
1582
|
+
logger_1.logger.info('');
|
|
1583
|
+
logger_1.logger.info(`⚖️ 契约冲突裁决 — ${task.id}${arbConfig.mode !== 'full' ? ` [mode=${arbConfig.mode}]` : ''}`);
|
|
1584
|
+
// L1 机器契约
|
|
1585
|
+
if (arbResult.report.L1.total > 0) {
|
|
1586
|
+
logger_1.logger.info(` ⚙️ L1 机器契约: ${arbResult.report.L1.passed}/${arbResult.report.L1.total} 通过`);
|
|
1587
|
+
if (arbResult.report.L1.failed > 0) {
|
|
1588
|
+
logger_1.logger.warn(` ❌ ${arbResult.report.L1.failed} 项致命错误,已自动裁决驳回`);
|
|
1589
|
+
allPassed = false;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
else {
|
|
1593
|
+
logger_1.logger.info(` ⚙️ L1 机器契约: ✅ 全部通过`);
|
|
1594
|
+
}
|
|
1595
|
+
// L2 规范契约
|
|
1596
|
+
if (arbResult.report.L2.total > 0) {
|
|
1597
|
+
logger_1.logger.info(` 🤖 L2 规范契约: ${arbResult.report.L2.passed}/${arbResult.report.L2.total} 通过, ${arbResult.report.L2.pending} 待确认`);
|
|
1598
|
+
if (arbResult.report.L2.pending > 0) {
|
|
1599
|
+
logger_1.logger.info(` 💡 ${arbResult.report.L2.pending} 项需确认修复方案(见 ARBITRATION_REPORT.md)`);
|
|
1600
|
+
}
|
|
1601
|
+
if (arbResult.report.L2.failed > 0) {
|
|
1602
|
+
allPassed = false;
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
else {
|
|
1606
|
+
logger_1.logger.info(` 🤖 L2 规范契约: ✅ 全部通过`);
|
|
1607
|
+
}
|
|
1608
|
+
// L3 架构契约
|
|
1609
|
+
if (arbResult.report.L3.total > 0) {
|
|
1610
|
+
logger_1.logger.info(` 👤 L3 架构契约: ${arbResult.report.L3.passed}/${arbResult.report.L3.total} 通过, ${arbResult.report.L3.pending} 待裁决`);
|
|
1611
|
+
if (arbResult.report.L3.pending > 0) {
|
|
1612
|
+
logger_1.logger.warn(` ⚠️ ${arbResult.report.L3.pending} 项需人工裁决`);
|
|
1613
|
+
logger_1.logger.info(` 执行: speccore verdict --list --task ${task.id}`);
|
|
1614
|
+
allPassed = false;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
else {
|
|
1618
|
+
logger_1.logger.info(` 👤 L3 架构契约: ✅ 全部通过`);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
if (!arbResult.canProceed) {
|
|
1622
|
+
allPassed = false;
|
|
1623
|
+
if (!options.auto) {
|
|
1624
|
+
for (const c of arbResult.report.conflicts.filter(c => c.level === 'L1' && c.status === 'resolved')) {
|
|
1625
|
+
await (0, issue_tracker_1.logIssue)(taskDir, {
|
|
1626
|
+
type: 'error',
|
|
1627
|
+
severity: 'critical',
|
|
1628
|
+
summary: `L1 契约违反: ${c.contractName}`,
|
|
1629
|
+
detail: `任务: ${task.id},轮次: ${round}/3,${c.message}`,
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
const testConflict = arbResult.report.conflicts.find(c => c.contractName === '单元测试通过');
|
|
1635
|
+
testPassed = !testConflict || testConflict.status !== 'resolved';
|
|
1564
1636
|
}
|
|
1565
1637
|
// ── Step 2: 文档同步 — 根据单元测试结果更新 TEST.md ──
|
|
1566
|
-
const testCheck = gate.report.checks.find(c => c.name === '单元测试');
|
|
1567
|
-
const testPassed = testCheck?.status === 'pass';
|
|
1568
1638
|
await (0, verify_engine_1.syncTestDocFromResults)(taskDir, testPassed);
|
|
1569
1639
|
// ── Step 3: 检查 REVIEW.md(人工审查清单)──
|
|
1570
1640
|
const platDirsRound = await getPlatformSubtaskDirs(taskDir);
|
|
@@ -1625,7 +1695,8 @@ async function executionVerifyLoop(tasks, iteration, options) {
|
|
|
1625
1695
|
if (round < maxRounds) {
|
|
1626
1696
|
logger_1.logger.info(` 💡 AI 将修复未通过项。使用 speccore execute --task=${task.id} --force 重新执行代码生成`);
|
|
1627
1697
|
await (0, fs_extra_1.writeFile)((0, path_1.join)(taskDir, '.needs-retry'), String(round));
|
|
1628
|
-
// 输出 [SPECCORE_EXEC] 让 AI
|
|
1698
|
+
// 输出 [SPECCORE_EXEC] 让 AI 修复(回退到质量门禁报告)
|
|
1699
|
+
const gate = await (0, verify_engine_1.runQualityGate)(task.id, taskCodePath, taskDir);
|
|
1629
1700
|
if (!gate.passed) {
|
|
1630
1701
|
await (0, verify_engine_1.outputFixTag)(gate.report, taskDir, round);
|
|
1631
1702
|
}
|
|
@@ -1635,29 +1706,60 @@ async function executionVerifyLoop(tasks, iteration, options) {
|
|
|
1635
1706
|
if (allPassed) {
|
|
1636
1707
|
await (0, fs_extra_1.writeFile)((0, path_1.join)(taskDir, '.verification'), 'passed');
|
|
1637
1708
|
logger_1.logger.info(` ✅ ${task.id} 全部检查通过,可以 speccore done`);
|
|
1638
|
-
// v8.
|
|
1709
|
+
// v8.3.23+: 执行通过后检测可复用模式候选(适配端平铺结构 + 自动写入)
|
|
1639
1710
|
try {
|
|
1640
|
-
const codeDirs =
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1711
|
+
const codeDirs = await (0, pattern_detector_1.resolveCodeDirsFromTask)(taskDir);
|
|
1712
|
+
if (codeDirs.length === 0) {
|
|
1713
|
+
// 无代码目录时静默跳过(代码可能在外部工程)
|
|
1714
|
+
return;
|
|
1715
|
+
}
|
|
1645
1716
|
const candidates = await (0, pattern_detector_1.detectPatternCandidates)(codeDirs, `task:${task.id}`);
|
|
1646
|
-
if (candidates.length
|
|
1717
|
+
if (candidates.length === 0)
|
|
1718
|
+
return;
|
|
1719
|
+
const mode = await (0, pattern_detector_1.getPatternAutoSaveMode)();
|
|
1720
|
+
const autoSaved = [];
|
|
1721
|
+
const manual = [];
|
|
1722
|
+
for (const c of candidates) {
|
|
1723
|
+
const result = await (0, pattern_detector_1.autoSavePattern)(c, `task:${task.id}`, mode);
|
|
1724
|
+
if (result.saved && result.path) {
|
|
1725
|
+
autoSaved.push(`${c.name} [${result.confidence}]`);
|
|
1726
|
+
}
|
|
1727
|
+
else if (!(0, pattern_detector_1.isHighConfidenceCandidate)(c) && mode === 'smart') {
|
|
1728
|
+
manual.push(`${c.name} [${c.category}]`);
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
logger_1.logger.info('');
|
|
1732
|
+
logger_1.logger.info('🧩 执行完成,检测到以下可复用模式候选:');
|
|
1733
|
+
const byPlatform = (0, pattern_detector_1.groupCandidatesByPlatform)(candidates);
|
|
1734
|
+
for (const [plat, list] of Object.entries(byPlatform)) {
|
|
1735
|
+
const platLabel = plat === 'shared' ? '🌐 跨端共享' : plat === 'backend' ? '⚙️ 后端' : plat === 'frontend' ? '🎨 前端' : '📦 其他';
|
|
1736
|
+
logger_1.logger.info(` ${platLabel}:`);
|
|
1737
|
+
for (const c of list.slice(0, 2)) {
|
|
1738
|
+
logger_1.logger.info(` • ${c.name} [${c.category}] — ${c.reason}`);
|
|
1739
|
+
}
|
|
1740
|
+
if (list.length > 2) {
|
|
1741
|
+
logger_1.logger.info(` ... 还有 ${list.length - 2} 个`);
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
if (autoSaved.length > 0) {
|
|
1647
1745
|
logger_1.logger.info('');
|
|
1648
|
-
logger_1.logger.info(
|
|
1649
|
-
const
|
|
1650
|
-
|
|
1651
|
-
const platLabel = plat === 'shared' ? '🌐 跨端共享' : plat === 'backend' ? '⚙️ 后端' : plat === 'frontend' ? '🎨 前端' : '📦 其他';
|
|
1652
|
-
logger_1.logger.info(` ${platLabel}:`);
|
|
1653
|
-
for (const c of list.slice(0, 2)) {
|
|
1654
|
-
logger_1.logger.info(` • ${c.name} [${c.category}] — ${c.reason}`);
|
|
1655
|
-
}
|
|
1656
|
-
if (list.length > 2) {
|
|
1657
|
-
logger_1.logger.info(` ... 还有 ${list.length - 2} 个`);
|
|
1658
|
-
}
|
|
1746
|
+
logger_1.logger.info(` ✅ 已自动保存 ${autoSaved.length} 个高置信度模式到 .speccore/PATTERNS/`);
|
|
1747
|
+
for (const s of autoSaved.slice(0, 3)) {
|
|
1748
|
+
logger_1.logger.info(` • ${s}`);
|
|
1659
1749
|
}
|
|
1660
|
-
|
|
1750
|
+
}
|
|
1751
|
+
if (manual.length > 0 && mode === 'smart') {
|
|
1752
|
+
logger_1.logger.info('');
|
|
1753
|
+
logger_1.logger.info(` 💡 以下 ${manual.length} 个候选置信度较低,建议手动确认后保存:`);
|
|
1754
|
+
for (const m of manual.slice(0, 3)) {
|
|
1755
|
+
logger_1.logger.info(` • ${m}`);
|
|
1756
|
+
}
|
|
1757
|
+
logger_1.logger.info(' 命令: speccore pattern save --name=<模式名> --file=<文件路径>');
|
|
1758
|
+
}
|
|
1759
|
+
if (mode === 'off') {
|
|
1760
|
+
logger_1.logger.info('');
|
|
1761
|
+
logger_1.logger.info(' 💡 检测到可复用模式,自动保存已关闭。如需保存请执行:');
|
|
1762
|
+
logger_1.logger.info(' speccore pattern save --name=<模式名> --file=<文件路径>');
|
|
1661
1763
|
}
|
|
1662
1764
|
}
|
|
1663
1765
|
catch { /* 静默失败 */ }
|