# ACM-CLI

基于 LLM 的 Git Commit Message 自动生成工具。分析暂存区代码变更，自动生成符合 Conventional Commits 规范的 commit message。

## 功能特性

- **自动生成 commit message** — 分析 `git diff --staged`，调用 LLM 生成 `type(scope): 描述` 格式的 message
- **流式输出** — LLM 生成过程实时逐字显示，后台线程异步拉取数据，渲染与网络 I/O 解耦，零卡顿
- **交互式操作** — 确认提交、编辑、反馈重新生成、放弃，一次搞定
- **反馈学习** — 自动记录编辑和反馈偏好，后续生成时智能匹配相关历史反馈注入 prompt
- **智能 diff 截断** — 按行数和字符数双重截断，避免超出模型 token 上限
- **智能拆分提交** — `--split` 将一次大变更拆分为多个原子提交
- **自动暂存** — 暂存区为空时提示自动执行 `git add -A`
- **同类变更合并** — 多文件同类操作自动合并 scope，避免冗余描述
- **多提供商支持** — 内置通义千问，兼容所有 OpenAI API 格式的提供商（DeepSeek、Ollama、智谱等）
- **灵活配置** — 全局配置 + 项目级配置，TOML 格式，支持环境变量

## 环境要求

- Python >= 3.8
- Git

## 安装

```bash
# 使用 pip
pip install acm-cli

# 使用 uv
uv pip install acm-cli

# 从源码安装（开发模式）
git clone https://github.com/hz-lxt/auto_commit_cli.git && cd auto_commit_cli
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"
```

安装完成后，终端即可使用 `acm` 命令。

## 快速开始

### 1. 初始化配置

首次使用需要配置 LLM 提供商和 API Key：

```bash
acm init
```

按提示依次完成：

```
ACM 配置初始化

可选提供商：
  1. qwen
  2. other
选择提供商: 1
输入 API Key: ****
输入模型名称 (必填): qwen-plus
自定义 Base URL (留空使用默认):
输出语言 (zh-CN, en) [zh-CN]: zh-CN

v 配置已保存到: .acm.toml
```

生成全局配置（所有项目共用）：

```bash
acm init --global
```

### 2. 日常使用

```bash
# 先暂存要提交的文件
git add .

# 自动生成 commit message
acm
```

工具会展示变更摘要，然后实时流式显示生成的 message，最后等待你选择操作：

```
> 分析暂存区变更...

  修改了 3 个文件 (+45, -12)
  ├── src/auth/login.py    (+30, -5)
  ├── src/auth/models.py   (+10, -2)
  └── tests/test_login.py  (+5, -5)

╭──────── Commit Message ────────╮
│                                │
│  feat(auth): 实现用户登录认证功能    │
│                                │
│  - 新增基于JWT的登录接口            │
│  - 添加用户模型字段校验             │
│  - 更新登录相关单元测试             │
│                                │
╰────────────────────────────────╯

确认提交(y)  编辑(e)  反馈重新生成(r)  放弃(q)
>
```

| 操作 | 说明 |
|------|------|
| `y` | 确认，执行 `git commit` |
| `e` | 打开编辑器修改 message 后提交 |
| `r` | 输入反馈，LLM 根据反馈重新生成（可多次） |
| `q` | 放弃，不提交 |

### 3. 反馈重新生成

输入 `r` 后可以告诉 AI 如何改进：

```
> r
> 请输入你的反馈（告诉AI如何改进）:
> type应该是refactor不是feat

╭──────── Commit Message ────────╮
│  refactor(auth): 重构用户登录认证逻辑  │
╰────────────────────────────────╯
```

反馈可以多次进行，直到满意为止。每次反馈都会被记录，用于后续生成优化。

### 4. 自动暂存

当暂存区为空但工作区存在未暂存的修改或未跟踪文件时，acm 会提示你是否自动执行 `git add -A`：

```
! 暂存区为空，但检测到未暂存的修改
是否执行 git add . 将所有变更添加到暂存区并继续？ [Y/n]: y
v 已执行 git add -A，所有变更已添加到暂存区

> 分析暂存区变更...
```

### 5. 智能拆分提交

使用 `--split` 标志将大变更拆分为多个原子提交：

```bash
acm --split
```

```
> 分析变更，生成拆分建议...

  建议拆分为 2 个原子提交：

  提交 1: feat(auth): 添加用户登录功能
    - src/auth/login.py
    - src/auth/models.py

  提交 2: test(auth): 添加登录功能单元测试
    - tests/test_login.py

是否按上述方案执行拆分提交？ [Y/n]:
```

### 6. 反馈学习

acm 会自动记录你的偏好到本地（`~/.acm/feedback.json`），包括：

- 使用反馈重新生成（`r`）时：记录原始 message、反馈内容、改进后 message
- 手动编辑（`e`）时：记录编辑前后的 message 差异

后续生成时，acm 会智能匹配与当前 diff 最相关的历史反馈（按 scope 和关键词匹配，最多注入 5 条），注入 prompt 让 LLM 学习你的偏好。最多保留最近 20 条记录。

