gitbasher 5.2.0 → 5.2.1
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/CHANGELOG.md +6 -0
- package/dist/gitb +61 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to gitbasher are generated automatically by [semantic-release](https://github.com/semantic-release/semantic-release) from [Conventional Commits](https://www.conventionalcommits.org/) on `main`. The project follows [Semantic Versioning](https://semver.org/).
|
|
4
4
|
|
|
5
|
+
## [5.2.1](https://github.com/maxbolgarin/gitbasher/compare/v5.2.0...v5.2.1) (2026-07-11)
|
|
6
|
+
|
|
7
|
+
### 🐛 Bug Fixes
|
|
8
|
+
|
|
9
|
+
* **commit:** gate AI split by scope count and stop discarding near-complete groupings ([90becec](https://github.com/maxbolgarin/gitbasher/commit/90becec0f49a7a3e57e57e11a71b6909884ab337))
|
|
10
|
+
|
|
5
11
|
## [5.2.0](https://github.com/maxbolgarin/gitbasher/compare/v5.1.0...v5.2.0) (2026-07-07)
|
|
6
12
|
|
|
7
13
|
### 🚀 Features
|
package/dist/gitb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -o pipefail
|
|
3
|
-
GITBASHER_VERSION="5.2.
|
|
3
|
+
GITBASHER_VERSION="5.2.1"
|
|
4
4
|
if [ "$1" == "init" ] || [ "$1" == "i" ]; then
|
|
5
5
|
git init
|
|
6
6
|
fi
|
|
@@ -6972,6 +6972,18 @@ function get_max_split_groups {
|
|
|
6972
6972
|
[ "$v" -gt 20 ] && v=20
|
|
6973
6973
|
printf '%s' "$v"
|
|
6974
6974
|
}
|
|
6975
|
+
function should_attempt_ai_grouping {
|
|
6976
|
+
local scope_count="$1" mode="$2"
|
|
6977
|
+
case "$mode" in
|
|
6978
|
+
always) return 0 ;;
|
|
6979
|
+
never) return 1 ;;
|
|
6980
|
+
esac
|
|
6981
|
+
case "$scope_count" in
|
|
6982
|
+
''|*[!0-9]*) return 1 ;;
|
|
6983
|
+
esac
|
|
6984
|
+
[ "$scope_count" -ge 3 ] && return 0
|
|
6985
|
+
return 1
|
|
6986
|
+
}
|
|
6975
6987
|
#
|
|
6976
6988
|
#
|
|
6977
6989
|
#
|
|
@@ -7146,6 +7158,7 @@ Read <diff> to decide which files implement the same feature. Output TSV (scope<
|
|
|
7146
7158
|
local ai_response
|
|
7147
7159
|
ai_response=$(call_ai_api "$system_prompt" "$user_prompt" "$AI_MAX_TOKENS_FULL" "" "" "low" 2>/dev/null)
|
|
7148
7160
|
if [ $? -ne 0 ] || [ -z "$ai_response" ]; then
|
|
7161
|
+
ai_grouping_fail_reason="API error"
|
|
7149
7162
|
return 1
|
|
7150
7163
|
fi
|
|
7151
7164
|
ai_response=$(printf '%s' "$ai_response" | LC_ALL=C sed -e 's/^```[a-zA-Z]*$//' -e 's/^```$//')
|
|
@@ -7153,6 +7166,14 @@ Read <diff> to decide which files implement the same feature. Output TSV (scope<
|
|
|
7153
7166
|
while IFS= read -r f; do
|
|
7154
7167
|
[ -n "$f" ] && gset_add staged_set "$f"
|
|
7155
7168
|
done <<< "$staged_files"
|
|
7169
|
+
gmap_clear folder_scope_of
|
|
7170
|
+
local _fk _ff
|
|
7171
|
+
for _fk in "${split_group_keys[@]}"; do
|
|
7172
|
+
while IFS= read -r _ff; do
|
|
7173
|
+
[ -n "$_ff" ] && gmap_set folder_scope_of "$_ff" "$_fk"
|
|
7174
|
+
done <<< "$(gmap_get split_groups "$_fk")"
|
|
7175
|
+
done
|
|
7176
|
+
gmap_clear assigned_set
|
|
7156
7177
|
gmap_clear new_groups
|
|
7157
7178
|
local -a new_keys=()
|
|
7158
7179
|
local line scope file tab_count
|
|
@@ -7174,6 +7195,8 @@ Read <diff> to decide which files implement the same feature. Output TSV (scope<
|
|
|
7174
7195
|
fi
|
|
7175
7196
|
scope=$(printf '%s' "$scope" | LC_ALL=C tr '[:upper:]' '[:lower:]')
|
|
7176
7197
|
gset_has staged_set "$file" || continue
|
|
7198
|
+
gset_has assigned_set "$file" && continue
|
|
7199
|
+
gset_add assigned_set "$file"
|
|
7177
7200
|
if ! gmap_has new_groups "$scope"; then
|
|
7178
7201
|
new_keys+=("$scope")
|
|
7179
7202
|
gmap_set new_groups "$scope" "$file"
|
|
@@ -7181,15 +7204,44 @@ Read <diff> to decide which files implement the same feature. Output TSV (scope<
|
|
|
7181
7204
|
gmap_set new_groups "$scope" "$(gmap_get new_groups "$scope")"$'\n'"$file"
|
|
7182
7205
|
fi
|
|
7183
7206
|
done <<< "$ai_response"
|
|
7184
|
-
local total_assigned=0 total_staged
|
|
7207
|
+
local total_assigned=0 total_staged unmatched
|
|
7185
7208
|
local key
|
|
7186
7209
|
for key in "${new_keys[@]}"; do
|
|
7187
7210
|
total_assigned=$((total_assigned + $(printf '%s\n' "$(gmap_get new_groups "$key")" | grep -c .)))
|
|
7188
7211
|
done
|
|
7189
7212
|
total_staged=$(printf '%s\n' "$staged_files" | grep -c .)
|
|
7190
|
-
if [
|
|
7213
|
+
if [ ${#new_keys[@]} -lt 1 ] || [ "$total_assigned" -eq 0 ]; then
|
|
7214
|
+
ai_grouping_fail_reason="no usable grouping returned"
|
|
7215
|
+
return 1
|
|
7216
|
+
fi
|
|
7217
|
+
unmatched=$((total_staged - total_assigned))
|
|
7218
|
+
[ "$unmatched" -lt 0 ] && unmatched=0 # dedup should prevent this; be safe
|
|
7219
|
+
if [ "$unmatched" -gt 0 ] && [ $((unmatched * 5)) -gt "$total_staged" ]; then
|
|
7220
|
+
ai_grouping_fail_reason="${unmatched} of ${total_staged} files unassigned"
|
|
7191
7221
|
return 1
|
|
7192
7222
|
fi
|
|
7223
|
+
if [ "$unmatched" -gt 0 ]; then
|
|
7224
|
+
local single_group=""
|
|
7225
|
+
[ ${#new_keys[@]} -eq 1 ] && single_group="${new_keys[0]}"
|
|
7226
|
+
local sf leftover_scope
|
|
7227
|
+
while IFS= read -r sf; do
|
|
7228
|
+
[ -z "$sf" ] && continue
|
|
7229
|
+
gset_has assigned_set "$sf" && continue
|
|
7230
|
+
if [ -n "$single_group" ]; then
|
|
7231
|
+
leftover_scope="$single_group"
|
|
7232
|
+
else
|
|
7233
|
+
leftover_scope=$(gmap_get folder_scope_of "$sf")
|
|
7234
|
+
[ -z "$leftover_scope" ] && leftover_scope="misc"
|
|
7235
|
+
fi
|
|
7236
|
+
if ! gmap_has new_groups "$leftover_scope"; then
|
|
7237
|
+
new_keys+=("$leftover_scope")
|
|
7238
|
+
gmap_set new_groups "$leftover_scope" "$sf"
|
|
7239
|
+
else
|
|
7240
|
+
gmap_set new_groups "$leftover_scope" "$(gmap_get new_groups "$leftover_scope")"$'\n'"$sf"
|
|
7241
|
+
fi
|
|
7242
|
+
gset_add assigned_set "$sf"
|
|
7243
|
+
done <<< "$staged_files"
|
|
7244
|
+
fi
|
|
7193
7245
|
gmap_clear split_groups
|
|
7194
7246
|
split_group_keys=()
|
|
7195
7247
|
for key in "${new_keys[@]}"; do
|
|
@@ -7606,18 +7658,17 @@ function try_offer_commit_split {
|
|
|
7606
7658
|
local ai_grouping
|
|
7607
7659
|
ai_grouping=$(get_config_value gitbasher.commit-ai-grouping "auto")
|
|
7608
7660
|
local should_use_ai="false"
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
*) should_use_ai="true" ;; # auto + always: attempt AI
|
|
7612
|
-
esac
|
|
7613
|
-
if [ -z "$llm" ]; then
|
|
7614
|
-
should_use_ai="false"
|
|
7661
|
+
if [ -n "$llm" ] && should_attempt_ai_grouping "${#split_group_keys[@]}" "$ai_grouping"; then
|
|
7662
|
+
should_use_ai="true"
|
|
7615
7663
|
fi
|
|
7616
7664
|
if [ "$should_use_ai" = "true" ] && check_ai_available 2>/dev/null; then
|
|
7617
7665
|
echo
|
|
7618
7666
|
echo -e "${YELLOW}Grouping changes by feature with AI...${ENDCOLOR}"
|
|
7667
|
+
local ai_grouping_fail_reason=""
|
|
7619
7668
|
if ! group_files_by_feature_with_ai; then
|
|
7620
|
-
|
|
7669
|
+
local reason_suffix=""
|
|
7670
|
+
[ -n "$ai_grouping_fail_reason" ] && reason_suffix=" (${ai_grouping_fail_reason})"
|
|
7671
|
+
echo -e "${YELLOW}AI feature grouping failed${reason_suffix}, using folder-based grouping.${ENDCOLOR}"
|
|
7621
7672
|
fi
|
|
7622
7673
|
consolidate_split_groups "$(get_max_split_groups)"
|
|
7623
7674
|
fi
|