speccrew 0.6.6 → 0.6.8
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/agents/speccrew-feature-designer.md +25 -20
- package/.speccrew/agents/speccrew-product-manager.md +99 -47
- package/.speccrew/agents/speccrew-system-designer.md +33 -28
- package/.speccrew/agents/speccrew-system-developer.md +34 -29
- package/.speccrew/agents/speccrew-test-manager.md +47 -42
- package/.speccrew/skills/speccrew-knowledge-bizs-dispatch/SKILL.md +104 -69
- package/.speccrew/skills/speccrew-knowledge-bizs-identify-entries/SKILL.md +10 -4
- package/.speccrew/skills/speccrew-knowledge-bizs-init-features/SKILL.md +33 -24
- package/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js +23 -6
- package/.speccrew/skills/speccrew-pm-knowledge-detector/SKILL.md +8 -4
- package/package.json +1 -1
- package/workspace-template/scripts/path-utils.js +134 -0
|
@@ -61,21 +61,26 @@ Stage 4: System Summary
|
|
|
61
61
|
| `head_commit` | (incremental only) Git HEAD commit hash | `HEAD` |
|
|
62
62
|
| `changed_files` | (incremental only) Pre-computed changed file list | — |
|
|
63
63
|
| `max_concurrent_workers` | Maximum parallel Worker Agents | `5` |
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
| `
|
|
64
|
+
| `workspace_path` | **(required)** Absolute path to speccrew-workspace directory | — |
|
|
65
|
+
| `sync_state_bizs_dir` | **(required)** Absolute path to `knowledges/base/sync-state/knowledge-bizs/` | — |
|
|
66
|
+
| `ide_skills_dir` | **(required)** Absolute path to IDE skills directory (e.g., `.qoder/skills`, `.cursor/skills`) | — |
|
|
67
|
+
| `configs_dir` | **(required)** Absolute path to `docs/configs/` directory | — |
|
|
68
|
+
| `graph_root` | Graph data output root path (absolute path preferred) | `{workspace_path}/knowledges/bizs/graph` |
|
|
69
|
+
| `completed_dir` | Marker file output directory for Worker results (absolute path required) | `{sync_state_bizs_dir}/completed` |
|
|
70
|
+
|
|
71
|
+
> **MANDATORY**: All path parameters MUST be absolute paths provided by the caller. DO NOT use ListDir to search for script locations. DO NOT construct paths by guessing or relative path resolution.
|
|
67
72
|
|
|
68
73
|
> **Note**: Ensure `graph_root` directory exists before first execution. If it does not exist, create it: `mkdir -p "{graph_root}"` (or equivalent on Windows: `New-Item -ItemType Directory -Path "{graph_root}" -Force`).
|
|
69
74
|
|
|
70
75
|
## Output
|
|
71
76
|
|
|
72
|
-
- Entry directories: `
|
|
73
|
-
- Feature inventory: `
|
|
74
|
-
- Feature docs: `
|
|
75
|
-
- Module overviews: `
|
|
76
|
-
- UI style patterns: `
|
|
77
|
-
- System overview: `
|
|
78
|
-
- Graph data: `
|
|
77
|
+
- Entry directories: `{sync_state_bizs_dir}/entry-dirs-{platform}.json`
|
|
78
|
+
- Feature inventory: `{sync_state_bizs_dir}/features-{platform}.json`
|
|
79
|
+
- Feature docs: `{workspace_path}/knowledges/bizs/{platform}/{module}/features/*.md`
|
|
80
|
+
- Module overviews: `{workspace_path}/knowledges/bizs/{platform}/{module}/*-overview.md`
|
|
81
|
+
- UI style patterns: `{workspace_path}/knowledges/techs/{platform_id}/ui-style-patterns/` (page-types/, components/, layouts/)
|
|
82
|
+
- System overview: `{workspace_path}/knowledges/bizs/system-overview.md`
|
|
83
|
+
- Graph data: `{workspace_path}/knowledges/bizs/graph/`
|
|
79
84
|
|
|
80
85
|
## Workflow Overview
|
|
81
86
|
|
|
@@ -194,7 +199,7 @@ flowchart TB
|
|
|
194
199
|
|
|
195
200
|
> For detailed entry identification logic, exclusion rules, JSON format, and validation rules, refer to the `speccrew-knowledge-bizs-identify-entries` skill documentation.
|
|
196
201
|
|
|
197
|
-
**Output**: `{
|
|
202
|
+
**Output**: `{sync_state_bizs_dir}/entry-dirs-{platform_id}.json`
|
|
198
203
|
|
|
199
204
|
**JSON Format**:
|
|
200
205
|
```json
|
|
@@ -223,19 +228,17 @@ flowchart TB
|
|
|
223
228
|
> **IMPORTANT**: This stage is executed **directly by the dispatch agent (Leader)**, NOT delegated to a Worker Agent.
|
|
224
229
|
> Worker Agents do not have `run_in_terminal` capability, which is required for script execution.
|
|
225
230
|
|
|
226
|
-
**Prerequisite**: Stage 1a completed. `entry-dirs-{platform_id}.json` files exist in `{
|
|
231
|
+
**Prerequisite**: Stage 1a completed. `entry-dirs-{platform_id}.json` files exist in `{sync_state_bizs_dir}/`.
|
|
227
232
|
|
|
228
233
|
**Action** (dispatch executes directly via `run_in_terminal`):
|
|
229
234
|
|
|
230
|
-
1. **Read platform mapping**: Read `
|
|
231
|
-
2. **
|
|
232
|
-
- Script location: `{ide_skills_dir}/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js`
|
|
233
|
-
- Where `{ide_skills_dir}` is the IDE-specific skills directory (e.g., `.qoder/skills/`, `.cursor/skills/`, `.vscode/skills/`, `.speccrew/skills/`)
|
|
234
|
-
- Use `ListDir` to locate the script if the exact path is unknown
|
|
235
|
-
3. **Execute inventory script** for each platform:
|
|
235
|
+
1. **Read platform mapping**: Read `{configs_dir}/platform-mapping.json` and `{configs_dir}/tech-stack-mappings.json` for platform configuration
|
|
236
|
+
2. **Execute inventory script** for each platform:
|
|
236
237
|
```
|
|
237
|
-
node "{
|
|
238
|
+
node "{ide_skills_dir}/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js" --entryDirsFile "{sync_state_bizs_dir}/entry-dirs-{platform_id}.json"
|
|
238
239
|
```
|
|
240
|
+
- Script location: `{ide_skills_dir}/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js`
|
|
241
|
+
- The `{ide_skills_dir}` parameter is passed by the caller as an absolute path
|
|
239
242
|
|
|
240
243
|
**Script Parameters**:
|
|
241
244
|
- `--entryDirsFile`: Path to the `entry-dirs-{platform_id}.json` file generated in Stage 1a (required)
|
|
@@ -248,7 +251,7 @@ flowchart TB
|
|
|
248
251
|
- `--excludeDirs`: Additional directories to exclude
|
|
249
252
|
|
|
250
253
|
**Output**:
|
|
251
|
-
- `{
|
|
254
|
+
- `{sync_state_bizs_dir}/features-{platform_id}.json` — Per-platform feature inventory files
|
|
252
255
|
- Each file contains: platform metadata, modules list, and flat features array with `analyzed` status
|
|
253
256
|
|
|
254
257
|
**Features JSON Structure**:
|
|
@@ -291,17 +294,16 @@ flowchart TB
|
|
|
291
294
|
|
|
292
295
|
**Prerequisite**: Stage 1b completed.
|
|
293
296
|
|
|
294
|
-
**Skip condition**: If no `features-*.new.json` files exist in `{
|
|
297
|
+
**Skip condition**: If no `features-*.new.json` files exist in `{sync_state_bizs_dir}/`, skip this Stage entirely and proceed to Stage 2.
|
|
295
298
|
|
|
296
299
|
**Action** (dispatch executes directly via `run_in_terminal`):
|
|
297
300
|
|
|
298
|
-
1. **
|
|
299
|
-
- Script location: `{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/merge-features.js`
|
|
300
|
-
|
|
301
|
-
2. **Execute merge script**:
|
|
301
|
+
1. **Execute merge script**:
|
|
302
302
|
```
|
|
303
|
-
node "{
|
|
303
|
+
node "{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/merge-features.js" --syncStatePath "{sync_state_bizs_dir}" --completedDir "{completed_dir}" --projectRoot "{source_path}"
|
|
304
304
|
```
|
|
305
|
+
- Script location: `{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/merge-features.js`
|
|
306
|
+
- The `{ide_skills_dir}` parameter is passed by the caller as an absolute path
|
|
305
307
|
|
|
306
308
|
3. **Read output JSON** from stdout and report merge results:
|
|
307
309
|
- Added features: new source files discovered
|
|
@@ -374,15 +376,12 @@ node -e "require('fs').mkdirSync('{completed_dir}', {recursive: true}); console.
|
|
|
374
376
|
|
|
375
377
|
**Step 1: Get Next Batch**
|
|
376
378
|
|
|
377
|
-
1. **
|
|
378
|
-
- Script location: `{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/batch-orchestrator.js`
|
|
379
|
-
- Where `{ide_skills_dir}` is the IDE-specific skills directory (e.g., `.qoder/skills/`, `.cursor/skills/`, `.vscode/skills/`, `.speccrew/skills/`)
|
|
380
|
-
- Use `ListDir` to locate the script if the exact path is unknown
|
|
381
|
-
|
|
382
|
-
2. **Execute get-batch**:
|
|
379
|
+
1. **Execute get-batch**:
|
|
383
380
|
```
|
|
384
|
-
node "{
|
|
381
|
+
node "{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/batch-orchestrator.js" get-batch --syncStatePath "{sync_state_bizs_dir}" --batchSize 5
|
|
385
382
|
```
|
|
383
|
+
- Script location: `{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/batch-orchestrator.js`
|
|
384
|
+
- The `{ide_skills_dir}` parameter is passed by the caller as an absolute path
|
|
386
385
|
|
|
387
386
|
- If output `action` is `"done"` → All features processed. Exit Stage 2, proceed to Stage 3.
|
|
388
387
|
- If output `action` is `"process"` → The `batch` array contains features to analyze. Proceed to Step 2.
|
|
@@ -422,6 +421,8 @@ After each analyze worker completes (writes `.done.json` marker), immediately di
|
|
|
422
421
|
"api_analysis_path": "<feature.documentPath>",
|
|
423
422
|
"platform_id": "<feature.platform_id>",
|
|
424
423
|
"output_dir": "<completed_dir_absolute_path>",
|
|
424
|
+
"workspace_path": "<workspace_path_absolute_path>",
|
|
425
|
+
"sync_state_bizs_dir": "<sync_state_bizs_dir_absolute_path>",
|
|
425
426
|
"module": "<feature.module>",
|
|
426
427
|
"fileName": "<feature.fileName>",
|
|
427
428
|
"sourcePath": "<feature.sourcePath>",
|
|
@@ -446,6 +447,8 @@ After each analyze worker completes (writes `.done.json` marker), immediately di
|
|
|
446
447
|
"platform_type": "<feature.platform_type>",
|
|
447
448
|
"platform_subtype": "<feature.platform_subtype>",
|
|
448
449
|
"completed_dir": "<completed_dir_absolute_path>",
|
|
450
|
+
"workspace_path": "<workspace_path_absolute_path>",
|
|
451
|
+
"sync_state_bizs_dir": "<sync_state_bizs_dir_absolute_path>",
|
|
449
452
|
"sourceFile": "<feature.sourceFile>",
|
|
450
453
|
"status": "<analysis_status>",
|
|
451
454
|
"analysisNotes": "<analysis_notes>",
|
|
@@ -468,7 +471,7 @@ Example: If batch has 5 features → create and launch 5 Worker Tasks simultaneo
|
|
|
468
471
|
```json
|
|
469
472
|
{
|
|
470
473
|
"skill_name": "speccrew-knowledge-bizs-ui-analyze",
|
|
471
|
-
"instructions": "请分析以下源代码文件,生成详细的功能文档。\n\n⚠️ CRITICAL - Template Fill-in Workflow (MANDATORY):\n1. First, copy the analysis template to documentPath (template structure = document skeleton)\n2. Then fill each Section using search_replace to replace placeholders with actual data\n3. NEVER use create_file to rewrite the entire document — this destroys template structure\n4. NEVER delete or skip any template Section — if no data available, fill with
|
|
474
|
+
"instructions": "请分析以下源代码文件,生成详细的功能文档。\n\n⚠️ CRITICAL - Template Fill-in Workflow (MANDATORY):\n1. First, copy the analysis template to documentPath (template structure = document skeleton)\n2. Then fill each Section using search_replace to replace placeholders with actual data\n3. NEVER use create_file to rewrite the entire document — this destroys template structure\n4. NEVER delete or skip any template Section — if no data available, fill with "N/A"\n5. NEVER create custom Section structures — use ONLY the template's predefined Sections\n\n要求:\n- 读取源代码文件,理解相关功能接口\n- 生成详细的文档到 documentPath\n- 创建两个标记文件到 completed_dir\n- 使用 {skill_name} 技能完成此任务",
|
|
472
475
|
"context": {
|
|
473
476
|
"fileName": "<feature.fileName>",
|
|
474
477
|
"sourcePath": "<feature.sourcePath>",
|
|
@@ -478,6 +481,8 @@ Example: If batch has 5 features → create and launch 5 Worker Tasks simultaneo
|
|
|
478
481
|
"platformSubtype": "<feature.platformSubtype>",
|
|
479
482
|
"language": "<user language>",
|
|
480
483
|
"completed_dir": "<completed_dir_absolute_path>",
|
|
484
|
+
"workspace_path": "<workspace_path_absolute_path>",
|
|
485
|
+
"sync_state_bizs_dir": "<sync_state_bizs_dir_absolute_path>",
|
|
481
486
|
"sourceFile": "<feature.sourceFile>"
|
|
482
487
|
}
|
|
483
488
|
}
|
|
@@ -507,32 +512,56 @@ Example: If batch has 5 features → create and launch 5 Worker Tasks simultaneo
|
|
|
507
512
|
|
|
508
513
|
### **CRITICAL - Marker File Naming Convention (STRICT RULES)**
|
|
509
514
|
|
|
515
|
+
#### Formula
|
|
516
|
+
|
|
517
|
+
**Pattern**: `{module}-{subpath}-{fileName}.{type}.json`
|
|
518
|
+
|
|
519
|
+
| Component | Description | Example |
|
|
520
|
+
|-----------|-------------|---------|
|
|
521
|
+
| `module` | Business module name | `chat`, `user`, `order` |
|
|
522
|
+
| `subpath` | Sub-path within module, `/` replaced with `-`. Empty if file is directly under module | `admin`, `api-v2` |
|
|
523
|
+
| `fileName` | Source file name WITHOUT extension | `UserController`, `ChatService` |
|
|
524
|
+
| `type` | Marker type: `done`, `error`, or `skip` | `done` |
|
|
525
|
+
|
|
526
|
+
**Examples**:
|
|
527
|
+
| Source File Path | Marker File Name |
|
|
528
|
+
|-----------------|------------------|
|
|
529
|
+
| `chat/ChatController.java` | `chat-ChatController.done.json` |
|
|
530
|
+
| `user/admin/UserController.java` | `user-admin-UserController.done.json` |
|
|
531
|
+
| `order/api/v2/OrderService.java` | `order-api-v2-OrderService.done.json` |
|
|
532
|
+
|
|
533
|
+
> **NOTE**: This naming convention is implemented in `workspace-template/scripts/path-utils.js` via the `getMarkerFileName(moduleName, subpath, fileName, type)` function.
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
#### Full Path Format
|
|
538
|
+
|
|
510
539
|
**✅ CORRECT Format - MUST USE:**
|
|
511
540
|
```
|
|
512
|
-
{completed_dir}/{module}-{subpath}-{
|
|
513
|
-
{completed_dir}/{module}-{subpath}-{
|
|
541
|
+
{completed_dir}/{module}-{subpath}-{fileName}.done.json ← Completion status marker (JSON format)
|
|
542
|
+
{completed_dir}/{module}-{subpath}-{fileName}.graph.json ← Graph data marker (JSON format)
|
|
514
543
|
```
|
|
515
544
|
|
|
516
545
|
**Naming Rule Explanation:**
|
|
517
546
|
|
|
518
|
-
The marker filename MUST follow the composite naming pattern `{module}-{subpath}-{
|
|
547
|
+
The marker filename MUST follow the composite naming pattern `{module}-{subpath}-{fileName}` to prevent conflicts between same-named source files.
|
|
519
548
|
|
|
520
549
|
**How Workers Generate the Filename:**
|
|
521
550
|
|
|
522
551
|
1. **module**: Use the `{{module}}` input variable directly
|
|
523
552
|
|
|
524
|
-
2. **subpath**: Extract from `{{
|
|
553
|
+
2. **subpath**: Extract from `{{sourcePath}}`:
|
|
525
554
|
- For UI (Vue/React): Middle path between `views/` or `pages/` and the file name
|
|
526
555
|
- For API (Java): Middle path between controller root and the file name
|
|
527
556
|
- Replace path separators (`/`) with hyphens (`-`)
|
|
528
557
|
- Omit if file is at module root (empty subpath)
|
|
529
558
|
|
|
530
|
-
3. **
|
|
559
|
+
3. **fileName**: Use `{{fileName}}` input variable (file name WITHOUT extension)
|
|
531
560
|
|
|
532
561
|
**Examples:**
|
|
533
562
|
|
|
534
|
-
| Source File | module | subpath |
|
|
535
|
-
|
|
563
|
+
| Source File | module | subpath | fileName | Marker Filename |
|
|
564
|
+
|-------------|--------|---------|----------|-----------------|
|
|
536
565
|
| `yudao-ui/.../views/system/notify/message/index.vue` | `system` | `notify-message` | `index` | `system-notify-message-index.done.json` |
|
|
537
566
|
| `yudao-ui/.../views/system/user/index.vue` | `system` | `user` | `index` | `system-user-index.done.json` |
|
|
538
567
|
| `yudao-module-system/.../controller/admin/user/UserController.java` | `system` | `controller-admin-user` | `UserController` | `system-controller-admin-user-UserController.done.json` |
|
|
@@ -543,11 +572,11 @@ The marker filename MUST follow the composite naming pattern `{module}-{subpath}
|
|
|
543
572
|
|
|
544
573
|
**❌ WRONG Format - NEVER USE:**
|
|
545
574
|
```
|
|
546
|
-
{
|
|
547
|
-
{
|
|
548
|
-
{
|
|
549
|
-
{
|
|
550
|
-
{
|
|
575
|
+
{fileName}.done.json ← WRONG: missing module and subpath (causes conflicts)
|
|
576
|
+
{fileName}.graph.json ← WRONG: missing module and subpath (causes conflicts)
|
|
577
|
+
{fileName}.completed.json ← WRONG extension
|
|
578
|
+
{fileName}.done ← WRONG extension (missing .json)
|
|
579
|
+
{fileName}_done.json ← WRONG separator and extension
|
|
551
580
|
```
|
|
552
581
|
|
|
553
582
|
**❌ WRONG Filename Examples - NEVER USE:**
|
|
@@ -611,6 +640,9 @@ The marker filename MUST follow the composite naming pattern `{module}-{subpath}
|
|
|
611
640
|
|
|
612
641
|
**Marker File Naming Convention Summary:**
|
|
613
642
|
|
|
643
|
+
> **Reference**: See [Marker File Naming Convention Formula](#critical---marker-file-naming-convention-strict-rules) for the complete formula and examples.
|
|
644
|
+
> **Implementation**: `getMarkerFileName()` in `workspace-template/scripts/path-utils.js`
|
|
645
|
+
|
|
614
646
|
| Marker Type | File Name Format | Example |
|
|
615
647
|
|-------------|------------------|---------|
|
|
616
648
|
| Completion marker | `{module}-{subpath}-{fileName}.done.json` | `system-notify-message-index.done.json`, `system-controller-admin-user-UserController.done.json` |
|
|
@@ -628,15 +660,12 @@ The marker filename MUST follow the composite naming pattern `{module}-{subpath}
|
|
|
628
660
|
|
|
629
661
|
**Step 3: Process Batch Results**
|
|
630
662
|
|
|
631
|
-
1. **
|
|
632
|
-
- Script location: `{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/batch-orchestrator.js`
|
|
633
|
-
- Where `{ide_skills_dir}` is the IDE-specific skills directory (e.g., `.qoder/skills/`, `.cursor/skills/`, `.vscode/skills/`, `.speccrew/skills/`)
|
|
634
|
-
- Use `ListDir` to locate the script if the exact path is unknown
|
|
635
|
-
|
|
636
|
-
2. **Execute process-results**:
|
|
663
|
+
1. **Execute process-results**:
|
|
637
664
|
```
|
|
638
|
-
node "{
|
|
665
|
+
node "{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/batch-orchestrator.js" process-results --syncStatePath "{sync_state_bizs_dir}" --graphRoot "{graph_root}" --platformId "{platformId}"
|
|
639
666
|
```
|
|
667
|
+
- Script location: `{ide_skills_dir}/speccrew-knowledge-bizs-dispatch/scripts/batch-orchestrator.js`
|
|
668
|
+
- The `{ide_skills_dir}` parameter is passed by the caller as an absolute path
|
|
640
669
|
|
|
641
670
|
This script:
|
|
642
671
|
- Scans `.done.json` files → updates feature status to `completed` in features-*.json
|
|
@@ -657,7 +686,7 @@ Dispatch 采用完全无状态的文件驱动设计。如果执行过程中发
|
|
|
657
686
|
#### Stage 2 Output
|
|
658
687
|
|
|
659
688
|
- Generated by Analyze Workers: Feature documentation at `feature.documentPath` (one .md per feature); marker files (`.done.json`) in `completed_dir`
|
|
660
|
-
- Generated by Graph Workers: Graph data files (`.graph.json`) in `completed_dir`; consolidated graph data in `
|
|
689
|
+
- Generated by Graph Workers: Graph data files (`.graph.json`) in `completed_dir`; consolidated graph data in `{workspace_path}/knowledges/bizs/graph/`
|
|
661
690
|
- Updated by `process-results`: Each `features-{platform}.json` updated with analysis timestamps and status
|
|
662
691
|
- Marker files cleaned up after each batch
|
|
663
692
|
|
|
@@ -685,12 +714,14 @@ When dealing with modules containing more than **20 features**, consider the fol
|
|
|
685
714
|
**Prerequisite**: Stage 2 completed for the module (in full or incremental mode).
|
|
686
715
|
|
|
687
716
|
**Action (full mode)**:
|
|
688
|
-
- Read all `features-{platform}.json` files from `
|
|
717
|
+
- Read all `features-{platform}.json` files from `{sync_state_bizs_dir}/`
|
|
689
718
|
- For each platform, group features by `module` to identify unique modules
|
|
690
719
|
- For each module, invoke 1 Worker Agent (`speccrew-task-worker.md`) with `skill_name: speccrew-knowledge-module-summarize`
|
|
691
720
|
- Parameters to pass to skill:
|
|
692
721
|
- `module_name`: Module code_name
|
|
693
|
-
- `module_path`: Path to module directory (e.g., `
|
|
722
|
+
- `module_path`: Path to module directory (e.g., `{workspace_path}/knowledges/bizs/{platform_id}/{module_name}/`)
|
|
723
|
+
- `workspace_path`: Absolute path to speccrew-workspace directory — **REQUIRED**
|
|
724
|
+
- `sync_state_bizs_dir`: Absolute path to sync-state/knowledge-bizs directory — **REQUIRED**
|
|
694
725
|
- `language`: User's language — **REQUIRED**
|
|
695
726
|
- **Behavior constraint**: Worker MUST NOT create any temporary scripts or workaround files. If execution fails, STOP and report error immediately.
|
|
696
727
|
|
|
@@ -724,20 +755,22 @@ Platform: Mobile App (mobile-flutter)
|
|
|
724
755
|
|
|
725
756
|
**Platform Filter**: Only execute for frontend platforms (platformType = web, mobile, desktop). Backend platforms skip this stage.
|
|
726
757
|
|
|
727
|
-
**Directory Creation**: The `ui-style-extract` skill automatically creates the output directory (`knowledges/techs/{platform_id}/ui-style-patterns/`) if it does not exist. No pre-check required.
|
|
758
|
+
**Directory Creation**: The `ui-style-extract` skill automatically creates the output directory (`{workspace_path}/knowledges/techs/{platform_id}/ui-style-patterns/`) if it does not exist. No pre-check required.
|
|
728
759
|
|
|
729
760
|
**Action**:
|
|
730
|
-
- Read all `features-{platform}.json` files
|
|
761
|
+
- Read all `features-{platform}.json` files from `{sync_state_bizs_dir}/`
|
|
731
762
|
- Filter platforms where platformType is web/mobile/desktop
|
|
732
763
|
- Determine platform_id (format: `{platformType}-{platformSubtype}`, e.g., `web-vue`, `mobile-uniapp`, `backend-system`)
|
|
733
764
|
- For each qualifying platform, launch 1 Worker Agent (`speccrew-task-worker`) with `skill_name: speccrew-knowledge-bizs-ui-style-extract`
|
|
734
765
|
- Parameters to pass:
|
|
735
766
|
- `platform_id`: Platform identifier
|
|
736
767
|
- `platform_type`: Platform type
|
|
737
|
-
- `feature_docs_path`: Feature document base path for that platform
|
|
738
|
-
- `features_manifest_path`: Path to the corresponding `features-{platform}.json`
|
|
739
|
-
- `module_overviews_path`: **Parent directory** containing all module overview subdirectories for that platform (e.g., `knowledges/bizs/web-vue/`). This directory contains `{module}/module-overview.md` or `{module}/{module}-overview.md` files. **NOT** a specific module directory.
|
|
740
|
-
- `output_path`: `
|
|
768
|
+
- `feature_docs_path`: Feature document base path for that platform (e.g., `{workspace_path}/knowledges/bizs/{platform_id}`)
|
|
769
|
+
- `features_manifest_path`: Path to the corresponding `{sync_state_bizs_dir}/features-{platform}.json`
|
|
770
|
+
- `module_overviews_path`: **Parent directory** containing all module overview subdirectories for that platform (e.g., `{workspace_path}/knowledges/bizs/web-vue/`). This directory contains `{module}/module-overview.md` or `{module}/{module}-overview.md` files. **NOT** a specific module directory.
|
|
771
|
+
- `output_path`: `{workspace_path}/knowledges/techs/{platform_id}/ui-style-patterns/`
|
|
772
|
+
- `workspace_path`: Absolute path to speccrew-workspace directory — **REQUIRED**
|
|
773
|
+
- `sync_state_bizs_dir`: Absolute path to sync-state/knowledge-bizs directory — **REQUIRED**
|
|
741
774
|
- `language`: User's language
|
|
742
775
|
- **Behavior constraint**: Worker MUST NOT create any temporary scripts or workaround files. If execution fails, STOP and report error immediately.
|
|
743
776
|
|
|
@@ -751,7 +784,7 @@ Platform: Mobile App (mobile-flutter)
|
|
|
751
784
|
|
|
752
785
|
**Output per Platform**:
|
|
753
786
|
```
|
|
754
|
-
|
|
787
|
+
{workspace_path}/knowledges/techs/{platform_id}/ui-style-patterns/
|
|
755
788
|
├── page-types/
|
|
756
789
|
│ └── {pattern-name}.md
|
|
757
790
|
├── components/
|
|
@@ -771,18 +804,20 @@ speccrew-workspace/knowledges/techs/{platform_id}/ui-style-patterns/
|
|
|
771
804
|
**Prerequisite**: All Stage 3 tasks completed.
|
|
772
805
|
|
|
773
806
|
**Action**:
|
|
774
|
-
- Read all `features-{platform}.json` files from `
|
|
807
|
+
- Read all `features-{platform}.json` files from `{sync_state_bizs_dir}/` to get platform structure
|
|
775
808
|
- Invoke 1 Worker Agent (`speccrew-task-worker.md`) with `skill_name: speccrew-knowledge-system-summarize`
|
|
776
809
|
- Parameters to pass to skill:
|
|
777
|
-
- `modules_path`: Path to knowledge base directory containing all platform modules (e.g., `
|
|
778
|
-
- `output_path`: Output path for system-overview.md (e.g., `
|
|
810
|
+
- `modules_path`: Path to knowledge base directory containing all platform modules (e.g., `{workspace_path}/knowledges/bizs/`)
|
|
811
|
+
- `output_path`: Output path for system-overview.md (e.g., `{workspace_path}/knowledges/bizs/`)
|
|
812
|
+
- `workspace_path`: Absolute path to speccrew-workspace directory — **REQUIRED**
|
|
813
|
+
- `sync_state_bizs_dir`: Absolute path to sync-state/knowledge-bizs directory — **REQUIRED**
|
|
779
814
|
- `language`: User's language — **REQUIRED**
|
|
780
815
|
- **Behavior constraint**: Worker MUST NOT create any temporary scripts or workaround files. If execution fails, STOP and report error immediately.
|
|
781
816
|
|
|
782
817
|
Expected Worker Return: `{ "status": "success|failed", "output_file": "system-overview.md", "message": "..." }`
|
|
783
818
|
|
|
784
819
|
**Output**:
|
|
785
|
-
- `
|
|
820
|
+
- `{workspace_path}/knowledges/bizs/system-overview.md` (complete with platform index and module hierarchy)
|
|
786
821
|
|
|
787
822
|
> ✅ **Stage 4 Milestone**: System overview generated. All stages complete. Pipeline finished successfully.
|
|
788
823
|
|
|
@@ -849,8 +884,8 @@ After all 5 stages complete, return a summary object to the caller:
|
|
|
849
884
|
"stage4": { "status": "completed" }
|
|
850
885
|
},
|
|
851
886
|
"output": {
|
|
852
|
-
"system_overview": "
|
|
853
|
-
"graph_root": "
|
|
887
|
+
"system_overview": "{workspace_path}/knowledges/bizs/system-overview.md",
|
|
888
|
+
"graph_root": "{workspace_path}/knowledges/bizs/graph/"
|
|
854
889
|
}
|
|
855
890
|
}
|
|
856
891
|
```
|
|
@@ -13,12 +13,14 @@ Analyze source directory structures to identify business module entry directorie
|
|
|
13
13
|
| Parameter | Type | Required | Description |
|
|
14
14
|
|-----------|------|----------|-------------|
|
|
15
15
|
| `{platforms}` | array | Yes | Platform list from detection phase. Each item: `{platformId, sourcePath, platformType, platformSubtype, techStack}` |
|
|
16
|
-
| `{workspace_path}` | string | Yes |
|
|
16
|
+
| `{workspace_path}` | string | Yes | Absolute path to speccrew-workspace directory |
|
|
17
|
+
| `{sync_state_bizs_dir}` | string | Yes | Absolute path to entry-dirs JSON output directory |
|
|
18
|
+
| `{configs_dir}` | string | Yes | Absolute path to configuration files directory (for `tech-stack-mappings.json`) |
|
|
17
19
|
|
|
18
20
|
## Output
|
|
19
21
|
|
|
20
22
|
For each platform, generates:
|
|
21
|
-
- `{
|
|
23
|
+
- `{sync_state_bizs_dir}/entry-dirs-{platform_id}.json`
|
|
22
24
|
|
|
23
25
|
## Workflow
|
|
24
26
|
|
|
@@ -57,7 +59,7 @@ Based on the directory tree and technology stack, analyze and identify entry dir
|
|
|
57
59
|
|
|
58
60
|
### Step 3: Load Exclusion Rules
|
|
59
61
|
|
|
60
|
-
Read `{
|
|
62
|
+
Read `{configs_dir}/tech-stack-mappings.json` to load exclusion patterns. Apply the following exclusion rules:
|
|
61
63
|
|
|
62
64
|
**Pure Technical Directories**:
|
|
63
65
|
`config`, `framework`, `enums`, `exception`, `util`, `utils`, `common`, `constant`, `constants`, `type`, `types`, `dto`, `vo`, `entity`, `model`, `mapper`, `repository`, `dao`, `service`, `impl`
|
|
@@ -76,7 +78,7 @@ Read `{workspace_path}/docs/configs/tech-stack-mappings.json` to load exclusion
|
|
|
76
78
|
|
|
77
79
|
### Step 4: Generate entry-dirs JSON
|
|
78
80
|
|
|
79
|
-
Output file: `{
|
|
81
|
+
Output file: `{sync_state_bizs_dir}/entry-dirs-{platform_id}.json`
|
|
80
82
|
|
|
81
83
|
**JSON Format**:
|
|
82
84
|
```json
|
|
@@ -131,6 +133,8 @@ If entry directory recognition fails for a platform, STOP and report the error w
|
|
|
131
133
|
- [ ] `entryDirs` paths are correct and accessible
|
|
132
134
|
- [ ] JSON format is valid
|
|
133
135
|
|
|
136
|
+
> **MANDATORY**: Use the provided absolute paths directly. DO NOT construct or derive paths yourself.
|
|
137
|
+
|
|
134
138
|
## Example Usage
|
|
135
139
|
|
|
136
140
|
```
|
|
@@ -153,4 +157,6 @@ Args:
|
|
|
153
157
|
}
|
|
154
158
|
]
|
|
155
159
|
workspace_path: "/path/to/speccrew-workspace"
|
|
160
|
+
sync_state_bizs_dir: "/path/to/speccrew-workspace/knowledges/base/sync-state/knowledge-bizs"
|
|
161
|
+
configs_dir: "/path/to/speccrew-workspace/docs/configs"
|
|
156
162
|
```
|
|
@@ -8,12 +8,16 @@ tools: Read, Write, Glob, Grep, SearchCodebase, Skill, Bash
|
|
|
8
8
|
|
|
9
9
|
| Parameter | Type | Required | Description |
|
|
10
10
|
|-----------|------|----------|-------------|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
11
|
+
| `source_path` | string | No | Source code directory path (default: project root) |
|
|
12
|
+
| `language` | string | Yes | Target language for generated content (e.g., "zh", "en") |
|
|
13
|
+
| `sync_state_bizs_dir` | string | Yes | Absolute path to features and entry-dirs JSON output directory |
|
|
14
|
+
| `configs_dir` | string | Yes | Absolute path to configuration files directory |
|
|
15
|
+
| `ide_skills_dir` | string | Yes | Absolute path to IDE skills directory (e.g., `.qoder/skills`) |
|
|
13
16
|
|
|
14
17
|
## Output
|
|
15
18
|
|
|
16
|
-
- `
|
|
19
|
+
- `{sync_state_bizs_dir}/features-{platform}.json` - Platform-specific feature inventory files
|
|
20
|
+
- `{sync_state_bizs_dir}/entry-dirs-{platform}.json` - Entry directories configuration files
|
|
17
21
|
|
|
18
22
|
## Workflow
|
|
19
23
|
|
|
@@ -31,8 +35,8 @@ flowchart TD
|
|
|
31
35
|
**Detection Process:**
|
|
32
36
|
|
|
33
37
|
1. **Read Configuration:**
|
|
34
|
-
- `
|
|
35
|
-
- `
|
|
38
|
+
- `{configs_dir}/platform-mapping.json` - Platform type and subtype mappings
|
|
39
|
+
- `{configs_dir}/tech-stack-mappings.json` - Tech stack configurations and exclude directories
|
|
36
40
|
|
|
37
41
|
2. Scan `{source_path}` for platform-specific configuration files (e.g., package.json, pubspec.yaml, pom.xml)
|
|
38
42
|
|
|
@@ -63,9 +67,11 @@ Dispatch Worker with `speccrew-knowledge-bizs-identify-entries` skill:
|
|
|
63
67
|
| Parameter | Value |
|
|
64
68
|
|-----------|-------|
|
|
65
69
|
| `platforms` | Platform list from Step 1 (each with platformId, sourcePath, platformType, platformSubtype, techStack) |
|
|
66
|
-
| `workspace_path` |
|
|
70
|
+
| `workspace_path` | Absolute path to speccrew-workspace |
|
|
71
|
+
| `sync_state_bizs_dir` | `{sync_state_bizs_dir}` |
|
|
72
|
+
| `configs_dir` | `{configs_dir}` |
|
|
67
73
|
|
|
68
|
-
Worker generates `entry-dirs-{platform_id}.json` files in `{
|
|
74
|
+
Worker generates `entry-dirs-{platform_id}.json` files in `{sync_state_bizs_dir}/`.
|
|
69
75
|
|
|
70
76
|
**Option B: Direct Execution**
|
|
71
77
|
|
|
@@ -75,8 +81,8 @@ If executing directly (without Worker dispatch), follow the same logic as the `s
|
|
|
75
81
|
- **Backend**: Find directories containing `*Controller.*` files, extract business package names
|
|
76
82
|
- **Frontend**: Find `views/` or `pages/` directories, use first-level subdirectories as modules
|
|
77
83
|
- **Mobile**: Find `pages/` subdirectories + top-level `pages-*` directories
|
|
78
|
-
3. Apply exclusion rules from `tech-stack-mappings.json`
|
|
79
|
-
4. Generate `entry-dirs-{platform_id}.json` files
|
|
84
|
+
3. Apply exclusion rules from `{configs_dir}/tech-stack-mappings.json`
|
|
85
|
+
4. Generate `entry-dirs-{platform_id}.json` files to `{sync_state_bizs_dir}/`
|
|
80
86
|
|
|
81
87
|
**Verification**: Confirm each entry-dirs JSON has non-empty `modules` array with business-meaningful names.
|
|
82
88
|
|
|
@@ -89,26 +95,27 @@ Execute the inventory script for each platform using the entry-dirs JSON from St
|
|
|
89
95
|
**Prerequisites:**
|
|
90
96
|
- Node.js 14.0+
|
|
91
97
|
|
|
92
|
-
**Script Location
|
|
93
|
-
- All Platforms: `{
|
|
98
|
+
**Script Location:**
|
|
99
|
+
- All Platforms: `{ide_skills_dir}/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js`
|
|
94
100
|
|
|
95
101
|
**Execution Command:**
|
|
96
102
|
```bash
|
|
97
|
-
node "{
|
|
103
|
+
node "{ide_skills_dir}/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js" --entryDirsFile "{sync_state_bizs_dir}/entry-dirs-{platform_id}.json" --outputDir "{sync_state_bizs_dir}"
|
|
98
104
|
```
|
|
99
105
|
|
|
100
|
-
|
|
106
|
+
**Parameters:**
|
|
107
|
+
- `--entryDirsFile`: Path to the `entry-dirs-{platform_id}.json` file in `{sync_state_bizs_dir}/`
|
|
108
|
+
- `--outputDir`: Output directory for `features-{platform}.json` (use `{sync_state_bizs_dir}`)
|
|
101
109
|
|
|
102
110
|
**Example:**
|
|
103
111
|
```bash
|
|
104
112
|
# Execute for each platform's entry-dirs file
|
|
105
|
-
node "scripts/generate-inventory.js" --entryDirsFile "d:/project/speccrew-workspace/knowledges/base/sync-state/knowledge-bizs/entry-dirs-backend-system.json"
|
|
106
|
-
|
|
107
|
-
node "scripts/generate-inventory.js" --entryDirsFile "d:/project/speccrew-workspace/knowledges/base/sync-state/knowledge-bizs/entry-dirs-web-vue.json"
|
|
113
|
+
node "d:/project/.qoder/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js" --entryDirsFile "d:/project/speccrew-workspace/knowledges/base/sync-state/knowledge-bizs/entry-dirs-backend-system.json" --outputDir "d:/project/speccrew-workspace/knowledges/base/sync-state/knowledge-bizs"
|
|
108
114
|
```
|
|
109
115
|
|
|
110
116
|
**Script Parameters**:
|
|
111
|
-
- `--entryDirsFile`: (Required) Path to the `entry-dirs-{platform_id}.json` file
|
|
117
|
+
- `--entryDirsFile`: (Required) Path to the `entry-dirs-{platform_id}.json` file in `{sync_state_bizs_dir}/`
|
|
118
|
+
- `--outputDir`: (Required) Output directory for `features-{platform}.json` (use `{sync_state_bizs_dir}`)
|
|
112
119
|
- `--techIdentifier`: (Optional) Technology identifier for tech-stack lookup (auto-detected from platform mapping if omitted)
|
|
113
120
|
- `--fileExtensions`: (Optional) Comma-separated list of file extensions to include
|
|
114
121
|
- `--excludeDirs`: (Optional) Additional directories to exclude
|
|
@@ -171,23 +178,23 @@ Feature Inventory Generated
|
|
|
171
178
|
|
|
172
179
|
Platform Inventory Files:
|
|
173
180
|
- Web Frontend:
|
|
174
|
-
- Inventory File:
|
|
181
|
+
- Inventory File: {sync_state_bizs_dir}/features-web.json
|
|
175
182
|
- Total Features: [N]
|
|
176
183
|
- Status: Generated ✓
|
|
177
184
|
- Mobile App:
|
|
178
|
-
- Inventory File:
|
|
185
|
+
- Inventory File: {sync_state_bizs_dir}/features-mobile.json
|
|
179
186
|
- Total Features: [N]
|
|
180
187
|
- Status: Generated ✓
|
|
181
188
|
- Backend API:
|
|
182
|
-
- Inventory File:
|
|
189
|
+
- Inventory File: {sync_state_bizs_dir}/features-api.json
|
|
183
190
|
- Total Features: [N]
|
|
184
191
|
- Status: Generated ✓
|
|
185
192
|
|
|
186
193
|
Final Output:
|
|
187
194
|
- Platform Files:
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
-
|
|
195
|
+
- {sync_state_bizs_dir}/features-web.json
|
|
196
|
+
- {sync_state_bizs_dir}/features-mobile.json
|
|
197
|
+
- {sync_state_bizs_dir}/features-api.json
|
|
191
198
|
```
|
|
192
199
|
|
|
193
200
|
## Checklist
|
|
@@ -210,7 +217,9 @@ Final Output:
|
|
|
210
217
|
- [ ] **File paths correct**: All `sourcePath` and `documentPath` values are accurate (sourcePath MUST be project-root-relative path)
|
|
211
218
|
|
|
212
219
|
### Output Generation
|
|
213
|
-
- [ ] All platform inventory files generated in `
|
|
220
|
+
- [ ] All platform inventory files generated in `{sync_state_bizs_dir}` directory
|
|
214
221
|
- [ ] Output path verified
|
|
215
222
|
- [ ] Results reported
|
|
216
223
|
|
|
224
|
+
> **MANDATORY**: Use the provided absolute paths directly. DO NOT construct or derive paths yourself. DO NOT manually create JSON files.
|
|
225
|
+
|
package/.speccrew/skills/speccrew-knowledge-bizs-init-features/scripts/generate-inventory.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Scans source directory for page files and generates a flat feature list with analysis status tracking.
|
|
6
6
|
* All configuration is passed via parameters - the script does not infer anything.
|
|
7
7
|
*
|
|
8
|
-
* Usage: node generate-inventory.js --sourcePath <path> --outputFileName <name> --platformName <name> --platformType <type> --techStack <json> --fileExtensions <json> [--platformSubtype <subtype>] [--techIdentifier <identifier>] [--analysisMethod <method>] [--excludeDirs <json>] [--includeDataObjects <true|false>]
|
|
8
|
+
* Usage: node generate-inventory.js --sourcePath <path> --outputFileName <name> --platformName <name> --platformType <type> --techStack <json> --fileExtensions <json> [--platformSubtype <subtype>] [--techIdentifier <identifier>] [--analysisMethod <method>] [--excludeDirs <json>] [--includeDataObjects <true|false>] [--outputDir <dir>]
|
|
9
9
|
* Array parameters (--techStack, --fileExtensions, --excludeDirs) accept both JSON format and comma-separated format.
|
|
10
10
|
*
|
|
11
11
|
* Whitelist Mode (using --entryDirsFile):
|
|
@@ -20,6 +20,11 @@
|
|
|
20
20
|
* The suffixes are read from tech-stack-mappings.json (exclude_file_suffixes field).
|
|
21
21
|
* Use --includeDataObjects true to include them.
|
|
22
22
|
*
|
|
23
|
+
* Output Directory (--outputDir):
|
|
24
|
+
* By default, the script uses findProjectRoot() to locate the project root and outputs to:
|
|
25
|
+
* <projectRoot>/speccrew-workspace/knowledges/base/sync-state/knowledge-bizs/
|
|
26
|
+
* Use --outputDir to explicitly specify the output directory, bypassing findProjectRoot().
|
|
27
|
+
*
|
|
23
28
|
* Example (full scan mode):
|
|
24
29
|
* node generate-inventory.js \
|
|
25
30
|
* --sourcePath "src/views" \
|
|
@@ -639,8 +644,14 @@ function main() {
|
|
|
639
644
|
|
|
640
645
|
console.log(`Platform config: type=${platformType}, subtype=${platformSubtype}, framework=${framework}`);
|
|
641
646
|
|
|
642
|
-
// Set output directory
|
|
643
|
-
|
|
647
|
+
// Set output directory (prefer --outputDir parameter, fallback to findProjectRoot)
|
|
648
|
+
let outputDir;
|
|
649
|
+
if (params.outputDir) {
|
|
650
|
+
outputDir = path.resolve(params.outputDir);
|
|
651
|
+
console.log(`Using outputDir from parameter: ${outputDir}`);
|
|
652
|
+
} else {
|
|
653
|
+
outputDir = path.join(projectRoot, 'speccrew-workspace', 'knowledges', 'base', 'sync-state', 'knowledge-bizs');
|
|
654
|
+
}
|
|
644
655
|
|
|
645
656
|
// Generate features from entry dirs
|
|
646
657
|
const success = generateFromEntryDirs(entryDirsData, platformConfig, projectRoot, outputDir);
|
|
@@ -735,13 +746,19 @@ function main() {
|
|
|
735
746
|
|
|
736
747
|
// Validate required parameters
|
|
737
748
|
if (!sourcePath || !outputFileName || !platformName || !platformType || !techStackStr || !fileExtensionsStr) {
|
|
738
|
-
console.error('Usage: node generate-inventory.js --sourcePath <path> --outputFileName <name> --platformName <name> --platformType <type> --techStack <json> --fileExtensions <json> [--platformSubtype <subtype>] [--techIdentifier <identifier>] [--analysisMethod <method>] [--excludeDirs <json>] [--includeDataObjects <true|false>]');
|
|
749
|
+
console.error('Usage: node generate-inventory.js --sourcePath <path> --outputFileName <name> --platformName <name> --platformType <type> --techStack <json> --fileExtensions <json> [--platformSubtype <subtype>] [--techIdentifier <identifier>] [--analysisMethod <method>] [--excludeDirs <json>] [--includeDataObjects <true|false>] [--outputDir <dir>]');
|
|
739
750
|
console.error('Example: node generate-inventory.js --sourcePath "src/views" --outputFileName "features-web.json" --platformName "Web Frontend" --platformType "web" --platformSubtype "vue" --techStack "vue,typescript" --fileExtensions ".vue,.ts" --analysisMethod "ui-based" --excludeDirs "components,composables,hooks,utils"');
|
|
740
751
|
process.exit(1);
|
|
741
752
|
}
|
|
742
753
|
|
|
743
|
-
// Find sync-state directory
|
|
744
|
-
|
|
754
|
+
// Find sync-state directory (prefer --outputDir parameter, fallback to findProjectRoot)
|
|
755
|
+
let syncStateDir;
|
|
756
|
+
if (params.outputDir) {
|
|
757
|
+
syncStateDir = path.resolve(params.outputDir);
|
|
758
|
+
console.log(`Using outputDir from parameter: ${syncStateDir}`);
|
|
759
|
+
} else {
|
|
760
|
+
syncStateDir = path.join(projectRoot, 'speccrew-workspace', 'knowledges', 'base', 'sync-state', 'knowledge-bizs');
|
|
761
|
+
}
|
|
745
762
|
const outputPath = path.join(syncStateDir, outputFileName);
|
|
746
763
|
|
|
747
764
|
// Calculate relative source path from project root
|