speccore 8.3.121 → 8.3.126

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.
Files changed (143) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/cli.js.map +1 -1
  3. package/dist/commands/about.d.ts.map +1 -1
  4. package/dist/commands/about.js +16 -0
  5. package/dist/commands/about.js.map +1 -1
  6. package/dist/commands/analyze.d.ts +1 -0
  7. package/dist/commands/analyze.d.ts.map +1 -1
  8. package/dist/commands/analyze.js +198 -70
  9. package/dist/commands/analyze.js.map +1 -1
  10. package/dist/commands/change.js +14 -7
  11. package/dist/commands/change.js.map +1 -1
  12. package/dist/commands/context.js +25 -31
  13. package/dist/commands/context.js.map +1 -1
  14. package/dist/commands/deploy.d.ts.map +1 -1
  15. package/dist/commands/deploy.js +6 -1
  16. package/dist/commands/deploy.js.map +1 -1
  17. package/dist/commands/done.js +29 -28
  18. package/dist/commands/done.js.map +1 -1
  19. package/dist/commands/execute.d.ts.map +1 -1
  20. package/dist/commands/execute.js +281 -20
  21. package/dist/commands/execute.js.map +1 -1
  22. package/dist/commands/import.js +1 -1
  23. package/dist/commands/import.js.map +1 -1
  24. package/dist/commands/init.d.ts.map +1 -1
  25. package/dist/commands/init.js +512 -28
  26. package/dist/commands/init.js.map +1 -1
  27. package/dist/commands/iteration/create.js +1 -1
  28. package/dist/commands/iteration/split.d.ts.map +1 -1
  29. package/dist/commands/iteration/split.js +158 -70
  30. package/dist/commands/iteration/split.js.map +1 -1
  31. package/dist/commands/iteration-from-global.js +1 -2
  32. package/dist/commands/iteration-from-global.js.map +1 -1
  33. package/dist/commands/pattern.js +30 -16
  34. package/dist/commands/pattern.js.map +1 -1
  35. package/dist/commands/pipeline.d.ts.map +1 -1
  36. package/dist/commands/pipeline.js +15 -4
  37. package/dist/commands/pipeline.js.map +1 -1
  38. package/dist/commands/retro.d.ts.map +1 -1
  39. package/dist/commands/retro.js +15 -8
  40. package/dist/commands/retro.js.map +1 -1
  41. package/dist/commands/status-panel.js +1 -1
  42. package/dist/commands/status-panel.js.map +1 -1
  43. package/dist/commands/sync.js +15 -8
  44. package/dist/commands/sync.js.map +1 -1
  45. package/dist/commands/trace.js +27 -24
  46. package/dist/commands/trace.js.map +1 -1
  47. package/dist/commands/update-env-configs.d.ts.map +1 -1
  48. package/dist/commands/update-env-configs.js +33 -5
  49. package/dist/commands/update-env-configs.js.map +1 -1
  50. package/dist/commands/update.d.ts.map +1 -1
  51. package/dist/commands/update.js +29 -0
  52. package/dist/commands/update.js.map +1 -1
  53. package/dist/commands/verify.d.ts +1 -1
  54. package/dist/commands/verify.d.ts.map +1 -1
  55. package/dist/commands/verify.js +25 -0
  56. package/dist/commands/verify.js.map +1 -1
  57. package/dist/core/ai-context-generator.js +35 -22
  58. package/dist/core/ai-context-generator.js.map +1 -1
  59. package/dist/core/ai-impact-analyzer.d.ts.map +1 -1
  60. package/dist/core/ai-impact-analyzer.js +1 -1
  61. package/dist/core/ai-impact-analyzer.js.map +1 -1
  62. package/dist/core/analyze-engine.d.ts +2 -1
  63. package/dist/core/analyze-engine.d.ts.map +1 -1
  64. package/dist/core/analyze-engine.js +217 -53
  65. package/dist/core/analyze-engine.js.map +1 -1
  66. package/dist/core/ask-engine.d.ts.map +1 -1
  67. package/dist/core/ask-engine.js +31 -13
  68. package/dist/core/ask-engine.js.map +1 -1
  69. package/dist/core/change-detection.d.ts.map +1 -1
  70. package/dist/core/change-detection.js +21 -5
  71. package/dist/core/change-detection.js.map +1 -1
  72. package/dist/core/code-scanner.d.ts +12 -3
  73. package/dist/core/code-scanner.d.ts.map +1 -1
  74. package/dist/core/code-scanner.js +376 -10
  75. package/dist/core/code-scanner.js.map +1 -1
  76. package/dist/core/context-builder.d.ts +2 -1
  77. package/dist/core/context-builder.d.ts.map +1 -1
  78. package/dist/core/context-builder.js +104 -25
  79. package/dist/core/context-builder.js.map +1 -1
  80. package/dist/core/deploy/engine.d.ts.map +1 -1
  81. package/dist/core/deploy/engine.js +21 -6
  82. package/dist/core/deploy/engine.js.map +1 -1
  83. package/dist/core/git-integration.d.ts +5 -1
  84. package/dist/core/git-integration.d.ts.map +1 -1
  85. package/dist/core/git-integration.js +52 -15
  86. package/dist/core/git-integration.js.map +1 -1
  87. package/dist/core/knowledge-graph.d.ts +2 -0
  88. package/dist/core/knowledge-graph.d.ts.map +1 -1
  89. package/dist/core/knowledge-graph.js +246 -232
  90. package/dist/core/knowledge-graph.js.map +1 -1
  91. package/dist/core/name-validator.js +1 -1
  92. package/dist/core/name-validator.js.map +1 -1
  93. package/dist/core/pipeline-test.d.ts.map +1 -1
  94. package/dist/core/pipeline-test.js +7 -4
  95. package/dist/core/pipeline-test.js.map +1 -1
  96. package/dist/core/prompt-builder.d.ts +3 -0
  97. package/dist/core/prompt-builder.d.ts.map +1 -1
  98. package/dist/core/prompt-builder.js +629 -77
  99. package/dist/core/prompt-builder.js.map +1 -1
  100. package/dist/core/rag-engine.d.ts +10 -5
  101. package/dist/core/rag-engine.d.ts.map +1 -1
  102. package/dist/core/rag-engine.js +134 -16
  103. package/dist/core/rag-engine.js.map +1 -1
  104. package/dist/core/spec-paths.d.ts +42 -2
  105. package/dist/core/spec-paths.d.ts.map +1 -1
  106. package/dist/core/spec-paths.js +207 -11
  107. package/dist/core/spec-paths.js.map +1 -1
  108. package/dist/core/structured-extractor.d.ts +67 -0
  109. package/dist/core/structured-extractor.d.ts.map +1 -1
  110. package/dist/core/structured-extractor.js +1298 -23
  111. package/dist/core/structured-extractor.js.map +1 -1
  112. package/dist/core/test-config.d.ts +1 -1
  113. package/dist/core/test-config.d.ts.map +1 -1
  114. package/dist/core/test-config.js +85 -65
  115. package/dist/core/test-config.js.map +1 -1
  116. package/dist/core/ui-verify/report-generator.d.ts.map +1 -1
  117. package/dist/core/ui-verify/report-generator.js +7 -3
  118. package/dist/core/ui-verify/report-generator.js.map +1 -1
  119. package/dist/core/ui-verify/smoke-engine.js +7 -1
  120. package/dist/core/ui-verify/smoke-engine.js.map +1 -1
  121. package/dist/core/unified-config.d.ts +43 -3
  122. package/dist/core/unified-config.d.ts.map +1 -1
  123. package/dist/core/unified-config.js +133 -13
  124. package/dist/core/unified-config.js.map +1 -1
  125. package/dist/core/unified-retrieval.d.ts.map +1 -1
  126. package/dist/core/unified-retrieval.js +41 -15
  127. package/dist/core/unified-retrieval.js.map +1 -1
  128. package/dist/core/unit-context-assembler.js +2 -2
  129. package/dist/core/unit-context-assembler.js.map +1 -1
  130. package/dist/core/validator.d.ts.map +1 -1
  131. package/dist/core/validator.js +59 -44
  132. package/dist/core/validator.js.map +1 -1
  133. package/dist/core/verify-engine.d.ts +9 -2
  134. package/dist/core/verify-engine.d.ts.map +1 -1
  135. package/dist/core/verify-engine.js +274 -108
  136. package/dist/core/verify-engine.js.map +1 -1
  137. package/dist/core/verify-report-aggregator.js +9 -20
  138. package/dist/core/verify-report-aggregator.js.map +1 -1
  139. package/dist/utils/synonyms.d.ts +24 -0
  140. package/dist/utils/synonyms.d.ts.map +1 -0
  141. package/dist/utils/synonyms.js +114 -0
  142. package/dist/utils/synonyms.js.map +1 -0
  143. package/package.json +1 -1
