speccore 6.49.7 → 6.49.9
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.js +54 -58
- package/dist/commands/analyze.js.map +1 -1
- package/dist/commands/execute.js +145 -190
- package/dist/commands/execute.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +4 -10
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/iteration/split.js +1 -1
- package/dist/commands/status-panel.d.ts.map +1 -1
- package/dist/commands/status-panel.js +56 -16
- package/dist/commands/status-panel.js.map +1 -1
- package/dist/core/prompt-builder.d.ts.map +1 -1
- package/dist/core/prompt-builder.js +31 -18
- package/dist/core/prompt-builder.js.map +1 -1
- package/dist/core/spec-paths.d.ts +2 -1
- package/dist/core/spec-paths.d.ts.map +1 -1
- package/dist/core/spec-paths.js +3 -0
- package/dist/core/spec-paths.js.map +1 -1
- package/package.json +1 -1
package/dist/commands/execute.js
CHANGED
|
@@ -641,7 +641,7 @@ async function processBatch(tasks, state, iteration) {
|
|
|
641
641
|
type: task.type || 'feature',
|
|
642
642
|
status: 'completed',
|
|
643
643
|
summary: `${task.name || task.id} 骨架已生成`,
|
|
644
|
-
outputs: ['00-specs/', '
|
|
644
|
+
outputs: ['00-specs/', '{platform}/(子任务)/'],
|
|
645
645
|
dependencies: task.dependencies || [],
|
|
646
646
|
completedAt: new Date().toISOString(),
|
|
647
647
|
};
|
|
@@ -701,32 +701,51 @@ async function generateTaskSkeleton(task, iteration) {
|
|
|
701
701
|
const specRules = await (0, spec_rules_1.loadSpecRules)();
|
|
702
702
|
const techStack = await (0, spec_rules_1.loadTechStack)();
|
|
703
703
|
logger_1.logger.info(` Tech Stack: ${techStack.backendFramework} + ${techStack.frontendFramework}`);
|
|
704
|
-
//
|
|
704
|
+
// v6.49.9+: 扫描平铺的端目录(新结构: {platform}/{subtask}/)
|
|
705
705
|
const { readdir: rd } = await Promise.resolve().then(() => __importStar(require('fs-extra')));
|
|
706
706
|
const taskEntries = await rd(taskDir, { withFileTypes: true });
|
|
707
|
+
const platformList = await (0, spec_paths_1.parsePlatformList)();
|
|
707
708
|
const backendSubtaskDirs = [];
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
709
|
+
const frontendSubtaskDirs = [];
|
|
710
|
+
// 新结构: 所有端平铺在任务目录下
|
|
711
|
+
for (const entry of taskEntries) {
|
|
712
|
+
if (!entry.isDirectory() || entry.name.startsWith('.'))
|
|
713
|
+
continue;
|
|
714
|
+
if (!platformList.includes(entry.name))
|
|
715
|
+
continue;
|
|
716
|
+
const platDir = (0, path_1.join)(taskDir, entry.name);
|
|
717
|
+
const isBk = entry.name === 'backend' || entry.name.startsWith('后台') || /-(service|api|server|backend)$/i.test(entry.name);
|
|
718
|
+
const subEntries = await rd(platDir, { withFileTypes: true });
|
|
719
|
+
for (const st of subEntries) {
|
|
720
|
+
if (st.isDirectory() && !st.name.startsWith('.')) {
|
|
721
|
+
if (isBk)
|
|
722
|
+
backendSubtaskDirs.push((0, path_1.join)(platDir, st.name));
|
|
723
|
+
else
|
|
724
|
+
frontendSubtaskDirs.push((0, path_1.join)(platDir, st.name));
|
|
721
725
|
}
|
|
722
726
|
}
|
|
723
727
|
}
|
|
724
|
-
// 回退: 旧结构 10
|
|
725
|
-
if (backendSubtaskDirs.length === 0) {
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
728
|
+
// 回退: 旧结构 10-backend/ 和 20-frontend/
|
|
729
|
+
if (backendSubtaskDirs.length === 0 && frontendSubtaskDirs.length === 0) {
|
|
730
|
+
for (const catName of ['10-backend', '20-frontend']) {
|
|
731
|
+
const catDir = (0, path_1.join)(taskDir, catName);
|
|
732
|
+
if (await (0, fs_extra_1.pathExists)(catDir)) {
|
|
733
|
+
const svcEntries = await rd(catDir, { withFileTypes: true });
|
|
734
|
+
for (const svc of svcEntries) {
|
|
735
|
+
if (!svc.isDirectory())
|
|
736
|
+
continue;
|
|
737
|
+
const subEntries = await rd((0, path_1.join)(catDir, svc.name), { withFileTypes: true });
|
|
738
|
+
for (const st of subEntries) {
|
|
739
|
+
if (st.isDirectory() && !st.name.startsWith('.')) {
|
|
740
|
+
if (catName === '10-backend')
|
|
741
|
+
backendSubtaskDirs.push((0, path_1.join)(catDir, svc.name, st.name));
|
|
742
|
+
else
|
|
743
|
+
frontendSubtaskDirs.push((0, path_1.join)(catDir, svc.name, st.name));
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
730
749
|
}
|
|
731
750
|
for (const backendDir of backendSubtaskDirs) {
|
|
732
751
|
const reqPath = (0, path_1.join)(taskDir, '00-specs', 'REQ.md');
|
|
@@ -770,31 +789,7 @@ async function generateTaskSkeleton(task, iteration) {
|
|
|
770
789
|
filesUpdated++;
|
|
771
790
|
}
|
|
772
791
|
}
|
|
773
|
-
//
|
|
774
|
-
const frontendSubtaskDirs = [];
|
|
775
|
-
// 新结构: 20-frontend/{端名}/{子任务}/
|
|
776
|
-
const frontendCategoryDir = (0, path_1.join)(taskDir, '20-frontend');
|
|
777
|
-
if (await (0, fs_extra_1.pathExists)(frontendCategoryDir)) {
|
|
778
|
-
const platformEntries = await rd(frontendCategoryDir, { withFileTypes: true });
|
|
779
|
-
for (const plat of platformEntries) {
|
|
780
|
-
if (!plat.isDirectory())
|
|
781
|
-
continue;
|
|
782
|
-
const platformDir = (0, path_1.join)(frontendCategoryDir, plat.name);
|
|
783
|
-
const subtaskEntries = await rd(platformDir, { withFileTypes: true });
|
|
784
|
-
for (const st of subtaskEntries) {
|
|
785
|
-
if (st.isDirectory() && !st.name.startsWith('.')) {
|
|
786
|
-
frontendSubtaskDirs.push((0, path_1.join)(platformDir, st.name));
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
// 回退: 旧结构 20-*/ 直接在任务根目录
|
|
792
|
-
if (frontendSubtaskDirs.length === 0) {
|
|
793
|
-
const legacy = taskEntries
|
|
794
|
-
.filter((d) => d.isDirectory() && d.name.startsWith('20-'))
|
|
795
|
-
.map((d) => (0, path_1.join)(taskDir, d.name));
|
|
796
|
-
frontendSubtaskDirs.push(...legacy);
|
|
797
|
-
}
|
|
792
|
+
// 前端各平台代码生成(v6.49.9+: 已统一在上方扫描)
|
|
798
793
|
for (const frontendDir of frontendSubtaskDirs) {
|
|
799
794
|
const componentName = convertToClassName(task.name || task.id);
|
|
800
795
|
const vueCode = generateVueComponent(componentName);
|
|
@@ -1000,38 +995,29 @@ async function filterByPlatform(tasks, iteration, platform) {
|
|
|
1000
995
|
filtered.push(task);
|
|
1001
996
|
continue;
|
|
1002
997
|
}
|
|
1003
|
-
//
|
|
998
|
+
// v6.49.9+: 新结构 — 所有端平铺在任务目录下
|
|
1004
999
|
const taskDir = await resolveTaskDir(iterDir, task.id);
|
|
1000
|
+
const platformDir = (0, path_1.join)(taskDir, platform);
|
|
1001
|
+
if (await (0, fs_extra_1.pathExists)(platformDir)) {
|
|
1002
|
+
filtered.push(task);
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
// 回退: 旧结构 10-backend/{端}/ 或 20-frontend/{端}/
|
|
1005
1006
|
const isBackend = platform === 'backend' || platform.startsWith('后台');
|
|
1006
1007
|
const categoryDir = isBackend ? (0, path_1.join)(taskDir, '10-backend') : (0, path_1.join)(taskDir, '20-frontend');
|
|
1007
1008
|
const serviceName = isBackend && platform === 'backend' ? 'api' : platform;
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
if (await (0, fs_extra_1.pathExists)(platformDir)) {
|
|
1009
|
+
const legacyPlatformDir = (0, path_1.join)(categoryDir, serviceName);
|
|
1010
|
+
if (await (0, fs_extra_1.pathExists)(legacyPlatformDir)) {
|
|
1011
1011
|
filtered.push(task);
|
|
1012
1012
|
continue;
|
|
1013
1013
|
}
|
|
1014
|
-
//
|
|
1015
|
-
try {
|
|
1016
|
-
if (await (0, fs_extra_1.pathExists)(categoryDir)) {
|
|
1017
|
-
const { readdir: readDir } = await Promise.resolve().then(() => __importStar(require('fs-extra')));
|
|
1018
|
-
const entries = await readDir(categoryDir, { withFileTypes: true });
|
|
1019
|
-
const matched = entries.find((d) => d.isDirectory() && d.name === serviceName);
|
|
1020
|
-
if (matched) {
|
|
1021
|
-
filtered.push(task);
|
|
1022
|
-
continue;
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
catch { /* ignore */ }
|
|
1027
|
-
// 旧结构回退: 10-{端}/ 或 20-{端}/ 直接在任务根目录
|
|
1014
|
+
// 更旧结构回退: backend/ 或 frontend/{platform}/
|
|
1028
1015
|
const subtaskPrefix = isBackend ? '10-' : '20-';
|
|
1029
1016
|
const legacyDir = (0, path_1.join)(taskDir, `${subtaskPrefix}${serviceName}`);
|
|
1030
1017
|
if (await (0, fs_extra_1.pathExists)(legacyDir)) {
|
|
1031
1018
|
filtered.push(task);
|
|
1032
1019
|
continue;
|
|
1033
1020
|
}
|
|
1034
|
-
// 更旧结构回退: frontend/{platform}/
|
|
1035
1021
|
const legacyDir2 = (0, path_1.join)(taskDir, 'frontend', platform);
|
|
1036
1022
|
if (await (0, fs_extra_1.pathExists)(legacyDir2))
|
|
1037
1023
|
filtered.push(task);
|
|
@@ -1102,29 +1088,16 @@ async function preFlightCheck(tasks, iteration, options) {
|
|
|
1102
1088
|
else {
|
|
1103
1089
|
issues.push('缺少 TECH.md');
|
|
1104
1090
|
}
|
|
1105
|
-
// 3. Test cases
|
|
1091
|
+
// 3. Test cases(v6.49.9+: 扫描平铺的端目录)
|
|
1106
1092
|
let testFound = false;
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
if (!sub.isDirectory())
|
|
1116
|
-
continue;
|
|
1117
|
-
const tp = (0, path_1.join)(catPath, svc.name, sub.name, 'TEST.md');
|
|
1118
|
-
if (await (0, fs_extra_1.pathExists)(tp)) {
|
|
1119
|
-
const test = await (0, fs_extra_1.readFile)(tp, 'utf-8');
|
|
1120
|
-
const n = (test.match(/⬜|✅|❌/g) || []).length;
|
|
1121
|
-
logger_1.logger.info(` 3. 测试[${svc.name}/${sub.name}]: ${n} 用例`);
|
|
1122
|
-
testFound = true;
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
catch { /* 跳过 */ }
|
|
1093
|
+
const platDirs3 = await getPlatformSubtaskDirs(taskDir);
|
|
1094
|
+
for (const { platform, subtask, fullPath } of platDirs3) {
|
|
1095
|
+
const tp = (0, path_1.join)(fullPath, 'TEST.md');
|
|
1096
|
+
if (await (0, fs_extra_1.pathExists)(tp)) {
|
|
1097
|
+
const test = await (0, fs_extra_1.readFile)(tp, 'utf-8');
|
|
1098
|
+
const n = (test.match(/⬜|✅|❌/g) || []).length;
|
|
1099
|
+
logger_1.logger.info(` 3. 测试[${platform}/${subtask}]: ${n} 用例`);
|
|
1100
|
+
testFound = true;
|
|
1128
1101
|
}
|
|
1129
1102
|
}
|
|
1130
1103
|
if (!testFound) {
|
|
@@ -1136,26 +1109,12 @@ async function preFlightCheck(tasks, iteration, options) {
|
|
|
1136
1109
|
logger_1.logger.info(` 3. 测试: ${n} 用例`);
|
|
1137
1110
|
}
|
|
1138
1111
|
}
|
|
1139
|
-
// 4. Review
|
|
1112
|
+
// 4. Review(v6.49.9+: 扫描平铺的端目录)
|
|
1140
1113
|
let reviewFound = false;
|
|
1141
|
-
for (const
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
for (const svc of await (0, fs_extra_1.readdir)(catPath, { withFileTypes: true })) {
|
|
1146
|
-
if (!svc.isDirectory())
|
|
1147
|
-
continue;
|
|
1148
|
-
for (const sub of await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true })) {
|
|
1149
|
-
if (!sub.isDirectory())
|
|
1150
|
-
continue;
|
|
1151
|
-
if (await (0, fs_extra_1.pathExists)((0, path_1.join)(catPath, svc.name, sub.name, 'REVIEW.md'))) {
|
|
1152
|
-
logger_1.logger.info(` 4. 审查[${svc.name}/${sub.name}]: ✅`);
|
|
1153
|
-
reviewFound = true;
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
catch { /* 跳过 */ }
|
|
1114
|
+
for (const { platform, subtask, fullPath } of platDirs3) {
|
|
1115
|
+
if (await (0, fs_extra_1.pathExists)((0, path_1.join)(fullPath, 'REVIEW.md'))) {
|
|
1116
|
+
logger_1.logger.info(` 4. 审查[${platform}/${subtask}]: ✅`);
|
|
1117
|
+
reviewFound = true;
|
|
1159
1118
|
}
|
|
1160
1119
|
}
|
|
1161
1120
|
if (!reviewFound) {
|
|
@@ -1164,34 +1123,30 @@ async function preFlightCheck(tasks, iteration, options) {
|
|
|
1164
1123
|
// 5. API(00-specs/ 优先,_shared/ 回退)
|
|
1165
1124
|
const hasApiContract = await (0, fs_extra_1.pathExists)((0, path_1.join)(taskDir, '00-specs', 'API_CONTRACT.yaml')) || await (0, fs_extra_1.pathExists)((0, path_1.join)(taskDir, '_shared', 'API_CONTRACT.yaml'));
|
|
1166
1125
|
logger_1.logger.info(` 5. 契约: ${hasApiContract ? '✅' : '⚠️'}`);
|
|
1167
|
-
// 6. Platform
|
|
1168
|
-
const subtaskDirs =
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1126
|
+
// 6. Platform(v6.49.9+: 扫描平铺的端目录)
|
|
1127
|
+
const subtaskDirs = platDirs3.map(p => `${p.platform}/${p.subtask}`);
|
|
1128
|
+
// 回退: 旧结构 10-backend/ 和 20-frontend/
|
|
1129
|
+
if (subtaskDirs.length === 0) {
|
|
1130
|
+
for (const catDir of ['10-backend', '20-frontend']) {
|
|
1131
|
+
const catPath = (0, path_1.join)(taskDir, catDir);
|
|
1132
|
+
if (await (0, fs_extra_1.pathExists)(catPath)) {
|
|
1133
|
+
try {
|
|
1134
|
+
const platEntries = (0, fs_1.readdirSync)(catPath, { withFileTypes: true });
|
|
1135
|
+
for (const pe of platEntries) {
|
|
1136
|
+
if (pe.isDirectory()) {
|
|
1137
|
+
const stEntries = (0, fs_1.readdirSync)((0, path_1.join)(catPath, pe.name), { withFileTypes: true });
|
|
1138
|
+
for (const st of stEntries) {
|
|
1139
|
+
if (st.isDirectory() && !st.name.startsWith('.')) {
|
|
1140
|
+
subtaskDirs.push(`${catDir}/${pe.name}/${st.name}`);
|
|
1141
|
+
}
|
|
1180
1142
|
}
|
|
1181
1143
|
}
|
|
1182
1144
|
}
|
|
1183
1145
|
}
|
|
1146
|
+
catch { /* ignore */ }
|
|
1184
1147
|
}
|
|
1185
|
-
catch { /* ignore */ }
|
|
1186
1148
|
}
|
|
1187
1149
|
}
|
|
1188
|
-
// 回退: 旧结构 10-*/20-*
|
|
1189
|
-
if (subtaskDirs.length === 0) {
|
|
1190
|
-
const legacy = (0, fs_1.readdirSync)(taskDir, { withFileTypes: true })
|
|
1191
|
-
.filter((d) => d.isDirectory() && (d.name.startsWith('10-') || d.name.startsWith('20-')))
|
|
1192
|
-
.map((d) => d.name);
|
|
1193
|
-
subtaskDirs.push(...legacy);
|
|
1194
|
-
}
|
|
1195
1150
|
if (subtaskDirs.length > 0) {
|
|
1196
1151
|
logger_1.logger.info(` 6. 子任务: ${subtaskDirs.join(', ')}`);
|
|
1197
1152
|
}
|
|
@@ -1412,18 +1367,17 @@ function buildAgentContext(tasks, agent) {
|
|
|
1412
1367
|
ctx += `Status: ${task.status} | Priority: ${task.priority} | Type: ${task.type}\n\n`;
|
|
1413
1368
|
// Progressive loading order
|
|
1414
1369
|
ctx += `**Read in this order (progressive disclosure):**\n`;
|
|
1415
|
-
ctx += `1. \`Iteration-*/${task.id}/
|
|
1416
|
-
ctx += `2. \`Iteration-*/${task.id}/
|
|
1417
|
-
ctx += `3. \`Iteration-*/${task.id}/00-specs/
|
|
1418
|
-
ctx += `4. \`Iteration-*/${task.id}/00-specs/
|
|
1419
|
-
ctx += `5. \`Iteration-*/${task.id}/00-specs/API_CONTRACT.yaml\` — API 契约 (if exists)\n\n`;
|
|
1370
|
+
ctx += `1. \`Iteration-*/${task.id}/{platform}/{subtask}/TASK.md\` — 子任务概览(所有端平铺)\n`;
|
|
1371
|
+
ctx += `2. \`Iteration-*/${task.id}/00-specs/REQ.md\` — 需求 + 验收标准\n`;
|
|
1372
|
+
ctx += `3. \`Iteration-*/${task.id}/00-specs/TECH.md\` — 技术设计\n`;
|
|
1373
|
+
ctx += `4. \`Iteration-*/${task.id}/00-specs/API_CONTRACT.yaml\` — API 契约 (if exists)\n\n`;
|
|
1420
1374
|
ctx += `**Supplementary (read only if needed):**\n`;
|
|
1421
1375
|
ctx += `- 子任务目录/TEST.md (测试用例) | 子任务目录/REVIEW.md (评审清单)\n`;
|
|
1422
1376
|
ctx += `- 00-specs/SCHEMA.md (DB schema) | 子任务目录/ADR.md (架构决策)\n`;
|
|
1423
1377
|
ctx += `- 子任务目录/RISK.md (风险+回滚) | 子任务目录/DEPS.md (依赖) | 子任务目录/MONITOR.md (监控)\n`;
|
|
1424
1378
|
ctx += `- 子任务目录/ERROR_CODES.md (错误码) | 子任务目录/DEPLOY.md (部署)\n\n`;
|
|
1425
1379
|
ctx += `**Frontend design docs (if exists):**\n`;
|
|
1426
|
-
ctx += `-
|
|
1380
|
+
ctx += `- {platform}/COMPONENT_TREE.md | ROUTES.md | STATE.md | STYLE_GUIDE.md\n\n`;
|
|
1427
1381
|
}
|
|
1428
1382
|
// 3. Global rules (load last, only if needed)
|
|
1429
1383
|
ctx += `### Step N: Global rules (load last)\n`;
|
|
@@ -1447,26 +1401,13 @@ async function executionVerifyLoop(tasks, iteration, options) {
|
|
|
1447
1401
|
if (round > 1)
|
|
1448
1402
|
logger_1.logger.info(` 🔄 第 ${round} 轮修复...`);
|
|
1449
1403
|
allPassed = true;
|
|
1450
|
-
// 1. 检查 TEST.md
|
|
1404
|
+
// 1. 检查 TEST.md(v6.49.9+: 扫描平铺的端目录)
|
|
1451
1405
|
const testFiles = [];
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
if (!svc.isDirectory())
|
|
1458
|
-
continue;
|
|
1459
|
-
for (const sub of await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true })) {
|
|
1460
|
-
if (!sub.isDirectory())
|
|
1461
|
-
continue;
|
|
1462
|
-
const fp = (0, path_1.join)(catPath, svc.name, sub.name, 'TEST.md');
|
|
1463
|
-
if (await (0, fs_extra_1.pathExists)(fp))
|
|
1464
|
-
testFiles.push(fp);
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
}
|
|
1468
|
-
catch { /* 跳过 */ }
|
|
1469
|
-
}
|
|
1406
|
+
const platDirsRound = await getPlatformSubtaskDirs(taskDir);
|
|
1407
|
+
for (const { fullPath } of platDirsRound) {
|
|
1408
|
+
const fp = (0, path_1.join)(fullPath, 'TEST.md');
|
|
1409
|
+
if (await (0, fs_extra_1.pathExists)(fp))
|
|
1410
|
+
testFiles.push(fp);
|
|
1470
1411
|
}
|
|
1471
1412
|
if (testFiles.length === 0) {
|
|
1472
1413
|
// 旧结构回退
|
|
@@ -1489,26 +1430,12 @@ async function executionVerifyLoop(tasks, iteration, options) {
|
|
|
1489
1430
|
logger_1.logger.info(` 🧪 ${label}: ${done}/${total} ✅`);
|
|
1490
1431
|
}
|
|
1491
1432
|
}
|
|
1492
|
-
// 2. 检查 REVIEW.md
|
|
1433
|
+
// 2. 检查 REVIEW.md(v6.49.9+: 扫描平铺的端目录)
|
|
1493
1434
|
const reviewFiles = [];
|
|
1494
|
-
for (const
|
|
1495
|
-
const
|
|
1496
|
-
if (await (0, fs_extra_1.pathExists)(
|
|
1497
|
-
|
|
1498
|
-
for (const svc of await (0, fs_extra_1.readdir)(catPath, { withFileTypes: true })) {
|
|
1499
|
-
if (!svc.isDirectory())
|
|
1500
|
-
continue;
|
|
1501
|
-
for (const sub of await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true })) {
|
|
1502
|
-
if (!sub.isDirectory())
|
|
1503
|
-
continue;
|
|
1504
|
-
const fp = (0, path_1.join)(catPath, svc.name, sub.name, 'REVIEW.md');
|
|
1505
|
-
if (await (0, fs_extra_1.pathExists)(fp))
|
|
1506
|
-
reviewFiles.push(fp);
|
|
1507
|
-
}
|
|
1508
|
-
}
|
|
1509
|
-
}
|
|
1510
|
-
catch { /* 跳过 */ }
|
|
1511
|
-
}
|
|
1435
|
+
for (const { fullPath } of platDirsRound) {
|
|
1436
|
+
const fp = (0, path_1.join)(fullPath, 'REVIEW.md');
|
|
1437
|
+
if (await (0, fs_extra_1.pathExists)(fp))
|
|
1438
|
+
reviewFiles.push(fp);
|
|
1512
1439
|
}
|
|
1513
1440
|
if (reviewFiles.length === 0) {
|
|
1514
1441
|
const legacy = (0, path_1.join)(taskDir, '99-artifacts', 'REVIEW.md');
|
|
@@ -1530,26 +1457,12 @@ async function executionVerifyLoop(tasks, iteration, options) {
|
|
|
1530
1457
|
logger_1.logger.info(` 📋 ${label}: ${doneR}/${total} ✅`);
|
|
1531
1458
|
}
|
|
1532
1459
|
}
|
|
1533
|
-
// 3. 检查 DEPLOY.md
|
|
1460
|
+
// 3. 检查 DEPLOY.md(v6.49.9+: 扫描平铺的端目录)
|
|
1534
1461
|
const deployFiles = [];
|
|
1535
|
-
for (const
|
|
1536
|
-
const
|
|
1537
|
-
if (await (0, fs_extra_1.pathExists)(
|
|
1538
|
-
|
|
1539
|
-
for (const svc of await (0, fs_extra_1.readdir)(catPath, { withFileTypes: true })) {
|
|
1540
|
-
if (!svc.isDirectory())
|
|
1541
|
-
continue;
|
|
1542
|
-
for (const sub of await (0, fs_extra_1.readdir)((0, path_1.join)(catPath, svc.name), { withFileTypes: true })) {
|
|
1543
|
-
if (!sub.isDirectory())
|
|
1544
|
-
continue;
|
|
1545
|
-
const fp = (0, path_1.join)(catPath, svc.name, sub.name, 'DEPLOY.md');
|
|
1546
|
-
if (await (0, fs_extra_1.pathExists)(fp))
|
|
1547
|
-
deployFiles.push(fp);
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
}
|
|
1551
|
-
catch { /* 跳过 */ }
|
|
1552
|
-
}
|
|
1462
|
+
for (const { fullPath } of platDirsRound) {
|
|
1463
|
+
const fp = (0, path_1.join)(fullPath, 'DEPLOY.md');
|
|
1464
|
+
if (await (0, fs_extra_1.pathExists)(fp))
|
|
1465
|
+
deployFiles.push(fp);
|
|
1553
1466
|
}
|
|
1554
1467
|
if (deployFiles.length === 0) {
|
|
1555
1468
|
const legacy = (0, path_1.join)(taskDir, '99-artifacts', 'DEPLOY.md');
|
|
@@ -1934,4 +1847,46 @@ function readStdin() {
|
|
|
1934
1847
|
resolve('');
|
|
1935
1848
|
});
|
|
1936
1849
|
}
|
|
1850
|
+
async function getPlatformSubtaskDirs(taskDir) {
|
|
1851
|
+
const result = [];
|
|
1852
|
+
const platformList = await (0, spec_paths_1.parsePlatformList)();
|
|
1853
|
+
// 新结构: 所有端平铺在任务目录下
|
|
1854
|
+
for (const platform of platformList) {
|
|
1855
|
+
const platDir = (0, path_1.join)(taskDir, platform);
|
|
1856
|
+
if (!(await (0, fs_extra_1.pathExists)(platDir)))
|
|
1857
|
+
continue;
|
|
1858
|
+
try {
|
|
1859
|
+
const entries = await (0, fs_extra_1.readdir)(platDir, { withFileTypes: true });
|
|
1860
|
+
for (const entry of entries) {
|
|
1861
|
+
if (entry.isDirectory() && !entry.name.startsWith('.')) {
|
|
1862
|
+
result.push({ platform, subtask: entry.name, fullPath: (0, path_1.join)(platDir, entry.name) });
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
catch { /* ignore */ }
|
|
1867
|
+
}
|
|
1868
|
+
// 回退: 旧结构 10-backend/ 和 20-frontend/
|
|
1869
|
+
if (result.length === 0) {
|
|
1870
|
+
for (const catName of ['10-backend', '20-frontend']) {
|
|
1871
|
+
const catDir = (0, path_1.join)(taskDir, catName);
|
|
1872
|
+
if (!(await (0, fs_extra_1.pathExists)(catDir)))
|
|
1873
|
+
continue;
|
|
1874
|
+
try {
|
|
1875
|
+
const svcEntries = await (0, fs_extra_1.readdir)(catDir, { withFileTypes: true });
|
|
1876
|
+
for (const svc of svcEntries) {
|
|
1877
|
+
if (!svc.isDirectory())
|
|
1878
|
+
continue;
|
|
1879
|
+
const subEntries = await (0, fs_extra_1.readdir)((0, path_1.join)(catDir, svc.name), { withFileTypes: true });
|
|
1880
|
+
for (const st of subEntries) {
|
|
1881
|
+
if (st.isDirectory() && !st.name.startsWith('.')) {
|
|
1882
|
+
result.push({ platform: `${catName}/${svc.name}`, subtask: st.name, fullPath: (0, path_1.join)(catDir, svc.name, st.name) });
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
catch { /* ignore */ }
|
|
1888
|
+
}
|
|
1889
|
+
}
|
|
1890
|
+
return result;
|
|
1891
|
+
}
|
|
1937
1892
|
//# sourceMappingURL=execute.js.map
|