speccore 8.3.180 → 8.3.182

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":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/core/prompt-builder.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prompt-builder.d.ts","sourceRoot":"","sources":["../../src/core/prompt-builder.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAoD,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAgDtG,gBAAgB;AAChB,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;AAErE,YAAY;AACZ,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,eAAe;AACf,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,WAAW;AACX,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC/D;AAED,WAAW;AACX,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,gBAAgB;AAChB,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,gBAAgB;AAChB,MAAM,WAAW,QAAQ;IACvB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,WAAW;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,sBAAsB;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,0BAA0B;AAC1B,MAAM,WAAW,aAAa;IAC5B,6BAA6B;IAC7B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,gBAAgB,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACvD,0BAA0B;IAC1B,GAAG,EAAE,QAAQ,EAAE,CAAC;CACjB;AAED,0BAA0B;AAC1B,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,mBAAmB,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,aAAa,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,UAAU,EAAE,aAAa,EAAE,CAAC;IAC5B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAE1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IAEnB,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAshCD;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,aAAa,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,aAAa,CAAC,CAmFxB;AAsCD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,aAAa,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAwHjF;AAmVD,wBAAsB,WAAW,CAC/B,OAAO,EAAE,aAAa,EACtB,OAAO,EAAE;IACP,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,WAAW,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,eAAe,GAAG,eAAe,CAAC;IACzE,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,cAAc,CAAC,EAAE,GAAG,CAAC;IAErB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GACA,OAAO,CAAC,cAAc,CAAC,CAioBzB;AAiBD;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAqG/E;AAED,4BAA4B;AAC5B,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAkI9D;AAED;;GAEG;AACH,wCAAwC;AACxC,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ1D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CAsB5H;AAMD,YAAY;AACZ,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,uBAAuB,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE;QACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;KACtB,CAAC;CACH;AA8DD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GAAG,IAAI,CAgF3E;AA+ND;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,EACtB,YAAY,CAAC,EAAE,iBAAiB,EAChC,OAAO,CAAC,EAAE;IACR,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACA,OAAO,CAAC,MAAM,CAAC,CAejB"}
@@ -410,9 +410,22 @@ async function loadExtraSpecs(cwd, taskDir, platform, iteration, options) {
410
410
  if (content.trim().length <= 50 || content.trim().match(/^#+\s*待填充|^<!--\s*AI-FILL\s*-->$/m)) {
411
411
  continue;
412
412
  }
413
- // 单文件大小限制
414
- if (content.length > MAX_PER_FILE) {
415
- content = content.slice(0, MAX_PER_FILE) + `\n\n> ... (已截断,原文件 ${rawContent.length} 字,完整内容请 Read: ${fullPath})`;
413
+ // v8.3.181+: 按文件类型细分预算
414
+ const fileName = (0, path_1.basename)(f.path);
415
+ const budget = getFileBudget(fileName);
416
+ if (content.length > budget.limit) {
417
+ if (budget.mode === 'error') {
418
+ logger_1.logger.error(`[prompt-builder] ${fileName} 超过预算上限 (${content.length} > ${budget.limit})。`);
419
+ logger_1.logger.error(` 该文件属于"必须完整"类型,不会被截断。建议精简方式:`);
420
+ logger_1.logger.error(` - 删除过时的注释和示例代码`);
421
+ logger_1.logger.error(` - 将详细说明链接到外部文档`);
422
+ logger_1.logger.error(` - 使用表格代替冗长的列表`);
423
+ logger_1.logger.error(` - 精简后重新执行: speccore execute --resume`);
424
+ // 不截断,保留完整内容
425
+ }
426
+ else {
427
+ content = content.slice(0, budget.limit) + `\n\n> ... (已截断,原文件 ${rawContent.length} 字,预算上限 ${budget.limit},完整内容请 Read: ${fullPath})`;
428
+ }
416
429
  }
417
430
  // 总大小限制
418
431
  if (totalChars + content.length > MAX_TOTAL) {
@@ -449,8 +462,10 @@ async function loadExtraSpecs(cwd, taskDir, platform, iteration, options) {
449
462
  if (content.trim().length <= 50 || content.trim().match(/^#+\s*待填充|^<!--\s*AI-FILL\s*-->$/m)) {
450
463
  continue;
451
464
  }
452
- if (content.length > MAX_PER_FILE) {
453
- content = content.slice(0, MAX_PER_FILE) + `\n\n> ... (已截断,原文件 ${content.length} 字)`;
465
+ // v8.3.181+: 自定义文件使用默认预算
466
+ const customBudget = getFileBudget((0, path_1.basename)(uf.path));
467
+ if (content.length > customBudget.limit) {
468
+ content = content.slice(0, customBudget.limit) + `\n\n> ... (已截断,原文件 ${content.length} 字,预算上限 ${customBudget.limit})`;
454
469
  }
455
470
  if (totalChars + content.length > MAX_TOTAL) {
456
471
  const remain = MAX_TOTAL - totalChars;
@@ -523,15 +538,51 @@ async function loadExtraSpecs(cwd, taskDir, platform, iteration, options) {
523
538
  return extras;
524
539
  }
525
540
  /**
526
- * v8.3.15+: 扫描用户自定义文档
527
- * 扫描 00-specs/ 和子任务目录下所有 .md/.yaml/.yml/.json 文件
528
- * 排除白名单已覆盖的文件和系统目录
541
+ * v8.3.181+: 扫描用户自定义文档(白名单模式)
542
+ * 只加载 ALLOWED_EXTRA_FILES 白名单内的文件,防止上下文污染
543
+ * 白名单外文件将被忽略并输出提示
529
544
  */
545
+ // v8.3.182+: 白名单分两级(核心 + 条件)
546
+ // 核心白名单:所有任务都需要
547
+ const CORE_EXTRA_FILES = new Set([
548
+ 'CONTEXT.md', // 任务上下文(来源追溯 + 关联任务)
549
+ 'ERROR_CODES.md', // 错误码定义
550
+ ]);
551
+ // 条件白名单:按平台类型加载
552
+ function getPlatformExtraFiles(platform) {
553
+ if (!platform)
554
+ return new Set();
555
+ const p = platform.toLowerCase();
556
+ if (p.includes('backend') || p.includes('service') || p.includes('api') || p.includes('server')) {
557
+ return new Set(['SCHEMA.md']);
558
+ }
559
+ if (p.includes('web') || p.includes('mobile') || p.includes('h5') || p.includes('frontend') || p.includes('admin')) {
560
+ return new Set(['COMPONENT_TREE.md', 'ROUTES.md', 'STATE.md']);
561
+ }
562
+ return new Set();
563
+ }
564
+ // v8.3.181+: 按文件类型细分预算(必须完整 vs 可以截断)
565
+ const FILE_BUDGETS = {
566
+ 'CONSTITUTION.md': { limit: 6000, mode: 'error' },
567
+ 'REQ.md': { limit: 2000, mode: 'error' },
568
+ 'API_CONTRACT.yaml': { limit: 2000, mode: 'error' },
569
+ 'TASK.md': { limit: 1500, mode: 'truncate' },
570
+ 'TECH.md': { limit: 3000, mode: 'truncate' },
571
+ 'DEV_GUIDE.md': { limit: 2000, mode: 'truncate' },
572
+ };
573
+ const DEFAULT_BUDGET = { limit: 1000, mode: 'truncate' };
574
+ function getFileBudget(fileName) {
575
+ return FILE_BUDGETS[fileName] ?? DEFAULT_BUDGET;
576
+ }
530
577
  async function scanUserCustomFiles(cwd, taskDir, platform, seenPaths) {
531
578
  const results = [];
532
579
  const validExts = ['.md', '.yaml', '.yml', '.json', '.html', '.htm'];
533
580
  const skipDirs = new Set(['.meta', '.git', 'node_modules', 'tests', 'src', 'dist', 'build']);
534
- // 1. 扫描 00-specs/ 下所有文件(排除已在白名单中的)
581
+ const ignoredFiles = [];
582
+ // v8.3.182+: 合并核心白名单 + 条件白名单
583
+ const platformExtras = getPlatformExtraFiles(platform);
584
+ const allowedFiles = new Set([...CORE_EXTRA_FILES, ...platformExtras]);
585
+ // 1. 扫描 00-specs/ 下白名单内的文件
535
586
  const specsDir = (0, path_1.join)(cwd, taskDir, '00-specs');
536
587
  try {
537
588
  if (await (0, fs_extra_1.pathExists)(specsDir)) {
@@ -542,6 +593,10 @@ async function scanUserCustomFiles(cwd, taskDir, platform, seenPaths) {
542
593
  const ext = e.name.slice(e.name.lastIndexOf('.'));
543
594
  if (!validExts.includes(ext))
544
595
  continue;
596
+ if (!allowedFiles.has(e.name)) {
597
+ ignoredFiles.push(`00-specs/${e.name}`);
598
+ continue;
599
+ }
545
600
  const relPath = (0, path_1.join)('00-specs', e.name);
546
601
  const fullPath = (0, path_1.join)(cwd, taskDir, relPath);
547
602
  if (!seenPaths.has(fullPath)) {
@@ -551,7 +606,7 @@ async function scanUserCustomFiles(cwd, taskDir, platform, seenPaths) {
551
606
  }
552
607
  }
553
608
  catch { /* 忽略 */ }
554
- // 2. 扫描子任务目录下所有文件(递归)
609
+ // 2. 扫描子任务目录下白名单内的文件(递归)
555
610
  if (platform) {
556
611
  const platformBase = (0, path_1.join)(cwd, taskDir, platform);
557
612
  try {
@@ -561,16 +616,26 @@ async function scanUserCustomFiles(cwd, taskDir, platform, seenPaths) {
561
616
  if (!subE.isDirectory() || subE.name.startsWith('.'))
562
617
  continue;
563
618
  const subtaskDir = (0, path_1.join)(platformBase, subE.name);
564
- await scanDirRecursive(subtaskDir, (0, path_1.join)(platform, subE.name), results, seenPaths, skipDirs, validExts, cwd, taskDir);
619
+ await scanDirRecursive(subtaskDir, (0, path_1.join)(platform, subE.name), results, seenPaths, skipDirs, validExts, cwd, taskDir, ignoredFiles, allowedFiles);
565
620
  }
566
621
  }
567
622
  }
568
623
  catch { /* 忽略 */ }
569
624
  }
625
+ // 输出被忽略的文件提示
626
+ if (ignoredFiles.length > 0) {
627
+ console.warn(`[prompt-builder] 以下文件不在白名单中,已忽略(如需加载请在 TASK.md 中声明):`);
628
+ for (const f of ignoredFiles.slice(0, 10)) {
629
+ console.warn(` - ${f}`);
630
+ }
631
+ if (ignoredFiles.length > 10) {
632
+ console.warn(` ... 还有 ${ignoredFiles.length - 10} 个文件被忽略`);
633
+ }
634
+ }
570
635
  return results;
571
636
  }
572
- /** 递归扫描目录,收集用户自定义文档 */
573
- async function scanDirRecursive(dir, relPrefix, results, seenPaths, skipDirs, validExts, cwd, taskDir) {
637
+ /** 递归扫描目录,收集用户自定义文档(白名单模式) */
638
+ async function scanDirRecursive(dir, relPrefix, results, seenPaths, skipDirs, validExts, cwd, taskDir, ignoredFiles, allowedFiles) {
574
639
  try {
575
640
  const entries = await (0, fs_extra_1.readdir)(dir, { withFileTypes: true });
576
641
  for (const e of entries) {
@@ -579,12 +644,16 @@ async function scanDirRecursive(dir, relPrefix, results, seenPaths, skipDirs, va
579
644
  if (e.isDirectory()) {
580
645
  if (skipDirs.has(e.name) || e.name.startsWith('.'))
581
646
  continue;
582
- await scanDirRecursive((0, path_1.join)(dir, e.name), relPath, results, seenPaths, skipDirs, validExts, cwd, taskDir);
647
+ await scanDirRecursive((0, path_1.join)(dir, e.name), relPath, results, seenPaths, skipDirs, validExts, cwd, taskDir, ignoredFiles, allowedFiles);
583
648
  }
584
649
  else if (e.isFile()) {
585
650
  const ext = e.name.slice(e.name.lastIndexOf('.'));
586
651
  if (!validExts.includes(ext))
587
652
  continue;
653
+ if (!allowedFiles.has(e.name)) {
654
+ ignoredFiles.push(relPath);
655
+ continue;
656
+ }
588
657
  if (!seenPaths.has(fullPath)) {
589
658
  results.push({ name: `用户补充/${relPath}`, path: relPath });
590
659
  }
@@ -623,8 +692,23 @@ async function loadAllTaskContext(cwd, taskDir, platform, iteration, graph) {
623
692
  }
624
693
  if (content.trim().length <= 50 || content.trim().match(/^#+\s*待填充|^<!--\s*AI-FILL\s*-->$/m))
625
694
  return;
626
- if (content.length > MAX_PER_FILE) {
627
- content = content.slice(0, MAX_PER_FILE) + `\n\n> ... (已截断,原文件 ${rawContent.length} 字,完整内容请 Read: ${fullPath})`;
695
+ // v8.3.181+: 兜底模式也按文件类型检查预算(放宽到 2 倍)
696
+ const fileName = (0, path_1.basename)(fullPath);
697
+ const budget = getFileBudget(fileName);
698
+ const fallbackLimit = budget.limit * 2;
699
+ if (content.length > fallbackLimit) {
700
+ if (budget.mode === 'error') {
701
+ logger_1.logger.error(`[prompt-builder] ${fileName} 超过兜底预算上限 (${content.length} > ${fallbackLimit})。`);
702
+ logger_1.logger.error(` 该文件属于"必须完整"类型,不会被截断。建议精简方式:`);
703
+ logger_1.logger.error(` - 删除过时的注释和示例代码`);
704
+ logger_1.logger.error(` - 将详细说明链接到外部文档`);
705
+ logger_1.logger.error(` - 使用表格代替冗长的列表`);
706
+ logger_1.logger.error(` - 精简后重新执行: speccore execute --resume`);
707
+ // 不截断
708
+ }
709
+ else {
710
+ content = content.slice(0, fallbackLimit) + `\n\n> ... (已截断,原文件 ${rawContent.length} 字,兜底预算上限 ${fallbackLimit})`;
711
+ }
628
712
  }
629
713
  if (totalChars + content.length > MAX_TOTAL)
630
714
  return;