@atlashub/smartstack-cli 4.38.0 → 4.40.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.
@@ -24,6 +24,7 @@ Parse `$ARGUMENTS` to determine the command:
24
24
  | `migration` | **Agent** `efcore-migration` | sonnet |
25
25
  | `squash` | **Agent** `efcore-squash` | sonnet |
26
26
  | `rebase-snapshot` | **Agent** `efcore-rebase-snapshot` | sonnet |
27
+ | (none) | **Inline** `<command-help>` | — |
27
28
 
28
29
  **Inline commands:** Execute directly following the matching `<command-*>` section below.
29
30
  **Agent commands:** Delegate via Agent tool:
@@ -31,11 +32,19 @@ Parse `$ARGUMENTS` to determine the command:
31
32
  Agent(
32
33
  subagent_type: "{agent_name}",
33
34
  model: "sonnet",
34
- prompt: "Execute /efcore {command} in {cwd}. Branch: {branch}. Flags: {flags}. Description: {description}"
35
+ prompt: "Execute /efcore {command}.
36
+ Working directory: {cwd}
37
+ Branch: {branch}
38
+ Context: {--context value if provided, else 'auto-detect'}
39
+ Force: {true if --force flag, else false}
40
+ Description: {user description if provided}
41
+ "
35
42
  )
36
43
  ```
37
44
 
38
- **Flags:** `--context <name>` (CoreDbContext/ExtensionsDbContext), `--force` (skip confirmations)
45
+ **Flags:**
46
+ - `--context <name>` — Force DbContext (`CoreDbContext` or `ExtensionsDbContext`), skip auto-detection
47
+ - `--force` — Skip all confirmations (backup still created)
39
48
 
40
49
  </routing>
41
50
 
@@ -91,6 +100,8 @@ Pattern: `{context}_v{version}_{sequence}_{Description}`
91
100
 
92
101
  **READ-ONLY: Never modify database or migrations.**
93
102
 
103
+ > **Troubleshooting:** See `references/troubleshooting.md` for common errors.
104
+
94
105
  1. Call MCP `mcp__smartstack__check_migrations` with `branch: {current_branch}`
95
106
  2. If MCP unavailable, fallback: `dotnet ef migrations list --no-build --context {Context}` per context
96
107
  3. Display compact summary
@@ -117,11 +128,14 @@ BRANCH: {branch}
117
128
 
118
129
  **ONLY runs `dotnet ef database update`. Never creates/deletes migrations.**
119
130
 
120
- 1. Verify `appsettings.Local.json` exists in the API project
121
- 2. Apply Core: `dotnet ef database update --context CoreDbContext --verbose`
122
- 3. Apply Extensions: `dotnet ef database update --context ExtensionsDbContext --verbose`
131
+ > **Reference:** See `references/database-operations.md` for connection test and migration count utilities.
132
+
133
+ 1. Detect projects: `INFRA_PROJECT=$(find src -name "*Infrastructure.csproj" | head -1)` and `STARTUP_PROJECT=$(find src -name "*.Api.csproj" | head -1)`
134
+ 2. Verify `appsettings.Local.json` exists in the API project
135
+ 3. Apply Core: `dotnet ef database update --context CoreDbContext --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT" --verbose`
136
+ 4. Apply Extensions: `dotnet ef database update --context ExtensionsDbContext --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT" --verbose`
123
137
 
124
- If connection fails: suggest verifying SQL Server, appsettings.Local.json, or `/efcore db-reset`.
138
+ If connection fails: suggest verifying SQL Server, appsettings.Local.json, or `/efcore db-reset`. See `references/troubleshooting.md`.
125
139
 
126
140
  ```
127
141
  DB DEPLOY
@@ -138,15 +152,18 @@ DB DEPLOY
138
152
 
139
153
  **ONLY operates on database. Never creates/deletes migration files.**
140
154
 
141
- 1. **Confirm** (MANDATORY unless `--force`):
155
+ > **Reference:** See `references/reset-operations.md` for drop/recreate commands.
156
+
157
+ 1. Detect projects: `INFRA_PROJECT=$(find src -name "*Infrastructure.csproj" | head -1)` and `STARTUP_PROJECT=$(find src -name "*.Api.csproj" | head -1)`
158
+ 2. **Confirm** (MANDATORY unless `--force`):
142
159
  ```
143
160
  AskUserQuestion({ question: "DELETE the database? All data will be lost.", options: ["Yes, delete", "No, cancel"] })
