@atlashub/smartstack-cli 1.35.0 → 1.36.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.
@@ -13,16 +13,15 @@ Display complete GitFlow state including branches, worktrees, remotes, and pendi
13
13
 
14
14
  ## EXECUTION:
15
15
 
16
- ### 1. Repository Info
16
+ ### 1. Load Config and Repository Info
17
17
 
18
18
  ```bash
19
- REPO_NAME=$(basename $(git rev-parse --show-toplevel))
20
- CURRENT=$(git rev-parse --abbrev-ref HEAD)
21
- REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "No remote")
19
+ # Load GitFlow config (sets GF_* variables)
20
+ read_gitflow_config || { echo "❌ Run /gitflow init first."; exit 1; }
22
21
 
23
- # Detect provider
24
- [[ "$REMOTE_URL" == *"github.com"* ]] && GIT_PROVIDER="GitHub"
25
- [[ "$REMOTE_URL" == *"dev.azure.com"* ]] && GIT_PROVIDER="Azure DevOps"
22
+ REPO_NAME="$GF_PROJECT_NAME"
23
+ CURRENT=$(git rev-parse --abbrev-ref HEAD)
24
+ GIT_PROVIDER="$GF_PROVIDER"
26
25
  ```
27
26
 
28
27
  ### 2. Branch Status
@@ -30,27 +29,27 @@ REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "No remote")
30
29
  ```bash
31
30
  git fetch origin --quiet
32
31
 
33
- # Main branches
34
- MAIN_LOCAL=$(git rev-parse --short main 2>/dev/null || echo "N/A")
35
- MAIN_REMOTE=$(git rev-parse --short origin/main 2>/dev/null || echo "N/A")
36
- DEVELOP_LOCAL=$(git rev-parse --short develop 2>/dev/null || echo "N/A")
37
- DEVELOP_REMOTE=$(git rev-parse --short origin/develop 2>/dev/null || echo "N/A")
32
+ # Main branches (from config)
33
+ MAIN_LOCAL=$(git rev-parse --short $GF_MAIN_BRANCH 2>/dev/null || echo "N/A")
34
+ MAIN_REMOTE=$(git rev-parse --short origin/$GF_MAIN_BRANCH 2>/dev/null || echo "N/A")
35
+ DEVELOP_LOCAL=$(git rev-parse --short $GF_DEVELOP_BRANCH 2>/dev/null || echo "N/A")
36
+ DEVELOP_REMOTE=$(git rev-parse --short origin/$GF_DEVELOP_BRANCH 2>/dev/null || echo "N/A")
38
37
 
39
38
  # Divergence
40
- DEVELOP_AHEAD=$(git rev-list --count origin/main..origin/develop 2>/dev/null || echo "0")
39
+ DEVELOP_AHEAD=$(git rev-list --count origin/$GF_MAIN_BRANCH..origin/$GF_DEVELOP_BRANCH 2>/dev/null || echo "0")
41
40
  ```
42
41
 
43
42
  ### 3. Active Branches
44
43
 
45
44
  ```bash
46
- # Feature branches
47
- FEATURES=$(git branch -r | grep "origin/feature/" | sed 's/origin\///')
45
+ # Feature branches (using prefixes from config)
46
+ FEATURES=$(git branch -r | grep "origin/${GF_FEATURE_PREFIX}" | sed 's/origin\///')
48
47
 
49
48
  # Release branches
50
- RELEASES=$(git branch -r | grep "origin/release/" | sed 's/origin\///')
49
+ RELEASES=$(git branch -r | grep "origin/${GF_RELEASE_PREFIX}" | sed 's/origin\///')
51
50
 
52
51
  # Hotfix branches
53
- HOTFIXES=$(git branch -r | grep "origin/hotfix/" | sed 's/origin\///')
52
+ HOTFIXES=$(git branch -r | grep "origin/${GF_HOTFIX_PREFIX}" | sed 's/origin\///')
54
53
  ```
55
54
 
56
55
  ### 4. Worktree Status
@@ -28,20 +28,26 @@ Validate changes, check EF Core migrations, and create commit with proper messag
28
28
 
