@atlashub/smartstack-cli 4.45.0 → 4.47.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.45.0",
3
+ "version": "4.47.0",
4
4
  "description": "SmartStack Claude Code automation toolkit - GitFlow, EF Core migrations, prompts and more",
5
5
  "author": {
6
6
  "name": "SmartStack",
@@ -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)
@@ -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)
@@ -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
 
@@ -16,8 +16,8 @@
16
16
  | `entities.json` | Entity definitions | `entities[]` | — |
17
17
  | `rules.json` | Business rules | `rules[]` | `businessRules[]` |
18
18
  | `usecases.json` | Use cases | `useCases[]` | `usecases[]` (lowercase) |
19
- | `permissions.json` | Roles and permission matrix | `permissionPaths[]` | `permissionSet.permissions[]`, `permissions[]`, `actions[]` |
20
- | `screens.json` | UI screen specifications | `screens[]` | `sections[].resources[]` |
19
+ | `permissions.json` | Roles and permission matrix | `permissionPaths[]` | `permissionSet.permissions[]`, `basePermissions[]`, `actions[]`, `permissions[]` |
20
+ | `screens.json` | UI screen specifications | `screens[]` | `sections[].resources[]`, `sections[]`, `wireframes[]` |
21
21
 
22
22
  The validation script **assembles** these files before checking.
23
23
 
@@ -66,17 +66,30 @@ const fs = require('fs');
66
66
  const path = require('path');
67
67
  const dir = process.argv[1];
68
68
 
69
- // Load index.json
70
- const index = JSON.parse(fs.readFileSync(path.join(dir, 'index.json'), 'utf-8'));
69
+ // Load index.json (optional — may not exist at module level)
70
+ let index = {};
71
+ const indexPath = path.join(dir, 'index.json');
72
+ if (fs.existsSync(indexPath)) {
73
+ index = JSON.parse(fs.readFileSync(indexPath, 'utf-8'));
74
+ }
71
75
  const files = index.files || {};
72
76
 
73
- // Load flat files (with fallbacks)
77
+ // Load flat files: try index.json refs first, fallback to direct file load
74
78
  function loadFile(key) {
79
+ // Strategy 1: resolve via index.json > files references
75
80
  const ref = files[key];
76
- if (!ref || !ref.path) return null;
77
- const filePath = path.join(dir, ref.path);
78
- if (!fs.existsSync(filePath)) return null;
79
- return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
81
+ if (ref && ref.path) {
82
+ const filePath = path.join(dir, ref.path);
83
+ if (fs.existsSync(filePath)) {
84
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
85
+ }
86
+ }
87
+ // Strategy 2: direct file load (module dirs without index.json)
88
+ const directPath = path.join(dir, key + '.json');
89
+ if (fs.existsSync(directPath)) {
90
+ return JSON.parse(fs.readFileSync(directPath, 'utf-8'));
91
+ }
92
+ return null;
80
93
  }
81
94
 
82
95
  const entitiesData = loadFile('entities') || {};
@@ -91,19 +104,40 @@ const hasReferencedEntities = (entitiesData.referencedEntities || []).length > 0
91
104
  const useCases = usecasesData.useCases || usecasesData.usecases || [];
92
105
  const rules = rulesData.rules || rulesData.businessRules || [];
93
106
 