@@ -55,23 +55,68 @@ const logger_1 = require("../utils/logger");
55
55
  // v6.84.0+: AGENTS 引擎集成
56
56
  const agents_1 = require("./agents");
57
57
  const spec_skeleton_1 = require("./spec-skeleton");
58
+ // v8.3.125+: 同义词扩展,避免 "登录" 与 "auth" 等跨语言/缩写不匹配导致验证漏检
59
+ const synonyms_1 = require("../utils/synonyms");
58
60
  // ============================================================
59
61
  // 项目类型检测
60
62
  // ============================================================
63
+ /**
64
+ * v8.3.105+: 支持更多工程类型,检测顺序从具体到一般
65
+ */
61
66
  async function detectProjectType(codePath) {
67
+ // 1. Flutter(有 pubspec.yaml,且通常包含 android/ios 目录)
68
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'pubspec.yaml')))
69
+ return 'flutter';
70
+ // 2. iOS(Podfile / .xcodeproj / .xcworkspace)
71
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'Podfile')))
72
+ return 'ios';
73
+ try {
74
+ const files = await (0, fs_extra_1.readdir)(codePath);
75
+ if (files.some(f => f.endsWith('.xcodeproj') || f.endsWith('.xcworkspace')))
76
+ return 'ios';
77
+ }
78
+ catch { /* ignore */ }
79
+ // 3. Android(AndroidManifest.xml 或 app/build.gradle)
80
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'AndroidManifest.xml')))
81
+ return 'android';
82
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'app', 'build.gradle')))
83
+ return 'android';
84
+ // 4. Rust
85
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'Cargo.toml')))
86
+ return 'rust';
87
+ // 5. C#(.csproj 或 .sln)
88
+ try {
89
+ const files = await (0, fs_extra_1.readdir)(codePath);
90
+ if (files.some(f => f.endsWith('.csproj')))
91
+ return 'csharp';
92
+ if (files.some(f => f.endsWith('.sln')))
93
+ return 'csharp';
94
+ }
95
+ catch { /* ignore */ }
96
+ // 6. Node.js
62
97
  if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'package.json')))