29
29
  ### 0. Pre-commit Guards
30
30
 
31
+ **0.0 Load Config:**
32
+ ```bash
33
+ # Load GitFlow config (sets GF_* variables)
34
+ read_gitflow_config || { echo "❌ Run /gitflow init first."; exit 1; }
35
+ ```
36
+
31
37
  **0.1 Branch Protection:**
32
38
  ```bash
33
39
  CURRENT=$(git rev-parse --abbrev-ref HEAD)
34
40
 
35
41
  # BLOCK: main
36
- [[ "$CURRENT" == "main" ]] && {
37
- echo "⛔ COMMIT BLOCKED - main is protected"
42
+ [[ "$CURRENT" == "$GF_MAIN_BRANCH" ]] && {
43
+ echo "⛔ COMMIT BLOCKED - $GF_MAIN_BRANCH is protected"
38
44
  echo "→ Use: /gitflow start hotfix <name>"
39
45
  STOP
40
46
  }
41
47
 
42
48
  # WARNING: develop
43
- [[ "$CURRENT" == "develop" ]] && {
44
- echo "⚠️ Direct commits to develop are discouraged"
49
+ [[ "$CURRENT" == "$GF_DEVELOP_BRANCH" ]] && {
50
+ echo "⚠️ Direct commits to $GF_DEVELOP_BRANCH are discouraged"
45
51
  # Offer RESCUE TO FEATURE
46
52
  }
47
53
  ```
@@ -52,7 +58,7 @@ git fetch origin --quiet
52
58
  STAGED=$(git diff --cached --name-only | wc -l)
53
59
  MODIFIED=$(git diff --name-only | wc -l)
54
60
  UNTRACKED=$(git ls-files --others --exclude-standard | wc -l)
55
- LOCAL_COMMITS=$(git rev-list --count origin/develop..HEAD 2>/dev/null || echo "0")
61
+ LOCAL_COMMITS=$(git rev-list --count origin/$GF_DEVELOP_BRANCH..HEAD 2>/dev/null || echo "0")
56
62
 
57
63
  # If there are changes or commits, offer rescue
58
64
  [ "$STAGED" -gt 0 ] || [ "$MODIFIED" -gt 0 ] || [ "$LOCAL_COMMITS" -gt 0 ] && {
@@ -16,9 +16,12 @@ Create tags for releases/hotfixes, merge back to develop, clean up worktree and
16
16
 
17
17
  ## EXECUTION SEQUENCE:
18
18
 
19
- ### 1. Determine Branch Context
19
+ ### 1. Load Config and Determine Branch Context
20
20
 
21
21
  ```bash
22
+ # Load GitFlow config (sets GF_* variables)
23
+ read_gitflow_config || { echo "❌ Run /gitflow init first."; exit 1; }
24
+
22
25
  # Get current or specified branch
23
26
  BRANCH=${1:-$(git rev-parse --abbrev-ref HEAD)}
24
27
  BRANCH_TYPE=$(echo $BRANCH | cut -d'/' -f1)
@@ -27,8 +30,8 @@ BRANCH_NAME=$(echo $BRANCH | cut -d'/' -f2)
27
30
  # Validate branch type
28
31
  case "$BRANCH_TYPE" in
29
32
  feature|release|hotfix) ;;
30
- main|develop)
31
- echo "❌ Cannot finish main or develop branch"
33
+ $GF_MAIN_BRANCH|$GF_DEVELOP_BRANCH)
34
+ echo "❌ Cannot finish $GF_MAIN_BRANCH or $GF_DEVELOP_BRANCH branch"
32
35
  STOP
33
36
  ;;
34
37
  *)
@@ -46,12 +49,12 @@ git fetch origin
46
49
  # Check if branch was merged
47
50
  case "$BRANCH_TYPE" in
48
51
  feature)
49
- MERGED=$(git branch -r --merged origin/develop | grep "$BRANCH" | wc -l)
50
- TARGET="develop"
52
+ MERGED=$(git branch -r --merged origin/$GF_DEVELOP_BRANCH | grep "$BRANCH" | wc -l)
53
+ TARGET="$GF_DEVELOP_BRANCH"
51
54
  ;;
52
55
  release|hotfix)
53
- MERGED=$(git branch -r --merged origin/main | grep "$BRANCH" | wc -l)
54
- TARGET="main"
56
+ MERGED=$(git branch -r --merged origin/$GF_MAIN_BRANCH | grep "$BRANCH" | wc -l)
57
+ TARGET="$GF_MAIN_BRANCH"
55
58
  ;;
56
59
  esac
57
60
 
@@ -74,8 +77,8 @@ esac
74
77
 
75
78
  ```bash
76
79
  if [ "$BRANCH_TYPE" = "release" ] || [ "$BRANCH_TYPE" = "hotfix" ]; then
77
- # Get version
78
- VERSION=$(grep -oP '"current":\s*"\K[^"]+' .claude/gitflow/config.json 2>/dev/null)
80
+ # Get version from config (already loaded)
81
+ VERSION="$GF_VERSION"
79
82
 
80
83
  # For hotfix, increment patch
81
84
  if [ "$BRANCH_TYPE" = "hotfix" ]; then
@@ -95,8 +98,8 @@ if [ "$BRANCH_TYPE" = "release" ] || [ "$BRANCH_TYPE" = "hotfix" ]; then
95
98
  }
