@atlashub/smartstack-cli 2.7.2 → 2.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/.documentation/agents.html +0 -4
  2. package/.documentation/business-analyse.html +0 -4
  3. package/.documentation/cli-commands.html +0 -4
  4. package/.documentation/commands.html +0 -77
  5. package/.documentation/css/styles.css +0 -8
  6. package/.documentation/efcore.html +0 -4
  7. package/.documentation/gitflow.html +0 -4
  8. package/.documentation/hooks.html +0 -4
  9. package/.documentation/index.html +2 -28
  10. package/.documentation/init.html +8 -14
  11. package/.documentation/installation.html +0 -11
  12. package/.documentation/js/app.js +2 -16
  13. package/.documentation/ralph-loop.html +0 -4
  14. package/.documentation/test-web.html +0 -4
  15. package/README.md +0 -1
  16. package/dist/index.js +3 -7
  17. package/dist/index.js.map +1 -1
  18. package/package.json +2 -3
  19. package/templates/agents/docs-sync-checker.md +2 -2
  20. package/templates/agents/efcore/squash.md +3 -1
  21. package/templates/hooks/docs-drift-check.md +4 -5
  22. package/templates/skills/_resources/context-digest-template.md +2 -2
  23. package/templates/skills/_resources/doc-context-cache.md +0 -2
  24. package/templates/skills/_resources/docs-manifest-schema.md +1 -3
  25. package/templates/skills/_resources/mcp-validate-documentation-spec.md +1 -3
  26. package/templates/skills/_shared.md +24 -25
  27. package/templates/skills/application/steps/step-04-backend.md +185 -11
  28. package/templates/skills/application/steps/step-06-migration.md +41 -2
  29. package/templates/skills/application/templates-seed.md +151 -0
  30. package/templates/skills/business-analyse/steps/step-05-handoff.md +59 -17
  31. package/templates/skills/controller/steps/step-01-analyze.md +1 -1
  32. package/templates/skills/efcore/steps/squash/step-03-create.md +39 -0
  33. package/templates/skills/ralph-loop/SKILL.md +35 -3
  34. package/templates/skills/ralph-loop/steps/step-00-init.md +93 -0
  35. package/templates/skills/ralph-loop/steps/step-01-task.md +202 -3
  36. package/templates/skills/ralph-loop/steps/step-02-execute.md +75 -3
  37. package/templates/skills/ralph-loop/steps/step-03-commit.md +8 -1
  38. package/templates/skills/ralph-loop/steps/step-04-check.md +77 -13
  39. package/templates/skills/ralph-loop/steps/step-05-report.md +79 -0
  40. package/.documentation/apex.html +0 -1027
  41. package/templates/skills/apex/SKILL.md +0 -297
  42. package/templates/skills/apex/steps/step-00-init.md +0 -212
  43. package/templates/skills/apex/steps/step-01-analyze.md +0 -263
  44. package/templates/skills/apex/steps/step-02-plan.md +0 -255
  45. package/templates/skills/apex/steps/step-03-execute.md +0 -217
  46. package/templates/skills/apex/steps/step-04-validate.md +0 -273
  47. package/templates/skills/apex/steps/step-04b-doc-sync.md +0 -162
  48. package/templates/skills/apex/steps/step-05-examine.md +0 -214
  49. package/templates/skills/apex/steps/step-06-resolve.md +0 -181
  50. package/templates/skills/apex/steps/step-07-tests.md +0 -206
  51. package/templates/skills/apex/steps/step-08-run-tests.md +0 -207
  52. package/templates/skills/apex/templates/00-context.md +0 -46
  53. package/templates/skills/apex/templates/01-analyze.md +0 -63
  54. package/templates/skills/apex/templates/02-plan.md +0 -63
  55. package/templates/skills/apex/templates/03-execute.md +0 -34
  56. package/templates/skills/apex/templates/04-validate.md +0 -61
  57. package/templates/skills/apex/templates/04b-doc-sync.md +0 -31
  58. package/templates/skills/apex/templates/05-examine.md +0 -58
  59. package/templates/skills/apex/templates/06-resolve.md +0 -39
  60. package/templates/skills/apex/templates/07-tests.md +0 -56
  61. package/templates/skills/apex/templates/08-run-tests.md +0 -41
  62. package/templates/skills/apex/templates/README.md +0 -69
  63. package/templates/skills/apex/templates/context-digest.md +0 -35