94
- // Permissions: canonical permissionPaths[] OR extract from nested structures
95
- const permissions = permissionsData.permissionPaths
96
- || (permissionsData.permissionSet && permissionsData.permissionSet.permissions || []).map(function(p) { return p.code || p.path || ''; })
97
- || (permissionsData.permissions || []).map(function(p) { return typeof p === 'string' ? p : (p.code || p.path || ''); })
98
- || (permissionsData.actions || []).map(function(a) { return a.code || ''; })
99
- || [];
100
-
101
- // Screens: canonical screens[] OR flatten sections[].resources[]
102
- const screens = screensData.screens || [];
103
- const sectionsAsScreens = (screensData.sections || []).reduce(function(acc, s) { return acc.concat(s.resources || []); }, []);
104
- const allScreens = screens.length > 0 ? screens : sectionsAsScreens;
107
+ // Permissions: try all known variants, extract into flat array
108
+ function extractPermissions(data) {
109
+ if (data.permissionPaths && data.permissionPaths.length > 0) return data.permissionPaths;
110
+ if (data.permissionSet && data.permissionSet.permissions && data.permissionSet.permissions.length > 0) {
111
+ return data.permissionSet.permissions.map(function(p) { return p.code || p.path || ''; });
112
+ }
113
+ if (data.basePermissions && data.basePermissions.length > 0) {
114
+ return data.basePermissions.map(function(p) { return p.code || p.path || ''; });
115
+ }
116
+ if (data.actions && data.actions.length > 0) {
117
+ return data.actions.map(function(a) { return a.code || ''; });
118
+ }
119
+ if (data.permissions && data.permissions.length > 0) {
120
+ return data.permissions.map(function(p) { return typeof p === 'string' ? p : (p.code || p.path || ''); });
121
+ }
122
+ return [];
123
+ }
124
+ const permissions = extractPermissions(permissionsData);
125
+
126
+ // Screens: canonical screens[] OR sections[] (with or without .resources sub-array)
127
+ function extractScreens(data) {
128
+ if (data.screens && data.screens.length > 0) return data.screens;
129
+ if (data.sections && data.sections.length > 0) {
130
+ // sections may contain resources[] or be screens themselves
131
+ var fromResources = data.sections.reduce(function(acc, s) { return acc.concat(s.resources || []); }, []);
132
+ return fromResources.length > 0 ? fromResources : data.sections;
133
+ }
134
+ if (data.wireframes && data.wireframes.length > 0) return data.wireframes;
135
+ return [];
136
+ }
137
+ const allScreens = extractScreens(screensData);
105
138
 
106
- const status = index.metadata?.status || 'unknown';
139
+ // Status: from index.json if present, or 'specified' if module has thematic files but no index.json
140
+ const status = (index.metadata && index.metadata.status) || (Object.keys(index).length === 0 ? 'specified' : 'unknown');
107
141
 
108
142
  const fails = [];
109
143
 
@@ -71,32 +71,27 @@ FOR each module:
71
71
 
72
72
  ### 4. Load Flat Files Per Module
73
73
 
74
- For each module, load the separate JSON files referenced in `index.json > files`:
74
+ For each module, load the separate JSON files directly (index.json may not exist at module level):
75
75
 
76
76
  ```javascript
77
- // Module index.json contains file references:
78
- // { "files": { "entities": { "path": "entities.json" }, "usecases": { "path": "usecases.json" }, ... } }
79
-
80
- const entitiesData = READ(moduleDir + '/entities.json');
81
- const usecasesData = READ(moduleDir + '/usecases.json');
82
- const rulesData = READ(moduleDir + '/rules.json');
83
- const permissionsData = READ(moduleDir + '/permissions.json');
84
- const screensData = READ(moduleDir + '/screens.json');
77
+ // Load thematic files directly from module directory
78
+ const entitiesData = READ(moduleDir + '/entities.json') || {};
79
+ const usecasesData = READ(moduleDir + '/usecases.json') || {};
80
+ const rulesData = READ(moduleDir + '/rules.json') || {};
81
+ const permissionsData = READ(moduleDir + '/permissions.json') || {};
82
+ const screensData = READ(moduleDir + '/screens.json') || {};
85
83
 
86
84
  // NORMALISATION: tolerate ba-writer + LLM field name variants
85
+ // See acceptance-criteria.md for the full extraction functions
87
86
  const moduleData = {
88
- index: READ(moduleDir + '/index.json'),
89
87
  entities: entitiesData.entities || [],
90
88
  hasReferencedEntities: (entitiesData.referencedEntities || []).length > 0,
91
89
  useCases: usecasesData.useCases || usecasesData.usecases || [],
92
90
  rules: rulesData.rules || rulesData.businessRules || [],
93
- permissions: permissionsData.permissionPaths
94
- || (permissionsData.permissionSet?.permissions || []).map(p => p.code || p.path)
95
- || (permissionsData.permissions || []).map(p => typeof p === 'string' ? p : (p.code || p.path))
96
- || [],
97
- screens: (screensData.screens || []).length > 0
98
- ? screensData.screens
99
- : (screensData.sections || []).flatMap(s => s.resources || [])
91
+ permissions: extractPermissions(permissionsData),
92
+ // tries: permissionPaths > permissionSet.permissions > basePermissions > actions > permissions
93
+ screens: extractScreens(screensData),
94
+ // tries: screens > sections[].resources > sections > wireframes
100
95
  };
101
96
  ```
102
97