144
161
  ```
145
- 2. **Backup** (optional): `sqlcmd -S "$SERVER" -E -Q "BACKUP DATABASE [$DB] TO DISK='$FILE' WITH FORMAT, INIT, COMPRESSION"`
146
- 3. **Drop**: `dotnet ef database drop --force`
147
- 4. **Recreate Core**: `dotnet ef database update --context CoreDbContext`
148
- 5. **Recreate Extensions**: `dotnet ef database update --context ExtensionsDbContext`
149
- 6. **Ask** if user wants `/efcore db-seed`
162
+ 3. **Backup** (optional): `sqlcmd -S "$SERVER" -E -Q "BACKUP DATABASE [$DB] TO DISK='$FILE' WITH FORMAT, INIT, COMPRESSION"`
163
+ 4. **Drop**: `dotnet ef database drop --force --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT"`
164
+ 5. **Recreate Core**: `dotnet ef database update --context CoreDbContext --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT"`
165
+ 6. **Recreate Extensions**: `dotnet ef database update --context ExtensionsDbContext --project "$INFRA_PROJECT" --startup-project "$STARTUP_PROJECT"`
166
+ 7. **Ask** if user wants `/efcore db-seed`
150
167
 
151
168
  Block if ASPNETCORE_ENVIRONMENT=Production.
152
169
 
@@ -167,6 +184,8 @@ Next: /efcore db-status, /efcore db-seed
167
184
 
168
185
  **Never drop or recreate database.**
169
186
 
187
+ > **Reference:** See `references/seed-methods.md` for detection and execution details.
188
+
170
189
  1. **Detect** seeding method:
171
190
  - `HasData()` in EF configs → apply via `dotnet ef database update --context {Context}`
172
191
  - `IDataSeeder` / `--seed` CLI arg → `dotnet run --project {startup} -- --seed`
@@ -250,3 +269,27 @@ If conflict:
250
269
  ```
251
270
 
252
271
  </command-conflicts>
272
+
273
+ <command-help>
274
+
275
+ ## (no command) — Show available commands
276
+
277
+ Display the list of available `/efcore` commands:
278
+
279
+ ```
280
+ EF CORE COMMANDS
281
+ ────────────────
282
+ db-status Migration state check
283
+ db-deploy Apply pending migrations
284
+ db-reset Drop + recreate database
285
+ db-seed Populate test data
286
+ scan Cross-branch migration scanner
287
+ conflicts Migration conflict analyzer
288
+ migration Create/recreate migration
289
+ squash Consolidate migrations
290
+ rebase-snapshot Resync ModelSnapshot with parent
291
+
292
+ Usage: /efcore <command> [--context <name>] [--force]
293
+ ```
294
+
295
+ </command-help>
@@ -7,8 +7,7 @@
7
7
  ```bash
8
8
  # Validate required variables from step-00-init
9
9
  for VAR_NAME in DBCONTEXT DBCONTEXT_TYPE INFRA_PROJECT STARTUP_PROJECT SELECTED_ENV; do
10
- eval VAR_VALUE=\$$VAR_NAME
11
- if [ -z "$VAR_VALUE" ]; then
10
+ if [ -z "${!VAR_NAME}" ]; then
12
11
  echo "ERROR: Required variable $VAR_NAME is not set"
13
12
  echo "Run step-00-init first"
14
13
  exit 1
@@ -38,7 +37,7 @@ fi
38
37
  ## Connection Test
39
38
 
40
39
  ```bash
41
- CONNECTION_TEST=$(dotnet ef database list \
40
+ CONNECTION_TEST=$(dotnet ef migrations list \
42
41
  --context "$DBCONTEXT" \
43
42
  --project "$INFRA_PROJECT" \
44
43
  --startup-project "$STARTUP_PROJECT" 2>&1)
@@ -27,7 +27,7 @@ if grep -q "\-\-seed" ./src/*/Program.cs 2>/dev/null; then
27
27
  fi
28
28
 
29
29
  # WARNING: SQL scripts detected
30
- if [ -f "./scripts/seed.sql" ] || find . -name "seed*.sql" 2>/dev/null | grep -q .; then
30
+ if [ -f "./scripts/seed.sql" ] || find src -name "seed*.sql" -not -path "*/bin/*" -not -path "*/obj/*" 2>/dev/null | grep -q .; then
31
31
  echo ""
32
32
  echo "WARNING: SQL seed scripts detected - FORBIDDEN by conventions"
33
33
  echo "Migrate to HasData() or IDataSeeder"
@@ -58,7 +58,7 @@ the .NET SDK may not be found even if `dotnet-ef` is. Use `$USERPROFILE` first o
58
58
  ```bash