@@ -960,3 +960,154 @@ Level 5: RESOURCE (finest granularity)
960
960
  └─ Path: {context}.{application}.{module}.{section}.{resource}.{action}
961
961
  └─ E.g.: platform.administration.ai.prompts.blocks.delete
962
962
  ```
963
+
964
+ ---
965
+
966
+ ## SQL OBJECTS INFRASTRUCTURE
967
+
968
+ > **Usage:** SQL Server functions (TVFs, scalar), views, and stored procedures managed as embedded resources
969
+ > **Pattern:** Same as SmartStack.app — `CREATE OR ALTER` for idempotency, applied via migrations
970
+ > **Location:** `Infrastructure/Persistence/SqlObjects/`
971
+
972
+ ### Directory Structure
973
+
974
+ ```
975
+ Infrastructure/Persistence/SqlObjects/
976
+ ├── SqlObjectHelper.cs ← Helper to apply SQL from embedded resources
977
+ ├── Functions/ ← Table-Valued & Scalar functions
978
+ │ └── fn_{FunctionName}.sql ← CREATE OR ALTER FUNCTION [schema].[fn_Name]
979
+ ├── Views/ ← Future: SQL views
980
+ │ └── vw_{ViewName}.sql
981
+ └── StoredProcedures/ ← Future: Stored procedures
982
+ └── sp_{ProcName}.sql
983
+ ```
984
+
985
+ ### SqlObjectHelper Pattern
986
+
987
+ ```csharp
988
+ // Infrastructure/Persistence/SqlObjects/SqlObjectHelper.cs
989
+
990
+ using System.Reflection;
991
+ using Microsoft.EntityFrameworkCore.Migrations;
992
+
993
+ namespace {BaseNamespace}.Infrastructure.Persistence.SqlObjects;
994
+
995
+ /// <summary>
996
+ /// Helper for applying SQL objects from embedded resources.
997
+ /// SQL files use CREATE OR ALTER for idempotency — safe to re-run on any migration or squash.
998
+ /// </summary>
999
+ public static class SqlObjectHelper
1000
+ {
1001
+ private static readonly Assembly Assembly = typeof(SqlObjectHelper).Assembly;
1002
+ private const string ResourcePrefix = "{BaseNamespace}.Infrastructure.Persistence.SqlObjects.";
1003
+
1004
+ /// <summary>
1005
+ /// Applies all SQL objects (functions, views, stored procedures).
1006
+ /// Call in Up() method of a migration, especially after a squash.
1007
+ /// </summary>
1008
+ public static void ApplyAll(MigrationBuilder migrationBuilder)
1009
+ {
1010
+ ApplyAllFunctions(migrationBuilder);
1011
+ }
1012
+
1013
+ public static void ApplyAllFunctions(MigrationBuilder migrationBuilder)
1014
+ {
1015
+ ApplyCategory(migrationBuilder, "Functions");
1016
+ }
1017
+
1018
+ public static void ApplyOne(MigrationBuilder migrationBuilder, string resourceName)
1019
+ {
1020
+ var sql = ReadSqlObject(resourceName);
1021
+ migrationBuilder.Sql(sql);
1022
+ }
1023
+
1024
+ public static string ReadSqlObject(string resourceName)
1025
+ {
1026
+ var fullName = ResourcePrefix + resourceName;
1027
+ using var stream = Assembly.GetManifestResourceStream(fullName)
1028
+ ?? throw new InvalidOperationException(
1029
+ $"SQL object resource '{fullName}' not found. " +
1030
+ $"Ensure the .sql file is marked as EmbeddedResource in the .csproj. " +
1031
+ $"Available: {string.Join(", ", Assembly.GetManifestResourceNames().Where(n => n.EndsWith(".sql")))}");
1032
+ using var reader = new StreamReader(stream);
1033
+ return reader.ReadToEnd();
1034
+ }
1035
+
1036
+ private static void ApplyCategory(MigrationBuilder migrationBuilder, string category)
1037
+ {
1038
+ var prefix = ResourcePrefix + category + ".";
1039
+ var resources = Assembly.GetManifestResourceNames()
1040
+ .Where(n => n.StartsWith(prefix, StringComparison.Ordinal)
1041
+ && n.EndsWith(".sql", StringComparison.Ordinal))
1042
+ .OrderBy(n => n, StringComparer.Ordinal);
1043
+
1044
+ foreach (var resource in resources)
1045
+ {
1046
+ using var stream = Assembly.GetManifestResourceStream(resource)!;
1047
+ using var reader = new StreamReader(stream);
1048
+ migrationBuilder.Sql(reader.ReadToEnd());
1049
+ }
1050
+ }
1051
+ }
1052
+ ```
1053
+
1054
+ ### .csproj Configuration (REQUIRED)
1055
+
1056
+ ```xml
1057
+ <ItemGroup>
1058
+ <EmbeddedResource Include="Persistence\SqlObjects\**\*.sql" />
1059
+ </ItemGroup>
1060
+ ```
1061
+
1062
+ ### SQL File Convention
1063
+
1064
+ All `.sql` files MUST use `CREATE OR ALTER` for idempotency:
1065
+
1066
+ ```sql
1067
+ -- Infrastructure/Persistence/SqlObjects/Functions/fn_GetUserGroupHierarchy.sql
1068
+ CREATE OR ALTER FUNCTION [extensions].[fn_GetEntityHierarchy](@EntityId UNIQUEIDENTIFIER)
1069
+ RETURNS TABLE
1070
+ AS
1071
+ RETURN
1072
+ (
1073
+ WITH Hierarchy AS (
1074
+ SELECT Id, ParentId, 0 AS Level
1075
+ FROM [extensions].[fb_Entities]
1076
+ WHERE Id = @EntityId
1077
+ UNION ALL
1078
+ SELECT child.Id, child.ParentId, parent.Level + 1
1079
+ FROM [extensions].[fb_Entities] child
1080
+ INNER JOIN Hierarchy parent ON child.ParentId = parent.Id
1081
+ WHERE parent.Level < 10
1082
+ )
1083
+ SELECT DISTINCT Id FROM Hierarchy
1084
+ );
1085
+ ```
1086
+
1087
+ ### Migration Integration
1088
+
1089
+ In a migration's `Up()` method, call SqlObjectHelper to apply/re-apply SQL objects:
1090
+
1091
+ ```csharp
1092
+ protected override void Up(MigrationBuilder migrationBuilder)
1093
+ {
1094
+ // ... table creation, indexes, etc.
1095
+
1096
+ // Apply all SQL objects (idempotent — CREATE OR ALTER)
1097
+ SqlObjectHelper.ApplyAll(migrationBuilder);
1098
+ }
1099
+ ```
1100
+
1101
+ Or apply a single function:
1102
+ ```csharp
1103
+ SqlObjectHelper.ApplyOne(migrationBuilder, "Functions.fn_GetEntityHierarchy.sql");
1104
+ ```
1105
+
1106
+ ### When to Use SQL Objects
1107
+
1108
+ | Need | Solution |
1109
+ |------|----------|
1110
+ | Recursive hierarchy traversal | TVF with CTE (fn_GetXxxHierarchy) |
1111
+ | Complex aggregation for reports | SQL View (vw_XxxSummary) |
1112
+ | Bulk operations with business logic | Stored Procedure (sp_XxxBatch) |
1113
+ | Simple CRUD, filtering, sorting | EF Core LINQ (no SQL needed) |
@@ -313,43 +313,43 @@ From `specification.uiWireframes[]`, `specification.dashboards[]` and `analysis.
313
313
  ```json
314
314
  "seedData": [
315
315
  {
316
- "path": "src/Infrastructure/Data/SeedData/{ModuleName}/NavigationModuleConfiguration.cs",
317
- "type": "HasData",
316
+ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/NavigationModuleSeedData.cs",
317
+ "type": "SeedData",
318
318
  "category": "core",
319
319
  "source": "specification.seedDataCore.navigationModules",
320
320
  "module": "{moduleCode}"
321
321
  },
322
322
  {
323
- "path": "src/Infrastructure/Data/SeedData/{ModuleName}/PermissionsConfiguration.cs",
324
- "type": "HasData",
323
+ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/PermissionsSeedData.cs",
324
+ "type": "SeedData",
325
325
  "category": "core",
326
326
  "source": "specification.seedDataCore.permissions",
327
327
  "module": "{moduleCode}"
328
328
  },
329
329
  {
330
- "path": "src/Infrastructure/Data/SeedData/{ModuleName}/RolesConfiguration.cs",
331
- "type": "HasData",
330
+ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/RolesSeedData.cs",
331
+ "type": "SeedData",
332
332
  "category": "core",
333
333
  "source": "specification.seedDataCore.roles",
334
334
  "module": "{moduleCode}"
335
335
  },
336
336
  {
337
- "path": "src/Infrastructure/Data/SeedData/{ModuleName}/TenantConfiguration.cs",
338
- "type": "HasData",
337
+ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/TenantSeedData.cs",
338
+ "type": "SeedData",
339
339
  "category": "core",
340
340
  "source": "specification.seedDataCore.tenants",
341
341
  "module": "{moduleCode}"
342
342
  },
343
343
  {
344
- "path": "src/Infrastructure/Data/SeedData/{ModuleName}/UserConfiguration.cs",
345
- "type": "HasData",
344
+ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/UserSeedData.cs",
345
+ "type": "SeedData",
346
346
  "category": "core",
347
347
  "source": "specification.seedDataCore.users",
348
348
  "module": "{moduleCode}"
349
349
  },
350
350
  {
351
- "path": "src/Infrastructure/Data/SeedData/{ModuleName}/{Entity}SeedData.cs",
352
- "type": "HasData",
351
+ "path": "src/Infrastructure/Persistence/Seeding/Data/{ModuleName}/{Entity}SeedData.cs",
352
+ "type": "SeedData",
353
353
  "category": "business",
354
354
  "source": "specification.seedDataBusiness.{module}",
355
355
  "module": "{moduleCode}"
@@ -357,12 +357,51 @@ From `specification.uiWireframes[]`, `specification.dashboards[]` and `analysis.
357
357
  ]
