speccrew 0.6.56 → 0.6.57
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/.speccrew/skills/speccrew-knowledge-bizs-dispatch-xml/SKILL.md +32 -7
- package/.speccrew/skills/speccrew-knowledge-bizs-identify-entries-xml/SKILL.md +8 -0
- package/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js +95 -28
- package/.speccrew/skills/speccrew-knowledge-techs-dispatch-xml/SKILL.md +19 -5
- package/package.json +1 -1
|
@@ -278,13 +278,17 @@ Continue with knowledge base generation?
|
|
|
278
278
|
<sequence id="S1a" name="Stage 1a: Entry Directory Recognition" status="pending" desc="Identify entry directories for each platform and classify into business modules">
|
|
279
279
|
|
|
280
280
|
<block type="rule" id="S1a-R1" level="mandatory" desc="Stage 1a mandatory rules">
|
|
281
|
-
<field name="text">
|
|
281
|
+
<field name="text">ALL platform entry directory recognition tasks MUST be dispatched IN PARALLEL — sequential execution is FORBIDDEN</field>
|
|
282
|
+
<field name="text">ALL Worker dispatch calls in S1a-L1 MUST be issued SIMULTANEOUSLY in a SINGLE orchestration turn</field>
|
|
283
|
+
<field name="text">DO NOT wait for any Worker to complete before dispatching the next Worker</field>
|
|
284
|
+
<field name="text">Dispatch all ${max_concurrent_workers} workers at once, then wait for ALL to complete</field>
|
|
285
|
+
<field name="text">Sequential one-by-one dispatch is STRICTLY FORBIDDEN</field>
|
|
282
286
|
</block>
|
|
283
287
|
|
|
284
|
-
<block type="loop" id="S1a-L1" over="${platforms}" as="platform" desc="
|
|
288
|
+
<block type="loop" id="S1a-L1" over="${platforms}" as="platform" parallel="true" max-concurrency="${max_concurrent_workers}" desc="Dispatch entry directory recognition for each platform IN PARALLEL">
|
|
285
289
|
<!-- Step 1: Read source directory tree -->
|
|
286
|
-
<block type="task" id="S1a-B1" action="
|
|
287
|
-
<field name="
|
|
290
|
+
<block type="task" id="S1a-B1" action="dispatch-to-worker" status="pending" desc="Dispatch entry identification to Worker">
|
|
291
|
+
<field name="worker">speccrew-knowledge-bizs-identify-entries-xml</field>
|
|
288
292
|
<field name="source_path" value="${platform.sourcePath}"/>
|
|
289
293
|
<field name="platform_id" value="${platform.platformId}"/>
|
|
290
294
|
<field name="platform_type" value="${platform.platformType}"/>
|
|
@@ -317,11 +321,15 @@ Continue with knowledge base generation?
|
|
|
317
321
|
<sequence id="S1b" name="Stage 1b: Generate Feature Inventory" status="pending" desc="Generate Feature inventory for each platform">
|
|
318
322
|
|
|
319
323
|
<block type="rule" id="S1b-R1" level="mandatory" desc="Stage 1b mandatory rules">
|
|
320
|
-
<field name="text">
|
|
324
|
+
<field name="text">ALL platform feature inventory generation tasks MUST be dispatched IN PARALLEL — sequential execution is FORBIDDEN</field>
|
|
325
|
+
<field name="text">ALL Worker dispatch calls in S1b-L1 MUST be issued SIMULTANEOUSLY in a SINGLE orchestration turn</field>
|
|
326
|
+
<field name="text">DO NOT wait for any Worker to complete before dispatching the next Worker</field>
|
|
327
|
+
<field name="text">Dispatch all ${max_concurrent_workers} workers at once, then wait for ALL to complete</field>
|
|
328
|
+
<field name="text">Sequential one-by-one dispatch is STRICTLY FORBIDDEN</field>
|
|
321
329
|
<field name="text">Worker Agents do not have run_in_terminal capability, which is required for script execution</field>
|
|
322
330
|
</block>
|
|
323
331
|
|
|
324
|
-
<block type="loop" id="S1b-L1" over="${platforms}" as="platform" desc="Generate Feature inventory for each platform">
|
|
332
|
+
<block type="loop" id="S1b-L1" over="${platforms}" as="platform" parallel="true" max-concurrency="${max_concurrent_workers}" desc="Generate Feature inventory for each platform IN PARALLEL">
|
|
325
333
|
<!-- Step 1: Read platform mapping config -->
|
|
326
334
|
<block type="task" id="S1b-B1" action="run-script" status="pending" desc="Read platform mapping config">
|
|
327
335
|
<field name="command">node "${ide_skills_dir}/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js"</field>
|
|
@@ -422,6 +430,10 @@ Continue with knowledge base generation?
|
|
|
422
430
|
<field name="text">MUST use batch-orchestrator for batch management — DO NOT manually track batches</field>
|
|
423
431
|
<field name="text">MUST dispatch Workers for feature analysis — DO NOT analyze features yourself</field>
|
|
424
432
|
<field name="text">ALL workers for the same stage MUST be dispatched in PARALLEL — sequential execution is FORBIDDEN</field>
|
|
433
|
+
<field name="text">ALL Worker dispatch calls in S2-L2 MUST be issued SIMULTANEOUSLY in a SINGLE orchestration turn</field>
|
|
434
|
+
<field name="text">DO NOT wait for any Worker to complete before dispatching the next Worker</field>
|
|
435
|
+
<field name="text">Dispatch all ${max_concurrent_workers} workers at once, then wait for ALL to complete</field>
|
|
436
|
+
<field name="text">Sequential one-by-one dispatch is STRICTLY FORBIDDEN</field>
|
|
425
437
|
<field name="text">Monitor completion via marker files, NOT by polling worker status</field>
|
|
426
438
|
</block>
|
|
427
439
|
|
|
@@ -470,6 +482,7 @@ Continue with knowledge base generation?
|
|
|
470
482
|
</block>
|
|
471
483
|
|
|
472
484
|
<!-- Step 2: Dispatch Worker for each Feature -->
|
|
485
|
+
<!-- PARALLEL EXECUTION MANDATORY: All Workers MUST be dispatched SIMULTANEOUSLY in ONE turn -->
|
|
473
486
|
<block type="loop" id="S2-L2" over="${batch_response.batch}" as="feature" parallel="true" max-concurrency="${max_concurrent_workers}" desc="Dispatch analysis Worker for each Feature">
|
|
474
487
|
|
|
475
488
|
<!-- Route to different Skill based on platformType -->
|
|
@@ -552,6 +565,7 @@ Requirements:
|
|
|
552
565
|
</block>
|
|
553
566
|
|
|
554
567
|
<!-- Step 2.5: Dispatch Graph Worker -->
|
|
568
|
+
<!-- PARALLEL EXECUTION MANDATORY: All Graph Workers MUST be dispatched SIMULTANEOUSLY in ONE turn -->
|
|
555
569
|
<block type="loop" id="S2-L25" over="${batch_response.batch}" as="feature" parallel="true" max-concurrency="${max_concurrent_workers}" desc="Dispatch Graph Worker for each Feature IN PARALLEL">
|
|
556
570
|
<block type="gateway" id="S2-G2" mode="exclusive" desc="Route Graph Worker based on analysis type">
|
|
557
571
|
<branch test="${feature.platformType} == 'backend'" name="API Graph">
|
|
@@ -656,6 +670,11 @@ Requirements:
|
|
|
656
670
|
|
|
657
671
|
<block type="rule" id="S3-R1" level="mandatory" desc="Stage 3 mandatory rules">
|
|
658
672
|
<field name="text">Worker dispatch is handled by the calling Agent (Team Leader). This Skill only prepares the task plan and parameters.</field>
|
|
673
|
+
<field name="text">ALL module summary workers MUST be dispatched IN PARALLEL — sequential execution is FORBIDDEN</field>
|
|
674
|
+
<field name="text">ALL Worker dispatch calls in S3-L2 MUST be issued SIMULTANEOUSLY in a SINGLE orchestration turn</field>
|
|
675
|
+
<field name="text">DO NOT wait for any Worker to complete before dispatching the next Worker</field>
|
|
676
|
+
<field name="text">Dispatch all ${max_concurrent_workers} workers at once, then wait for ALL to complete</field>
|
|
677
|
+
<field name="text">Sequential one-by-one dispatch is STRICTLY FORBIDDEN</field>
|
|
659
678
|
<field name="text">Workers MUST NOT create any temporary scripts or workaround files</field>
|
|
660
679
|
</block>
|
|
661
680
|
|
|
@@ -666,7 +685,7 @@ Requirements:
|
|
|
666
685
|
</block>
|
|
667
686
|
|
|
668
687
|
<!-- Step 2: Prepare module summary tasks for each platform -->
|
|
669
|
-
<block type="loop" id="S3-L1" over="${platforms}" as="platform" desc="Prepare module summary tasks for each platform">
|
|
688
|
+
<block type="loop" id="S3-L1" over="${platforms}" as="platform" parallel="true" max-concurrency="${max_concurrent_workers}" desc="Prepare module summary tasks for each platform IN PARALLEL">
|
|
670
689
|
<!-- Step 2.1: Read platform features -->
|
|
671
690
|
<block type="task" id="S3-B2" action="run-script" status="pending" desc="Read platform features">
|
|
672
691
|
<field name="command">node -e "console.log(require('fs').readFileSync('${sync_state_bizs_dir}/features-${platform.platformId}.json', 'utf8'))"</field>
|
|
@@ -680,6 +699,7 @@ Requirements:
|
|
|
680
699
|
</block>
|
|
681
700
|
|
|
682
701
|
<!-- Step 2.3: Dispatch Worker for each module -->
|
|
702
|
+
<!-- PARALLEL EXECUTION MANDATORY: All Module Summary Workers MUST be dispatched SIMULTANEOUSLY in ONE turn -->
|
|
683
703
|
<block type="loop" id="S3-L2" over="${platform_modules}" as="module_name" parallel="true" max-concurrency="${max_concurrent_workers}" desc="Dispatch summary Worker for each module">
|
|
684
704
|
<block type="task" id="S3-B4" action="dispatch-to-worker" status="pending" desc="Dispatch module summary Worker">
|
|
685
705
|
<field name="worker">speccrew-knowledge-module-summarize-xml</field>
|
|
@@ -725,10 +745,15 @@ Requirements:
|
|
|
725
745
|
<block type="rule" id="S35-R1" level="mandatory" desc="Stage 3.5 mandatory rules">
|
|
726
746
|
<field name="text">Worker dispatch is handled by the calling Agent (Team Leader). This Skill only prepares the task plan and parameters.</field>
|
|
727
747
|
<field name="text">ALL UI style extraction workers MUST be dispatched IN PARALLEL — sequential execution is FORBIDDEN</field>
|
|
748
|
+
<field name="text">ALL Worker dispatch calls in S35-L1 MUST be issued SIMULTANEOUSLY in a SINGLE orchestration turn</field>
|
|
749
|
+
<field name="text">DO NOT wait for any Worker to complete before dispatching the next Worker</field>
|
|
750
|
+
<field name="text">Dispatch all ${max_concurrent_workers} workers at once, then wait for ALL to complete</field>
|
|
751
|
+
<field name="text">Sequential one-by-one dispatch is STRICTLY FORBIDDEN</field>
|
|
728
752
|
<field name="text">This stage writes to techs knowledge base, not bizs knowledge base</field>
|
|
729
753
|
</block>
|
|
730
754
|
|
|
731
755
|
<!-- Dispatch UI Style Extract Worker for each frontend platform -->
|
|
756
|
+
<!-- PARALLEL EXECUTION MANDATORY: All UI Style Workers MUST be dispatched SIMULTANEOUSLY in ONE turn -->
|
|
732
757
|
<block type="loop" id="S35-L1" over="${platforms}" as="platform" parallel="true" max-concurrency="${max_concurrent_workers}" desc="Dispatch UI style extraction Workers for frontend platforms IN PARALLEL">
|
|
733
758
|
<block type="gateway" id="S35-G1" mode="exclusive" desc="Execute for UI platforms only">
|
|
734
759
|
<branch test="${platform.platformType} in ['web', 'mobile', 'desktop']" name="UI platform">
|
|
@@ -63,6 +63,14 @@ For each platform, generates:
|
|
|
63
63
|
<field name="text">Do not include leading or trailing slashes in entryDirs paths</field>
|
|
64
64
|
</block>
|
|
65
65
|
|
|
66
|
+
<block type="rule" id="R-TECHSTACK" level="mandatory" desc="techStack values MUST match tech-stack-mappings.json keys">
|
|
67
|
+
<field name="text">
|
|
68
|
+
The techStack array values MUST exactly match keys defined in tech-stack-mappings.json (e.g., "fastapi", "vue3", "uniapp").
|
|
69
|
+
DO NOT prefix with language name (e.g., use "fastapi" NOT "python-fastapi", use "express" NOT "node-express").
|
|
70
|
+
The tech_identifier input parameter value should be used as the primary techStack entry.
|
|
71
|
+
</field>
|
|
72
|
+
</block>
|
|
73
|
+
|
|
66
74
|
<!-- ============================================================
|
|
67
75
|
Global Continuous Execution Rules
|
|
68
76
|
============================================================ -->
|
package/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js
CHANGED
|
@@ -110,6 +110,21 @@ function parseArgs() {
|
|
|
110
110
|
return params;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Parse boolean parameter from string value
|
|
115
|
+
* @param {string|boolean} value - Parameter value
|
|
116
|
+
* @param {boolean} defaultValue - Default value if not provided
|
|
117
|
+
* @returns {boolean} Parsed boolean value
|
|
118
|
+
*/
|
|
119
|
+
function parseBooleanParam(value, defaultValue = false) {
|
|
120
|
+
if (value === undefined || value === null) return defaultValue;
|
|
121
|
+
if (typeof value === 'boolean') return value;
|
|
122
|
+
if (typeof value === 'string') {
|
|
123
|
+
return value.toLowerCase() === 'true';
|
|
124
|
+
}
|
|
125
|
+
return defaultValue;
|
|
126
|
+
}
|
|
127
|
+
|
|
113
128
|
// Normalize path separators to forward slashes
|
|
114
129
|
function normalizePath(filePath) {
|
|
115
130
|
if (!filePath) return '';
|
|
@@ -215,6 +230,23 @@ function loadPlatformConfig(platformId, projectRoot) {
|
|
|
215
230
|
return platformConfig;
|
|
216
231
|
}
|
|
217
232
|
|
|
233
|
+
/**
|
|
234
|
+
* Normalize tech identifier by removing common language prefixes.
|
|
235
|
+
* @param {string} id - Tech identifier like "python-fastapi", "node-express"
|
|
236
|
+
* @returns {string} Normalized identifier like "fastapi", "express"
|
|
237
|
+
*/
|
|
238
|
+
function normalizeTechIdentifier(id) {
|
|
239
|
+
if (!id) return id;
|
|
240
|
+
// Remove common language prefixes: python-, node-, java-, etc.
|
|
241
|
+
const prefixes = ['python-', 'node-', 'java-', 'kotlin-', 'swift-', 'dart-', 'go-', 'rust-', 'php-', 'ruby-'];
|
|
242
|
+
for (const prefix of prefixes) {
|
|
243
|
+
if (id.toLowerCase().startsWith(prefix)) {
|
|
244
|
+
return id.substring(prefix.length);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return id;
|
|
248
|
+
}
|
|
249
|
+
|
|
218
250
|
/**
|
|
219
251
|
* Load tech stack configuration from tech-stack-mappings.json
|
|
220
252
|
* @param {string} platformType - Platform type like "backend", "web"
|
|
@@ -228,21 +260,38 @@ function loadTechStackConfig(platformType, framework, projectRoot) {
|
|
|
228
260
|
console.error(`Warning: tech-stack-mappings.json not found at ${configPath}`);
|
|
229
261
|
return { extensions: [], exclude_file_suffixes: [] };
|
|
230
262
|
}
|
|
231
|
-
|
|
263
|
+
|
|
232
264
|
const configContent = fs.readFileSync(configPath, 'utf8');
|
|
233
265
|
const config = JSON.parse(configContent);
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
266
|
+
|
|
267
|
+
// Try exact match first
|
|
268
|
+
let techConfig = null;
|
|
269
|
+
if (config.tech_stacks &&
|
|
270
|
+
config.tech_stacks[platformType] &&
|
|
237
271
|
config.tech_stacks[platformType][framework]) {
|
|
238
|
-
|
|
272
|
+
techConfig = config.tech_stacks[platformType][framework];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// If not found, try normalized identifier (remove language prefix)
|
|
276
|
+
if (!techConfig) {
|
|
277
|
+
const normalizedFramework = normalizeTechIdentifier(framework);
|
|
278
|
+
if (normalizedFramework !== framework &&
|
|
279
|
+
config.tech_stacks &&
|
|
280
|
+
config.tech_stacks[platformType] &&
|
|
281
|
+
config.tech_stacks[platformType][normalizedFramework]) {
|
|
282
|
+
techConfig = config.tech_stacks[platformType][normalizedFramework];
|
|
283
|
+
console.log(`Using normalized tech identifier: ${framework} → ${normalizedFramework}`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (techConfig) {
|
|
239
288
|
return {
|
|
240
289
|
extensions: techConfig.extensions || [],
|
|
241
290
|
exclude_file_suffixes: techConfig.exclude_file_suffixes || [],
|
|
242
291
|
exclude_file_names: techConfig.exclude_file_names || []
|
|
243
292
|
};
|
|
244
293
|
}
|
|
245
|
-
|
|
294
|
+
|
|
246
295
|
return { extensions: [], exclude_file_suffixes: [], exclude_file_names: [] };
|
|
247
296
|
}
|
|
248
297
|
|
|
@@ -389,7 +438,7 @@ function findFilesInDir(dir, extensions, baseDir) {
|
|
|
389
438
|
* @param {string} outputDir - Output directory for features JSON
|
|
390
439
|
* @returns {boolean} Success status
|
|
391
440
|
*/
|
|
392
|
-
function generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outputDir) {
|
|
441
|
+
function generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outputDir, overwrite) {
|
|
393
442
|
const { platformId, sourcePath, modules } = entryDirsData;
|
|
394
443
|
const { platformType, platformSubtype, framework } = platformConfig;
|
|
395
444
|
|
|
@@ -506,8 +555,8 @@ function generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outpu
|
|
|
506
555
|
const outputFileName = `features-${platformId}.json`;
|
|
507
556
|
const outputPath = path.join(outputDir, outputFileName);
|
|
508
557
|
|
|
509
|
-
// Incremental: if features file already exists, write to *.new.json
|
|
510
|
-
const actualOutputPath = fs.existsSync(outputPath)
|
|
558
|
+
// Incremental: if features file already exists and overwrite is not set, write to *.new.json
|
|
559
|
+
const actualOutputPath = (!overwrite && fs.existsSync(outputPath))
|
|
511
560
|
? outputPath.replace(/\.json$/, '.new.json')
|
|
512
561
|
: outputPath;
|
|
513
562
|
|
|
@@ -566,6 +615,9 @@ function findFiles(dir, extensions, excludeDirs, baseDir) {
|
|
|
566
615
|
function main() {
|
|
567
616
|
const params = parseArgs();
|
|
568
617
|
|
|
618
|
+
// Parse overwrite parameter (default: false for backward compatibility)
|
|
619
|
+
const overwrite = parseBooleanParam(params.overwrite, false);
|
|
620
|
+
|
|
569
621
|
// Check for whitelist mode (--entryDirsFile provided)
|
|
570
622
|
if (params.entryDirsFile) {
|
|
571
623
|
// Whitelist mode: scan only specified entry directories
|
|
@@ -654,7 +706,7 @@ function main() {
|
|
|
654
706
|
}
|
|
655
707
|
|
|
656
708
|
// Generate features from entry dirs
|
|
657
|
-
const success = generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outputDir);
|
|
709
|
+
const success = generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outputDir, overwrite);
|
|
658
710
|
process.exit(success ? 0 : 1);
|
|
659
711
|
}
|
|
660
712
|
|
|
@@ -696,38 +748,53 @@ function main() {
|
|
|
696
748
|
|
|
697
749
|
// Load tech-stack-specific exclude_dirs
|
|
698
750
|
let techExcludeDirs = [];
|
|
699
|
-
|
|
700
|
-
|
|
751
|
+
let effectiveTechIdentifier = techIdentifier;
|
|
752
|
+
|
|
753
|
+
// Try exact match first
|
|
754
|
+
if (config.tech_stacks &&
|
|
755
|
+
config.tech_stacks[platformType] &&
|
|
701
756
|
config.tech_stacks[platformType][techIdentifier] &&
|
|
702
757
|
config.tech_stacks[platformType][techIdentifier].exclude_dirs) {
|
|
703
758
|
techExcludeDirs = config.tech_stacks[platformType][techIdentifier].exclude_dirs;
|
|
759
|
+
} else {
|
|
760
|
+
// Try normalized identifier (remove language prefix like "python-fastapi" → "fastapi")
|
|
761
|
+
const normalizedIdentifier = normalizeTechIdentifier(techIdentifier);
|
|
762
|
+
if (normalizedIdentifier !== techIdentifier &&
|
|
763
|
+
config.tech_stacks &&
|
|
764
|
+
config.tech_stacks[platformType] &&
|
|
765
|
+
config.tech_stacks[platformType][normalizedIdentifier] &&
|
|
766
|
+
config.tech_stacks[platformType][normalizedIdentifier].exclude_dirs) {
|
|
767
|
+
techExcludeDirs = config.tech_stacks[platformType][normalizedIdentifier].exclude_dirs;
|
|
768
|
+
effectiveTechIdentifier = normalizedIdentifier;
|
|
769
|
+
console.log(`Using normalized tech identifier for exclude_dirs: ${techIdentifier} → ${normalizedIdentifier}`);
|
|
770
|
+
}
|
|
704
771
|
}
|
|
705
|
-
|
|
772
|
+
|
|
706
773
|
// Load global exclude_dirs (applies to all platforms)
|
|
707
774
|
const globalExcludeDirs = config.global_exclude_dirs || [];
|
|
708
|
-
|
|
775
|
+
|
|
709
776
|
// Merge: global + tech-specific
|
|
710
777
|
const mergedDirs = [...new Set([...globalExcludeDirs, ...techExcludeDirs])];
|
|
711
778
|
excludeDirsStr = JSON.stringify(mergedDirs);
|
|
712
779
|
console.log(`Loaded exclude_dirs from tech-stack-mappings.json (${globalExcludeDirs.length} global + ${techExcludeDirs.length} tech-specific = ${mergedDirs.length} total)`);
|
|
713
|
-
|
|
780
|
+
|
|
714
781
|
// Load tech-stack-specific exclude_file_suffixes
|
|
715
|
-
if (config.tech_stacks &&
|
|
716
|
-
config.tech_stacks[platformType] &&
|
|
717
|
-
config.tech_stacks[platformType][
|
|
718
|
-
config.tech_stacks[platformType][
|
|
719
|
-
excludeFileSuffixes = config.tech_stacks[platformType][
|
|
782
|
+
if (config.tech_stacks &&
|
|
783
|
+
config.tech_stacks[platformType] &&
|
|
784
|
+
config.tech_stacks[platformType][effectiveTechIdentifier] &&
|
|
785
|
+
config.tech_stacks[platformType][effectiveTechIdentifier].exclude_file_suffixes) {
|
|
786
|
+
excludeFileSuffixes = config.tech_stacks[platformType][effectiveTechIdentifier].exclude_file_suffixes;
|
|
720
787
|
if (excludeFileSuffixes.length > 0) {
|
|
721
788
|
console.log(`Loaded exclude_file_suffixes from tech-stack-mappings.json: ${excludeFileSuffixes.join(', ')}`);
|
|
722
789
|
}
|
|
723
790
|
}
|
|
724
|
-
|
|
791
|
+
|
|
725
792
|
// Load tech-stack-specific exclude_file_names
|
|
726
|
-
if (config.tech_stacks &&
|
|
727
|
-
config.tech_stacks[platformType] &&
|
|
728
|
-
config.tech_stacks[platformType][
|
|
729
|
-
config.tech_stacks[platformType][
|
|
730
|
-
excludeFileNames = config.tech_stacks[platformType][
|
|
793
|
+
if (config.tech_stacks &&
|
|
794
|
+
config.tech_stacks[platformType] &&
|
|
795
|
+
config.tech_stacks[platformType][effectiveTechIdentifier] &&
|
|
796
|
+
config.tech_stacks[platformType][effectiveTechIdentifier].exclude_file_names) {
|
|
797
|
+
excludeFileNames = config.tech_stacks[platformType][effectiveTechIdentifier].exclude_file_names;
|
|
731
798
|
if (excludeFileNames.length > 0) {
|
|
732
799
|
console.log(`Loaded exclude_file_names from tech-stack-mappings.json: ${excludeFileNames.join(', ')}`);
|
|
733
800
|
}
|
|
@@ -924,8 +991,8 @@ function main() {
|
|
|
924
991
|
fs.mkdirSync(syncStateDir, { recursive: true });
|
|
925
992
|
}
|
|
926
993
|
|
|
927
|
-
// Incremental: if features file already exists, write to *.new.json
|
|
928
|
-
const actualOutputPath = fs.existsSync(outputPath)
|
|
994
|
+
// Incremental: if features file already exists and overwrite is not set, write to *.new.json
|
|
995
|
+
const actualOutputPath = (!overwrite && fs.existsSync(outputPath))
|
|
929
996
|
? outputPath.replace(/\.json$/, '.new.json')
|
|
930
997
|
: outputPath;
|
|
931
998
|
|
|
@@ -264,12 +264,17 @@ Output: ${sync_state_techs_dir}/techs-manifest.json</field>
|
|
|
264
264
|
<field name="text">DO NOT finish one platform before starting the next — this wastes time and violates the pipeline design</field>
|
|
265
265
|
<field name="text">The calling Agent MUST use concurrent task dispatch (e.g., dispatch 3 workers in one turn for 3 platforms)</field>
|
|
266
266
|
<field name="text">Sequential platform-by-platform execution is FORBIDDEN</field>
|
|
267
|
+
<field name="text">Loops S2-L1, S2-L2, S2-L3, and S2-L4 have parallel="true" and MUST execute concurrently for ALL platforms</field>
|
|
268
|
+
<field name="text">ALL platform status updates (S2-L1) MUST be done SIMULTANEOUSLY in PARALLEL</field>
|
|
269
|
+
<field name="text">ALL conventions worker task preparations (S2-L2) MUST be done SIMULTANEOUSLY in PARALLEL</field>
|
|
270
|
+
<field name="text">ALL UI-style worker task preparations (S2-L3) MUST be done SIMULTANEOUSLY in PARALLEL</field>
|
|
267
271
|
</block>
|
|
268
272
|
|
|
269
273
|
<block type="rule" id="S2-R2" level="forbidden" desc="Stage 2 forbidden actions">
|
|
270
274
|
<field name="text">DO NOT process platforms sequentially — PARALLEL execution is MANDATORY</field>
|
|
271
275
|
<field name="text">DO NOT wait for one platform to complete before starting another</field>
|
|
272
276
|
<field name="text">DO NOT proceed to Stage 2.5 until ALL workers have completed or failed</field>
|
|
277
|
+
<field name="text">Sequential execution of S2-L1, S2-L2, S2-L3, or S2-L4 is STRICTLY FORBIDDEN</field>
|
|
273
278
|
</block>
|
|
274
279
|
|
|
275
280
|
<!-- Step 0: Ensure completed_dir exists -->
|
|
@@ -278,7 +283,7 @@ Output: ${sync_state_techs_dir}/techs-manifest.json</field>
|
|
|
278
283
|
</block>
|
|
279
284
|
|
|
280
285
|
<!-- Step 1: Update manifest status to processing -->
|
|
281
|
-
<block type="loop" id="S2-L1" over="${techs_manifest.platforms}" as="platform" desc="Update each platform status to processing">
|
|
286
|
+
<block type="loop" id="S2-L1" over="${techs_manifest.platforms}" as="platform" parallel="true" max-concurrency="${techs_manifest.platforms.length}" desc="Update each platform status to processing">
|
|
282
287
|
<block type="task" id="S2-B1a" action="run-script" status="pending" desc="Update platform status in manifest">
|
|
283
288
|
<field name="command">node -e "
|
|
284
289
|
const fs = require('fs');
|
|
@@ -304,7 +309,7 @@ if (platform) {
|
|
|
304
309
|
<field name="message">Preparing conventions worker task plans for ${techs_manifest.platforms.length} platforms...</field>
|
|
305
310
|
</block>
|
|
306
311
|
|
|
307
|
-
<block type="loop" id="S2-L2" over="${techs_manifest.platforms}" as="platform" desc="Prepare conventions worker task for each platform">
|
|
312
|
+
<block type="loop" id="S2-L2" over="${techs_manifest.platforms}" as="platform" parallel="true" max-concurrency="${techs_manifest.platforms.length}" desc="Prepare conventions worker task for each platform">
|
|
308
313
|
<block type="task" id="S2-B2" action="prepare-task" status="pending" desc="Prepare conventions worker task specification">
|
|
309
314
|
<field name="skill_name">speccrew-knowledge-techs-generate-conventions-xml</field>
|
|
310
315
|
<field name="context">
|
|
@@ -327,7 +332,7 @@ if (platform) {
|
|
|
327
332
|
<field name="message">Preparing UI-style worker task plans for frontend platforms...</field>
|
|
328
333
|
</block>
|
|
329
334
|
|
|
330
|
-
<block type="loop" id="S2-L3" over="${techs_manifest.platforms}" as="platform" desc="Prepare UI-style worker task for frontend platforms">
|
|
335
|
+
<block type="loop" id="S2-L3" over="${techs_manifest.platforms}" as="platform" parallel="true" max-concurrency="${techs_manifest.platforms.length}" desc="Prepare UI-style worker task for frontend platforms">
|
|
331
336
|
<block type="gateway" id="S2-G1" mode="guard" test="${platform.platform_type} IN ['web', 'mobile', 'desktop']" fail-action="skip" desc="Only for frontend platforms">
|
|
332
337
|
<field name="message">Skipping UI-style for backend platform: ${platform.platform_id}</field>
|
|
333
338
|
</block>
|
|
@@ -352,6 +357,12 @@ if (platform) {
|
|
|
352
357
|
</block>
|
|
353
358
|
|
|
354
359
|
<!-- Step 5: Monitor Completion Markers -->
|
|
360
|
+
<block type="rule" id="S2-R3" level="mandatory" desc="Platform monitoring parallel execution rule">
|
|
361
|
+
<field name="text">ALL platform monitoring tasks MUST be dispatched SIMULTANEOUSLY in a SINGLE orchestration turn</field>
|
|
362
|
+
<field name="text">DO NOT process platforms one-by-one. Sequential execution is FORBIDDEN</field>
|
|
363
|
+
<field name="text">ALL completion marker checks for ALL platforms MUST run in PARALLEL</field>
|
|
364
|
+
</block>
|
|
365
|
+
|
|
355
366
|
<block type="loop" id="S2-L4" over="${techs_manifest.platforms}" as="platform" parallel="true" max-concurrency="${techs_manifest.platforms.length}" desc="Monitor completion markers for each platform">
|
|
356
367
|
|
|
357
368
|
<!-- Check conventions worker marker -->
|
|
@@ -440,6 +451,9 @@ if (platform) {
|
|
|
440
451
|
<field name="text">MUST scan ALL completion markers before proceeding</field>
|
|
441
452
|
<field name="text">MUST verify document existence and completeness</field>
|
|
442
453
|
<field name="text">MUST update stage2-status.json with verification results</field>
|
|
454
|
+
<field name="text">ALL platform scans MUST be executed SIMULTANEOUSLY in PARALLEL — sequential scanning is FORBIDDEN</field>
|
|
455
|
+
<field name="text">ALL platform integrity checks MUST be executed SIMULTANEOUSLY in PARALLEL — sequential verification is FORBIDDEN</field>
|
|
456
|
+
<field name="text">Stage 2.5 loops S2_5-L1 and S2_5-L2 have parallel="true" and MUST execute concurrently</field>
|
|
443
457
|
</block>
|
|
444
458
|
|
|
445
459
|
<!-- Step A: Scan Completion Markers -->
|
|
@@ -447,7 +461,7 @@ if (platform) {
|
|
|
447
461
|
<field name="message">Stage 2.5 Step A: Scanning completion markers...</field>
|
|
448
462
|
</block>
|
|
449
463
|
|
|
450
|
-
<block type="loop" id="S2_5-L1" over="${techs_manifest.platforms}" as="platform" desc="Scan markers for each platform">
|
|
464
|
+
<block type="loop" id="S2_5-L1" over="${techs_manifest.platforms}" as="platform" parallel="true" max-concurrency="${techs_manifest.platforms.length}" desc="Scan markers for each platform">
|
|
451
465
|
<block type="task" id="S2_5-B1" action="run-script" status="pending" desc="Check all markers for platform">
|
|
452
466
|
<field name="command">node -e "
|
|
453
467
|
const fs = require('fs');
|
|
@@ -473,7 +487,7 @@ console.log(JSON.stringify(markers));
|
|
|
473
487
|
<field name="message">Stage 2.5 Step B: Verifying output integrity...</field>
|
|
474
488
|
</block>
|
|
475
489
|
|
|
476
|
-
<block type="loop" id="S2_5-L2" over="${techs_manifest.platforms}" as="platform" desc="Verify documents for each platform">
|
|
490
|
+
<block type="loop" id="S2_5-L2" over="${techs_manifest.platforms}" as="platform" parallel="true" max-concurrency="${techs_manifest.platforms.length}" desc="Verify documents for each platform">
|
|
477
491
|
<block type="task" id="S2_5-B2" action="run-script" status="pending" desc="Check required documents exist">
|
|
478
492
|
<field name="command">node -e "
|
|
479
493
|
const fs = require('fs');
|