96
99
 
97
100
  # Create tag on main
98
- git checkout main
99
- git pull origin main
101
+ git checkout $GF_MAIN_BRANCH
102
+ git pull origin $GF_MAIN_BRANCH
100
103
  git tag -a "$TAG_NAME" -m "$BRANCH_TYPE: $BRANCH_NAME"
101
104
  git push origin "$TAG_NAME"
102
105
 
@@ -108,13 +111,13 @@ fi
108
111
 
109
112
  ```bash
110
113
  if [ "$BRANCH_TYPE" = "release" ] || [ "$BRANCH_TYPE" = "hotfix" ]; then
111
- echo "Merging $TAG_NAME back to develop..."
114
+ echo "Merging $TAG_NAME back to $GF_DEVELOP_BRANCH..."
112
115
 
113
- git checkout develop
114
- git pull origin develop
116
+ git checkout $GF_DEVELOP_BRANCH
117
+ git pull origin $GF_DEVELOP_BRANCH
115
118
 
116
119
  # Merge with merge commit (preserve history)
117
- git merge main -m "Merge $TAG_NAME back to develop"
120
+ git merge $GF_MAIN_BRANCH -m "Merge $TAG_NAME back to $GF_DEVELOP_BRANCH"
118
121
 
119
122
  # Handle conflicts
120
123
  CONFLICTS=$(git diff --name-only --diff-filter=U | wc -l)
@@ -125,48 +128,55 @@ if [ "$BRANCH_TYPE" = "release" ] || [ "$BRANCH_TYPE" = "hotfix" ]; then
125
128
  # Options: resolve, abort
126
129
  }
127
130
 
128
- git push origin develop
131
+ git push origin $GF_DEVELOP_BRANCH
129
132
 
130
133
  # CRITICAL: Verify push and update tracking refs
131
- git fetch origin develop:refs/remotes/origin/develop --force --quiet
134
+ git fetch origin $GF_DEVELOP_BRANCH:refs/remotes/origin/$GF_DEVELOP_BRANCH --force --quiet
132
135
  LOCAL_SHA=$(git rev-parse HEAD)
133
- REMOTE_SHA=$(git rev-parse origin/develop)
136
+ REMOTE_SHA=$(git rev-parse origin/$GF_DEVELOP_BRANCH)
134
137
  if [ "$LOCAL_SHA" = "$REMOTE_SHA" ]; then
135
138
  echo "✅ Push verified - local/remote in sync"
136
139
  else
137
140
  echo "⚠️ Push verification FAILED"
138
141
  echo " Local: $LOCAL_SHA"
139
142
  echo " Remote: $REMOTE_SHA"
140
- echo " → Try: git push origin develop --force-with-lease"
143
+ echo " → Try: git push origin $GF_DEVELOP_BRANCH --force-with-lease"
141
144
  fi
142
145
 
143
- echo "✅ Merged back to develop"
146
+ echo "✅ Merged back to $GF_DEVELOP_BRANCH"
144
147
  fi
145
148
  ```