358
358
  ```
359
359
 
360
+ **For client projects (ExtensionsDbContext), add these MANDATORY infrastructure files:**
361
+
362
+ ```json
363
+ "seedData": [
364
+ // ... 5 core + business entries above ...
365
+ {
366
+ "path": "src/Infrastructure/Persistence/Seeding/{AppPascalName}SeedDataProvider.cs",
367
+ "type": "IClientSeedDataProvider",
368
+ "category": "infrastructure",
369
+ "description": "Runtime provider that injects core seed data (navigation, permissions, roles) into Core schema",
370
+ "source": "specification.seedDataCore",
371
+ "module": "{moduleCode}"
372
+ },
373
+ {
374
+ "path": "src/Infrastructure/Persistence/Seeding/DevDataSeeder.cs",
375
+ "type": "DevDataSeeder",
376
+ "category": "infrastructure",
377
+ "description": "Seeds development/demo data for domain entities at startup",
378
+ "module": "{moduleCode}"
379
+ },
380
+ {
381
+ "path": "src/Infrastructure/Persistence/Seeding/Data/SeedConstants.cs",
382
+ "type": "SeedConstants",
383
+ "category": "infrastructure",
384
+ "description": "Shared constants for deterministic seed data",
385
+ "module": "{moduleCode}"
386
+ }
387
+ ]
388
+ ```
389
+
390
+ **Path convention:** All seed data files MUST be under `Persistence/Seeding/Data/` (matching SmartStack.app architecture).
391
+ NEVER use `Data/SeedData/` or `Infrastructure/Data/SeedData/`.
392
+
393
+ **IClientSeedDataProvider (MANDATORY for client projects):** This provider injects core seed data
394
+ (navigation, permissions, roles) into the Core schema at runtime. Generated at
395
+ `src/Infrastructure/Persistence/Seeding/{AppPascalName}SeedDataProvider.cs`.
396
+ See `/application` skill step-03b-provider for the full pattern.
397
+ Without this provider, the 5 core SeedData files are DEAD CODE and will have no effect.
398
+
360
399
  Core categories (ALWAYS 5):
361
- 1. NavigationModuleConfiguration (navigation items for module)
362
- 2. PermissionsConfiguration (RBAC permissions)
363
- 3. RolesConfiguration (roles using permissions)
364
- 4. TenantConfiguration (test tenants)
365
- 5. UserConfiguration (test users)
400
+ 1. NavigationModuleSeedData (navigation items for module)
401
+ 2. PermissionsSeedData (RBAC permissions)
402
+ 3. RolesSeedData (roles using permissions)
403
+ 4. TenantSeedData (test tenants)
404
+ 5. UserSeedData (test users)
366
405
 
367
406
  Business categories (from specification.seedDataBusiness):
368
407
  - Domain-specific reference data
@@ -635,6 +674,8 @@ Generate `.ralph/progress.txt` as main task tracker:
635
674
  □ Create {Entity2}Repository
636
675
  □ Configure DbContext for module
637
676
  □ Setup specifications for complex queries
677
+ □ Create IClientSeedDataProvider (client projects ONLY - injects core seeds at runtime)
678
+ □ Create DevDataSeeder + SeedConstants (if first module)
638
679
  Total: A tasks
639
680
 
640
681
  [API] REST Endpoints & Controllers
@@ -652,6 +693,7 @@ Generate `.ralph/progress.txt` as main task tracker:
652
693
  □ Create custom hook use{ModuleName}
653
694
  □ Implement pagination, filtering, sorting
654
695
  □ Validate all pages match their wireframe layout
696
+ □ ⚠️ Routes MUST be INSIDE Layout wrapper (AdminLayout/BusinessLayout/UserLayout)
655
697
  Total: C tasks
656
698
 
657
699
  [I18N] Internationalization Keys
@@ -35,7 +35,7 @@ Glob: "src/SmartStack.Domain/**/{entity}s.cs"
35
35
  **If Entity NOT found:**
36
36
  ```
