@@ -93,9 +93,20 @@ while [ $i -le $# ]; do
9393 i=$(( i + 1 ))
9494done
9595
96- # Auto-append '/' if branch prefix is non-empty and doesn't end with '/'
97- if [ -n " $BRANCH_PREFIX " ] && [[ ! " $BRANCH_PREFIX " =~ /$ ]]; then
98- BRANCH_PREFIX=" $BRANCH_PREFIX /"
96+ # Validate and normalize branch prefix
97+ if [ -n " $BRANCH_PREFIX " ]; then
98+ BRANCH_PREFIX=$( echo " $BRANCH_PREFIX " | sed ' s/^[[:space:]]*//;s/[[:space:]]*$//' )
99+ if [ -z " $BRANCH_PREFIX " ]; then
100+ echo ' Error: --prefix cannot be empty or whitespace' >&2
101+ exit 1
102+ fi
103+ # Strip optional trailing '/' before checking for embedded slashes
104+ _check_prefix=" ${BRANCH_PREFIX%/ } "
105+ if [[ " $_check_prefix " == * /* ]]; then
106+ echo ' Error: --prefix must be a single segment (no embedded slashes); e.g. "feature", "bugfix"' >&2
107+ exit 1
108+ fi
109+ BRANCH_PREFIX=" $_check_prefix /"
99110fi
100111
101112FEATURE_DESCRIPTION=" ${ARGS[*]} "
325336 BRANCH_NAME=" ${BRANCH_PREFIX}${FEATURE_NUM} -${BRANCH_SUFFIX} "
326337fi
327338
339+ # Directory-safe name (no prefix slash) for specs/ paths
340+ FEATURE_DIR_NAME=" ${FEATURE_NUM} -${BRANCH_SUFFIX} "
341+
328342# GitHub enforces a 244-byte limit on branch names
329343# Validate and truncate if necessary
330344MAX_BRANCH_LENGTH=244
@@ -333,21 +347,22 @@ if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then
333347 # Account for prefix length: timestamp (15) + hyphen (1) = 16, or sequential (3) + hyphen (1) = 4
334348 PREFIX_LENGTH=$(( ${# BRANCH_PREFIX} + ${# FEATURE_NUM} + 1 ))
335349 MAX_SUFFIX_LENGTH=$(( MAX_BRANCH_LENGTH - PREFIX_LENGTH))
336-
350+
337351 # Truncate suffix at word boundary if possible
338352 TRUNCATED_SUFFIX=$( echo " $BRANCH_SUFFIX " | cut -c1-$MAX_SUFFIX_LENGTH )
339353 # Remove trailing hyphen if truncation created one
340354 TRUNCATED_SUFFIX=$( echo " $TRUNCATED_SUFFIX " | sed ' s/-$//' )
341-
355+
342356 ORIGINAL_BRANCH_NAME=" $BRANCH_NAME "
343357 BRANCH_NAME=" ${BRANCH_PREFIX}${FEATURE_NUM} -${TRUNCATED_SUFFIX} "
344-
358+ FEATURE_DIR_NAME=" ${FEATURE_NUM} -${TRUNCATED_SUFFIX} "
359+
345360 >&2 echo " [specify] Warning: Branch name exceeded GitHub's 244-byte limit"
346361 >&2 echo " [specify] Original: $ORIGINAL_BRANCH_NAME (${# ORIGINAL_BRANCH_NAME} bytes)"
347362 >&2 echo " [specify] Truncated to: $BRANCH_NAME (${# BRANCH_NAME} bytes)"
348363fi
349364
350- FEATURE_DIR=" $SPECS_DIR /$BRANCH_NAME "
365+ FEATURE_DIR=" $SPECS_DIR /$FEATURE_DIR_NAME "
351366SPEC_FILE=" $FEATURE_DIR /spec.md"
352367
353368if [ " $DRY_RUN " != true ]; then
@@ -403,7 +418,7 @@ if [ "$DRY_RUN" != true ]; then
403418 fi
404419
405420 # Inform the user how to persist the feature variable in their own shell
406- printf ' # To persist: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME " >&2
421+ printf ' # To persist: export SPECIFY_FEATURE=%q\n' " $FEATURE_DIR_NAME " >&2
407422fi
408423
409424if $JSON_MODE ; then
433448 echo " SPEC_FILE: $SPEC_FILE "
434449 echo " FEATURE_NUM: $FEATURE_NUM "
435450 if [ " $DRY_RUN " != true ]; then
436- printf ' # To persist in your shell: export SPECIFY_FEATURE=%q\n' " $BRANCH_NAME "
451+ printf ' # To persist in your shell: export SPECIFY_FEATURE=%q\n' " $FEATURE_DIR_NAME "
437452 fi
438453fi
0 commit comments