146
149
 
147
- ### 5. Update Version (Release only)
150
+ ### 5. Update Version (Release and Hotfix)
148
151
 
149
152
  ```bash
150
- if [ "$BRANCH_TYPE" = "release" ]; then
151
- # Increment minor version for next development
153
+ if [ "$BRANCH_TYPE" = "release" ] || [ "$BRANCH_TYPE" = "hotfix" ]; then
152
154
  MAJOR=$(echo $VERSION | cut -d'.' -f1)
153
155
  MINOR=$(echo $VERSION | cut -d'.' -f2)
154
- NEXT_VERSION="$MAJOR.$((MINOR + 1)).0"
156
+ PATCH=$(echo $VERSION | cut -d'.' -f3)
157
+
158
+ if [ "$BRANCH_TYPE" = "release" ]; then
159
+ # Release: increment minor, reset patch
160
+ NEXT_VERSION="$MAJOR.$((MINOR + 1)).0"
161
+ else
162
+ # Hotfix: increment patch (patch was already bumped for the tag, bump again for next dev)
163
+ NEXT_VERSION="$MAJOR.$MINOR.$((PATCH + 2))"
164
+ fi
155
165
 
156
- # Update config
157
- sed -i "s/\"current\": \"$VERSION\"/\"current\": \"$NEXT_VERSION\"/" .claude/gitflow/config.json
166
+ # Update config (using resolved config path)
167
+ sed -i "s/\"current\": \".*\"/\"current\": \"$NEXT_VERSION\"/" "$GF_CONFIG_FILE"
158
168
 
159
169
  # Update source files
160
170
  # csproj, package.json, etc.
161
171
 
162
172
  git add -A
163
173
  git commit -m "chore: bump version to $NEXT_VERSION for development"
164
- git push origin develop
174
+ git push origin $GF_DEVELOP_BRANCH
165
175
 
166
176
  # CRITICAL: Verify push and update tracking refs
167
- git fetch origin develop:refs/remotes/origin/develop --force --quiet
177
+ git fetch origin $GF_DEVELOP_BRANCH:refs/remotes/origin/$GF_DEVELOP_BRANCH --force --quiet
168
178
  LOCAL_SHA=$(git rev-parse HEAD)
169
- REMOTE_SHA=$(git rev-parse origin/develop)
179
+ REMOTE_SHA=$(git rev-parse origin/$GF_DEVELOP_BRANCH)
170
180
  if [ "$LOCAL_SHA" = "$REMOTE_SHA" ]; then
171
181
  echo "✅ Push verified - local/remote in sync"
172
182
  else
@@ -182,14 +192,14 @@ fi
182
192
  ### 6. Clean Up Worktree
183
193
 
184
194
  ```bash
185
- # Find worktree for this branch
186
- WORKTREE_PATH=$(git worktree list | grep "$BRANCH" | awk '{print $1}')
195
+ # Find worktree for this branch (use --porcelain for reliable parsing)
196
+ WORKTREE_PATH=$(git worktree list --porcelain | grep -B2 "branch refs/heads/$BRANCH" | grep "^worktree " | sed 's/^worktree //')
187
197
 
188
198
  if [ -n "$WORKTREE_PATH" ] && [ -d "$WORKTREE_PATH" ]; then
189
199
  echo "Removing worktree: $WORKTREE_PATH"
190
200
 
191
- # Make sure we're not in the worktree
192
- cd $(git rev-parse --show-toplevel)
201
+ # Make sure we're not in the worktree directory
202
+ cd "$GF_DEVELOP_PATH" 2>/dev/null || cd "$(git rev-parse --show-toplevel)"
193
203
 