37
37
  STOP - Entity {entity} not found in Domain layer.
38
- Create entity first: /apex add {entity} entity to Domain
38
+ Create entity first using /application skill to add the entity to Domain
39
39
  ```
40
40
 
41
41
  ### 2. Check DbContext
@@ -131,6 +131,45 @@ echo " Up methods: $UP_METHODS"
131
131
  echo " Down methods: $DOWN_METHODS"
132
132
  ```
133
133
 
134
+ ### 6. Inject SQL Objects (Functions, Views, SP)
135
+
136
+ EF Core ne génère PAS de DDL pour les TVF, vues et procédures stockées.
137
+ Les scripts SQL source sont dans `Persistence/SqlObjects/` (Embedded Resources).
138
+ Après un squash, il faut les réinjecter dans la migration consolidée.
139
+
140
+ ```bash
141
+ # Check if SqlObjects folder exists with .sql files
142
+ SQL_OBJECTS_DIR="$INFRA_PROJECT_DIR/Persistence/SqlObjects"
143
+ SQL_FILES=$(find "$SQL_OBJECTS_DIR" -name "*.sql" 2>/dev/null | wc -l)
144
+
145
+ if [ "$SQL_FILES" -gt 0 ]; then
146
+ echo ""
147
+ echo "Found $SQL_FILES SQL object(s) in SqlObjects/"
148
+ echo "Injecting SqlObjectHelper.ApplyAll(migrationBuilder) into migration..."
149
+
150
+ # Add using directive if not present
151
+ if ! grep -q "using SmartStack.Infrastructure.Persistence.SqlObjects;" "$MIGRATION_FILE"; then
152
+ sed -i '1s/^/using SmartStack.Infrastructure.Persistence.SqlObjects;\n/' "$MIGRATION_FILE"
153
+ fi
154
+
155
+ # Add SqlObjectHelper.ApplyAll at the end of Up() method
156
+ # Find the closing brace of Up() and insert before it
157
+ sed -i '/protected override void Up/,/^ }/ {
158
+ /^ }/ i\
159
+ \ // Apply SQL objects (TVF, Views, SP) from embedded resources\
160
+ \ SqlObjectHelper.ApplyAll(migrationBuilder);
161
+ }' "$MIGRATION_FILE"
162
+
163
+ echo " ✅ SqlObjectHelper.ApplyAll(migrationBuilder) injected"
164
+ find "$SQL_OBJECTS_DIR" -name "*.sql" -exec basename {} \; | while read f; do
165
+ echo " 📄 $f"
166
+ done
167
+ else
168
+ echo ""
169
+ echo "No SQL objects found in SqlObjects/ - skipping injection"
170
+ fi
171
+ ```
172
+
134
173
  ---