63
98
  return 'node';
99
+ // 7. Java(pom.xml / build.gradle,但无 Android 特征)
64
100
  if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'pom.xml')))
65
101
  return 'java';
66
- if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'build.gradle')) || await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'build.gradle.kts')))
102
+ if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'build.gradle')) || await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'build.gradle.kts'))) {
103
+ // 再次确认不是 Android(前面已检测过 AndroidManifest.xml 和 app/build.gradle)
67
104
  return 'java';
105
+ }
106
+ // 8. Go
68
107
  if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'go.mod')))
69
108
  return 'go';
109
+ // 9. Python
70
110
  if (await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'requirements.txt')) || await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'setup.py')) || await (0, fs_extra_1.pathExists)((0, path_1.join)(codePath, 'pyproject.toml')))
71
111
  return 'python';
72
112
  return 'unknown';
73
113
  }
114
+ /**
115
+ * v8.3.105+: 获取跨平台的验证命令
116
+ * 去掉 2>&1 和 || true,因为 runCheck 的 execSync 已捕获输出和异常
117
+ */
74
118
  function getCommands(projectType, codePath) {
119
+ const isWin = process.platform === 'win32';
75
120
  switch (projectType) {
76
121
  case 'node':
77
122
  return {
@@ -79,23 +124,57 @@ function getCommands(projectType, codePath) {
79
124
  lint: detectNodeLintCommand(codePath),
80
125
  test: detectNodeTestCommand(codePath),
81
126
  };
82
- case 'java':
127
+ case 'java': {
128
+ const mvnw = isWin ? 'mvnw.cmd' : './mvnw';
83
129
  return {
84
- compile: 'mvn compile -q 2>&1 || ./mvnw compile -q 2>&1',
85
- lint: 'mvn checkstyle:check -q 2>&1 || true',
86
- test: 'mvn test -q 2>&1 || ./mvnw test -q 2>&1',
130
+ compile: `mvn compile -q || ${mvnw} compile -q`,
131
+ lint: 'mvn checkstyle:check -q',
132
+ test: `mvn test -q || ${mvnw} test -q`,
87
133
  };
134
+ }
88
135
  case 'go':
89
136
  return {
90
- compile: 'go build ./... 2>&1',
91
- lint: 'golangci-lint run 2>&1 || true',
92
- test: 'go test ./... -v 2>&1',
137
+ compile: 'go build ./...',
138
+ lint: 'golangci-lint run',
139
+ test: 'go test ./... -v',
93
140
  };
94
141
  case 'python':
95
142
  return {
96
- compile: 'python -m py_compile $(find . -name "*.py") 2>&1 || python3 -m compileall . -q 2>&1',
97
- lint: 'flake8 . 2>&1 || pylint . 2>&1 || ruff check . 2>&1 || true',
98
- test: 'pytest -v 2>&1 || python -m pytest -v 2>&1 || true',
143
+ compile: 'python3 -m compileall . -q || python -m compileall . -q',
144
+ lint: 'flake8 . || pylint . || ruff check .',
145
+ test: 'pytest -v || python -m pytest -v',
146
+ };
147
+ case 'android': {
148
+ const gradlew = isWin ? 'gradlew.bat' : './gradlew';
149
+ return {
150
+ compile: `${gradlew} assembleDebug`,
151
+ lint: `${gradlew} lint`,
152
+ test: `${gradlew} test`,
153
+ };
154
+ }
155
+ case 'ios':
156
+ return {
157
+ compile: 'xcodebuild build',
158
+ lint: null, // iOS 无标准 lint 工具
159
+ test: 'xcodebuild test',
160
+ };
161
+ case 'flutter':
162
+ return {
163
+ compile: 'flutter build apk',
164
+ lint: 'flutter analyze',
165
+ test: 'flutter test',
166
+ };
167
+ case 'rust':
168
+ return {
169
+ compile: 'cargo build',
170
+ lint: 'cargo clippy',
171
+ test: 'cargo test',
172
+ };
173
+ case 'csharp':
174
+ return {
175
+ compile: 'dotnet build',
176
+ lint: 'dotnet format --verify-no-changes',
177
+ test: 'dotnet test',
99
178
  };
100
179
  default:
101
180
  return { compile: null, lint: null, test: null };
@@ -253,14 +332,103 @@ ${check.output.slice(0, 3000)}
253
332
  // ============================================================
254
333
  // 主入口
255
334
  // ============================================================
335
+ /**
336
+ * v8.3.105+: 从 CONSTITUTION.md 工程类型字符串推断 ProjectType
337
+ */
338
+ function inferProjectTypeFromConstitution(typeStr) {
339
+ const t = typeStr.toLowerCase();
340
+ if (t.includes('java'))
341
+ return 'java';
342
+ if (t.includes('node') || t.includes('前端') || t.includes('h5') || t.includes('web') || t.includes('小程序'))
343
+ return 'node';
344
+ if (t.includes('go'))
345
+ return 'go';
346
+ if (t.includes('python'))
347
+ return 'python';
348
+ if (t.includes('android'))
349
+ return 'android';
350
+ if (t.includes('ios'))
351
+ return 'ios';
352
+ if (t.includes('flutter'))
353
+ return 'flutter';
354
+ if (t.includes('rust'))
355
+ return 'rust';
356
+ if (t.includes('csharp') || t.includes('c#') || t.includes('.net'))
357
+ return 'csharp';
358
+ return null;
359
+ }
360
+ /**
361
+ * v8.3.105+: 检查前端构建产物
362
+ */
363
+ async function runArtifactCheck(codePath, projectType) {
364
+ const start = Date.now();
365
+ // 确定期望的产物目录
366
+ let expectedDirs = [];
367
+ switch (projectType) {
368
+ case 'node':
369
+ expectedDirs = ['dist', 'build', 'out'];
370
+ break;
371
+ case 'java':
372
+ expectedDirs = ['target', (0, path_1.join)('build', 'libs')];
373
+ break;
374
+ case 'android':
375
+ expectedDirs = [(0, path_1.join)('app', 'build', 'outputs')];
376
+ break;
377
+ case 'flutter':
378
+ expectedDirs = [(0, path_1.join)('build', 'app', 'outputs')];
379
+ break;
380
+ default:
381
+ return { name: '产物检查', status: 'skip', duration: 0, output: '', details: '该类型暂不支持产物检查', blocking: false };
382
+ }
383
+ for (const dir of expectedDirs) {
384
+ const fullPath = (0, path_1.join)(codePath, dir);
385
+ if (await (0, fs_extra_1.pathExists)(fullPath)) {
386
+ const duration = Date.now() - start;
387
+ return { name: '产物检查', status: 'pass', duration, output: '', details: `发现产物目录: ${dir}`, blocking: false };
388
+ }
389
+ }
390
+ const duration = Date.now() - start;
391
+ return {
392
+ name: '产物检查',
393
+ status: 'warn',
394
+ duration,
395
+ output: `未在以下路径找到产物目录: ${expectedDirs.map(d => (0, path_1.join)(codePath, d)).join(', ')}`,
396
+ details: '未找到构建产物(需先执行构建)',
397
+ blocking: false,
398
+ };
399
+ }
256
400
  async function runVerification(taskId, codePath, options) {
257
401
  const checkType = options?.type || 'all';
258
402
  const timeout = options?.timeout || 120000;
259
403
  logger_1.logger.info(`🔍 开始验证: ${taskId}`);
260
404
  logger_1.logger.info(` 代码路径: ${codePath}`);
261
- // 检测项目类型
262
- const projectType = await detectProjectType(codePath);
263
- logger_1.logger.info(` 项目类型: ${projectType}`);
405
+ // v8.3.105+: 项目类型解析优先级:显式传入 > CONSTITUTION.md > 自动检测
406
+ let projectType = 'unknown';
407
+ if (options?.projectType) {
408
+ projectType = options.projectType;
409
+ logger_1.logger.info(` 项目类型: ${projectType}(显式指定)`);
410
+ }
411
+ else if (options?.platformName) {
412
+ // 尝试从 CONSTITUTION.md 读取工程类型
413
+ try {
414
+ const { parsePlatformTypes } = await Promise.resolve().then(() => __importStar(require('./spec-paths')));
415
+ const typeMap = await parsePlatformTypes();
416
+ const constitutionType = typeMap.get(options.platformName);
417
+ if (constitutionType) {
418
+ const inferred = inferProjectTypeFromConstitution(constitutionType);
419
+ if (inferred) {
420
+ projectType = inferred;
421
+ logger_1.logger.info(` 项目类型: ${projectType}(来自 CONSTITUTION.md: ${constitutionType})`);
422
+ }
423
+ }
424
+ }
425
+ catch { /* ignore */ }
426
+ }
427
+ // 如果还没确定,自动检测
428
+ if (projectType === 'unknown') {
429
+ projectType = await detectProjectType(codePath);
430
+ logger_1.logger.info(` 项目类型: ${projectType}(自动检测)`);
431
+ }
264
432
  if (projectType === 'unknown') {
265
433
  logger_1.logger.warn(' 未识别项目类型,跳过验证');
266
434
  return {
@@ -295,6 +463,13 @@ async function runVerification(taskId, codePath, options) {
295
463
  checks.push(result);
296
464
  logger_1.logger.info(` ${result.status === 'pass' ? '✅' : result.status === 'fail' ? '❌' : '⏭️'} ${result.details} (${(result.duration / 1000).toFixed(1)}s)`);
297
465
  }
466
+ // v8.3.105+: 产物检查
467
+ if (checkType === 'all' || checkType === 'artifact') {
468
+ logger_1.logger.info(' 📦 产物检查...');
469
+ const result = await runArtifactCheck(codePath, projectType);
470
+ checks.push(result);
471
+ logger_1.logger.info(` ${result.status === 'pass' ? '✅' : result.status === 'fail' ? '❌' : '⏭️'} ${result.details} (${(result.duration / 1000).toFixed(1)}s)`);
472
+ }
298
473
  // 汇总
299
474
  const report = {
300
475
  taskId,
@@ -348,8 +523,8 @@ async function generateFixPrompt(report, taskDir) {
348
523
  }
349
524
  // ── v8.2.0+: 注入知识图谱上下文(依赖链 + 相邻任务) ──
350
525
  try {
351
- const { loadKnowledgeGraph, traceDependencyChain } = await Promise.resolve().then(() => __importStar(require('./knowledge-graph')));
352
- const graph = await loadKnowledgeGraph(process.cwd());
526
+ const { loadFreshKnowledgeGraph, traceDependencyChain } = await Promise.resolve().then(() => __importStar(require('./knowledge-graph')));
527
+ const graph = await loadFreshKnowledgeGraph(process.cwd());
353
528
  if (graph && report.taskId) {
354
529
  const chains = traceDependencyChain(graph, report.taskId, 2);
355
530
  if (chains.length > 0) {
@@ -743,26 +918,23 @@ async function checkTestCoverage(codePath, taskDir) {
743
918
  const testPaths = [
744
919
  (0, path_1.join)(taskDir, 'TEST.md'),
745
920
  ];
746
- // 扫描子任务目录下的 TEST.md(新结构: 10-backend/svc/sub/ 20-frontend/plat/sub/)
747
- for (const catDir of ['10-backend', '20-frontend']) {
748
- const catPath = (0, path_1.join)(taskDir, catDir);
749
- if (await (0, fs_extra_1.pathExists)(catPath)) {
750
- try {
751
- const services = await (0, fs_extra_1.readdir)(catPath, { withFileTypes: true });
752
- for (const svc of services) {
753
- if (!svc.isDirectory())
754
- continue;
755
- const subs = await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true });
756
- for (const sub of subs) {
757
- if (!sub.isDirectory())
758
- continue;
759
- testPaths.push((0, path_1.join)(catPath, svc.name, sub.name, 'TEST.md'));
760
- }
761
- }
921
+ // v8.3.121+: 端平铺结构,直接扫描 taskDir 下的端目录(排除非端目录)
922
+ const EXCLUDE_DIRS = new Set(['00-specs', '_shared', '99-artifacts', '.meta']);
923
+ try {
924
+ const platformEntries = await (0, fs_extra_1.readdir)(taskDir, { withFileTypes: true });
925
+ for (const pe of platformEntries) {
926
+ if (!pe.isDirectory() || EXCLUDE_DIRS.has(pe.name))
927
+ continue;
928
+ const platformPath = (0, path_1.join)(taskDir, pe.name);
929
+ const subtaskEntries = await (0, fs_extra_1.readdir)(platformPath, { withFileTypes: true });
930
+ for (const sub of subtaskEntries) {
931
+ if (!sub.isDirectory())
932
+ continue;
933
+ testPaths.push((0, path_1.join)(platformPath, sub.name, 'TEST.md'));
762
934
  }
763
- catch { /* 跳过 */ }
764
935
  }
765
936
  }
937
+ catch { /* 跳过 */ }
766
938
  // 旧结构回退
767
939
  testPaths.push((0, path_1.join)(taskDir, '99-artifacts', 'TEST.md'));
768
940
  let testContent = '';
@@ -787,7 +959,9 @@ async function checkTestCoverage(codePath, taskDir) {
787
959
  ...(c.match(/[\u4e00-\u9fa5]{2,}/g) || []),
788
960
  ...(c.match(/[a-zA-Z]{3,}/g) || []),
789
961
  ];
790
- const found = keywords.some(kw => allCode.toLowerCase().includes(kw.toLowerCase()));
962
+ // v8.3.125+: 同义词扩展,避免 "登录" 与 "auth" 不匹配导致漏检
963
+ const expandedKws = [...(0, synonyms_1.expandSynonyms)(keywords)];
964
+ const found = expandedKws.some(kw => allCode.toLowerCase().includes(kw.toLowerCase()));
791
965
  if (found)
792
966
  covered.push(c);
793
967
  else
@@ -820,26 +994,23 @@ async function checkReviewCompliance(codePath, taskDir) {
820
994
  const reviewPaths = [
821
995
  (0, path_1.join)(taskDir, 'REVIEW.md'),
822
996
  ];
823
- // 扫描子任务目录下的 REVIEW.md(新结构)
824
- for (const catDir of ['10-backend', '20-frontend']) {
825
- const catPath = (0, path_1.join)(taskDir, catDir);
826
- if (await (0, fs_extra_1.pathExists)(catPath)) {
827
- try {
828
- const services = await (0, fs_extra_1.readdir)(catPath, { withFileTypes: true });
829
- for (const svc of services) {
830
- if (!svc.isDirectory())
831
- continue;
832
- const subs = await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true });
833
- for (const sub of subs) {
834
- if (!sub.isDirectory())
835
- continue;
836
- reviewPaths.push((0, path_1.join)(catPath, svc.name, sub.name, 'REVIEW.md'));
837
- }
838
- }
997
+ // v8.3.121+: 端平铺结构,直接扫描 taskDir 下的端目录
998
+ const EXCLUDE_DIRS = new Set(['00-specs', '_shared', '99-artifacts', '.meta']);
999
+ try {
1000
+ const platformEntries = await (0, fs_extra_1.readdir)(taskDir, { withFileTypes: true });
1001
+ for (const pe of platformEntries) {
1002
+ if (!pe.isDirectory() || EXCLUDE_DIRS.has(pe.name))
1003
+ continue;
1004
+ const platformPath = (0, path_1.join)(taskDir, pe.name);
1005
+ const subtaskEntries = await (0, fs_extra_1.readdir)(platformPath, { withFileTypes: true });
1006
+ for (const sub of subtaskEntries) {
1007
+ if (!sub.isDirectory())
1008
+ continue;
1009
+ reviewPaths.push((0, path_1.join)(platformPath, sub.name, 'REVIEW.md'));
839
1010
  }
840
- catch { /* 跳过 */ }
841
1011
  }
842
1012
  }
1013
+ catch { /* 跳过 */ }
843
1014
  // 旧结构回退
844
1015
  reviewPaths.push((0, path_1.join)(taskDir, '99-artifacts', 'REVIEW.md'));
845
1016
  let reviewContent = '';
@@ -864,7 +1035,9 @@ async function checkReviewCompliance(codePath, taskDir) {
864
1035
  ...(item.match(/[\u4e00-\u9fa5]{2,}/g) || []),
865
1036
  ...(item.match(/[a-zA-Z]{3,}/g) || []),
866
1037
  ];
867
- const found = keywords.some(kw => allCode.toLowerCase().includes(kw.toLowerCase()));
1038
+ // v8.3.125+: 同义词扩展
1039
+ const expandedKws = [...(0, synonyms_1.expandSynonyms)(keywords)];
1040
+ const found = expandedKws.some(kw => allCode.toLowerCase().includes(kw.toLowerCase()));
868
1041
  if (found)
869
1042
  passed.push(item);
870
1043
  else
@@ -897,26 +1070,23 @@ async function checkArtifactConsistency(codePath, taskDir, filename, checkName)
897
1070
  const filePaths = [
898
1071
  (0, path_1.join)(taskDir, filename),
899
1072
  ];
900
- // 扫描子任务目录(新结构)
901
- for (const catDir of ['10-backend', '20-frontend']) {
902
- const catPath = (0, path_1.join)(taskDir, catDir);
903
- if (await (0, fs_extra_1.pathExists)(catPath)) {
904
- try {
905
- const services = await (0, fs_extra_1.readdir)(catPath, { withFileTypes: true });
906
- for (const svc of services) {
907
- if (!svc.isDirectory())
908
- continue;
909
- const subs = await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true });
910
- for (const sub of subs) {
911
- if (!sub.isDirectory())
912
- continue;
913
- filePaths.push((0, path_1.join)(catPath, svc.name, sub.name, filename));
914
- }
915
- }
1073
+ // v8.3.121+: 端平铺结构,直接扫描 taskDir 下的端目录
1074
+ const EXCLUDE_DIRS = new Set(['00-specs', '_shared', '99-artifacts', '.meta']);
1075
+ try {
1076
+ const platformEntries = await (0, fs_extra_1.readdir)(taskDir, { withFileTypes: true });
1077
+ for (const pe of platformEntries) {
1078
+ if (!pe.isDirectory() || EXCLUDE_DIRS.has(pe.name))
1079
+ continue;
1080
+ const platformPath = (0, path_1.join)(taskDir, pe.name);
1081
+ const subtaskEntries = await (0, fs_extra_1.readdir)(platformPath, { withFileTypes: true });
1082
+ for (const sub of subtaskEntries) {
1083
+ if (!sub.isDirectory())
1084
+ continue;
1085
+ filePaths.push((0, path_1.join)(platformPath, sub.name, filename));
916
1086
  }
917
- catch { /* 跳过 */ }
918
1087
  }
919
1088
  }
1089
+ catch { /* 跳过 */ }
920
1090
  // 旧结构回退
921
1091
  filePaths.push((0, path_1.join)(taskDir, '99-artifacts', filename));
922
1092
  let content = '';
@@ -941,7 +1111,9 @@ async function checkArtifactConsistency(codePath, taskDir, filename, checkName)
941
1111
  ...(item.match(/[\u4e00-\u9fa5]{2,}/g) || []),
942
1112
  ...(item.match(/[a-zA-Z]{3,}/g) || []),
943
1113
  ];
944
- const found = keywords.some(kw => allCode.toLowerCase().includes(kw.toLowerCase()));
1114
+ // v8.3.125+: 同义词扩展
1115
+ const expandedKws = [...(0, synonyms_1.expandSynonyms)(keywords)];
1116
+ const found = expandedKws.some(kw => allCode.toLowerCase().includes(kw.toLowerCase()));
945
1117
  if (found)
946
1118
  matched.push(item);
947
1119
  else
@@ -1217,8 +1389,8 @@ async function checkSchemaConsistency(codePath, taskDir) {
1217
1389
  async function checkDependencyGraphConsistency(codePath, taskDir, taskId) {
1218
1390
  const start = Date.now();
1219
1391
  try {
1220
- const { loadKnowledgeGraph, traceDependencyChain } = await Promise.resolve().then(() => __importStar(require('./knowledge-graph')));
1221
- const graph = await loadKnowledgeGraph(process.cwd());
1392
+ const { loadFreshKnowledgeGraph, traceDependencyChain } = await Promise.resolve().then(() => __importStar(require('./knowledge-graph')));
1393
+ const graph = await loadFreshKnowledgeGraph(process.cwd());
1222
1394
  if (!graph) {
1223
1395
  return { name: '依赖一致性', status: 'skip', duration: Date.now() - start, output: '', details: '知识图谱未加载', blocking: false };
1224
1396
  }
@@ -1480,30 +1652,27 @@ async function checkSpecDocQuality(taskDir) {
1480
1652
  if (await (0, fs_extra_1.pathExists)(p))
1481
1653
  specFiles.push({ path: p, docName: doc });
1482
1654
  }
1483
- // 端子任务目录(10-backend/*/subtask/, 20-frontend/*/subtask/)
1484
- for (const catDir of ['10-backend', '20-frontend']) {
1485
- const catPath = (0, path_1.join)(taskDir, catDir);
1486
- if (!(await (0, fs_extra_1.pathExists)(catPath)))
1487
- continue;
1488
- try {
1489
- const services = await (0, fs_extra_1.readdir)(catPath, { withFileTypes: true });
1490
- for (const svc of services) {
1491
- if (!svc.isDirectory())
1655
+ // v8.3.121+: 端平铺结构,直接扫描 taskDir 下的端目录
1656
+ const EXCLUDE_DIRS = new Set(['00-specs', '_shared', '99-artifacts', '.meta']);
1657
+ try {
1658
+ const platformEntries = await (0, fs_extra_1.readdir)(taskDir, { withFileTypes: true });
1659
+ for (const pe of platformEntries) {
1660
+ if (!pe.isDirectory() || EXCLUDE_DIRS.has(pe.name))
1661
+ continue;
1662
+ const platformPath = (0, path_1.join)(taskDir, pe.name);
1663
+ const subtaskEntries = await (0, fs_extra_1.readdir)(platformPath, { withFileTypes: true });
1664
+ for (const sub of subtaskEntries) {
1665
+ if (!sub.isDirectory())
1492
1666
  continue;
1493
- const subs = await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true });
1494
- for (const sub of subs) {
1495
- if (!sub.isDirectory())
1496
- continue;
1497
- for (const doc of candidates) {
1498
- const p = (0, path_1.join)(catPath, svc.name, sub.name, doc);
1499
- if (await (0, fs_extra_1.pathExists)(p))
1500
- specFiles.push({ path: p, docName: doc });
1501
- }
1667
+ for (const doc of candidates) {
1668
+ const p = (0, path_1.join)(platformPath, sub.name, doc);
1669
+ if (await (0, fs_extra_1.pathExists)(p))
1670
+ specFiles.push({ path: p, docName: doc });
1502
1671
  }
1503
1672
  }
1504
1673
  }
1505
- catch { /* 跳过 */ }
1506
1674
  }
1675
+ catch { /* 跳过 */ }
1507
1676
  if (specFiles.length === 0) {
1508
1677
  return {
1509
1678
  name: '规格文档质量',
@@ -1594,26 +1763,23 @@ async function syncTestDocFromResults(taskDir, testPassed) {
1594
1763
  (0, path_1.join)(taskDir, 'TEST.md'),
1595
1764
  (0, path_1.join)(taskDir, '99-artifacts', 'TEST.md'),
1596
1765
  ];
1597
- // 扫描子任务目录下的 TEST.md(新结构)
1598
- for (const catDir of ['10-backend', '20-frontend']) {
1599
- const catPath = (0, path_1.join)(taskDir, catDir);
1600
- if (await (0, fs_extra_1.pathExists)(catPath)) {
1601
- try {
1602
- const services = await (0, fs_extra_1.readdir)(catPath, { withFileTypes: true });
1603
- for (const svc of services) {
1604
- if (!svc.isDirectory())
1605
- continue;
1606
- const subs = await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true });
1607
- for (const sub of subs) {
1608
- if (!sub.isDirectory())
1609
- continue;
1610
- testPaths.push((0, path_1.join)(catPath, svc.name, sub.name, 'TEST.md'));
1611
- }
1612
- }
1766
+ // v8.3.121+: 端平铺结构,直接扫描 taskDir 下的端目录
1767
+ const EXCLUDE_DIRS = new Set(['00-specs', '_shared', '99-artifacts', '.meta']);
1768
+ try {
1769
+ const platformEntries = await (0, fs_extra_1.readdir)(taskDir, { withFileTypes: true });
1770
+ for (const pe of platformEntries) {
1771
+ if (!pe.isDirectory() || EXCLUDE_DIRS.has(pe.name))
1772
+ continue;
1773
+ const platformPath = (0, path_1.join)(taskDir, pe.name);
1774
+ const subtaskEntries = await (0, fs_extra_1.readdir)(platformPath, { withFileTypes: true });
1775
+ for (const sub of subtaskEntries) {
1776
+ if (!sub.isDirectory())
1777
+ continue;
1778
+ testPaths.push((0, path_1.join)(platformPath, sub.name, 'TEST.md'));
1613
1779
  }
1614
- catch { /* 跳过 */ }
1615
1780
  }
1616
1781
  }
1782
+ catch { /* 跳过 */ }
1617
1783
  for (const testPath of testPaths) {
1618
1784
  if (!(await (0, fs_extra_1.pathExists)(testPath)))
1619
1785
  continue;