194
204
  git worktree remove "$WORKTREE_PATH" --force 2>/dev/null || {
195
205
  rm -rf "$WORKTREE_PATH"
@@ -452,6 +452,7 @@ mkdir -p "$DEVELOP_PATH/.claude/gitflow/{plans,logs,cache,backup}"
452
452
  "version": "2.0.0",
453
453
  "repository": {
454
454
  "name": "{PROJECT_NAME}",
455
+ "rootFolder": "{ROOT_FOLDER}",
455
456
  "nameVariants": {
456
457
  "pascalCaseDot": "{PascalCase.Dot}",
457
458
  "pascalCase": "{PascalCase}",
@@ -459,7 +460,7 @@ mkdir -p "$DEVELOP_PATH/.claude/gitflow/{plans,logs,cache,backup}"
459
460
  "snakeCase": "{snake_case}",
460
461
  "displayName": "{Display Name}"
461
462
  },
462
- "rootFolder": "{ROOT_FOLDER}",
463
+ "defaultBranch": "main",
463
464
  "remoteUrl": "{REPO_URL}"
464
465
  },
465
466
  "git": {
@@ -494,7 +495,8 @@ mkdir -p "$DEVELOP_PATH/.claude/gitflow/{plans,logs,cache,backup}"
494
495
  "efcore": {
495
496
  "enabled": true,
496
497
  "validateOnCommit": true,
497
- "blockDestructive": true
498
+ "blockDestructive": true,
499
+ "migrationNaming": "{context}_v{version}_{sequence}_{Description}"
498
500
  },
499
501
  "workflow": {
500
502
  "push": {
@@ -504,6 +506,9 @@ mkdir -p "$DEVELOP_PATH/.claude/gitflow/{plans,logs,cache,backup}"
504
506
  "autoLabels": true,
505
507
  "requireReview": true
506
508
  }
509
+ },
510
+ "language": {
511
+ "code": "{GF_LANG}"
507
512
  }
508
513
  }
509
514
  ```
@@ -16,19 +16,33 @@ Run through review checklist and merge the pull request with appropriate strateg
16
16
 
17
17
  ## EXECUTION SEQUENCE:
18
18
 
19
- ### 1. Load PR Context
19
+ ### 1. Load Config and PR Context
20
20
 
21
21
  ```bash
22
+ # Load GitFlow config (sets GF_* variables)
23
+ read_gitflow_config || { echo "❌ Run /gitflow init first."; exit 1; }
24
+
22
25
  CURRENT=$(git rev-parse --abbrev-ref HEAD)
23
- GIT_PROVIDER=$(grep -oP '"provider":\s*"\K[^"]+' .claude/gitflow/config.json 2>/dev/null || echo "github")
26
+ GIT_PROVIDER="$GF_PROVIDER"
27
+
28
+ # Try loading persisted PR state first
29
+ CONFIG_DIR=$(dirname "$GF_CONFIG_FILE")
30
+ PR_STATE_FILE="$CONFIG_DIR/cache/pr-state.json"
31
+ if [ -f "$PR_STATE_FILE" ]; then
32
+ PR_NUMBER=$(grep -oP '"pr_number":\s*"\K[^"]+' "$PR_STATE_FILE" | head -1)
33
+ TARGET_BRANCH=$(grep -oP '"target_branch":\s*"\K[^"]+' "$PR_STATE_FILE" | head -1)
34
+ echo "✓ Loaded PR state from cache: PR #$PR_NUMBER → $TARGET_BRANCH"
35
+ fi
24
36
 
25
- # Get PR number
26
- if [ "$GIT_PROVIDER" = "github" ]; then
27
- PR_NUMBER=$(gh pr list --head "$CURRENT" --json number --jq '.[0].number')
28
- PR_STATUS=$(gh pr view $PR_NUMBER --json state,mergeable,reviews --jq '.')
29
- elif [ "$GIT_PROVIDER" = "azuredevops" ]; then
30
- PR_NUMBER=$(az repos pr list --source-branch "$CURRENT" --query "[0].pullRequestId" -o tsv)
31
- PR_STATUS=$(az repos pr show --id $PR_NUMBER --query "{status:status,mergeStatus:mergeStatus}")
37
+ # Fallback: query provider if no cached state
38
+ if [ -z "$PR_NUMBER" ]; then
39
+ if [ "$GIT_PROVIDER" = "github" ]; then
40
+ PR_NUMBER=$(gh pr list --head "$CURRENT" --json number --jq '.[0].number')
41
+ PR_STATUS=$(gh pr view $PR_NUMBER --json state,mergeable,reviews --jq '.')
42
+ elif [ "$GIT_PROVIDER" = "azuredevops" ]; then
43
+ PR_NUMBER=$(az repos pr list --source-branch "$CURRENT" --query "[0].pullRequestId" -o tsv)
44
+ PR_STATUS=$(az repos pr show --id $PR_NUMBER --query "{status:status,mergeStatus:mergeStatus}")
45
+ fi
32
46
  fi
33
47
 
34
48
  [ -z "$PR_NUMBER" ] && {
@@ -125,7 +139,7 @@ case "$BRANCH_TYPE" in
125
139
  release|hotfix)
126
140
  MERGE_STRATEGY="merge"
127
141
  DELETE_BRANCH=true
128
- MERGE_BACK="develop"
142
+ MERGE_BACK="$GF_DEVELOP_BRANCH"
129
143
  ;;
130
144
  esac
131
145
  ```
@@ -16,23 +16,21 @@ Create a pull request with proper target, title, and description based on branch
16
16
 
17
17
  ## EXECUTION SEQUENCE:
18
18
 
19
- ### 1. Detect Git Provider
19
+ ### 1. Load Config and Detect Provider
20
20
 
21
21
  ```bash
22
- REMOTE_URL=$(git remote get-url origin)
23
-
24
- if [[ "$REMOTE_URL" == *"github.com"* ]]; then
25
- GIT_PROVIDER="github"
26
- elif [[ "$REMOTE_URL" == *"dev.azure.com"* ]] || [[ "$REMOTE_URL" == *"visualstudio.com"* ]]; then
27
- GIT_PROVIDER="azuredevops"
28
- # Extract Azure DevOps details
29
- [[ "$REMOTE_URL" =~ dev\.azure\.com/([^/]+)/([^/]+)/_git/([^/]+) ]] && {
22
+ # Load GitFlow config (sets GF_* variables)
23
+ read_gitflow_config || { echo "❌ Run /gitflow init first."; exit 1; }
24
+
25
+ GIT_PROVIDER="$GF_PROVIDER"
26
+
27
+ # Extract Azure DevOps details if needed
28
+ if [ "$GIT_PROVIDER" = "azuredevops" ]; then
29
+ [[ "$GF_REMOTE_URL" =~ dev\.azure\.com/([^/]+)/([^/]+)/_git/([^/]+) ]] && {
30
30
  AZURE_ORG="${BASH_REMATCH[1]}"
31
31
  AZURE_PROJECT="${BASH_REMATCH[2]}"
32
32
  AZURE_REPO="${BASH_REMATCH[3]}"
33
33
  }
34
- else
35
- GIT_PROVIDER="unknown"
36
34
  fi
37
35
  ```
38
36
 
@@ -42,10 +40,10 @@ fi
42
40
  CURRENT=$(git rev-parse --abbrev-ref HEAD)
43
41
 
44
42
  case "$CURRENT" in
45
- feature/*) TARGET_BRANCH="develop" ;;
46
- release/*) TARGET_BRANCH="main" ;;
47
- hotfix/*) TARGET_BRANCH="main" ;;
48
- *) TARGET_BRANCH="develop" ;;
43
+ ${GF_FEATURE_PREFIX}*) TARGET_BRANCH="$GF_DEVELOP_BRANCH" ;;
44
+ ${GF_RELEASE_PREFIX}*) TARGET_BRANCH="$GF_MAIN_BRANCH" ;;
45
+ ${GF_HOTFIX_PREFIX}*) TARGET_BRANCH="$GF_MAIN_BRANCH" ;;
46
+ *) TARGET_BRANCH="$GF_DEVELOP_BRANCH" ;;
49
47
  esac
50
48
  ```
51
49
 
@@ -90,16 +88,26 @@ EXISTING_PR=$(gh pr list --head "$CURRENT" --json number --jq '.[0].number' 2>/d
90
88
  ### 4. Run Pre-PR Checks
91
89
 
92
90
  ```bash
93
- # Build check
91
+ # Build check (multi-runtime detection)
94
92
  echo "Running build check..."
95
- dotnet build --no-restore 2>&1 || {
96
- echo "❌ Build failed. Fix before creating PR."
97
- STOP
98
- }
99
-
100
- # Migration check
101
- echo "Checking migrations..."
102
- dotnet ef migrations list 2>&1 || echo "No migrations or EF Core not configured"
93
+ if [ -f "*.sln" ] || ls *.csproj 2>/dev/null | head -1 > /dev/null; then
94
+ dotnet build --no-restore 2>&1 || {
95
+ echo "❌ .NET build failed. Fix before creating PR."
96
+ STOP
97
+ }
98
+ # Migration check
99
+ echo "Checking migrations..."
100
+ dotnet ef migrations list 2>&1 || echo "No migrations or EF Core not configured"
101
+ elif [ -f "package.json" ]; then
102
+ npm run build 2>&1 || {
103
+ echo "❌ npm build failed. Fix before creating PR."
104
+ STOP
105
+ }
106
+ elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
107
+ echo "Python project detected — skipping build check"
108
+ else
109
+ echo "⚠️ No known build system detected — skipping build check"
110
+ fi
103
111
  ```
104
112
 
105
113
  ### 5. Generate PR Content
@@ -112,7 +120,7 @@ BRANCH_TYPE=$(echo $CURRENT | cut -d'/' -f1)
112
120
  case "$BRANCH_TYPE" in
113
121
  feature) TITLE="feat: $BRANCH_NAME" ;;
114
122
  hotfix) TITLE="fix: $BRANCH_NAME" ;;
115
- release) TITLE="release: v$(grep -oP '"current":\s*"\K[^"]+' .claude/gitflow/config.json)" ;;
123
+ release) TITLE="release: v$GF_VERSION" ;;
116
124
  esac
