@atlashub/smartstack-cli 4.46.0 → 4.48.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlashub/smartstack-cli",
3
- "version": "4.46.0",
3
+ "version": "4.48.0",
4
4
  "description": "SmartStack Claude Code automation toolkit - GitFlow, EF Core migrations, prompts and more",
5
5
  "author": {
6
6
  "name": "SmartStack",
@@ -127,6 +127,20 @@ For each module, update screens.json to embed wireframes at the resource level:
127
127
 
128
128
  Write via ba-writer for each module. Update index.json hashes.
129
129
 
130
+ ## Consumer Contract (wireframe field names)
131
+
132
+ > **IMPORTANT:** Downstream consumers (`/business-analyse-html`) depend on these EXACT field names.
133
+ > Any rename requires updating `business-analyse-html/steps/step-02-build-data.md` (wireframe mapping).
134
+
135
+ | Field | Type | Description |
136
+ |-------|------|-------------|
137
+ | `mockupFormat` | `"ascii"` \| `"html"` | Wireframe rendering format |
138
+ | `mockup` | string | Wireframe content (ASCII art or HTML) |
139
+ | `elements` | string[] | UI element names |
140
+ | `componentMapping` | object[] | Wireframe element → React component mapping |
141
+ | `layout` | object | Layout type and regions |
142
+ | `permissionsRequired` | string[] | Permission paths needed |
143
+
130
144
  ## Validation
131
145
 
132
146
  - [ ] Every resource has a wireframe object
@@ -149,6 +149,8 @@ When the user invokes `/business-analyse-develop`, they are giving you the instr
149
149
  - Ask the user to choose between supervised/autonomous mode
150
150
  - Wait for user input between modules
151
151
  - Delegate the loop to sub-agents (except team mode and /apex delegation)
152
+ - Display a progress report then ask "shall I continue?" or present options (1/2/3)
153
+ - Pause because the scope is "large" or "ambitious" — execute ALL of it regardless of size
152
154
 
153
155
  **The ONLY valid stop conditions are:**
154
156
  - ALL objectives met / ALL tasks completed (→ report)
@@ -22,7 +22,7 @@ const queuePath = '.ralph/modules-queue.json';
22
22
  let currentPrdPath = '.ralph/prd.json';
23
23
  if (fileExists(queuePath)) {
24
24
  const queue = readJSON(queuePath);
25
- currentPrdPath = queue.queue[queue.currentIndex].prdFile;
25
+ currentPrdPath = queue.modules[queue.currentIndex].prdFile;
26
26
  }
27
27
  ```
28
28
 
@@ -226,6 +226,20 @@ for (const task of batch) {
226
226
  writeJSON(currentPrdPath, prd);
227
227
  ```
228
228
 
229
+ ### B1b. State Persistence (before delegation)
230
+
231
+ ```javascript
232
+ // Write state BEFORE delegating to apex so position survives context compression
233
+ writeJSON('.ralph/ralph-state.json', {
234
+ currentStep: 'compact-loop',
235
+ nextStep: 'step-04-check',
236
+ currentModule: {current_module},
237
+ phase: 'apex-delegating',
238
+ iteration: prdCheck?.config?.current_iteration || 'unknown',
239
+ timestamp: new Date().toISOString()
240
+ });
241
+ ```
242
+
229
243
  ### B2. Invoke /apex
230
244
 
231
245
  **INVOKE `/apex -d {currentPrdPath}`**
@@ -122,11 +122,21 @@ if (missing.length === 0) {
122
122
  // CONTEXT REFRESH: Force /compact between modules to prevent context degradation
123
123
  // (audit ba-002: quality degraded progressively — module 2 had more errors than module 1
124
124
  // because patterns from module 1 were lost during context compaction)
125
+ // STATE PERSISTENCE: Write state BEFORE compaction so position survives context compression
126
+ writeJSON('.ralph/ralph-state.json', {
127
+ currentStep: 'step-01-task',
128
+ currentModule: queue.modules[nextIndex].code,
129
+ reason: 'module-transition',
130
+ fromModule: currentModule.code,
131
+ timestamp: new Date().toISOString()
132
+ });
133
+
125
134
  console.log('Forcing /compact for fresh context before next module...');
126
135
  // The /compact command clears accumulated tool results and intermediate reasoning,
127
136
  // preserving only key decisions and the current state. This ensures the next module
128
137
  // starts with a clean context window instead of degraded fragments from the previous module.
129
138
  // INVOKE /compact
139
+ // After compaction: read .ralph/ralph-state.json to recover position if context lost
130
140
 
131
141
  // Return to step-01 to load next module's tasks
132
142
  // (step-01 will detect module-changed.json and load next PRD)
@@ -58,6 +58,8 @@ Ralph-loop is FULLY AUTONOMOUS by default. It executes ALL tasks from start to f
58
58
 
59
59
  **DO NOT** ask the user to confirm, choose a mode, or approve execution.
60
60
  **DO NOT** set max_iterations = 1 or any reduced value.
61
+ **DO NOT** display a progress report and then ask "shall I continue?" or present numbered options.
62
+ **DO NOT** pause because the scope seems large — 500+ files across 11 modules is NORMAL. Execute ALL of it.
61
63
 
62
64
  The loop runs autonomously until:
63
65
  - ALL tasks are completed (success)
@@ -89,6 +91,51 @@ See `references/multi-module-queue.md` for queue initialization.
89
91
 
90
92
  Quick: `glob('.ralph/prd-*.json').length > 1` → create modules-queue.json
91
93
 
94
+ ### 4b+. Normalize modules-queue.json (backward-compat with handoff v1 format)
95
+
96
+ ```javascript
97
+ const queuePath = '.ralph/modules-queue.json';
98
+ if (fileExists(queuePath)) {
99
+ const raw = readJSON(queuePath);
100
+ let dirty = false;
101
+
102
+ // RC1: Rename "queue" → "modules" property (handoff v1 used "queue")
103
+ if (raw.queue && !raw.modules) {
104
+ raw.modules = raw.queue;
105
+ delete raw.queue;
106
+ dirty = true;
107
+ }
108
+
109
+ // RC2: Rename "moduleCode" → "code" in each entry (handoff v1 used "moduleCode")
110
+ for (const mod of (raw.modules || [])) {
111
+ if (mod.moduleCode && !mod.code) {
112
+ mod.code = mod.moduleCode;
113
+ delete mod.moduleCode;
114
+ dirty = true;
115
+ }
116
+ }
117
+
118
+ // RC3: Add missing fields
119
+ if (raw.currentIndex === undefined) { raw.currentIndex = 0; dirty = true; }
120
+ if (raw.completedModules === undefined) { raw.completedModules = 0; dirty = true; }
121
+ if (raw.totalModules === undefined) { raw.totalModules = raw.modules?.length || 0; dirty = true; }
122
+ for (const mod of (raw.modules || [])) {
123
+ if (!mod.prdFile) { mod.prdFile = `.ralph/prd-${mod.code}.json`; dirty = true; }
124
+ if (!mod.status) { mod.status = 'pending'; dirty = true; }
125
+ }
126
+ // Set first module to in-progress if none started
127
+ if (raw.modules?.length && !raw.modules.some(m => m.status !== 'pending')) {
128
+ raw.modules[0].status = 'in-progress';
129
+ dirty = true;
130
+ }
131
+
132
+ if (dirty) {
133
+ writeJSON(queuePath, raw);
134
+ console.log('modules-queue.json normalized (format v2)');
135
+ }
136
+ }
137
+ ```
138
+
92
139
  ---
93
140
 
94
141
  ## 4c. Team Orchestration (multi-module LEGACY — dependency layer mode only)
@@ -173,4 +220,16 @@ MCP: Ready | Branch: {branch} | PRD: v{prd_version}
173
220
  -> Loading spec...
174
221
  ```
175
222
 
223
+ ### 7b. Initialize State File (context compression defense)
224
+
225
+ ```javascript
226
+ writeJSON('.ralph/ralph-state.json', {
227
+ currentStep: 'step-01-task',
228
+ currentModule: {current_module},
229
+ iteration: 1,
230
+ prdVersion: {prd_version},
231
+ timestamp: new Date().toISOString()
232
+ });
233
+ ```
234
+
176
235
  **Proceed directly to step-01-task.md**
@@ -6,6 +6,9 @@ next_step: steps/step-02-execute.md
6
6
 
7
7
  # Step 1: Load Task
8
8
 
9
+ > **STATE RECOVERY:** If you are unsure which step you are executing (e.g., after context compression),
10
+ > read `.ralph/ralph-state.json` to recover your position.
11
+
9
12
  > **MODULE TRANSITION CHECK:** Before "Only Read Once" rule, check for module transition:
10
13
 
11
14
  ```javascript
@@ -52,7 +55,7 @@ const queuePath = '.ralph/modules-queue.json';
52
55
  let currentPrdPath = '.ralph/prd.json';
53
56
  if (fileExists(queuePath)) {
54
57
  const queue = readJSON(queuePath);
55
- currentPrdPath = queue.queue[queue.currentIndex].prdFile;
58
+ currentPrdPath = queue.modules[queue.currentIndex].prdFile;
56
59
  }
57
60
  ```
58
61
 
@@ -7,6 +7,12 @@ next_step: steps/step-02-v4-verify.md
7
7
 
8
8
  # Step 01-v4: Continuous Module Execution
9
9
 
10
+ ## EXECUTION GUARANTEE — AUTONOMY RULES (MANDATORY)
11
+
12
+ > **NEVER stop between modules.** NEVER ask "shall I continue?". NEVER present options (1/2/3).
13
+ > **NEVER pause after a progress report.** Progress reports are LOG OUTPUT ONLY — print them and IMMEDIATELY continue to the next module.
14
+ > **The user invoked /business-analyse-develop to execute ALL modules to completion.** That is your mandate. Any stop that is not: all-complete, dead-end, or Ctrl+C is a **VIOLATION**.
15
+
10
16
  ## YOUR TASK
11
17
 
12
18
  For each module in topological order, delegate the ENTIRE module implementation to `/apex -d` in a continuous session. Run quality gates at natural checkpoints. Let server-side compaction manage context.
@@ -102,12 +108,14 @@ grep -rn "Assert.True(true)\|Assert.Pass()\|// TODO\|throw new NotImplementedExc
102
108
 
103
109
  If found → delegate fix to apex: "Replace stub tests with real implementations"
104
110
 
105
- ### 7. Module Complete
111
+ ### 7. Module Complete — CONTINUE IMMEDIATELY
106
112
 
107
113
  When ALL gates pass for a module:
108
114
  1. Log checkpoint: `"Module {moduleCode}: ALL GATES PASS"`
109
115
  2. Optionally append to progress.txt (human checkpoint)
110
- 3. Advance to next module in queue
116
+ 3. **IMMEDIATELY** advance to next module in queue — DO NOT pause, DO NOT ask user, DO NOT present options
117
+
118
+ > **ANTI-STOP GUARD:** After logging the progress report, your VERY NEXT action MUST be starting the next module delegation (`/apex -d`). If there are no more modules, go to step-02-v4-verify. Outputting a progress report and then waiting for user input is a **VIOLATION** of the execution guarantee.
111
119
 
112
120
  ---
113
121
 
@@ -35,7 +35,7 @@ const queuePath = '.ralph/modules-queue.json';
35
35
  let currentPrdPath = '.ralph/prd.json';
36
36
  if (fileExists(queuePath)) {
37
37
  const queue = readJSON(queuePath);
38
- currentPrdPath = queue.queue[queue.currentIndex].prdFile;
38
+ currentPrdPath = queue.modules[queue.currentIndex].prdFile;
39
39
  }
40
40
 
41
41
  const prd = readJSON(currentPrdPath);
@@ -75,6 +75,19 @@ See `references/parallel-execution.md` for complete parallel protocol:
75
75
 
76
76
  Continue with section-split mode or standard mode below.
77
77
 
78
+ #### 3a+. State Persistence (before delegation)
79
+
80
+ ```javascript
81
+ // Write state BEFORE delegating to apex so position survives context compression
82
+ writeJSON('.ralph/ralph-state.json', {
83
+ currentStep: 'step-02-execute',
84
+ nextStep: 'step-03-commit',
85
+ currentModule: {current_module},
86
+ phase: 'apex-delegating',
87
+ timestamp: new Date().toISOString()
88
+ });
89
+ ```
90
+
78
91
  #### 3b. Section-Split Mode
79
92
 
80
93
  ```javascript
@@ -12,6 +12,19 @@ After ALL modules are implemented, run final verification across the ENTIRE proj
12
12
 
13
13
  ---
14
14
 
15
+ ## VERSION GUARD
16
+
17
+ ```javascript
18
+ // This step is ONLY for v4 PRDs. If a v3 PRD reaches here, route back to step-05-report.md.
19
+ const prd = readJSON(currentPrdPath);
20
+ if (prd.$version !== '4.0.0') {
21
+ console.error(`step-02-v4-verify loaded with $version=${prd.$version} — expected 4.0.0`);
22
+ console.log('Routing to step-05-report.md (v3 report generation)');
23
+ // → Load steps/step-05-report.md instead
24
+ return;
25
+ }
26
+ ```
27
+
15
28
  ## FINAL VERIFICATION SEQUENCE
16
29
 
17
30
  ### 1. Full Solution Build
@@ -39,11 +52,18 @@ npm test -- --run 2>&1
39
52
 
40
53
  ### 4. File Reconciliation
41
54
 
42
- For each module's PRD, compare `expectedFiles` against actual files on disk:
55
+ For each module's PRD, compare expected files against actual files on disk:
43
56
 
44
57
  ```javascript
58
+ // v4 uses prd.expectedFiles, v3 uses prd.implementation.filesToCreate (guard: should be v4 here)
59
+ const fileManifest = prd.expectedFiles || prd.implementation?.filesToCreate;
60
+ if (!fileManifest) {
61
+ console.error('BLOCKING: PRD has no file manifest (neither expectedFiles nor implementation.filesToCreate)');
62
+ STOP;
63
+ }
64
+
45
65
  for (const category of ['domain', 'application', 'infrastructure', 'api', 'frontend', 'seedData', 'tests', 'documentation']) {
46
- const expected = prd.expectedFiles[category] || [];
66
+ const expected = fileManifest[category] || [];
47
67
  for (const file of expected) {
48
68
  if (!existsOnDisk(file.path)) {
49
69
  MISSING.push({ category, path: file.path, type: file.type });
@@ -27,7 +27,7 @@ const queuePath = '.ralph/modules-queue.json';
27
27
  let currentPrdPath = '.ralph/prd.json';
28
28
  if (fileExists(queuePath)) {
29
29
  const queue = readJSON(queuePath);
30
- currentPrdPath = queue.queue[queue.currentIndex].prdFile;
30
+ currentPrdPath = queue.modules[queue.currentIndex].prdFile;
31
31
  }
32
32
 
33
33
  const prd = readJSON(currentPrdPath);
@@ -6,6 +6,9 @@ next_step: steps/step-05-report.md OR steps/step-01-task.md
6
6
 
7
7
  # Step 4: Check Completion
8
8
 
9
+ > **STATE RECOVERY:** If you are unsure which step you are executing (e.g., after context compression),
10
+ > read `.ralph/ralph-state.json` to recover your position.
11
+
9
12
  ## YOUR TASK:
10
13
 
11
14
  Check if all tasks are complete and decide: output completion promise, advance module, or continue loop.
@@ -20,7 +23,7 @@ const queuePath = '.ralph/modules-queue.json';
20
23
  let currentPrdPath = '.ralph/prd.json';
21
24
  if (fileExists(queuePath)) {
22
25
  const queue = readJSON(queuePath);
23
- currentPrdPath = queue.queue[queue.currentIndex].prdFile;
26
+ currentPrdPath = queue.modules[queue.currentIndex].prdFile;
24
27
  }
25
28
 
26
29
  const prd = readJSON(currentPrdPath);
@@ -80,6 +80,47 @@ ss business-analyse-handoff --feature {path} --output .ralph/prd-{moduleCode}.js
80
80
 
81
81
  ---
82
82
 
83
+ ### 2b. PRD v4.0 Structure (spec-oriented)
84
+
85
+ > **v4 PRDs are generated with `--v4` flag.** They use `expectedFiles` instead of `implementation.filesToCreate`.
86
+
87
+ ```json
88
+ {
89
+ "$version": "4.0.0",
90
+ "objectives": [
91
+ { "description": "...", "acceptanceCriteria": ["..."] }
92
+ ],
93
+ "expectedFiles": {
94
+ "domain": [...],
95
+ "application": [...],
96
+ "infrastructure": [...],
97
+ "api": [...],
98
+ "frontend": [...],
99
+ "seedData": [...],
100
+ "tests": [...],
101
+ "documentation": [...]
102
+ },
103
+ "gates": { /* declarative quality gate definitions */ }
104
+ }
105
+ ```
106
+
107
+ **Key differences from v3:**
108
+
109
+ | Aspect | v3 (`$version: "3.0.0"`) | v4 (`$version: "4.0.0"`) |
110
+ |--------|--------------------------|--------------------------|
111
+ | File manifest | `implementation.filesToCreate` | `expectedFiles` (root level) |
112
+ | Task model | `tasks[]` (pre-computed) | `objectives[]` (goal-oriented) |
113
+ | Execution | Batch iterations (compact-loop) | Continuous (compaction-enabled) |
114
+
115
+ **Consumer code must handle both:**
116
+ ```javascript
117
+ const fileManifest = prd.$version === '4.0.0'
118
+ ? prd.expectedFiles
119
+ : prd.implementation?.filesToCreate;
120
+ ```
121
+
122
+ ---
123
+
83
124
  ### 3. Eight Categories (MANDATORY)
84
125
 
85
126
  All PRD files MUST include these 8 categories under `implementation.filesToCreate`:
@@ -157,7 +157,9 @@ After writing, verify:
157
157
  2. All 8 categories present
158
158
  3. brToCodeMapping non-empty
159
159
  4. Section resources have entity field
160
- Display: "POST-CHECK PASS: {moduleCode} -- 8 categories, {brCount} BRs mapped"
160
+ 5. SeedData contains CORE entries (NavigationModuleSeedData, NavigationSectionSeedData if sections exist, PermissionsSeedData, RolesSeedData)
161
+ 6. For FIRST module only: SeedData contains APP-LEVEL CORE entries (NavigationApplicationSeedData, ApplicationRolesSeedData)
162
+ Display: "POST-CHECK PASS: {moduleCode} -- 8 categories, {brCount} BRs mapped, {coreCount} core seeds"
161
163
  ```
162
164
 
163
165
  ### 3. Display Progress
@@ -99,11 +99,13 @@ Display verification table showing all 8 categories match between module JSON fi
99
99
 
100
100
  ```json
101
101
  {
102
- "queue": [
103
- { "moduleCode": "{code}", "order": 1, "dependencies": [], "complexity": "simple" },
104
- { "moduleCode": "{code}", "order": 2, "dependencies": ["{dep}"], "complexity": "medium" }
102
+ "modules": [
103
+ { "code": "{code}", "prdFile": ".ralph/prd-{code}.json", "status": "pending", "order": 1, "dependencies": [], "complexity": "simple" },
104
+ { "code": "{code}", "prdFile": ".ralph/prd-{code}.json", "status": "pending", "order": 2, "dependencies": ["{dep}"], "complexity": "medium" }
105
105
  ],
106
- "totalModules": {count},
106
+ "currentIndex": 0,
107
+ "totalModules": "{count}",
108
+ "completedModules": 0,
107
109
  "strategy": "topological"
108
110
  }
109
111
  ```
@@ -198,13 +198,34 @@ handoff: {
198
198
 
199
199
  ```javascript
200
200
  const mod = collected_data.modules[moduleCode];
201
- const screens = mod.screens?.screens || [];
202
201
 
203
- // Extract wireframes from screens that have mockup/wireframe data
202
+ // STEP 1: Collect wireframe sources from BOTH flat and nested structures
203
+ // Flat: mod.screens.screens[] with mockupFormat/mockup at top level
204
+ // Nested: mod.screens.sections[].resources[].wireframe (design step output)
205
+ let rawWireframes = [];
206
+
207
+ // Source A: flat screens[] array (original BA output or manually enriched)
208
+ const flatScreens = mod.screens?.screens || [];
209
+ rawWireframes.push(...flatScreens.filter(s => s.mockup || s.mockupFormat));
210
+
211
+ // Source B: nested sections[].resources[].wireframe (design step output)
212
+ const sections = mod.screens?.sections || [];
213
+ for (const section of sections) {
214
+ for (const resource of (section.resources || [])) {
215
+ if (resource.wireframe) {
216
+ // Unwrap nested wireframe and add section context
217
+ rawWireframes.push({
218
+ ...resource.wireframe,
219
+ section: resource.wireframe.section || section.sectionCode || "",
220
+ screen: resource.wireframe.screen || `${section.sectionCode}-${resource.code}` || ""
221
+ });
222
+ }
223
+ }
224
+ }
225
+
226
+ // STEP 2: Map to HTML format (RENAME: mockupFormat → format, mockup → content)
204
227
  wireframes: {
205
- [moduleCode]: screens
206
- .filter(s => s.wireframe || s.mockup || s.mockupFormat)
207
- .map(wf => ({
228
+ [moduleCode]: rawWireframes.map(wf => ({
208
229
  screen: wf.screen || wf.name || wf.title || wf.id || "",
209
230
  section: wf.section || "",
210
231
  format: wf.mockupFormat || "ascii", // RENAME: mockupFormat → format