13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
# File 'lib/hunkify/cli.rb', line 13
def run(argv)
context = argv[0]
UI.
begin
Git.root
rescue RuntimeError
puts Color.red(" ✗ This directory is not a Git repository.")
exit 1
end
unless Git.has_staged_changes?
puts Color.yellow(" ⚠️ No staged changes.")
puts Color.dim(" Run first: git add <files>")
exit 0
end
original_staged_files = Git.staged_files
puts Color.dim(" Parsing diff...")
raw_diff = Git.staged_diff
hunks = DiffParser.parse(raw_diff)
if hunks.empty?
puts Color.yellow(" ⚠️ No hunks found in staged diff.")
exit 0
end
UI.print_hunks_overview(hunks)
hunks_by_id = hunks.each_with_object({}) { |h, acc| acc[h.id] = h }
puts Color.dim(" Analyzing and grouping via Claude #{AnthropicAPI::MODEL}...")
puts
begin
result = AnthropicAPI.group_hunks(hunks, context: context)
rescue JSON::ParserError
puts Color.red(" ✗ Invalid AI response (malformed JSON). Try again.")
exit 1
rescue RuntimeError => e
puts Color.red(" ✗ #{e.message}")
exit 1
end
commits_data = result["commits"]
if commits_data.nil? || commits_data.empty?
puts Color.red(" ✗ The AI returned no commits.")
exit 1
end
commits_data.each do |c|
c["hunk_ids"] = c["hunk_ids"].select { |id| hunks_by_id.key?(id) }
end
commits_data.reject! { |c| c["hunk_ids"].empty? }
UI.print_grouping(commits_data, hunks_by_id)
UI.reassign_loop(commits_data, hunks_by_id, context: context)
plan = []
commits_data.each_with_index do |c, i|
puts Color.bold(" Commit #{i + 1}/#{commits_data.size}:")
msg = UI.prompt_edit_commit(c, i + 1, commits_data.size)
plan << [msg, c["hunk_ids"]] if msg
puts
end
if plan.empty?
puts Color.yellow(" No commit selected.")
exit 0
end
UI.confirm_plan(plan)
execute_commits(plan, hunks_by_id, original_staged_files)
puts
puts Color.bold(Color.green(" ✅ #{plan.size} commit(s) successfully created!"))
puts
end
|