管理反馈记录：

```bash
acm feedback list    # 查看所有历史反馈
acm feedback clear   # 清空所有反馈记录
```

## 命令参考

```bash
# 生成 commit message（默认命令）
acm                # 生成并交互式提交
acm --dry-run      # 仅生成，不执行 git commit
acm --verbose      # 输出调试信息（配置、prompt、LLM 响应等）
acm --split        # 智能拆分为多个原子提交
acm --version      # 查看版本

# 交互式初始化配置
acm init           # 生成项目级配置 .acm.toml
acm init --global  # 生成全局配置 ~/.acm/config.toml

# 配置管理
acm config list                              # 列出当前生效的所有配置
acm config get llm.model                     # 查看某个配置项
acm config set llm.model qwen-turbo          # 修改项目级配置
acm config set llm.model qwen-turbo --global # 修改全局配置

# 反馈记录管理
acm feedback list    # 列出所有历史反馈记录
acm feedback clear   # 清空所有反馈记录
```

## 配置文件

### 配置优先级

| 优先级 | 路径 | 说明 |
|--------|------|------|
| 高 | 项目根目录 `.acm.toml` | 项目级配置，仅当前项目生效 |
| 低 | `~/.acm/config.toml` | 全局配置，所有项目生效 |

项目级配置会覆盖全局配置中的同名字段。

### 完整配置示例

```toml
[llm]
provider = "qwen"                # 提供商名称
api_key = "sk-xxx"               # API Key（建议改用环境变量）
model = "qwen-plus"              # 模型名称（必填）
base_url = ""                    # 自定义 API 地址（留空使用提供商默认值）

[commit]
language = "zh-CN"               # 描述语言：zh-CN / en
max_diff_lines = 500             # diff 截断阈值（行数），默认 500
max_diff_chars = 15000           # diff 截断阈值（字符数），默认 15000
types = ["build", "ci"]          # 自定义类型（追加到内置标准类型之上）

[prompt]
system = ""                      # 自定义 system prompt（留空使用内置默认）
extra = ""                       # 追加到默认 prompt 之后的额外指令
```

> **关于 diff 截断**：acm 同时按行数和字符数两个维度截断 diff，取更严格的限制。当 diff 被截断时，会自动附加 `git diff --stat` 摘要，确保模型仍能了解完整的变更范围。如果遇到模型输入长度超限错误，可以降低 `max_diff_chars` 的值。

### API Key 管理

API Key 按以下优先级读取（高到低）：

1. 环境变量 `ACM_API_KEY`
2. 提供商专用环境变量（如通义千问的 `DASHSCOPE_API_KEY`）
3. 配置文件中的 `llm.api_key`

推荐使用环境变量，避免将密钥写入配置文件：

```bash
export ACM_API_KEY="sk-your-key-here"
# 或通义千问专用
export DASHSCOPE_API_KEY="sk-your-key-here"
```

## Commit Message 规范

生成的 message 格式为 `type(scope): 描述`。

### 内置 type 类型

| Type | 说明 |
|------|------|
| `feat` | 新功能 |
| `fix` | 缺陷修复 |
| `docs` | 文档变更 |
| `style` | 代码风格（不影响逻辑） |
| `refactor` | 重构 |
| `perf` | 性能优化 |
| `test` | 测试相关 |
| `chore` | 构建/工具变更 |

可通过 `commit.types` 配置项追加自定义类型。

### Scope 自动推断

根据变更文件所在目录自动推断。例如修改了 `src/auth/login.py`，scope 为 `auth`。

多文件同类操作自动合并 scope：

```
refactor(cve_service, cve_serializer): 优化导入和移除未使用模块
```

多模块不同类变更会分行描述：

```
feat(auth,api): 添加用户认证模块

- auth: 实现基于JWT的登录认证逻辑
- api: 新增 /login 和 /logout 接口
```

## 提供商配置

### 通义千问（内置）

```toml
[llm]
provider = "qwen"
model = "qwen-plus"    # 或 qwen-turbo, qwen-max 等
```

### 其他 OpenAI 兼容提供商

任何兼容 OpenAI Chat API 的服务都可以使用，只需配置 `base_url`：

```toml
# DeepSeek
[llm]
provider = "deepseek"
model = "deepseek-chat"
base_url = "https://api.deepseek.com/v1"

# Ollama 本地模型
[llm]
provider = "ollama"
model = "qwen2.5:7b"
base_url = "http://localhost:11434/v1"

# 智谱 AI
[llm]
provider = "zhipu"
model = "glm-4-flash"
base_url = "https://open.bigmodel.cn/api/paas/v4"
```

## 开发

```bash
# 克隆仓库
git clone https://github.com/hz-lxt/auto_commit_cli.git
cd auto_commit_cli

# 创建虚拟环境并安装依赖
uv venv && source .venv/bin/activate
uv pip install -e ".[dev]"

# 运行测试
uv run python -m pytest tests/ -v
```

## License

MIT