59
59
  detect_efcore_project() {
60
60
  # Find project with EF Core reference
61
- CSPROJ=$(find . -name "*.csproj" -exec grep -l "Microsoft.EntityFrameworkCore" {} \; | head -1)
61
+ CSPROJ=$(find src-name "*.csproj" -exec grep -l "Microsoft.EntityFrameworkCore" {} \; | head -1)
62
62
 
63
63
  if [ -z "$CSPROJ" ]; then
64
64
  echo "ERROR: No EF Core project found"
@@ -70,8 +70,8 @@ detect_efcore_project() {
70
70
  MIGRATIONS_DIR="$PROJECT_DIR/Persistence/Migrations"
71
71
 
72
72
  # Find startup and infrastructure projects
73
- STARTUP_PROJECT=$(find . -name "*.Api.csproj" -o -name "*Web.csproj" | head -1)
74
- INFRA_PROJECT=$(find . -name "*Infrastructure.csproj" | head -1)
73
+ STARTUP_PROJECT=$(find src-name "*.Api.csproj" -o -name "*Web.csproj" | head -1)
74
+ INFRA_PROJECT=$(find src-name "*Infrastructure.csproj" | head -1)
75
75
  [ -z "$INFRA_PROJECT" ] && INFRA_PROJECT="$CSPROJ"
76
76
 
77
77
  echo "Project: $PROJECT_NAME"
@@ -84,7 +84,7 @@ detect_efcore_project() {
84
84
  ```bash
85
85
  detect_dbcontext() {
86
86
  # Priority 1: SmartStack.Domain exists → SmartStack source project (Core only)
87
- if find . -type d -name "SmartStack.Domain" | grep -q .; then
87
+ if find src-type d -name "SmartStack.Domain" | grep -q .; then
88
88
  DBCONTEXT="CoreDbContext"
89
89
  DBCONTEXT_TYPE="core"
90
90
  SCHEMA="core"
@@ -94,7 +94,7 @@ detect_dbcontext() {
94
94
  fi
95
95
 
96
96
  # Priority 2: Client project with SmartStack NuGet → BOTH contexts
97
- if find . -name "*.csproj" -exec grep -ql "PackageReference.*SmartStack" {} \; 2>/dev/null; then
97
+ if find src-name "*.csproj" -exec grep -ql "PackageReference.*SmartStack" {} \; 2>/dev/null; then
98
98
  DBCONTEXT="CoreDbContext"
99
99
  DBCONTEXT_TYPE="both"
100
100
  SCHEMA="core"
@@ -105,8 +105,8 @@ detect_dbcontext() {
105
105
  fi
106
106
 
107
107
  # Priority 3: Scan for DbContext in code
108
- CORE_CTX=$(find . -name "*.cs" -exec grep -l "CoreDbContext" {} \; 2>/dev/null | head -1)
109
- EXT_CTX=$(find . -name "*.cs" -exec grep -l "ExtensionsDbContext" {} \; 2>/dev/null | head -1)
108
+ CORE_CTX=$(find src-name "*.cs" -exec grep -l "CoreDbContext" {} \; 2>/dev/null | head -1)
109
+ EXT_CTX=$(find src-name "*.cs" -exec grep -l "ExtensionsDbContext" {} \; 2>/dev/null | head -1)
110
110
 
111
111
  if [ -n "$CORE_CTX" ] && [ -n "$EXT_CTX" ]; then
112
112
  DBCONTEXT="CoreDbContext"
@@ -137,7 +137,7 @@ detect_dbcontext() {
137
137
 
138
138
  ```bash
139
139
  detect_environment() {
140
- API_DIR=$(find . -type d -name "*.Api" | head -1)
140
+ API_DIR=$(find src-type d -name "*.Api" | head -1)
141
141
  [ -z "$API_DIR" ] && API_DIR="src/SmartStack.Api"
142
142
 
143
143
  # Priority: --env flag > appsettings.Local.json > error
@@ -2,6 +2,8 @@
2
2
  Zero-downtime migration patterns for EF Core. Use when a migration contains destructive operations (column rename, type change, column drop) that could cause downtime during deployment.
3
3
 
4
4
  These patterns apply to production deployments where the application runs continuously. For development environments, standard migrations are sufficient.
5
+
6
+ > **Exception to "no raw SQL" rule:** `migrationBuilder.Sql(...)` is authorized ONLY for data backfill operations within zero-downtime migration patterns (e.g., `UPDATE ... SET NewCol = OldCol`). Never use it for DDL (CREATE/ALTER/DROP) — those must go through EF Core Fluent API or `SqlObjects/`.
5
7
  </overview>
6
8
 
7
9
  <when_to_use>
@@ -60,9 +60,21 @@ while read -r line; do
60
60
  continue
61
61
  fi
62
62
 
63
+ # Skip permanent branches
64
+ [[ "$WT_BRANCH" == "$GF_MAIN_BRANCH" ]] || [[ "$WT_BRANCH" == "$GF_DEVELOP_BRANCH" ]] && {
65
+ VALID+=("$WT_PATH:$WT_BRANCH")
66
+ continue
67
+ }
68
+
63
69
  # Check if branch still exists on remote
64
70
  REMOTE_EXISTS=$(git branch -r --list "origin/$WT_BRANCH" | wc -l)
65
- if [ "$REMOTE_EXISTS" -eq 0 ] && [[ "$WT_BRANCH" != "$GF_MAIN_BRANCH" ]] && [[ "$WT_BRANCH" != "$GF_DEVELOP_BRANCH" ]]; then
71
+
72
+ # Check if branch is merged into develop or main
73
+ MERGED_INTO_DEVELOP=$(git branch --merged "$GF_DEVELOP_BRANCH" | grep -c "$WT_BRANCH" 2>/dev/null || echo 0)
74
+ MERGED_INTO_MAIN=$(git branch --merged "$GF_MAIN_BRANCH" | grep -c "$WT_BRANCH" 2>/dev/null || echo 0)
75
+
76
+ # Stale if: no remote OR already merged
77
+ if [ "$REMOTE_EXISTS" -eq 0 ] || [ "$MERGED_INTO_DEVELOP" -gt 0 ] || [ "$MERGED_INTO_MAIN" -gt 0 ]; then
66
78
  STALE+=("$WT_PATH:$WT_BRANCH")
67
79
  continue
68
80
  fi
@@ -166,10 +178,14 @@ AskUserQuestion:
166
178
  # Remove orphaned
167
179
  for item in "${ORPHANED[@]}"; do
168
180
  WT_PATH=$(echo "$item" | cut -d':' -f1)
181
+ WT_BRANCH=$(echo "$item" | cut -d':' -f2)
169
182
  git worktree remove "$WT_PATH" --force 2>/dev/null || rm -rf "$WT_PATH"
183
+ # Delete remote branch if exists
184
+ git push origin --delete "$WT_BRANCH" 2>/dev/null
185
+ git branch -D "$WT_BRANCH" 2>/dev/null
170
186
  done
171
187
 
172
- # Prune
188
+ # Prune stale worktree references
173
189
  git worktree prune
174
190
 
175
191
  # Remove stale
@@ -178,15 +194,29 @@ for item in "${STALE[@]}"; do
178
194
  WT_BRANCH=$(echo "$item" | cut -d':' -f2)
179
195
 
180
196
  git worktree remove "$WT_PATH" --force 2>/dev/null || rm -rf "$WT_PATH"
197
+ # Delete remote branch if exists
198
+ git push origin --delete "$WT_BRANCH" 2>/dev/null
181
199
  git branch -D "$WT_BRANCH" 2>/dev/null
182
200
  done
201
+
202
+ # Final prune after all removals
203
+ git worktree prune
183
204
  ```
184
205
 
185
206
  **Branches:**
186
207
  ```bash
187
- # Delete merged branches
208
+ # Delete merged branches (local + remote)
188
209
  for branch in "${MERGED_BRANCHES[@]}"; do
189
210
  git branch -d "$branch"
211
+ git push origin --delete "$branch" 2>/dev/null
212
+ done
213
+ ```
214
+
215
+ **Empty parent directories:**
216
+ ```bash
217
+ # Clean up empty worktree parent directories
218
+ for dir in "$GF_FEATURES_DIR" "$GF_RELEASES_DIR" "$GF_HOTFIXES_DIR"; do
219
+ [ -d "$dir" ] && [ -z "$(ls -A "$dir" 2>/dev/null)" ] && rm -rf "$dir"
190
220
  done
191
221
  ```
192
222