speccore 8.3.249 → 8.3.251
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/.agents/skills/spec-once/SKILL.md +3 -2
- package/.agents/skills/speccore-router/SKILL.md +3 -3
- package/dist/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +62 -6
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/iteration/split.d.ts.map +1 -1
- package/dist/commands/iteration/split.js +66 -6
- package/dist/commands/iteration/split.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../../src/commands/iteration/split.ts"],"names":[],"mappings":"AA0KA,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAqLD,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../../src/commands/iteration/split.ts"],"names":[],"mappings":"AA0KA,MAAM,WAAW,qBAAqB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAqLD,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmsCzF"}
|
|
@@ -1129,6 +1129,9 @@ async function iterationSplitCommand(options) {
|
|
|
1129
1129
|
}
|
|
1130
1130
|
}
|
|
1131
1131
|
// ── 1. 检查 ANALYSIS.md + AI 智能拆分建议 ──
|
|
1132
|
+
// v8.3.249+: reqContent2/reqContent2Aggregated 提升到块外声明,供下方实际拆分源复用
|
|
1133
|
+
let reqContent2 = '';
|
|
1134
|
+
let reqContent2Aggregated = false;
|
|
1132
1135
|
const analysisPathNew = (0, path_1.join)(iterationDir, '020-specs', spec_paths_1.GLOBAL_SPECS_DIR, 'ANALYSIS.md');
|
|
1133
1136
|
const analysisPathOld = (0, path_1.join)(iterationDir, '020-specs', 'ANALYSIS.md');
|
|
1134
1137
|
const analysisPath = await (0, fs_extra_1.pathExists)(analysisPathNew) ? analysisPathNew : analysisPathOld;
|
|
@@ -1167,12 +1170,24 @@ async function iterationSplitCommand(options) {
|
|
|
1167
1170
|
const specDir2 = (0, path_1.join)(iterationDir, '020-specs');
|
|
1168
1171
|
// REQUIREMENT.md 从 overview/ 读取
|
|
1169
1172
|
const reqPath2 = (0, path_1.join)(specDir2, spec_paths_1.GLOBAL_SPECS_DIR, 'REQUIREMENT.md');
|
|
1170
|
-
let reqContent2 = '';
|
|
1171
1173
|
if (await (0, fs_extra_1.pathExists)(reqPath2)) {
|
|
1172
1174
|
reqContent2 = await (0, fs_extra_1.readFile)(reqPath2, 'utf-8');
|
|
1173
1175
|
}
|
|
1174
1176
|
// v8.3.160+: 如果全局 REQUIREMENT.md 为空/骨架,从各功能模块 overview/REQUIREMENT.md 聚合
|
|
1175
|
-
|
|
1177
|
+
// v8.3.249+: 增加陈旧检测——聚合文档不含当前 features 单元名时视为过期,强制重新聚合。
|
|
1178
|
+
// 此前仅按空/骨架判断,旧聚合文档与新切分单元不同步时 taskify 用陈旧数据拆分,
|
|
1179
|
+
// 漏掉新单元(--modules 指定新单元也匹配不到任何 section,反而全量拆分)。
|
|
1180
|
+
let reqContent2IsStale = false;
|
|
1181
|
+
if (reqContent2 && reqContent2.trim().length >= 200 && !reqContent2.includes('<!-- SPEC-SKELETON -->')) {
|
|
1182
|
+
const featuresAll = await (0, spec_paths_1.parseFeatureList)(iterationDir);
|
|
1183
|
+
for (const feature of featuresAll) {
|
|
1184
|
+
if (!reqContent2.includes(feature)) {
|
|
1185
|
+
reqContent2IsStale = true;
|
|
1186
|
+
break;
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
if (!reqContent2 || reqContent2.trim().length < 200 || reqContent2.includes('<!-- SPEC-SKELETON -->') || reqContent2IsStale) {
|
|
1176
1191
|
const featureReqParts = [];
|
|
1177
1192
|
const features = await (0, spec_paths_1.parseFeatureList)(iterationDir);
|
|
1178
1193
|
for (const feature of features) {
|
|
@@ -1186,6 +1201,7 @@ async function iterationSplitCommand(options) {
|
|
|
1186
1201
|
}
|
|
1187
1202
|
if (featureReqParts.length > 0) {
|
|
1188
1203
|
reqContent2 = featureReqParts.join('\n\n---\n\n');
|
|
1204
|
+
reqContent2Aggregated = true;
|
|
1189
1205
|
}
|
|
1190
1206
|
}
|
|
1191
1207
|
const specContents = [];
|
|
@@ -1273,7 +1289,9 @@ async function iterationSplitCommand(options) {
|
|
|
1273
1289
|
return;
|
|
1274
1290
|
}
|
|
1275
1291
|
const content = await (0, fs_extra_1.readFile)(reqFile, 'utf-8');
|
|
1276
|
-
|
|
1292
|
+
// v8.3.249+: 聚合后的最新需求内容(含新切分单元)优先于陈旧聚合文档作为实际拆分源
|
|
1293
|
+
const finalContent = (reqContent2Aggregated && reqContent2) ? reqContent2 : content;
|
|
1294
|
+
let sections = extractSections(finalContent, options.sections);
|
|
1277
1295
|
// v6.76.0+: 按功能模块过滤
|
|
1278
1296
|
if (options.modules) {
|
|
1279
1297
|
const moduleFilters = options.modules.split(',').map(m => m.trim()).filter(Boolean);
|
|
@@ -4398,7 +4416,9 @@ async function tryModuleDrivenSplit(iteration, iterationDir, options) {
|
|
|
4398
4416
|
catch { }
|
|
4399
4417
|
}
|
|
4400
4418
|
}
|
|
4401
|
-
// 3. 回退:读取 features/*/SOURCE.md(v8.3.226+,兼容旧 README.md
|
|
4419
|
+
// 3. 回退:读取 features/*/SOURCE.md(v8.3.226+,兼容旧 README.md)
|
|
4420
|
+
// v8.3.249+: 优先读 _matrix.md 端声明(unitize 切分时写入),替代全端兜底——
|
|
4421
|
+
// 此前全部配全端,单端功能(如仅 booking-service)也会拆出 4 个子任务
|
|
4402
4422
|
if (!modulePlatformsParsed) {
|
|
4403
4423
|
const featuresDir = (0, path_1.join)(reqDir, 'features');
|
|
4404
4424
|
if (await (0, fs_extra_1.pathExists)(featuresDir)) {
|
|
@@ -4408,10 +4428,23 @@ async function tryModuleDrivenSplit(iteration, iterationDir, options) {
|
|
|
4408
4428
|
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
4409
4429
|
const readmePath = await (0, feature_source_1.resolveUnitSourcePath)((0, path_1.join)(featuresDir, entry.name));
|
|
4410
4430
|
if (await (0, fs_extra_1.pathExists)(readmePath)) {
|
|
4431
|
+
let unitPlatforms = [...allPlatforms];
|
|
4432
|
+
const matrixPath = (0, path_1.join)(featuresDir, entry.name, '_matrix.md');
|
|
4433
|
+
if (await (0, fs_extra_1.pathExists)(matrixPath)) {
|
|
4434
|
+
const mc = await (0, fs_extra_1.readFile)(matrixPath, 'utf-8');
|
|
4435
|
+
const m = mc.match(/^platforms:\s*\n((?:\s+-\s+\S+\s*\n?)+)/m);
|
|
4436
|
+
if (m) {
|
|
4437
|
+
const declared = m[1].split('\n')
|
|
4438
|
+
.map(l => l.replace(/^\s+-\s+/, '').trim()).filter(Boolean);
|
|
4439
|
+
if (declared.length > 0) {
|
|
4440
|
+
unitPlatforms = declared.filter(p => allPlatforms.includes(p));
|
|
4441
|
+
}
|
|
4442
|
+
}
|
|
4443
|
+
}
|
|
4411
4444
|
modules.push({
|
|
4412
4445
|
name: entry.name, slug: slugify(entry.name), type: 'feature',
|
|
4413
4446
|
sourceFile: `features/${entry.name}/${(0, path_1.basename)(readmePath)}`,
|
|
4414
|
-
platforms:
|
|
4447
|
+
platforms: unitPlatforms,
|
|
4415
4448
|
});
|
|
4416
4449
|
}
|
|
4417
4450
|
}
|
|
@@ -4445,6 +4478,20 @@ async function tryModuleDrivenSplit(iteration, iterationDir, options) {
|
|
|
4445
4478
|
if (modules.length === 0) {
|
|
4446
4479
|
return false; // 无功能模块,回退到传统流程
|
|
4447
4480
|
}
|
|
4481
|
+
// v8.3.249+: --modules 过滤——模块驱动拆分此前完全忽略该选项,
|
|
4482
|
+
// 指定单个单元时仍全量拆分(FUNCTION_MAP 全部单元照拆)
|
|
4483
|
+
if (options.modules) {
|
|
4484
|
+
const moduleFilters = options.modules.split(',').map(m => m.trim()).filter(Boolean);
|
|
4485
|
+
const beforeCount = modules.length;
|
|
4486
|
+
const filtered = modules.filter(mod => moduleFilters.some(f => mod.name.includes(f) || mod.slug.includes(f)));
|
|
4487
|
+
if (filtered.length === 0) {
|
|
4488
|
+
logger_1.logger.warn(`没有匹配 "${options.modules}" 的功能模块(可用: ${modules.slice(0, 5).map(m => m.name).join(', ')}${modules.length > 5 ? '...' : ''}),回退传统流程`);
|
|
4489
|
+
return false;
|
|
4490
|
+
}
|
|
4491
|
+
modules.length = 0;
|
|
4492
|
+
modules.push(...filtered);
|
|
4493
|
+
logger_1.logger.info(` 🎯 模块过滤: ${beforeCount} → ${filtered.length}(只拆分: ${moduleFilters.join(', ')})`);
|
|
4494
|
+
}
|
|
4448
4495
|
// 检测已有任务
|
|
4449
4496
|
const existingTasks = await detectExistingTasks(iterationDir);
|
|
4450
4497
|
if (existingTasks.length > 0 && !options.force && !options.prune) {
|
|
@@ -4501,9 +4548,22 @@ async function tryModuleDrivenSplit(iteration, iterationDir, options) {
|
|
|
4501
4548
|
for (const mod of modules) {
|
|
4502
4549
|
const { id: taskId } = await (0, global_counters_1.nextTaskId)(mod.name, mod.slug);
|
|
4503
4550
|
const modPlatforms = mod.platforms.length > 0 ? mod.platforms : [...allPlatforms];
|
|
4551
|
+
// v8.3.249+: section.content 从 sourceFile(SOURCE.md 等)读取——此前硬编码空串,
|
|
4552
|
+
// 导致 REQ.md 四级回退全部落空(aiReq/analyzeReq/短 section.content 均不满足),
|
|
4553
|
+
// 最终写出「待补充」骨架,execute 阶段拿不到有价值的需求文档
|
|
4554
|
+
let sectionContent = '';
|
|
4555
|
+
if (mod.sourceFile) {
|
|
4556
|
+
try {
|
|
4557
|
+
const srcPath = (0, path_1.join)(iterationDir, '010-requirements', mod.sourceFile);
|
|
4558
|
+
if (await (0, fs_extra_1.pathExists)(srcPath)) {
|
|
4559
|
+
sectionContent = await (0, fs_extra_1.readFile)(srcPath, 'utf-8');
|
|
4560
|
+
}
|
|
4561
|
+
}
|
|
4562
|
+
catch { /* 读取失败保持空 */ }
|
|
4563
|
+
}
|
|
4504
4564
|
const section = {
|
|
4505
4565
|
name: mod.name,
|
|
4506
|
-
content:
|
|
4566
|
+
content: sectionContent,
|
|
4507
4567
|
level: 2,
|
|
4508
4568
|
};
|
|
4509
4569
|
section._topic = mod.slug;
|