speccore 8.3.221 → 8.3.223
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/dist/cli.js +29 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +491 -238
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/change.js +1 -0
- package/dist/commands/change.js.map +1 -1
- package/dist/commands/doc2spec.d.ts.map +1 -1
- package/dist/commands/doc2spec.js +205 -95
- package/dist/commands/doc2spec.js.map +1 -1
- package/dist/commands/execute.js +4 -4
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/iteration/split.d.ts.map +1 -1
- package/dist/commands/iteration/split.js +29 -182
- package/dist/commands/iteration/split.js.map +1 -1
- package/dist/commands/plan.d.ts.map +1 -1
- package/dist/commands/plan.js +67 -11
- package/dist/commands/plan.js.map +1 -1
- package/dist/commands/req-doc.d.ts.map +1 -1
- package/dist/commands/req-doc.js +122 -14
- package/dist/commands/req-doc.js.map +1 -1
- package/dist/commands/retro.d.ts +1 -1
- package/dist/commands/retro.d.ts.map +1 -1
- package/dist/commands/retro.js +87 -8
- package/dist/commands/retro.js.map +1 -1
- package/dist/commands/run.d.ts +1 -0
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +182 -14
- package/dist/commands/run.js.map +1 -1
- package/dist/core/agent-adapter.d.ts.map +1 -1
- package/dist/core/agent-adapter.js +13 -6
- package/dist/core/agent-adapter.js.map +1 -1
- package/dist/core/context-budget.d.ts +3 -2
- package/dist/core/context-budget.d.ts.map +1 -1
- package/dist/core/context-budget.js +16 -3
- package/dist/core/context-budget.js.map +1 -1
- package/dist/core/dispatch-loop.d.ts +81 -0
- package/dist/core/dispatch-loop.d.ts.map +1 -0
- package/dist/core/dispatch-loop.js +152 -0
- package/dist/core/dispatch-loop.js.map +1 -0
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +20 -0
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/requirement-clarifier.d.ts.map +1 -1
- package/dist/core/requirement-clarifier.js +36 -0
- package/dist/core/requirement-clarifier.js.map +1 -1
- package/dist/core/state.d.ts +3 -0
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +19 -1
- package/dist/core/state.js.map +1 -1
- package/dist/core/unit-context-assembler.d.ts +5 -0
- package/dist/core/unit-context-assembler.d.ts.map +1 -1
- package/dist/core/unit-context-assembler.js +225 -9
- package/dist/core/unit-context-assembler.js.map +1 -1
- package/package.json +2 -2
|
@@ -50,14 +50,13 @@ const spec_skeleton_1 = require("../../core/spec-skeleton");
|
|
|
50
50
|
const questions_1 = require("../../core/questions");
|
|
51
51
|
const pipeline_engine_1 = require("../../core/pipeline-engine");
|
|
52
52
|
const agent_adapter_1 = require("../../core/agent-adapter");
|
|
53
|
-
const code_scanner_1 = require("../../core/code-scanner");
|
|
54
|
-
const knowledge_graph_1 = require("../../core/knowledge-graph");
|
|
55
53
|
const git_integration_1 = require("../../core/git-integration");
|
|
56
54
|
const cleanup_1 = require("../cleanup");
|
|
57
55
|
const unified_config_1 = require("../../core/unified-config");
|
|
58
56
|
const ui_verify_1 = require("../../core/ui-verify");
|
|
59
57
|
// v8.3.125+: 公共同义词扩展模块(从 split.ts 提取,供全链路使用)
|
|
60
58
|
const synonyms_1 = require("../../utils/synonyms");
|
|
59
|
+
const unit_context_assembler_1 = require("../../core/unit-context-assembler");
|
|
61
60
|
/**
|
|
62
61
|
* 将 AI 返回的 scope 简写映射到 CONSTITUTION.md 标准端名
|
|
63
62
|
* v6.69.3+: 解决中文简写(如 "后端"、"admin")导致目录名错误的问题
|
|
@@ -354,7 +353,7 @@ async function iterationSplitCommand(options) {
|
|
|
354
353
|
``,
|
|
355
354
|
`[SPECCORE_NEXT_STEP]`,
|
|
356
355
|
`下一步: ${result.nextStepName || result.nextStepId}`,
|
|
357
|
-
|
|
356
|
+
`请在同一会话继续执行: ${nextCmd}`,
|
|
358
357
|
``,
|
|
359
358
|
`[SPECCORE_CONTEXT_SNAPSHOT]`,
|
|
360
359
|
JSON.stringify(result.contextSnapshot || {}),
|
|
@@ -380,7 +379,7 @@ async function iterationSplitCommand(options) {
|
|
|
380
379
|
const finalPrompt = prompt + `\n\n## ⚠️ Pipeline 模式:步骤隔离\n\n` +
|
|
381
380
|
`当前是 Split Pipeline 模式。当你通过 --response 写入任务拆分结果后,` +
|
|
382
381
|
`CLI 会自动输出 [SPECCORE_STEP_DONE] 标记,提示你在新会话中执行下一步。\n\n` +
|
|
383
|
-
`**看到 [SPECCORE_STEP_DONE]
|
|
382
|
+
`**看到 [SPECCORE_STEP_DONE] 后,请在同一会话继续执行下一步命令**。\n`;
|
|
384
383
|
process.stdout.write(`[SPECCORE_PROMPT]\n${finalPrompt}`);
|
|
385
384
|
process.exitCode = 10;
|
|
386
385
|
return;
|
|
@@ -402,7 +401,7 @@ async function iterationSplitCommand(options) {
|
|
|
402
401
|
const finalPrompt = prompt + `\n\n## ⚠️ Pipeline 模式:步骤隔离\n\n` +
|
|
403
402
|
`当前是 Split Pipeline 模式。当你通过 --response 写入任务拆分结果后,` +
|
|
404
403
|
`CLI 会自动输出 [SPECCORE_STEP_DONE] 标记,提示你在新会话中执行下一步。\n\n` +
|
|
405
|
-
`**看到 [SPECCORE_STEP_DONE]
|
|
404
|
+
`**看到 [SPECCORE_STEP_DONE] 后,请在同一会话继续执行下一步命令**。\n`;
|
|
406
405
|
process.stdout.write(`[SPECCORE_PROMPT]\n${finalPrompt}`);
|
|
407
406
|
process.exitCode = 10;
|
|
408
407
|
return;
|
|
@@ -566,7 +565,7 @@ async function iterationSplitCommand(options) {
|
|
|
566
565
|
``,
|
|
567
566
|
`[SPECCORE_NEXT_STEP]`,
|
|
568
567
|
`下一步: ${state.currentStep}`,
|
|
569
|
-
|
|
568
|
+
`请在同一会话继续执行: ${nextCmd}`,
|
|
570
569
|
``,
|
|
571
570
|
`[SPECCORE_CONTEXT_SNAPSHOT]`,
|
|
572
571
|
JSON.stringify(stepResult.contextSnapshot || {}),
|
|
@@ -686,6 +685,23 @@ async function iterationSplitCommand(options) {
|
|
|
686
685
|
section._scopePlatforms = taskScopePlatforms;
|
|
687
686
|
sections.push(section);
|
|
688
687
|
}
|
|
688
|
+
// v8.3.223+: 过滤骨架质量标准标题泄漏为功能单元名(spec-skeleton 注入的引导标题
|
|
689
|
+
// 「📋 质量标准({docName})」被 AI 当功能单元,产出垃圾任务名如 Task-NNN-requirement-md)
|
|
690
|
+
const rubricFiltered = sections.filter(s => {
|
|
691
|
+
const name = (s.functionalUnit || s.name || '').trim();
|
|
692
|
+
return !/^📋\s*质量标准/.test(name) && !/^质量标准\s*([^)]*)$/.test(name);
|
|
693
|
+
});
|
|
694
|
+
if (rubricFiltered.length < sections.length) {
|
|
695
|
+
const removed = sections.length - rubricFiltered.length;
|
|
696
|
+
logger_1.logger.warn(` 🧹 已过滤 ${removed} 个「质量标准」骨架标题伪功能单元(AI 未删除骨架引导标题)`);
|
|
697
|
+
logger_1.logger.warn(' 请检查 AI 拆分结果是否覆盖真实功能单元(参考 FUNCTION_MAP.md)');
|
|
698
|
+
sections.length = 0;
|
|
699
|
+
sections.push(...rubricFiltered);
|
|
700
|
+
if (sections.length === 0) {
|
|
701
|
+
logger_1.logger.error(' ❌ 过滤后无有效功能单元,拆分中止。请重新拆分并告诉 AI:不要将「质量标准」骨架标题作为功能单元');
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
689
705
|
// v8.3.4+: 校验所有任务的 scope 是否只含标准端名
|
|
690
706
|
const invalidScopes = [];
|
|
691
707
|
for (const sec of sections) {
|
|
@@ -1525,6 +1541,9 @@ const TEMPLATE_PATTERNS = [
|
|
|
1525
1541
|
/^建设目标$/,
|
|
1526
1542
|
/^业务背景$/,
|
|
1527
1543
|
/^技术背景$/,
|
|
1544
|
+
// v8.3.223+: 骨架质量标准引导标题(spec-skeleton 注入,AI 填充时可能未删除)不应成为任务
|
|
1545
|
+
/^📋\s*质量标准/,
|
|
1546
|
+
/^质量标准\s*([^)]*)$/,
|
|
1528
1547
|
];
|
|
1529
1548
|
function filterTemplateNoise(sections) {
|
|
1530
1549
|
return sections.filter(s => {
|
|
@@ -3318,7 +3337,7 @@ subagent, contextType) {
|
|
|
3318
3337
|
p += `> 以下是从 FUNCTION_MAP.md 中为每个功能单元提取的相关上下文。\n`;
|
|
3319
3338
|
p += `> 拆分时必须基于这些功能单元,每个功能单元对应 1~3 个任务。\n\n`;
|
|
3320
3339
|
for (const unit of funcUnits) {
|
|
3321
|
-
const unitCtx = await
|
|
3340
|
+
const unitCtx = await (0, unit_context_assembler_1.extractOverviewContext)(iterationDir, unit.name, unit.platforms);
|
|
3322
3341
|
p += `### 📌 功能单元: ${unit.name}\n`;
|
|
3323
3342
|
p += `- 涉及端: ${unit.platforms.join(', ')}\n`;
|
|
3324
3343
|
if (unit.sharedCapability && unit.sharedCapability !== '无')
|
|
@@ -4460,180 +4479,8 @@ async function tryModuleDrivenSplit(iteration, iterationDir, options) {
|
|
|
4460
4479
|
catch { }
|
|
4461
4480
|
return true;
|
|
4462
4481
|
}
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
* CLI 做计算(提取),AI 做内容(填充)
|
|
4466
|
-
*/
|
|
4467
|
-
async function assembleUnitContext(iterationDir, unitName, platforms) {
|
|
4468
|
-
const specsBase = (0, path_1.join)(iterationDir, '020-specs');
|
|
4469
|
-
const overviewDir = (0, path_1.join)(specsBase, spec_paths_1.GLOBAL_SPECS_DIR);
|
|
4470
|
-
const ctx = [];
|
|
4471
|
-
// 关键词拆分:将功能单元名拆成多个搜索词(如「预订管理」→「预订」「管理」)
|
|
4472
|
-
const keywords = unitName.split(/(?<=[\u4e00-\u9fff])(?=[\u4e00-\u9fff])/).filter(k => k.length >= 1);
|
|
4473
|
-
// 也加入英文关键词(如 booking、checkin)
|
|
4474
|
-
const slugKeywords = slugify(unitName).split('-').filter(k => k.length >= 3);
|
|
4475
|
-
const allKeywords = [...keywords, ...slugKeywords];
|
|
4476
|
-
const matchLine = (line) => allKeywords.some(k => line.includes(k));
|
|
4477
|
-
// 1. 从 overview/REQUIREMENT.md 提取相关章节
|
|
4478
|
-
const reqPath = (0, path_1.join)(overviewDir, 'REQUIREMENT.md');
|
|
4479
|
-
if (await (0, fs_extra_1.pathExists)(reqPath)) {
|
|
4480
|
-
try {
|
|
4481
|
-
const content = await (0, fs_extra_1.readFile)(reqPath, 'utf-8');
|
|
4482
|
-
const lines = content.split(/\r?\n/);
|
|
4483
|
-
const relevant = [];
|
|
4484
|
-
let inRelevantSection = false;
|
|
4485
|
-
for (const line of lines) {
|
|
4486
|
-
if (line.startsWith('## ') || line.startsWith('### ')) {
|
|
4487
|
-
inRelevantSection = matchLine(line);
|
|
4488
|
-
}
|
|
4489
|
-
if (inRelevantSection || (line.startsWith('|') && matchLine(line))) {
|
|
4490
|
-
relevant.push(line);
|
|
4491
|
-
}
|
|
4492
|
-
}
|
|
4493
|
-
if (relevant.length > 0) {
|
|
4494
|
-
ctx.push(`### 📋 需求规格(REQUIREMENT.md 相关片段)\n\`\`\`\n${relevant.slice(0, 60).join('\n')}\n\`\`\``);
|
|
4495
|
-
}
|
|
4496
|
-
}
|
|
4497
|
-
catch { }
|
|
4498
|
-
}
|
|
4499
|
-
// 2. 从 platforms/_shared/_MODULES.md 提取相关模块
|
|
4500
|
-
const modulesPath = (0, path_1.join)(specsBase, 'platforms', '_shared', '_MODULES.md');
|
|
4501
|
-
if (await (0, fs_extra_1.pathExists)(modulesPath)) {
|
|
4502
|
-
try {
|
|
4503
|
-
const content = await (0, fs_extra_1.readFile)(modulesPath, 'utf-8');
|
|
4504
|
-
const lines = content.split(/\r?\n/);
|
|
4505
|
-
const relevant = [];
|
|
4506
|
-
let inRelevantBlock = false;
|
|
4507
|
-
let blockLines = [];
|
|
4508
|
-
for (const line of lines) {
|
|
4509
|
-
if (line.startsWith('## ')) {
|
|
4510
|
-
// 保存上一个块
|
|
4511
|
-
if (inRelevantBlock && blockLines.length > 0) {
|
|
4512
|
-
relevant.push(...blockLines);
|
|
4513
|
-
}
|
|
4514
|
-
inRelevantBlock = matchLine(line);
|
|
4515
|
-
blockLines = [line];
|
|
4516
|
-
}
|
|
4517
|
-
else if (inRelevantBlock) {
|
|
4518
|
-
blockLines.push(line);
|
|
4519
|
-
}
|
|
4520
|
-
else if (line.startsWith('|') && matchLine(line)) {
|
|
4521
|
-
relevant.push(line);
|
|
4522
|
-
}
|
|
4523
|
-
}
|
|
4524
|
-
if (inRelevantBlock && blockLines.length > 0)
|
|
4525
|
-
relevant.push(...blockLines);
|
|
4526
|
-
if (relevant.length > 0) {
|
|
4527
|
-
ctx.push(`### 🧩 功能模块(_MODULES.md 相关片段)\n\`\`\`\n${relevant.slice(0, 50).join('\n')}\n\`\`\``);
|
|
4528
|
-
}
|
|
4529
|
-
}
|
|
4530
|
-
catch { }
|
|
4531
|
-
}
|
|
4532
|
-
// 3. 从各端 _INDEX.md 提取相关接口/页面
|
|
4533
|
-
for (const platform of platforms) {
|
|
4534
|
-
const indexPath = (0, path_1.join)(specsBase, 'platforms', platform, '_INDEX.md');
|
|
4535
|
-
if (await (0, fs_extra_1.pathExists)(indexPath)) {
|
|
4536
|
-
try {
|
|
4537
|
-
const content = await (0, fs_extra_1.readFile)(indexPath, 'utf-8');
|
|
4538
|
-
const lines = content.split(/\r?\n/);
|
|
4539
|
-
const relevant = [];
|
|
4540
|
-
let inRelevantSection = false;
|
|
4541
|
-
for (const line of lines) {
|
|
4542
|
-
if (line.startsWith('## ') || line.startsWith('### ')) {
|
|
4543
|
-
inRelevantSection = matchLine(line);
|
|
4544
|
-
}
|
|
4545
|
-
if (inRelevantSection || (line.startsWith('|') && matchLine(line))) {
|
|
4546
|
-
relevant.push(line);
|
|
4547
|
-
}
|
|
4548
|
-
}
|
|
4549
|
-
if (relevant.length > 0) {
|
|
4550
|
-
ctx.push(`### 🖥️ ${platform} 端相关(_INDEX.md 片段)\n\`\`\`\n${relevant.slice(0, 40).join('\n')}\n\`\`\``);
|
|
4551
|
-
}
|
|
4552
|
-
}
|
|
4553
|
-
catch { }
|
|
4554
|
-
}
|
|
4555
|
-
}
|
|
4556
|
-
// 4. 从 overview/FUNCTION_MAP.md 提取本单元行 + 依赖单元
|
|
4557
|
-
const funcMapPath = (0, path_1.join)(overviewDir, 'FUNCTION_MAP.md');
|
|
4558
|
-
if (await (0, fs_extra_1.pathExists)(funcMapPath)) {
|
|
4559
|
-
try {
|
|
4560
|
-
const content = await (0, fs_extra_1.readFile)(funcMapPath, 'utf-8');
|
|
4561
|
-
const lines = content.split(/\r?\n/);
|
|
4562
|
-
const matchedRows = lines.filter(l => l.startsWith('|') && matchLine(l));
|
|
4563
|
-
if (matchedRows.length > 0) {
|
|
4564
|
-
ctx.push(`### 🗺️ 功能映射(FUNCTION_MAP.md)\n\`\`\`\n${matchedRows.join('\n')}\n\`\`\``);
|
|
4565
|
-
}
|
|
4566
|
-
}
|
|
4567
|
-
catch { }
|
|
4568
|
-
}
|
|
4569
|
-
// 5. 从 overview/TECH.md 提取相关架构信息
|
|
4570
|
-
const techPath = (0, path_1.join)(overviewDir, 'TECH.md');
|
|
4571
|
-
if (await (0, fs_extra_1.pathExists)(techPath)) {
|
|
4572
|
-
try {
|
|
4573
|
-
const content = await (0, fs_extra_1.readFile)(techPath, 'utf-8');
|
|
4574
|
-
const lines = content.split(/\r?\n/);
|
|
4575
|
-
const relevant = [];
|
|
4576
|
-
let inRelevantSection = false;
|
|
4577
|
-
for (const line of lines) {
|
|
4578
|
-
if (line.startsWith('## ') || line.startsWith('### ')) {
|
|
4579
|
-
inRelevantSection = matchLine(line);
|
|
4580
|
-
}
|
|
4581
|
-
if (inRelevantSection)
|
|
4582
|
-
relevant.push(line);
|
|
4583
|
-
}
|
|
4584
|
-
if (relevant.length > 0) {
|
|
4585
|
-
ctx.push(`### 🏗️ 技术架构相关(TECH.md 片段)\n\`\`\`\n${relevant.slice(0, 40).join('\n')}\n\`\`\``);
|
|
4586
|
-
}
|
|
4587
|
-
}
|
|
4588
|
-
catch { }
|
|
4589
|
-
}
|
|
4590
|
-
// v8.2.0+: 知识图谱 + 源码关联增强
|
|
4591
|
-
// v8.3.125+: 自动检查过期并刷新
|
|
4592
|
-
try {
|
|
4593
|
-
const graph = await (0, knowledge_graph_1.loadFreshKnowledgeGraph)(process.cwd());
|
|
4594
|
-
if (graph) {
|
|
4595
|
-
const unitNameLower = unitName.toLowerCase();
|
|
4596
|
-
const matchedReqIds = new Set();
|
|
4597
|
-
const codeFiles = [];
|
|
4598
|
-
// 找匹配当前功能单元的 requirement 实体
|
|
4599
|
-
for (const entity of Object.values(graph.entities)) {
|
|
4600
|
-
if (entity.type !== 'requirement')
|
|
4601
|
-
continue;
|
|
4602
|
-
const titleLower = entity.title.toLowerCase();
|
|
4603
|
-
if (titleLower.includes(unitNameLower) || unitNameLower.includes(titleLower)) {
|
|
4604
|
-
matchedReqIds.add(entity.id);
|
|
4605
|
-
}
|
|
4606
|
-
}
|
|
4607
|
-
// 通过关系链找关联的 source-file 实体
|
|
4608
|
-
for (const rel of graph.relations) {
|
|
4609
|
-
if (!matchedReqIds.has(rel.from) && !matchedReqIds.has(rel.to))
|
|
4610
|
-
continue;
|
|
4611
|
-
const neighborId = matchedReqIds.has(rel.from) ? rel.to : rel.from;
|
|
4612
|
-
const neighbor = graph.entities[neighborId];
|
|
4613
|
-
if (neighbor && neighbor.type === 'source-file' && neighbor.file) {
|
|
4614
|
-
codeFiles.push(neighbor.file);
|
|
4615
|
-
}
|
|
4616
|
-
}
|
|
4617
|
-
if (codeFiles.length > 0) {
|
|
4618
|
-
ctx.push(`### 💻 相关源码文件(知识图谱关联)\n${codeFiles.slice(0, 5).map(f => `- \`${f}\``).join('\n')}`);
|
|
4619
|
-
}
|
|
4620
|
-
}
|
|
4621
|
-
}
|
|
4622
|
-
catch { /* ignore */ }
|
|
4623
|
-
// v8.2.0+: findRelevantCode 语义关联补充
|
|
4624
|
-
try {
|
|
4625
|
-
const matches = await (0, code_scanner_1.findRelevantCode)(unitName, 5);
|
|
4626
|
-
if (matches.length > 0) {
|
|
4627
|
-
const files = matches.map(m => `- \`${m.file}\` (相关度: ${m.score.toFixed(2)})`);
|
|
4628
|
-
ctx.push(`### 🔍 语义关联源码文件\n${files.join('\n')}`);
|
|
4629
|
-
}
|
|
4630
|
-
}
|
|
4631
|
-
catch { /* ignore */ }
|
|
4632
|
-
if (ctx.length === 0) {
|
|
4633
|
-
return `> 功能单元「${unitName}」未在分析文档中找到直接相关内容,请根据全局文档推断。`;
|
|
4634
|
-
}
|
|
4635
|
-
return ctx.join('\n\n');
|
|
4636
|
-
}
|
|
4482
|
+
// v8.3.223+: 本地 assembleUnitContext 副本已收敛到 core/unit-context-assembler.ts 的
|
|
4483
|
+
// extractOverviewContext(此前两套实现并存、已漂移),本文件统一引用该实现
|
|
4637
4484
|
/**
|
|
4638
4485
|
* 生成内容填充 Prompt — AI 为预创建的任务填充 REQ.md/TECH.md
|
|
4639
4486
|
* v7.4.2+: 每个功能单元注入精准上下文,而非让 AI 自己从全量文档中查找
|
|
@@ -4665,7 +4512,7 @@ async function buildContentFillingPrompt(iteration, iterationDir, sections, allP
|
|
|
4665
4512
|
p += ` - ${platform}/*/TECH.md — 子任务技术方案\n`;
|
|
4666
4513
|
}
|
|
4667
4514
|
// v7.4.2+: 注入该功能单元的精准上下文
|
|
4668
|
-
const unitCtx = await
|
|
4515
|
+
const unitCtx = await (0, unit_context_assembler_1.extractOverviewContext)(iterationDir, featureName, modPlatforms);
|
|
4669
4516
|
p += `\n#### 📎 功能单元「${featureName}」相关上下文\n\n${unitCtx}\n\n`;
|
|
4670
4517
|
p += `\n`;
|
|
4671
4518
|
}
|