@atlashub/smartstack-cli 3.22.0 → 3.23.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/dist/mcp-entry.mjs +87 -159
- package/dist/mcp-entry.mjs.map +1 -1
- package/package.json +1 -1
- package/templates/skills/apex/SKILL.md +21 -0
- package/templates/skills/apex/references/smartstack-api.md +481 -0
- package/templates/skills/apex/references/smartstack-layers.md +85 -15
- package/templates/skills/apex/steps/step-00-init.md +27 -14
- package/templates/skills/apex/steps/step-01-analyze.md +18 -0
- package/templates/skills/apex/steps/step-03-execute.md +8 -6
- package/templates/skills/apex/steps/step-04-validate.md +92 -0
- package/templates/skills/apex/steps/step-07-tests.md +29 -5
|
@@ -7,6 +7,14 @@ next_step: steps/step-01-analyze.md
|
|
|
7
7
|
|
|
8
8
|
# Step 0: Initialize
|
|
9
9
|
|
|
10
|
+
**Before anything else**, display the version banner:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
═══════════════════════════════════════════════════════════════
|
|
14
|
+
SmartStack APEX — v{{SMARTSTACK_VERSION}}
|
|
15
|
+
═══════════════════════════════════════════════════════════════
|
|
16
|
+
```
|
|
17
|
+
|
|
10
18
|
## LOAD SHARED
|
|
11
19
|
|
|
12
20
|
Read `_shared.md` for SmartStack detection patterns and MCP tools reference.
|
|
@@ -133,20 +141,25 @@ IF save_mode:
|
|
|
133
141
|
## 7. Display Context Summary
|
|
134
142
|
|
|
135
143
|
```
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
144
|
+
═══════════════════════════════════════════════════════════════
|
|
145
|
+
APEX INITIALIZATION COMPLETE
|
|
146
|
+
SmartStack CLI v{{SMARTSTACK_VERSION}}
|
|
147
|
+
═══════════════════════════════════════════════════════════════
|
|
148
|
+
|
|
149
|
+
| Field | Value |
|
|
150
|
+
|--------------------|----------------------------------------------|
|
|
151
|
+
| Task | {task_description} |
|
|
152
|
+
| Context | {context_code} / {app_name} / {module_code} |
|
|
153
|
+
| Sections | {sections} |
|
|
154
|
+
| PRD | {prd_path || "none"} |
|
|
155
|
+
| Feature | {feature_path || "none"} |
|
|
156
|
+
| Flags | {active_flags} |
|
|
157
|
+
| MCP | {available|degraded} |
|
|
158
|
+
| Needs migration | {yes|no} |
|
|
159
|
+
| Needs seed data | {yes|no} |
|
|
160
|
+
|
|
161
|
+
NEXT STEP: step-01-analyze
|
|
162
|
+
═══════════════════════════════════════════════════════════════
|
|
150
163
|
```
|
|
151
164
|
|
|
152
165
|
---
|
|
@@ -12,10 +12,28 @@ next_step: steps/step-02-plan.md
|
|
|
12
12
|
|
|
13
13
|
## LOAD CONDITIONALLY
|
|
14
14
|
|
|
15
|
+
- **ALWAYS** read `references/smartstack-api.md` — BaseEntity API, entity/config/controller patterns
|
|
15
16
|
- If NOT `{economy_mode}`: read `references/agent-teams-protocol.md`
|
|
16
17
|
|
|
17
18
|
---
|
|
18
19
|
|
|
20
|
+
## 0. Fresh Project Detection (Early Exit)
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
IF .smartstack/init-state.json exists:
|
|
24
|
+
Read it → check if project was recently initialized
|
|
25
|
+
Glob("src/**/Entities/**/*.cs") → count entity files
|
|
26
|
+
|
|
27
|
+
IF entity count == 0 AND no PRD AND no feature.json:
|
|
28
|
+
→ SKIP full code exploration (sections 2-3)
|
|
29
|
+
→ Declare: "Fresh project — all elements need to be CREATED"
|
|
30
|
+
→ Jump directly to section 4 (Gap Analysis) with all items marked "create"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This saves ~2 minutes of Glob searches on an empty project.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
19
37
|
## 1. Context Sources
|
|
20
38
|
|
|
21
39
|
Read available context (in order of priority):
|
|
@@ -13,6 +13,7 @@ All code goes through skills (/controller, /application, /ui-components, /efcore
|
|
|
13
13
|
|
|
14
14
|
## LOAD CONDITIONALLY
|
|
15
15
|
|
|
16
|
+
- **ALWAYS** read `references/smartstack-api.md` — BaseEntity API, entity/config/controller patterns
|
|
16
17
|
- Read `references/smartstack-layers.md` for execution rules per layer
|
|
17
18
|
- If NOT `{economy_mode}` AND Layer 1 has parallel work: read `references/agent-teams-protocol.md`
|
|
18
19
|
|
|
@@ -25,7 +26,8 @@ All code goes through skills (/controller, /application, /ui-components, /efcore
|
|
|
25
26
|
```
|
|
26
27
|
For each entity to create/modify:
|
|
27
28
|
→ MCP scaffold_extension (type: "entity", target: entity_name)
|
|
28
|
-
→ Verify: inherits
|
|
29
|
+
→ Verify: inherits BaseEntity, implements ITenantEntity + IAuditableEntity
|
|
30
|
+
→ Verify entity matches patterns in references/smartstack-api.md
|
|
29
31
|
```
|
|
30
32
|
|
|
31
33
|
### EF Core Configurations
|
|
@@ -43,7 +45,7 @@ For each entity:
|
|
|
43
45
|
1. MCP suggest_migration → get standardized name
|
|
44
46
|
2. dotnet ef migrations add {Name} --project src/{Infra}.csproj --startup-project src/{Api}.csproj -o Persistence/Migrations
|
|
45
47
|
3. dotnet ef database update (if local DB)
|
|
46
|
-
4. dotnet build
|
|
48
|
+
4. dotnet build → MUST PASS
|
|
47
49
|
```
|
|
48
50
|
|
|
49
51
|
**BLOCKING:** If build fails after migration, fix EF configs before proceeding.
|
|
@@ -51,10 +53,10 @@ For each entity:
|
|
|
51
53
|
### Post-Layer 0 Build Gate
|
|
52
54
|
|
|
53
55
|
```bash
|
|
54
|
-
dotnet build
|
|
56
|
+
dotnet build
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
**MUST PASS before Layer 1. If
|
|
59
|
+
**MUST PASS before Layer 1. If NuGet error, run `dotnet restore` first. If file lock (MSB3021), use `--output /tmp/{project}_build`.**
|
|
58
60
|
|
|
59
61
|
---
|
|
60
62
|
|
|
@@ -102,7 +104,7 @@ Spawn 2 teammates (Opus, full tools):
|
|
|
102
104
|
Wait for both teammates to report completion.
|
|
103
105
|
|
|
104
106
|
Build verification:
|
|
105
|
-
dotnet build
|
|
107
|
+
dotnet build (backend)
|
|
106
108
|
npm run typecheck (frontend, if applicable)
|
|
107
109
|
|
|
108
110
|
shutdown_request → shutdown_response → TeamDelete("apex-exec")
|
|
@@ -136,7 +138,7 @@ After Layer 1 completes:
|
|
|
136
138
|
- DI registration added
|
|
137
139
|
|
|
138
140
|
2. Build gate:
|
|
139
|
-
dotnet build
|
|
141
|
+
dotnet build → MUST PASS
|
|
140
142
|
npm run typecheck → MUST PASS (if frontend)
|
|
141
143
|
```
|
|
142
144
|
|
|
@@ -126,6 +126,7 @@ sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "IF DB_ID('$DB_NAME') IS NOT NULL BEGIN AL
|
|
|
126
126
|
|
|
127
127
|
| File | Checks |
|
|
128
128
|
|------|--------|
|
|
129
|
+
| NavigationApplicationSeedData | MUST be first, deterministic GUID, 4 lang translations |
|
|
129
130
|
| NavigationModuleSeedData | Deterministic GUIDs (SHA256), 4 languages, GetModuleEntry + GetTranslationEntries |
|
|
130
131
|
| PermissionsSeedData | MCP generate_permissions used, paths match Permissions.cs, wildcard + CRUD |
|
|
131
132
|
| RolesSeedData | Admin=wildcard, Manager=CRU, Contributor=CR, Viewer=R |
|
|
@@ -134,6 +135,97 @@ sqlcmd -S "(localdb)\MSSQLLocalDB" -Q "IF DB_ID('$DB_NAME') IS NOT NULL BEGIN AL
|
|
|
134
135
|
|
|
135
136
|
---
|
|
136
137
|
|
|
138
|
+
## 6b. BLOCKING POST-CHECKs (bash verification on real files)
|
|
139
|
+
|
|
140
|
+
> These checks run on the actual generated files. Model-interpreted checks are unreliable.
|
|
141
|
+
|
|
142
|
+
### POST-CHECK 1: Navigation routes must be full paths starting with /
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
# Find all seed data files and check route values
|
|
146
|
+
SEED_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*.cs" 2>/dev/null)
|
|
147
|
+
if [ -n "$SEED_FILES" ]; then
|
|
148
|
+
# Check for short routes (no leading /) in Create() calls for navigation entities
|
|
149
|
+
BAD_ROUTES=$(grep -Pn 'NavigationApplication\.Create\(|NavigationModule\.Create\(|NavigationSection\.Create\(|NavigationResource\.Create\(' $SEED_FILES | grep -v '"/[a-z]')
|
|
150
|
+
if [ -n "$BAD_ROUTES" ]; then
|
|
151
|
+
echo "BLOCKING: Navigation routes must be full paths starting with /"
|
|
152
|
+
echo "$BAD_ROUTES"
|
|
153
|
+
echo "Expected: \"/business/human-resources\" NOT \"humanresources\""
|
|
154
|
+
exit 1
|
|
155
|
+
fi
|
|
156
|
+
fi
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### POST-CHECK 2: All services must filter by TenantId (OWASP A01)
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
# Find all service implementation files
|
|
163
|
+
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
|
|
164
|
+
if [ -n "$SERVICE_FILES" ]; then
|
|
165
|
+
# Check each service file has TenantId reference (either _currentUser.TenantId or TenantId filter)
|
|
166
|
+
for f in $SERVICE_FILES; do
|
|
167
|
+
if ! grep -q "TenantId" "$f"; then
|
|
168
|
+
echo "BLOCKING (OWASP A01): Service missing TenantId filter: $f"
|
|
169
|
+
echo "Every service query MUST filter by _currentUser.TenantId"
|
|
170
|
+
exit 1
|
|
171
|
+
fi
|
|
172
|
+
if grep -q "Guid.Empty" "$f"; then
|
|
173
|
+
echo "BLOCKING (OWASP A01): Service uses Guid.Empty instead of _currentUser.TenantId: $f"
|
|
174
|
+
exit 1
|
|
175
|
+
fi
|
|
176
|
+
done
|
|
177
|
+
fi
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### POST-CHECK 3: Controllers must use [RequirePermission], not just [Authorize]
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
# Find all controller files
|
|
184
|
+
CTRL_FILES=$(find src/ -path "*/Controllers/*" -name "*Controller.cs" 2>/dev/null)
|
|
185
|
+
if [ -n "$CTRL_FILES" ]; then
|
|
186
|
+
for f in $CTRL_FILES; do
|
|
187
|
+
# Check controller has at least one RequirePermission attribute
|
|
188
|
+
if grep -q "\[Authorize\]" "$f" && ! grep -q "\[RequirePermission" "$f"; then
|
|
189
|
+
echo "WARNING: Controller uses [Authorize] without [RequirePermission]: $f"
|
|
190
|
+
echo "Use [RequirePermission(Permissions.{Module}.{Action})] on each endpoint"
|
|
191
|
+
fi
|
|
192
|
+
done
|
|
193
|
+
fi
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### POST-CHECK 4: Seed data must not use Guid.NewGuid()
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
SEED_FILES=$(find src/ -path "*/Seeding/Data/*" -name "*.cs" 2>/dev/null)
|
|
200
|
+
if [ -n "$SEED_FILES" ]; then
|
|
201
|
+
BAD_GUIDS=$(grep -n "Guid.NewGuid()" $SEED_FILES 2>/dev/null)
|
|
202
|
+
if [ -n "$BAD_GUIDS" ]; then
|
|
203
|
+
echo "BLOCKING: Seed data must use deterministic GUIDs (SHA256), not Guid.NewGuid()"
|
|
204
|
+
echo "$BAD_GUIDS"
|
|
205
|
+
exit 1
|
|
206
|
+
fi
|
|
207
|
+
fi
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### POST-CHECK 5: Services must inject ICurrentUser
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
SERVICE_FILES=$(find src/ -path "*/Services/*" -name "*Service.cs" ! -name "I*Service.cs" 2>/dev/null)
|
|
214
|
+
if [ -n "$SERVICE_FILES" ]; then
|
|
215
|
+
for f in $SERVICE_FILES; do
|
|
216
|
+
if ! grep -q "ICurrentUser" "$f"; then
|
|
217
|
+
echo "BLOCKING: Service missing ICurrentUser injection: $f"
|
|
218
|
+
echo "All services MUST inject ICurrentUser for tenant isolation"
|
|
219
|
+
exit 1
|
|
220
|
+
fi
|
|
221
|
+
done
|
|
222
|
+
fi
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**If ANY POST-CHECK fails → fix in step-03, re-validate.**
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
137
229
|
## 7. Acceptance Criteria POST-CHECK
|
|
138
230
|
|
|
139
231
|
For each AC inferred in step-01:
|
|
@@ -12,14 +12,15 @@ next_step: steps/step-08-run-tests.md
|
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
## 1. Ensure Test
|
|
15
|
+
## 1. Ensure Test Projects Exist
|
|
16
|
+
|
|
17
|
+
### 1a. Unit Test Project
|
|
16
18
|
|
|
17
19
|
```bash
|
|
18
|
-
# Check for existing test project
|
|
19
|
-
|
|
20
|
+
# Check for existing unit test project
|
|
21
|
+
UNIT_PROJECT=$(find tests/ -name "*.Tests.Unit.csproj" 2>/dev/null | head -1)
|
|
20
22
|
|
|
21
|
-
if [ -z "$
|
|
22
|
-
# Create test project
|
|
23
|
+
if [ -z "$UNIT_PROJECT" ]; then
|
|
23
24
|
PROJECT_NAME=$(basename *.sln .sln)
|
|
24
25
|
dotnet new xunit -n "${PROJECT_NAME}.Tests.Unit" -o "tests/${PROJECT_NAME}.Tests.Unit"
|
|
25
26
|
dotnet add "tests/${PROJECT_NAME}.Tests.Unit" package Moq
|
|
@@ -31,6 +32,29 @@ if [ -z "$TEST_PROJECT" ]; then
|
|
|
31
32
|
fi
|
|
32
33
|
```
|
|
33
34
|
|
|
35
|
+
### 1b. Integration Test Project (for step-04 DB validation)
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# Check for existing integration test project
|
|
39
|
+
INT_PROJECT=$(find tests/ -name "*.Tests.Integration.csproj" 2>/dev/null | head -1)
|
|
40
|
+
|
|
41
|
+
if [ -z "$INT_PROJECT" ]; then
|
|
42
|
+
PROJECT_NAME=$(basename *.sln .sln)
|
|
43
|
+
dotnet new xunit -n "${PROJECT_NAME}.Tests.Integration" -o "tests/${PROJECT_NAME}.Tests.Integration"
|
|
44
|
+
dotnet add "tests/${PROJECT_NAME}.Tests.Integration" package Moq
|
|
45
|
+
dotnet add "tests/${PROJECT_NAME}.Tests.Integration" package FluentAssertions
|
|
46
|
+
dotnet add "tests/${PROJECT_NAME}.Tests.Integration" package Respawn
|
|
47
|
+
dotnet add "tests/${PROJECT_NAME}.Tests.Integration" package Microsoft.EntityFrameworkCore.SqlServer
|
|
48
|
+
for proj in src/*/*.csproj; do
|
|
49
|
+
dotnet add "tests/${PROJECT_NAME}.Tests.Integration" reference "$proj"
|
|
50
|
+
done
|
|
51
|
+
dotnet sln add "tests/${PROJECT_NAME}.Tests.Integration/${PROJECT_NAME}.Tests.Integration.csproj"
|
|
52
|
+
fi
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
> **Note:** Integration tests use `DatabaseFixture` + `Respawn` with SQL Server LocalDB.
|
|
56
|
+
> See step-04 section 5c for details.
|
|
57
|
+
|
|
34
58
|
---
|
|
35
59
|
|
|
36
60
|
## 2. Scaffold Tests via MCP
|