#!/usr/bin/env bash set -euo pipefail # Script: setup.feature.sh # Description: Create feature branch and planning directory # Usage: ./setup.feature.sh "feature description" [--json] [--no-commit] [--branch-name "custom-name"] [--issue-number "123"] RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' print_error() { echo -e "${RED}ERROR: $1${NC}" >&2; } print_success() { echo -e "${GREEN}SUCCESS: $1${NC}"; } print_info() { echo -e "${YELLOW}INFO: $1${NC}"; } get_next_branch_number() { # Get all branches matching the pattern and extract the highest number local max_num=$(git branch -a | \ grep -oE '[0-9]{3}-' | \ grep -oE '[0-9]{3}' | \ sort -n | \ tail -1) if [[ -z "$max_num" ]]; then echo "001" else printf "%03d" $((10#$max_num + 1)) fi } generate_branch_name() { local description="$1" # Extract first two words and clean them local two_words=$(echo "$description" | \ tr '[:upper:]' '[:lower:]' | \ sed 's/[^a-z0-9 -]//g' | \ tr -s ' ' | \ awk '{print $1"-"$2}' | \ sed 's/^-//;s/-$//') # Get next branch number local branch_num=$(get_next_branch_number) echo "${branch_num}-${two_words}" } check_git_repo() { if ! git rev-parse --git-dir > /dev/null 2>&1; then print_error "Not a git repository" exit 1 fi } check_working_tree() { if ! git diff-index --quiet HEAD -- 2>/dev/null; then print_error "Uncommitted changes exist. Commit or stash first." exit 1 fi } check_branch_exists() { local branch_name="$1" if git rev-parse --verify "$branch_name" > /dev/null 2>&1; then print_error "Branch '$branch_name' already exists" exit 1 fi } main() { local feature_description="${1:-}" local json_output=false local no_commit=false local custom_branch_name="" local issue_number="" # Parse flags local i=2 while [[ $i -le $# ]]; do case "${!i}" in --json) json_output=true ;; --no-commit) no_commit=true ;; --branch-name) ((i++)) custom_branch_name="${!i}" ;; --issue-number) ((i++)) issue_number="${!i}" ;; esac ((i++)) done if [[ -z "$feature_description" ]]; then print_error "Feature description required" echo "Usage: $0 \"feature description\" [--json] [--no-commit] [--branch-name \"custom-name\"] [--issue-number \"123\"]" exit 1 fi check_git_repo check_working_tree local branch_name local branch_num # Determine branch number if [[ -n "$issue_number" ]]; then # Use issue number (padded to 3 digits) branch_num=$(printf "%03d" "$issue_number") else # Auto-increment (backward compatible) branch_num=$(get_next_branch_number) fi if [[ -n "$custom_branch_name" ]]; then # Use custom branch name with branch number branch_name="${branch_num}-${custom_branch_name}" else # Generate from description (backward compatible) # Extract first two words and clean them local two_words=$(echo "$feature_description" | \ tr '[:upper:]' '[:lower:]' | \ sed 's/[^a-z0-9 -]//g' | \ tr -s ' ' | \ awk '{print $1"-"$2}' | \ sed 's/^-//;s/-$//') branch_name="${branch_num}-${two_words}" fi check_branch_exists "$branch_name" local feature_dir=".specimin/plans/${branch_name}" # Create directory mkdir -p "$feature_dir" # Create and checkout branch git checkout -b "$branch_name" --quiet if [[ "$no_commit" == false ]]; then # Commit empty directory structure (backward compatible behavior) touch "$feature_dir/.gitkeep" git add "$feature_dir" git commit -m "Initialize feature: $feature_description" --quiet fi if [[ "$json_output" == true ]]; then cat << EOF { "branch_name": "$branch_name", "feature_dir": "$feature_dir", "absolute_path": "$(pwd)/$feature_dir", "status": "success" } EOF else print_success "Feature setup complete!" echo "" echo "Branch: $branch_name" echo "Directory: $feature_dir" if [[ "$no_commit" == false ]]; then echo "" echo "Next: Use spec template to create $feature_dir/spec.md" fi fi } if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then main "$@" fi