117
125
  ```
118
126
 
@@ -187,13 +195,19 @@ fi
187
195
  ### 8. Store PR Info
188
196
 
189
197
  ```bash
190
- # Save for merge step
198
+ # Persist PR info for merge step (uses config path for portability)
199
+ CONFIG_DIR=$(dirname "$GF_CONFIG_FILE")
200
+ cat > "$CONFIG_DIR/cache/pr-state.json" << EOF
191
201
  {
192
- "pr_number": $PR_NUMBER,
202
+ "pr_number": "$PR_NUMBER",
193
203
  "pr_url": "$PR_URL",
204
+ "source_branch": "$CURRENT",
194
205
  "target_branch": "$TARGET_BRANCH",
195
- "git_provider": "$GIT_PROVIDER"
206
+ "git_provider": "$GIT_PROVIDER",
207
+ "created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
196
208
  }
209
+ EOF
210
+ echo "✓ PR state saved to $CONFIG_DIR/cache/pr-state.json"
197
211
  ```
198
212
 
199
213
  ### 9. Summary
@@ -31,18 +31,22 @@ Create a new feature/release/hotfix branch with optional worktree setup.
31
31
 
32
32
  ## EXECUTION SEQUENCE:
33
33
 
34
- ### 1. Analyze Context
34
+ ### 1. Load Config and Analyze Context
35
35
 
36
36
  ```bash