135
174
 
136
175
  ## EXPECTED RESULT:
@@ -108,7 +108,7 @@ The loop only stops when this exact tag is output or max iterations reached.
108
108
  </ralph_concept>
109
109
 
110
110
  <workflow>
111
- **Standard flow:**
111
+ **Standard flow (single module):**
112
112
  1. Parse flags and task description
113
113
  2. Verify MCP servers are available (MANDATORY)
114
114
  3. Initialize .ralph/ structure and state files
@@ -117,6 +117,15 @@ The loop only stops when this exact tag is output or max iterations reached.
117
117
  6. Commit changes, update progress
118
118
  7. Check completion criteria
119
119
  8. If complete: generate final report
120
+
121
+ **Multi-module flow (from BA handoff):**
122
+ 1-3. Same as standard flow
123
+ 4. Detect `prd-*.json` files → create `modules-queue.json`
124
+ 5. Copy current module's prd to `prd.json`
125
+ 6. Execute all tasks for current module (standard loop: steps 01→02→03→04)
126
+ 7. When module complete: advance to next module in queue
127
+ 8. Repeat steps 5-7 for each module
128
+ 9. When all modules done: generate cross-module report
120
129
  </workflow>
121
130
 
122
131
  <state_variables>
@@ -136,6 +145,8 @@ The loop only stops when this exact tag is output or max iterations reached.
136
145
  | `{task_category}` | string | Task category (domain/application/infrastructure/api/frontend/i18n/test/validation) |
