speccore 7.5.0 → 8.0.0
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/commands/analyze.d.ts.map +1 -1
- package/dist/commands/analyze.js +67 -43
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/iteration/split.d.ts.map +1 -1
- package/dist/commands/iteration/split.js +63 -11
- package/dist/commands/iteration/split.js.map +1 -1
- package/dist/core/spec-paths.d.ts +3 -2
- package/dist/core/spec-paths.d.ts.map +1 -1
- package/dist/core/spec-paths.js +23 -20
- package/dist/core/spec-paths.js.map +1 -1
- package/dist/core/spec-skeleton.d.ts +72 -0
- package/dist/core/spec-skeleton.d.ts.map +1 -0
- package/dist/core/spec-skeleton.js +427 -0
- package/dist/core/spec-skeleton.js.map +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAiEA,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,CAAC;IACxC,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;IAElB,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;CACtB;AAED,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA2rC3E"}
|
package/dist/commands/analyze.js
CHANGED
|
@@ -59,6 +59,7 @@ const questions_1 = require("../core/questions");
|
|
|
59
59
|
const platform_registry_1 = require("../core/platform-registry");
|
|
60
60
|
const index_guard_1 = require("../core/index-guard");
|
|
61
61
|
const spec_paths_1 = require("../core/spec-paths");
|
|
62
|
+
const spec_skeleton_1 = require("../core/spec-skeleton");
|
|
62
63
|
const unified_retrieval_1 = require("../core/unified-retrieval");
|
|
63
64
|
const pipeline_engine_1 = require("../core/pipeline-engine");
|
|
64
65
|
const change_detection_1 = require("../core/change-detection");
|
|
@@ -523,10 +524,23 @@ async function analyzeCommand(options) {
|
|
|
523
524
|
else {
|
|
524
525
|
const iterForDirs = options.iteration || await (0, context_1.getDefaultIteration)();
|
|
525
526
|
if (iterForDirs) {
|
|
526
|
-
//
|
|
527
|
-
const
|
|
528
|
-
|
|
529
|
-
await
|
|
527
|
+
// v8.0.0+: 骨架优先架构 — CLI 预创建所有文件,AI 只覆盖内容
|
|
528
|
+
const iterDirForSkeleton = await (0, context_1.getIterationDir)(iterForDirs);
|
|
529
|
+
const specDir = (0, path_1.join)(iterDirForSkeleton, '020-specs');
|
|
530
|
+
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
531
|
+
const iterName = iterForDirs;
|
|
532
|
+
// v7.4.3+ 兼容:先运行一次旧版 sanitize 迁移遗留文件(一次性)
|
|
533
|
+
await sanitizeSpecDirectories(iterDirForSkeleton);
|
|
534
|
+
// v8.0.0+: 计算 manifest 并生成骨架
|
|
535
|
+
const phase = options.phase;
|
|
536
|
+
const manifest = (0, spec_skeleton_1.computeAnalyzeManifest)(platforms, phase, iterName);
|
|
537
|
+
const skeletonResult = await (0, spec_skeleton_1.generateSkeleton)(specDir, manifest);
|
|
538
|
+
if (skeletonResult.created.length > 0) {
|
|
539
|
+
logger_1.logger.info(`🦴 已创建 ${skeletonResult.created.length} 个文件骨架: ${skeletonResult.created.join(', ')}`);
|
|
540
|
+
}
|
|
541
|
+
if (skeletonResult.skipped.length > 0) {
|
|
542
|
+
logger_1.logger.info(`✅ 已有 ${skeletonResult.skipped.length} 个文件保留原内容`);
|
|
543
|
+
}
|
|
530
544
|
}
|
|
531
545
|
}
|
|
532
546
|
}
|
|
@@ -3215,19 +3229,22 @@ sequenceDiagram
|
|
|
3215
3229
|
else if (ctx.phase === '2') {
|
|
3216
3230
|
taskDocs = taskDocs.filter(([n]) => PLATFORM_DOCS.includes(n));
|
|
3217
3231
|
}
|
|
3218
|
-
//
|
|
3219
|
-
//
|
|
3232
|
+
// v8.0.0+: 骨架进度检测 — 每次只生成下一个未填充的文档
|
|
3233
|
+
// 替代 v7.5.0 的 detectIterationDocsStatus(基于文件是否存在)
|
|
3220
3234
|
let perDocStatus = null;
|
|
3221
3235
|
if (!isGlobal && !isTask && !ctx.phase && ctx.iteration && ctx.iteration !== 'GLOBAL') {
|
|
3222
3236
|
try {
|
|
3223
3237
|
const iterDir = await (0, context_1.getIterationDir)(ctx.iteration);
|
|
3224
3238
|
if (iterDir) {
|
|
3225
|
-
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3239
|
+
const specDir = (0, path_1.join)(iterDir, '020-specs');
|
|
3240
|
+
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
3241
|
+
const manifest = (0, spec_skeleton_1.computeAnalyzeManifest)(platforms, undefined, ctx.iteration);
|
|
3242
|
+
perDocStatus = await (0, spec_skeleton_1.detectSkeletonProgress)(specDir, manifest);
|
|
3243
|
+
if (perDocStatus.nextUnfilled) {
|
|
3244
|
+
const nextDocName = perDocStatus.nextUnfilled.docName;
|
|
3245
|
+
const nextDocPlatform = perDocStatus.nextUnfilled.platform || null;
|
|
3246
|
+
// 过滤 taskDocs 只保留下一个未填充的文档
|
|
3247
|
+
if (nextDocPlatform && perDocStatus.nextUnfilled.category === 'platform') {
|
|
3231
3248
|
// Phase 2 文档(端专属)
|
|
3232
3249
|
taskDocs = taskDocs.filter(([n]) => n === nextDocName);
|
|
3233
3250
|
ctx.platform = nextDocPlatform;
|
|
@@ -3236,11 +3253,15 @@ sequenceDiagram
|
|
|
3236
3253
|
// Phase 1 文档(overview)
|
|
3237
3254
|
taskDocs = taskDocs.filter(([n]) => n === nextDocName);
|
|
3238
3255
|
}
|
|
3256
|
+
logger_1.logger.info(`🦴 骨架进度: ${perDocStatus.filledCount}/${perDocStatus.totalCount} 已填充,下一个: ${perDocStatus.nextUnfilled.relPath}`);
|
|
3257
|
+
}
|
|
3258
|
+
else if (perDocStatus.filledCount === perDocStatus.totalCount) {
|
|
3259
|
+
logger_1.logger.info(`🎉 所有 ${perDocStatus.totalCount} 个骨架文件均已填充`);
|
|
3239
3260
|
}
|
|
3240
3261
|
}
|
|
3241
3262
|
}
|
|
3242
3263
|
catch (e) {
|
|
3243
|
-
logger_1.logger.debug(
|
|
3264
|
+
logger_1.logger.debug(`骨架进度检测失败(非关键): ${e.message}`);
|
|
3244
3265
|
}
|
|
3245
3266
|
}
|
|
3246
3267
|
// ── 任务级文档覆盖:00-specs/ 使用任务级文档集(v6.44.0+) ──
|
|
@@ -3407,28 +3428,29 @@ sequenceDiagram
|
|
|
3407
3428
|
prompt += `---\n\n`;
|
|
3408
3429
|
}
|
|
3409
3430
|
}
|
|
3410
|
-
// ──
|
|
3411
|
-
prompt += `##
|
|
3412
|
-
prompt +=
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
prompt +=
|
|
3430
|
-
prompt += `-
|
|
3431
|
-
prompt += `-
|
|
3431
|
+
// ── v8.0.0+: 骨架优先架构 — 简洁的文件写入指令 ──
|
|
3432
|
+
prompt += `## 📝 文件写入方式(v8.0.0+ 骨架模式)\n\n`;
|
|
3433
|
+
prompt += `CLI 已预创建所有文件骨架(含占位内容)。请逐个用 Write 工具覆盖为专业分析内容:\n\n`;
|
|
3434
|
+
// 动态生成骨架文件列表
|
|
3435
|
+
try {
|
|
3436
|
+
const iterDir = await (0, context_1.getIterationDir)(iter);
|
|
3437
|
+
if (iterDir) {
|
|
3438
|
+
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
3439
|
+
const phase = options?.phase;
|
|
3440
|
+
const manifest = (0, spec_skeleton_1.computeAnalyzeManifest)(platforms, phase, iter);
|
|
3441
|
+
const specDir = (0, path_1.join)(iterDir, '020-specs');
|
|
3442
|
+
prompt += (0, spec_skeleton_1.buildSkeletonFileList)(manifest, specDir);
|
|
3443
|
+
}
|
|
3444
|
+
}
|
|
3445
|
+
catch {
|
|
3446
|
+
// 回退:静态列表
|
|
3447
|
+
prompt += `- \`020-specs/overview/\` 下的 REQUIREMENT.md, ANALYSIS.md, TECH.md, DEPS.md, RISK.md, REVIEW.md, MONITOR.md, FUNCTION_MAP.md\n`;
|
|
3448
|
+
prompt += `- \`020-specs/{端名}/\` 下的 TECH.md, TEST.md, UI_SPEC.md\n\n`;
|
|
3449
|
+
}
|
|
3450
|
+
prompt += `\n**注意**:\n`;
|
|
3451
|
+
prompt += `- 只覆盖上述已存在的文件,不要创建新文件或新目录\n`;
|
|
3452
|
+
prompt += `- 每个文件写入正确路径(如 \`overview/ANALYSIS.md\`,不是根目录的 \`ANALYSIS.md\`)\n`;
|
|
3453
|
+
prompt += `- 写完后用 Read 验证文件内容已替换占位内容\n\n`;
|
|
3432
3454
|
prompt += `## ⚠️ 迭代名称仅为目录标识(重要)\n\n`;
|
|
3433
3455
|
prompt += `- 迭代名称("${iter}")仅为目录标识符,**不代表需求内容**\n`;
|
|
3434
3456
|
prompt += `- **需求文档是唯一事实来源**:所有分析必须 100% 基于 010-requirements/ 下的文档内容\n`;
|
|
@@ -3771,21 +3793,23 @@ sequenceDiagram
|
|
|
3771
3793
|
prompt += `请在生成综合文档后,**直接继续**生成各端专属文档(Phase 2)。\n`;
|
|
3772
3794
|
prompt += `执行命令:\`speccore analyze --prompt -I ${iter} --phase 2\`\n\n`;
|
|
3773
3795
|
}
|
|
3774
|
-
//
|
|
3775
|
-
if (perDocStatus && perDocStatus.
|
|
3776
|
-
const remainingAfterThis = perDocStatus.
|
|
3777
|
-
prompt += `\n## 🔗 逐文档自动链式推进(
|
|
3796
|
+
// v8.0.0+: 逐文档自动链式推进(基于骨架进度)
|
|
3797
|
+
if (perDocStatus && perDocStatus.filledCount < perDocStatus.totalCount) {
|
|
3798
|
+
const remainingAfterThis = perDocStatus.unfilled.length - 1;
|
|
3799
|
+
prompt += `\n## 🔗 逐文档自动链式推进(v8.0.0+ 骨架模式)\n\n`;
|
|
3778
3800
|
prompt += `> 当前为**单文档模式**:本次只生成 1 个文档,写入后立即推进下一个。\n`;
|
|
3779
|
-
prompt += `>
|
|
3801
|
+
prompt += `> 骨架进度: ${perDocStatus.filledCount}/${perDocStatus.totalCount} 已填充,剩余 ${perDocStatus.unfilled.length} 个\n`;
|
|
3802
|
+
prompt += `> 待填充: ${perDocStatus.unfilled.slice(0, 5).join('、')}${perDocStatus.unfilled.length > 5 ? '...' : ''}\n\n`;
|
|
3780
3803
|
if (remainingAfterThis > 0) {
|
|
3781
3804
|
prompt += `**当前文档写入完成后,立即输出以下标记推进下一个文档**:\n\n`;
|
|
3782
3805
|
prompt += `[SPECCORE_EXEC: speccore analyze --prompt -I ${iter}${options?.auto ? ' --auto' : ''}${options?.withCode ? ' --with-code' : ''}]\n\n`;
|
|
3783
|
-
prompt += `> 💡 CLI
|
|
3806
|
+
prompt += `> 💡 CLI 会自动检测下一个未填充的骨架文件并生成对应的 prompt。重复执行直到所有文件填充完毕。\n`;
|
|
3784
3807
|
}
|
|
3785
3808
|
else {
|
|
3786
|
-
prompt += `> 🎉
|
|
3809
|
+
prompt += `> 🎉 这是最后一个骨架文件!填充后所有迭代级分析文档将完整。\n`;
|
|
3787
3810
|
const platforms = await (0, spec_paths_1.parsePlatformList)();
|
|
3788
|
-
|
|
3811
|
+
const hasPlatformUnfilled = perDocStatus.unfilled.some(p => p.includes('/') && !p.startsWith('overview/'));
|
|
3812
|
+
if (platforms.length >= 2 && hasPlatformUnfilled) {
|
|
3789
3813
|
prompt += `> 下一步: 生成各端专属文档 → \`speccore analyze --prompt -I ${iter} --phase 2\`\n`;
|
|
3790
3814
|
}
|
|
3791
3815
|
else {
|