37
+ # Load GitFlow config (sets GF_* variables)
38
+ # See _shared.md → READ_GITFLOW_CONFIG for all variables
39
+ read_gitflow_config || { echo "❌ Run /gitflow init first."; exit 1; }
40
+
37
41
  CURRENT_BRANCH=$(git branch --show-current)
38
42
  git fetch origin --quiet
39
43
 
40
- # Version detection
41
- VERSION=$(grep -oP '"current":\s*"\K[^"]+' .claude/gitflow/config.json 2>/dev/null || echo "0.1.0")
44
+ # Version from config
45
+ VERSION="$GF_VERSION"
42
46
  LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "none")
43
47
 
44
48
  # Develop ahead of main?
45
- DEVELOP_AHEAD=$(git rev-list --count origin/main..origin/develop 2>/dev/null || echo "0")
49
+ DEVELOP_AHEAD=$(git rev-list --count origin/$GF_MAIN_BRANCH..origin/$GF_DEVELOP_BRANCH 2>/dev/null || echo "0")
46
50
 
47
51
  # Working directory status
48
52
  DIRTY=$(git status --porcelain | wc -l)
@@ -129,17 +133,17 @@ esac
129
133
 
130
134
  ### 6. Create Branch and Worktree
131
135
 
132
- **Read worktree mode from config:**
136
+ **Read worktree mode from config (already loaded by read_gitflow_config):**
133
137
  ```bash
134
- WORKTREE_MODE=$(grep -oP '"mode":\s*"\K[^"]+' .claude/gitflow/config.json 2>/dev/null || echo "organized")
138
+ WORKTREE_MODE="$GF_WORKTREE_MODE"
135
139
  ```
