speccore 8.3.219 → 8.3.221

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.
@@ -1 +1 @@
1
- {"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../../src/commands/iteration/split.ts"],"names":[],"mappings":"AAwKA,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;AA+ID,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2pCzF"}
1
+ {"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../../src/commands/iteration/split.ts"],"names":[],"mappings":"AAwKA,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;AAmKD,wBAAsB,qBAAqB,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA2pCzF"}
@@ -198,7 +198,9 @@ async function detectPlatforms(iterationDir, specified) {
198
198
  async function preSplitGate(iterationDir) {
199
199
  const items = [];
200
200
  const specDir = (0, path_1.join)(iterationDir, '020-specs');
201
- // 检查全局 FUNCTION_MAP.md(阻塞级)
201
+ // 检查全局 FUNCTION_MAP.md(警告级)
202
+ // v8.3.220+: 降级为 warn——功能单元的权威来源是 010-requirements/features/ 目录(doc2spec --split 产出),
203
+ // FUNCTION_MAP 仅作「功能×端映射」参考。split 的 prompt 构建已有多级回退(FUNCTION_MAP → ANALYSIS.md → features/)。
202
204
  const funcMapPath = (0, path_1.join)(specDir, spec_paths_1.GLOBAL_SPECS_DIR, 'FUNCTION_MAP.md');
203
205
  const funcMapExists = await (0, fs_extra_1.pathExists)(funcMapPath);
204
206
  let funcMapIsSkeleton = false;
@@ -209,13 +211,13 @@ async function preSplitGate(iterationDir) {
209
211
  items.push({
210
212
  path: funcMapPath,
211
213
  name: 'FUNCTION_MAP.md',
212
- purpose: '列出本迭代所有功能模块及涉及端,是 split 拆分的唯一依据',
213
- impact: '缺失或不完整时,split 不知道要拆哪些任务,可能拆出不完整或错误的任务',
214
+ purpose: '功能单元×端映射参考(权威来源为 010-requirements/features/ 目录)',
215
+ impact: '缺失或不完整时仅作提示,split 以 features/ 目录为准拆分,不影响任务生成',
214
216
  exists: funcMapExists,
215
217
  isSkeleton: funcMapIsSkeleton,
216
- level: 'block',
218
+ level: 'warn',
217
219
  });
218
- // 检查全局 REQUIREMENT.md(警告级)
220
+ // 检查全局 REQUIREMENT.md(阻塞级——taskify 的核心需求上下文,骨架则无法拆分)
219
221
  const reqPath = (0, path_1.join)(specDir, spec_paths_1.GLOBAL_SPECS_DIR, 'REQUIREMENT.md');
220
222
  const reqExists = await (0, fs_extra_1.pathExists)(reqPath);
221
223
  let reqIsSkeleton = false;
@@ -226,11 +228,28 @@ async function preSplitGate(iterationDir) {
226
228
  items.push({
227
229
  path: reqPath,
228
230
  name: 'REQUIREMENT.md',
229
- purpose: '本迭代的完整需求规格,包含功能模块清单和验收标准',
230
- impact: '缺失时,AI 拆分缺少需求上下文,可能遗漏功能点或拆分粒度过粗',
231
+ purpose: '本迭代的完整需求规格,包含功能模块清单和验收标准(taskify 拆分任务的核心依据)',
232
+ impact: '缺失或仍为骨架时,AI 拆分缺少需求上下文,会拆出无意义任务(如把「写作要求」当功能模块)',
231
233
  exists: reqExists,
232
234
  isSkeleton: reqIsSkeleton,
233
- level: 'warn',
235
+ level: 'block',
236
+ });
237
+ // v8.3.221+: 检查全局 ANALYSIS.md(阻塞级——功能分析,骨架说明 analyze 未落盘)
238
+ const analysisGatePath = (0, path_1.join)(specDir, spec_paths_1.GLOBAL_SPECS_DIR, 'ANALYSIS.md');
239
+ const analysisGateExists = await (0, fs_extra_1.pathExists)(analysisGatePath);
240
+ let analysisGateIsSkeleton = false;
241
+ if (analysisGateExists) {
242
+ const ac = await (0, fs_extra_1.readFile)(analysisGatePath, 'utf-8');
243
+ analysisGateIsSkeleton = ac.includes('<!-- SPEC-SKELETON -->') || ac.trim().length < 100;
244
+ }
245
+ items.push({
246
+ path: analysisGatePath,
247
+ name: 'ANALYSIS.md',
248
+ purpose: '需求功能分析(功能点清单 F-xx),taskify 拆分任务的输入之一',
249
+ impact: '仍为骨架说明 analyze 阶段未落盘,拆分会遗漏功能点',
250
+ exists: analysisGateExists,
251
+ isSkeleton: analysisGateIsSkeleton,
252
+ level: 'block',
234
253
  });
235
254
  // 检查功能模块级文档(警告级)
236
255
  const features = await (0, spec_paths_1.parseFeatureList)(iterationDir);
@@ -2242,7 +2261,7 @@ ${relatedTasks.length > 0 ? relatedTasks.join('\n') : '> 暂无关联任务(sp
2242
2261
 
2243
2262
  ## 跨端关联
2244
2263
 
2245
- > 来自 FUNCTION_MAP.md
2264
+ > 来自 FUNCTION_MAP.md(功能×端映射参考)
2246
2265
 
2247
2266
  | 属性 | 值 |
2248
2267
  |:---|:---|
@@ -3256,7 +3275,7 @@ subagent, contextType) {
3256
3275
  p += `4. \`020-specs/overview/REQUIREMENT.md\` — 黄金需求文档\n`;
3257
3276
  p += `5. \`020-specs/overview/TECH.md\` — 全局技术方案\n`;
3258
3277
  p += `6. \`020-specs/overview/ANALYSIS.md\` — 功能分析\n`;
3259
- p += `7. \`020-specs/overview/FUNCTION_MAP.md\` — 功能单元与端的映射(拆分核心依据)\n`;
3278
+ p += `7. \`020-specs/overview/FUNCTION_MAP.md\` — 功能单元与端的映射(参考,权威来源为 010-requirements/features/ 目录)\n`;
3260
3279
  if (await (0, fs_extra_1.pathExists)((0, path_1.join)(iterationDir || '', '020-specs', 'overview', 'INTERACTION_MAP.md'))) {
3261
3280
  p += `8. \`020-specs/overview/INTERACTION_MAP.md\` — 跨端交互时序\n`;
3262
3281
  }
@@ -3271,7 +3290,7 @@ subagent, contextType) {
3271
3290
  }
3272
3291
  p += `\n`;
3273
3292
  p += `> 📖 **读取策略**:\n`;
3274
- p += `> - 先 Read FUNCTION_MAP.md 了解功能单元划分和涉及端\n`;
3293
+ p += `> - 先 Read 010-requirements/features/ 目录了解功能单元划分(权威来源),FUNCTION_MAP.md 作功能×端映射参考\n`;
3275
3294
  p += `> - 按功能单元逐个处理,每次只 Read 当前单元相关的文档\n`;
3276
3295
  p += `> - reqContent 从 REQUIREMENT.md 和对应功能模块的需求文档提取\n`;
3277
3296
  p += `> - techContent 从 TECH.md 和对应功能模块的技术规格提取\n`;
@@ -3313,9 +3332,9 @@ subagent, contextType) {
3313
3332
  funcUnitsInjected = true;
3314
3333
  }
3315
3334
  }
3316
- // v7.5.0+: FUNCTION_MAP.md 不存在时,从 ANALYSIS.md 提取功能单元清单
3335
+ // v7.5.0+: FUNCTION_MAP.md 不存在或为空时,从 ANALYSIS.md 提取功能单元清单
3317
3336
  if (!funcUnitsInjected) {
3318
- const analysisPath = (0, path_1.join)(iterationDir, '020-specs', 'ANALYSIS.md');
3337
+ const analysisPath = (0, path_1.join)(iterationDir, '020-specs', spec_paths_1.GLOBAL_SPECS_DIR, 'ANALYSIS.md');
3319
3338
  if (await (0, fs_extra_1.pathExists)(analysisPath)) {
3320
3339
  const analysisContent = await (0, fs_extra_1.readFile)(analysisPath, 'utf-8');
3321
3340
  const analysisUnits = parseAnalysisFunctionalUnits(analysisContent, standardPlatforms);
@@ -3335,6 +3354,24 @@ subagent, contextType) {
3335
3354
  p += `- 不允许将不同端的功能单元合并到同一个任务\n\n`;
3336
3355
  }
3337
3356
  }
3357
+ // v8.3.220+: FUNCTION_MAP 和 ANALYSIS 都为空/骨架时,回退到 features/ 目录(功能单元权威来源)
3358
+ if (!funcUnitsInjected) {
3359
+ const featureDirs = await (0, spec_paths_1.parseFeatureList)(iterationDir);
3360
+ if (featureDirs.length > 0) {
3361
+ p += `## 🧩 功能单元清单(CLI 从 010-requirements/features/ 目录提取,v8.3.220+)\n\n`;
3362
+ p += `> 以下是从 features/ 目录读取的 **全部功能单元**(权威来源)。\n`;
3363
+ p += `> ⚠️ **你必须为每个功能单元创建至少 1 个任务,不允许遗漏任何功能单元。**\n\n`;
3364
+ p += `| 功能单元 |\n`;
3365
+ p += `|:---|\n`;
3366
+ for (const fn of featureDirs) {
3367
+ p += `| ${fn} |\n`;
3368
+ }
3369
+ p += `\n**拆分要求**:\n`;
3370
+ p += `- 每个功能单元必须在某个任务的 \`functionalUnit\` 字段中被引用\n`;
3371
+ p += `- 涉及端从 CONSTITUTION.md 端列表判断,或从 features/{单元}/.meta/source 读取\n\n`;
3372
+ funcUnitsInjected = true;
3373
+ }
3374
+ }
3338
3375
  }
3339
3376
  }
3340
3377
  catch { }
@@ -4249,7 +4286,7 @@ async function tryModuleDrivenSplit(iteration, iterationDir, options) {
4249
4286
  }
4250
4287
  // 2.5 v7.5.0+: 回退:从 ANALYSIS.md 提取功能单元清单(按端分节的 F-xx 表格)
4251
4288
  if (!modulePlatformsParsed) {
4252
- const analysisPath = (0, path_1.join)(iterationDir, '020-specs', 'ANALYSIS.md');
4289
+ const analysisPath = (0, path_1.join)(iterationDir, '020-specs', spec_paths_1.GLOBAL_SPECS_DIR, 'ANALYSIS.md');
4253
4290
  if (await (0, fs_extra_1.pathExists)(analysisPath)) {
4254
4291
  try {
4255
4292
  const content = await (0, fs_extra_1.readFile)(analysisPath, 'utf-8');