@atlashub/smartstack-cli 4.47.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 +1 -1
- package/templates/skills/business-analyse-design/steps/step-02-wireframes.md +14 -0
- package/templates/skills/business-analyse-develop/references/compact-loop.md +15 -1
- package/templates/skills/business-analyse-develop/references/module-transition.md +10 -0
- package/templates/skills/business-analyse-develop/steps/step-00-init.md +57 -0
- package/templates/skills/business-analyse-develop/steps/step-01-task.md +4 -1
- package/templates/skills/business-analyse-develop/steps/step-02-execute.md +14 -1
- package/templates/skills/business-analyse-develop/steps/step-02-v4-verify.md +22 -2
- package/templates/skills/business-analyse-develop/steps/step-03-commit.md +1 -1
- package/templates/skills/business-analyse-develop/steps/step-04-check.md +4 -1
- package/templates/skills/business-analyse-handoff/references/prd-generation.md +41 -0
- package/templates/skills/business-analyse-handoff/steps/step-01-transform.md +3 -1
- package/templates/skills/business-analyse-handoff/steps/step-02-export.md +6 -4
- package/templates/skills/business-analyse-html/steps/step-02-build-data.md +26 -5
package/package.json
CHANGED
|
@@ -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
|
|
@@ -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.
|
|
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)
|
|
@@ -91,6 +91,51 @@ See `references/multi-module-queue.md` for queue initialization.
|
|
|
91
91
|
|
|
92
92
|
Quick: `glob('.ralph/prd-*.json').length > 1` → create modules-queue.json
|
|
93
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
|
+
|
|
94
139
|
---
|
|
95
140
|
|
|
96
141
|
## 4c. Team Orchestration (multi-module LEGACY — dependency layer mode only)
|
|
@@ -175,4 +220,16 @@ MCP: Ready | Branch: {branch} | PRD: v{prd_version}
|
|
|
175
220
|
-> Loading spec...
|
|
176
221
|
```
|
|
177
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
|
+
|
|
178
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.
|
|
58
|
+
currentPrdPath = queue.modules[queue.currentIndex].prdFile;
|
|
56
59
|
}
|
|
57
60
|
```
|
|
58
61
|
|
|
@@ -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.
|
|
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
|
|
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 =
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
-
"
|
|
103
|
-
{ "
|
|
104
|
-
{ "
|
|
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
|
-
"
|
|
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
|
-
//
|
|
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]:
|
|
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
|