137
146
  | `{files_created}` | string[] | Files created during current task |
138
147
  | `{files_modified}` | string[] | Files modified during current task |
148
+ | `{current_module}` | string\|null | Current module code (multi-module only) |
149
+ | `{modules_queue}` | object\|null | Module queue state (multi-module only) |
139
150
 
140
151
  </state_variables>
141
152
 
@@ -184,14 +195,33 @@ Before ANY work, verify MCP servers:
184
195
 
185
196
  ```
186
197
  .ralph/
187
- ├── prd.json # Task list with status
188
- ├── progress.txt # Persistent memory between iterations
198
+ ├── prd.json # Task list with status (current module or single)
199
+ ├── progress.txt # Persistent memory between iterations
200
+ ├── modules-queue.json # Multi-module tracking (only if multiple prd-*.json exist)
201
+ ├── prd-{module1}.json # Per-module PRD from BA handoff (source, not modified)
202
+ ├── prd-{module2}.json # Per-module PRD from BA handoff (source, not modified)
189
203
  ├── logs/
190
204
  │ └── {timestamp}.log
191
205
  └── reports/
192
206
  └── {feature-name}.md
193
207
  ```
194
208
 
209
+ **modules-queue.json structure (multi-module only):**
210
+ ```json
211
+ {
212
+ "modules": [
213
+ {
214
+ "code": "module-code",
215
+ "prdFile": ".ralph/prd-module-code.json",
216
+ "status": "pending|in-progress|completed|failed|partial"
217
+ }
218
+ ],
219
+ "currentIndex": 0,
220
+ "totalModules": 3,
221
+ "completedModules": 0
222
+ }
223
+ ```
224
+
195
225
  **prd.json structure:**
196
226
  ```json
197
227
  {
@@ -267,6 +297,8 @@ Before ANY work, verify MCP servers:
267
297
  - Completion promise output when genuinely complete
268
298
  - Final report generated in `.ralph/reports/`
269
299
  - `prd.json` top-level `status` set to `"completed"` or `"partial"`
300
+ - **Multi-module:** All modules in `modules-queue.json` processed sequentially
301
+ - **Multi-module:** Cross-module aggregation in final report
270
302
  </success_criteria>
271
303
 
272
304
  <available_commands>
@@ -163,6 +163,22 @@ fi
163
163
  - Read `prd.config.completion_promise` → `{completion_promise}`
164
164
  - Read `prd.config.max_iterations` → `{max_iterations}`
165
165
  - Read progress.txt for context
166
+
167
+ 6. **Restore multi-module state (if applicable):**
168
+ ```javascript
169
+ if (fileExists('.ralph/modules-queue.json')) {
170
+ const queue = readJSON('.ralph/modules-queue.json');
171
+ const currentModule = queue.modules[queue.currentIndex];
172
+
173
+ // Restore module state
174
+ {modules_queue} = queue;
175
+ {current_module} = currentModule.code;
176
+
177
+ console.log(`Resuming multi-module: ${currentModule.code} (${queue.currentIndex + 1}/${queue.totalModules})`);
178
+ console.log(`Modules completed: ${queue.completedModules}/${queue.totalModules}`);
179
+ }
180
+ ```
181
+
166
182
  - Continue to step-01
167
183
 
168
184
  ### 4. Initialize .ralph/ Structure (new loop)
@@ -183,6 +199,80 @@ mkdir -p .ralph/logs
183
199
  mkdir -p .ralph/reports
184
200
  ```
185
201
 
