speccore 8.3.162 → 8.3.163

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":"AAwNA,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,CA09BzF"}
1
+ {"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../../src/commands/iteration/split.ts"],"names":[],"mappings":"AAwNA,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,CA6+BzF"}
@@ -505,6 +505,14 @@ async function iterationSplitCommand(options) {
505
505
  const iterDir = (0, path_1.join)(iterDirFull, '030-tasks');
506
506
  await (0, fs_extra_1.ensureDir)(iterDir);
507
507
  const backups = [];
508
+ // v8.3.163+: AI 上下文中禁用 --force(质量门禁和安全限制不可被 AI 自行绕过)
509
+ const isAiCtx = !process.stdout.isTTY;
510
+ if (options.force && isAiCtx) {
511
+ logger_1.logger.error('❌ AI 上下文中禁止使用 --force 参数');
512
+ logger_1.logger.info(' 质量门禁(任务数限制、拆分粒度校验)不可被 AI 自行绕过');
513
+ logger_1.logger.info(' 如需强制继续,请在交互式终端中执行此命令');
514
+ return;
515
+ }
508
516
  // v8.3.160+: 智能提取 JSON(支持 JSON 后附带 [PENDING] / [SPECCORE_EXEC] 标记)
509
517
  function extractJsonArray(text) {
510
518
  const result = { json: text };
@@ -674,20 +682,29 @@ async function iterationSplitCommand(options) {
674
682
  if (sections.length > MAX_TASKS_HARD && options.force) {
675
683
  logger_1.logger.warn(` ⚠️ 任务数 ${sections.length} 超出建议上限 ${MAX_TASKS_HARD},--force 已启用,继续...`);
676
684
  }
677
- // 🚨 逐功能单元校验:每个功能单元拆出的任务数不超过 3 个
678
- const MAX_TASKS_PER_UNIT = 3;
679
- const unitTaskCount = {};
685
+ // v8.3.162+: 逐功能单元×端校验:每个功能单元的每个端最多 3 个任务
686
+ // 拆分策略:功能单元先按端拆分,每个端内的子任务最多 3 个
687
+ const MAX_TASKS_PER_UNIT_PLATFORM = 3;
688
+ const unitPlatformTaskCount = {};
680
689
  let missingFunctionalUnit = 0;
681
- // 按 functionalUnit 分组统计(AI 在 JSON 中标注所属功能单元)
690
+ // 按 functionalUnit × platform 分组统计
682
691
  for (let i = 0; i < sections.length; i++) {
683
692
  const task = tasks[i];
684
693
  const unitName = task.functionalUnit;
694
+ const scopes = Array.isArray(task.scope) ? task.scope : [];
685
695
  if (!unitName) {
686
696
  missingFunctionalUnit++;
687
- unitTaskCount['__missing__'] = (unitTaskCount['__missing__'] || 0) + 1;
697
+ // 未标注功能单元的任务,按 scope 分别计入 __missing__
698
+ for (const platform of scopes) {
699
+ const key = `__missing__|${platform}`;
700
+ unitPlatformTaskCount[key] = (unitPlatformTaskCount[key] || 0) + 1;
701
+ }
688
702
  }
689
703
  else {
690
- unitTaskCount[unitName] = (unitTaskCount[unitName] || 0) + 1;
704
+ for (const platform of scopes) {
705
+ const key = `${unitName}|${platform}`;
706
+ unitPlatformTaskCount[key] = (unitPlatformTaskCount[key] || 0) + 1;
707
+ }
691
708
  }
692
709
  }
693
710
  // functionalUnit 缺失警告
@@ -696,23 +713,24 @@ async function iterationSplitCommand(options) {
696
713
  logger_1.logger.warn(` 💡 AI 未按约束填写功能单元,校验可能不准确`);
697
714
  logger_1.logger.warn(` 💡 建议重新执行 split,确保 Prompt 包含 functionalUnit 要求`);
698
715
  }
699
- // 检查每个功能单元的任务数
716
+ // 检查每个功能单元×端的任务数
700
717
  let hasOverSplit = false;
701
- for (const [unitName, count] of Object.entries(unitTaskCount)) {
702
- if (count > MAX_TASKS_PER_UNIT) {
718
+ for (const [key, count] of Object.entries(unitPlatformTaskCount)) {
719
+ if (count > MAX_TASKS_PER_UNIT_PLATFORM) {
703
720
  if (!hasOverSplit) {
704
- logger_1.logger.error(`\n ❌ 检测到过度拆分!某些功能单元拆出过多任务:`);
721
+ logger_1.logger.error(`\n ❌ 检测到过度拆分!某些功能单元在单个端内拆出过多任务:`);
705
722
  hasOverSplit = true;
706
723
  }
707
- const displayName = unitName === '__missing__' ? '(未标注功能单元)' : unitName;
708
- logger_1.logger.error(` 📌 "${displayName}" 拆出了 ${count} 个任务(上限 ${MAX_TASKS_PER_UNIT})`);
724
+ const [unitName, platform] = key.split('|');
725
+ const displayUnit = unitName === '__missing__' ? '(未标注功能单元)' : unitName;
726
+ logger_1.logger.error(` 📌 "${displayUnit}" 在 "${platform}" 端拆出了 ${count} 个任务(上限 ${MAX_TASKS_PER_UNIT_PLATFORM})`);
709
727
  }
710
728
  }
711
729
  if (hasOverSplit) {
712
- logger_1.logger.error(` 💡 核心原则:一个功能单元默认 1 个任务,最多 3 个`);
730
+ logger_1.logger.error(` 💡 核心原则:功能单元先按端拆分,每个端内默认 1 个任务,最多 3 个`);
713
731
  logger_1.logger.error(` 🔧 建议操作:`);
714
732
  logger_1.logger.error(` 1. 重新执行 split,并告诉 AI:"任务太多,请合并相关功能"`);
715
- logger_1.logger.error(` 2. 或者手动编辑 .speccore/prompts/split-suggestion-${iter}.md,明确要求"每个功能单元最多拆 2 个任务"`);
733
+ logger_1.logger.error(` 2. 或者手动编辑 .speccore/prompts/split-suggestion-${iter}.md,明确要求"每个功能单元的每个端最多拆 2 个任务"`);
716
734
  logger_1.logger.error(` 3. 如果确实需要这么多任务,使用 --force 跳过检查(不推荐)`);
717
735
  if (!options.force) {
718
736
  logger_1.logger.info('\n ℹ️ 如需强制继续,添加 --force 参数');