136
140
 
137
- **Mode: organized**
141
+ **Mode: organized (uses absolute paths from config)**
138
142
  ```bash
139
143
  case "$branch_type" in
140
- feature) WORKTREE_PATH="../features/$BRANCH_NAME" ;;
141
- release) WORKTREE_PATH="../releases/v$VERSION" ;;
142
- hotfix) WORKTREE_PATH="../hotfixes/$BRANCH_NAME" ;;
144
+ feature) WORKTREE_PATH="$GF_FEATURES_PATH/$BRANCH_NAME" ;;
145
+ release) WORKTREE_PATH="$GF_RELEASES_PATH/v$VERSION" ;;
146
+ hotfix) WORKTREE_PATH="$GF_HOTFIXES_PATH/$BRANCH_NAME" ;;
143
147
  esac
144
148
 
145
149
  mkdir -p "$(dirname $WORKTREE_PATH)"
@@ -181,13 +185,15 @@ API_DIR=$(find "$WORKTREE_PATH" -type d -name "*.Api" -path "*/src/*" | head -1)
181
185
  WEB_DIR=$(find "$WORKTREE_PATH" -type d -name "*-web" -path "*/web/*" | head -1)
182
186
 
183
187
  # Generate unique ports based on branch name hash (to avoid conflicts between worktrees)
184
- HASH=$(echo "$BRANCH_NAME" | md5sum | cut -c1-4)
188
+ # Use shasum (portable across macOS/Linux/Windows Git Bash) with md5sum fallback
189
+ HASH=$(echo "$BRANCH_NAME" | shasum 2>/dev/null || echo "$BRANCH_NAME" | md5sum 2>/dev/null || echo "$BRANCH_NAME" | cksum)
190
+ HASH=$(echo "$HASH" | cut -c1-4)
185
191
  HASH_NUM=$((16#$HASH % 100))
186
192
  API_PORT=$((5200 + HASH_NUM))
187
193
  WEB_PORT=$((5300 + HASH_NUM))
188
194
 
189
- # Project and DB naming
190
- PROJECT_NAME=$(basename $(pwd) | tr '[:upper:]' '[:lower:]')
195
+ # Project name from config (not from pwd)
196
+ PROJECT_NAME=$(echo "$GF_PROJECT_NAME" | tr '[:upper:]' '[:lower:]')
191
197
  DB_NAME=$(echo "${PROJECT_NAME}_${branch_type}_${BRANCH_NAME}" | cut -c1-63)
192
198
  ```
193
199
 
@@ -2,6 +2,7 @@
2
2
  "version": "2.0.0",
3
3
  "repository": {
4
4
  "name": "",
5
+ "rootFolder": "",
5
6
  "nameVariants": {
6
7
  "pascalCaseDot": "",
7
8
  "pascalCase": "",
@@ -13,7 +14,7 @@
13
14
  "remoteUrl": ""
14
15
  },
15
16
  "git": {
16
- "provider": "github",
17
+ "provider": "",
17
18
  "branches": {
18
19
  "main": "main",
19
20
  "develop": "develop"
@@ -28,9 +29,11 @@
28
29
  "enabled": true,
29
30
  "mode": "organized",
30
31
  "structure": {
31
- "features": "../features",
32
- "releases": "../releases",
33
- "hotfixes": "../hotfixes"
32
+ "main": "",
33
+ "develop": "",
34
+ "features": "",
35
+ "releases": "",
36
+ "hotfixes": ""
34
37
  }
35
38
  },
36
39
  "versioning": {