202
+ ### 4b. Detect Multi-Module PRDs (from BA Handoff)
203
+
204
+ **After creating `.ralph/` directory, check for per-module PRD files:**
205
+
206
+ ```bash
207
+ # Count prd-*.json files (generated by BA handoff via ss derive-prd)
208
+ PRD_FILES=$(ls .ralph/prd-*.json 2>/dev/null)
209
+ PRD_COUNT=$(echo "$PRD_FILES" | grep -c "prd-" 2>/dev/null || echo "0")
210
+ ```
211
+
212
+ **If multiple prd-*.json files found (PRD_COUNT > 0):**
213
+
214
+ 1. **Read module order from master feature.json (if available):**
215
+ ```bash
216
+ # Look for master feature.json that references modules
217
+ MASTER_FEATURE=$(find docs/business -maxdepth 4 -name "feature.json" -path "*/business-analyse/*" | head -1)
218
+ ```
219
+
220
+ 2. **Build module queue:**
221
+ ```javascript
222
+ const modules = [];
223
+
224
+ if (MASTER_FEATURE && masterJson.metadata?.workflow?.moduleOrder) {
225
+ // Use order from BA master feature.json
226
+ for (const mod of masterJson.metadata.workflow.moduleOrder) {
227
+ const prdFile = `.ralph/prd-${mod.code}.json`;
228
+ if (fileExists(prdFile)) {
229
+ modules.push({ code: mod.code, prdFile, status: "pending" });
230
+ }
231
+ }
232
+ } else {
233
+ // Fallback: alphabetical order from prd-*.json filenames
234
+ for (const file of prdFiles) {
235
+ const code = file.match(/prd-(.+)\.json$/)[1];
236
+ modules.push({ code, prdFile: `.ralph/${file}`, status: "pending" });
237
+ }
238
+ }
239
+ ```
240
+
241
+ 3. **Create modules-queue.json:**
242
+ ```json
243
+ {
244
+ "modules": [
245
+ { "code": "mod1", "prdFile": ".ralph/prd-mod1.json", "status": "pending" },
246
+ { "code": "mod2", "prdFile": ".ralph/prd-mod2.json", "status": "pending" }
247
+ ],
248
+ "currentIndex": 0,
249
+ "totalModules": 2,
250
+ "completedModules": 0
251
+ }
252
+ ```
253
+
254
+ 4. **Set first module as active:**
255
+ ```javascript
256
+ modules[0].status = "in-progress";
257
+ ```
258
+
259
+ 5. **Log detection:**
260
+ ```
261
+ Multi-module detected: {PRD_COUNT} modules
262
+ Queue: {module codes joined by " → "}
263
+ Starting with: {modules[0].code}
264
+ ```
265
+
266
+ **If only `.ralph/prd.json` exists (single module):**
267
+ - Skip queue creation (backward compatible)
268
+ - Proceed normally
269
+
270
+ **Store:**
271
+ ```
272
+ {modules_queue} = queue object or null
273
+ {current_module} = first module code or null
274
+ ```
275
+
186
276
  ### 5. Validate Completion Promise
187
277
 
188
278
  **If {completion_promise} is null:**
@@ -251,10 +341,12 @@ Branch: {CURRENT_BRANCH}
251
341
  ║ MCP: ✅ Ready ║
252
342
  ║ Schema: v2.0.0 ║
253
343
  ║ Branch: {CURRENT_BRANCH} ║
344
+ ║ {modules_queue ? "Modules: " + totalModules + " (" + module_codes.join(" → ") + ")" : "Mode: single module"} ║
254
345
  ╠══════════════════════════════════════════════════════════════════╣
255
346
  ║ Files: ║
256
347
  ║ - .ralph/prd.json (tasks) ║
257
348
  ║ - .ralph/progress.txt (memory) ║
349
+ ║ {modules_queue ? "- .ralph/modules-queue.json (module tracking)" : ""} ║
258
350
  ╚══════════════════════════════════════════════════════════════════╝
259
351
 
260
352
  -> Loading tasks...
@@ -273,6 +365,7 @@ Branch: {CURRENT_BRANCH}
273
365
  - Metadata collected (branch, version, MCP status)
274
366
  - prd.json v2 schema validated (if resume)
275
367
  - Branch integrity validated (if resume)
368
+ - Multi-module prd files detected and modules-queue.json created (if applicable)
276
369
  - Output is COMPACT
277
370
  - Proceeded to step-01 immediately after summary
278
371