80 lines
2.6 KiB
Go
80 lines
2.6 KiB
Go
package tui
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"fmt"
|
|
"os/exec"
|
|
"strings"
|
|
|
|
"ai-agent/internal/llm"
|
|
|
|
tea "charm.land/bubbletea/v2"
|
|
)
|
|
|
|
func runCommit(client llm.Client, model string, extraMsg string) tea.Cmd {
|
|
return func() tea.Msg {
|
|
diff, err := gitDiff()
|
|
if err != nil {
|
|
return CommitResultMsg{Err: fmt.Errorf("git diff: %w", err)}
|
|
}
|
|
if strings.TrimSpace(diff) == "" {
|
|
return CommitResultMsg{Err: fmt.Errorf("no staged changes (use `git add` first)")}
|
|
}
|
|
if len(diff) > 8000 {
|
|
diff = diff[:8000] + "\n... (truncated)"
|
|
}
|
|
prompt := "Write a concise git commit message for the following staged diff. " +
|
|
"Return ONLY the commit message, no explanation or markdown. " +
|
|
"Use conventional commit style (e.g. feat:, fix:, refactor:). " +
|
|
"Keep the first line under 72 characters."
|
|
if extraMsg != "" {
|
|
prompt += "\n\nAdditional context: " + extraMsg
|
|
}
|
|
prompt += "\n\nDiff:\n" + diff
|
|
var msgBuf strings.Builder
|
|
err = client.ChatStream(context.Background(), llm.ChatOptions{
|
|
Messages: []llm.Message{{Role: "user", Content: prompt}},
|
|
System: "You are a helpful assistant that writes git commit messages.",
|
|
}, func(chunk llm.StreamChunk) error {
|
|
if chunk.Text != "" {
|
|
msgBuf.WriteString(chunk.Text)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return CommitResultMsg{Err: fmt.Errorf("LLM error: %w", err)}
|
|
}
|
|
commitMsg := strings.TrimSpace(msgBuf.String())
|
|
if commitMsg == "" {
|
|
return CommitResultMsg{Err: fmt.Errorf("LLM returned empty commit message")}
|
|
}
|
|
commitMsg += fmt.Sprintf("\n\nAssisted-by: ai-agent (%s)", model)
|
|
if err := gitCommit(commitMsg); err != nil {
|
|
return CommitResultMsg{Err: fmt.Errorf("git commit: %w", err)}
|
|
}
|
|
return CommitResultMsg{Message: commitMsg}
|
|
}
|
|
}
|
|
|
|
func gitDiff() (string, error) {
|
|
cmd := exec.Command("git", "diff", "--cached", "--stat")
|
|
stat, _ := cmd.Output()
|
|
cmd = exec.Command("git", "diff", "--cached")
|
|
out, err := cmd.Output()
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(stat) + "\n" + string(out), nil
|
|
}
|
|
|
|
func gitCommit(msg string) error {
|
|
cmd := exec.Command("git", "commit", "-m", msg)
|
|
var stderr bytes.Buffer
|
|
cmd.Stderr = &stderr
|
|
if err := cmd.Run(); err != nil {
|
|
return fmt.Errorf("%s: %s", err, stderr.String())
|
|
}
|
|
return nil
|
|
}
|