diff --git a/.gitignore b/.gitignore index b60ccc0..1858e5b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,4 @@ config.toml .qoder/ CLAUDE.md **/agents/ -.scratch/ \ No newline at end of file +.scratch/ diff --git a/CHANGELOG.md b/CHANGELOG.md index ab0972e..dfbfd0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [0.9.0] - 2026-10-09 ### ✨ 新功能 - 新增 `quicommit ginit`(别名 `gi`):一条命令完成本地 Git 仓库起步——建库、写最简 `README.md`、按根目录标志文件生成 `.gitignore`、确立初始分支、按 `--add` 添加远程,并可用 `--profile` 套用已有 Git 配置。命令全程离线,不创建首个提交,不覆盖已存在的 `README.md` 与 `.gitignore`;`--dry-run` 只预览,`--yes` 仅跳过确认 diff --git a/Cargo.toml b/Cargo.toml index 329ab50..1ea3e10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "quicommit" -version = "0.8.2" +version = "0.9.0" edition = "2024" authors = ["Sidney Zhang "] description = "A powerful Git assistant tool with AI-powered commit/tag/changelog generation" diff --git a/RAODMAP.md b/RAODMAP.md index 32d1fd2..a9e9457 100644 --- a/RAODMAP.md +++ b/RAODMAP.md @@ -20,53 +20,19 @@ - [x] Git 凭证管理器(Credential Helper 协议、Windows/macOS/Linux 跨平台密钥环对接、PAT scope/有效期与过期提醒) - [x] DeepSeek 最新模型支持(`deepseek-chat` / `deepseek-reasoner` / `deepseek-v4`) - [x] 流式生成的 SSE(Server-Sent Events)基础接入 +- [x] 一键初始化本地 Git 仓库(`quicommit ginit` / `gi`):建库、写最简 `README.md`、按根目录标志文件生成 `.gitignore`、确立初始分支、按 `--add` 添加远程,可用 `--profile` 套用已有 Git 配置;全程离线、不创建首个提交、不覆盖已有 `README.md` 与 `.gitignore` --- ## 进行中 🚧 -- **`quicommit ginit`**(下方计划中条目 #1):规格与取舍已定稿于 `.scratch/ginit/spec.md`,并记录 ADR 0005(`init` 与 `ginit` 并存)与 ADR 0006(ginit 的产出边界);代码已落到 `main`,随下一个版本发布后移入「已完成」。 +- (暂无) --- ## 计划中 📋 -### 1. `quicommit ginit`:一键初始化本地 Git 仓库 `P0`(🚧 规格已定稿) - -**动机**:目前 QuiCommit 只覆盖"已有仓库"之后的提交、打标签、生成变更日志等场景,缺少"仓库起步"环节——用户需要先手动 `git init`、准备 `README.md` 与 `.gitignore`、创建分支、添加远程,才能开始使用 `quicommit commit`。`ginit` 目标是用一条命令完成这套初始化流程。 - -规格详见 `.scratch/ginit/spec.md`;边界取舍见 ADR 0006,命令命名见 ADR 0005。 - -- [ ] **仓库初始化**:把当前目录初始化为 Git 仓库,实现走 `git2::Repository::init_opts`(不 shell out `git init`,因此不必把 README 承诺的 `Git 2.0+` 下限抬高到 2.28) - - 当前目录已是仓库时跳过建库,但**继续补齐**下面各项——`ginit` 是可重复执行的补齐工具 - - 当前目录位于某个外层仓库之内时直接拒绝并报出该外层仓库路径,避免造出嵌套仓库、也避免把远程加到不相干的仓库上 - - 裸仓库跳过建库与文件生成(无工作目录),但仍允许添加远程 - - 不新增 `--force`:`git init` 对已存在仓库本就幂等,`--force` 唯一可能的语义是删 `.git` 重建,那是销毁用户历史 -- [ ] **自动生成 `README.md`** - - 已存在则逐字节不动 - - 不存在则只写一行 `# <目录名>`(LF、UTF-8 无 BOM、单个结尾换行、不加"由工具生成"署名,也不放占位段落) - - 目录名取不到有意义取值(盘根、UNC、`.`)时跳过并说明 -- [ ] **自动生成 `.gitignore`** - - 已存在则完全跳过,**绝不追加**(判断"条目是否已覆盖"要匹配 `/target`、`**/target/` 等多种写法,判错就是往用户手工维护的文件里写噪音) - - 不存在则写入"通用基线 + 命中的 Ecosystem 段" - - 基线(无条件):`build/`、`dist/`、`*.log`、`tmp/`、`.env`、`.env.*` - - Ecosystem 段按根目录标志文件命中,多生态取并集,跨段条目去重(保留首次出现)、去重后为空的段整段省略:Rust / Node / Python / Go / Maven / Gradle / Ruby / PHP / Flutter / C/C++ - - **不包含** OS 专属(`.DS_Store`、`Thumbs.db`)与 IDE 专属(`.vscode/`、`*.swp`)条目;也**不照抄**本仓库根目录的 `.gitignore`——它含 `# OS`、`# IDE` 两段,并把 `Cargo.lock`、`config.toml`、`CONTEXT.md`、`adr/`、`.claude/` 这类 QuiCommit 开发私货忽略了,只可参考其分节风格 - - Rust 段不忽略 `Cargo.lock`:新生成的仓库默认应可复现构建 -- [ ] **Initial branch** - - 优先级:`-b` / `--branch ` > 全局 `init.defaultBranch` > `main` - - 只在尚不存在任何分支时确立;已有提交的仓库传 `-b` 时忽略并说明原因(重命名分支归 `git branch -m`) -- [ ] **添加远程仓库** - - `--add `(远程名默认 `origin`)与 `--add =` 两种形态,`--add` 可重复传入以一次配好多个远程 - - 远程名已存在时该条添加失败,且**不改动**现有远程的 URL(覆盖远程地址难以逆转,改地址应由用户显式用 `git remote set-url`) - - URL 只校验非空、无空白、含 `/` 或 `:`,形态合法性交给 libgit2——严格 URL 校验会误杀 `git@host:user/repo.git` 这类 scp-like 地址 - - 不调托管平台 API 创建远端仓库、不验证远程可达性、不设置 upstream 跟踪分支:`ginit` 全程离线 -- [ ] **可选的身份配置**:`--profile ` 时才把该 GitProfile 应用到新仓库(`GitProfile::apply_to_repo`)并记录目录→profile 映射;不带该参数时不碰身份、也不创建或改动 `config.toml` -- [ ] **不创建首个提交**:结束后打印逐步汇总与下一步提示(`quicommit commit`),并在仓库与全局都取不到 `user.name` / `user.email` 时明确提示如何补 -- [ ] **交互与输出**:一个预览块 + 一次确认;`--yes` 只跳过确认、不改变产出(ADR 0004),`--dry-run` 磁盘上什么都不发生;输出遵循 ADR 0003 的通道约定;终端文案全部进 7 语言 i18n,生成文件的内容不翻译 -- [ ] **失败处理**:建库或嵌套仓库冲突立即报错终止;后续单步失败(文件写入、某条远程、profile)记录后继续执行,末尾汇总并以非零码退出,不回滚已写入的文件 - -### 2. Agent Skills 技能包完善 `P0`(新增) +### 1. Agent Skills 技能包完善 `P0`(新增) **动机**:`.claude/skills`、`skills/` 目录下现有内容零散,需要系统化沉淀为可复用的 QuiCommit Agent 技能,让编码助手(Claude、Qoder 等)能够开箱用地安装、调用 QuiCommit。 @@ -82,7 +48,7 @@ - [ ] **发布与复用** - 评估随 crate 发布(打包进 `skills/`)还是通过独立仓库 / 技能市场分发 -### 3. 新增模型支持 `P1` +### 2. 新增模型支持 `P1` 扩展 LLM 提供商和模型覆盖范围,满足更多场景和偏好。 @@ -105,7 +71,7 @@ - 模型特定的 prompt 模板优化 - 支持 function calling / tool use(用于复杂生成场景) -### 4. 生成体验优化 `P1` +### 3. 生成体验优化 `P1` 提升 AI 生成提交信息、标签说明和变更日志时的用户体验。 diff --git a/README.md b/README.md index 0e8d047..f3a7436 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ A powerful AI-powered Git assistant for generating conventional commits, tags, a ## Features +- **Repository Initialization**: Bootstrap a local Git repository with `quicommit ginit` — create `.git`, write a minimal `README.md`, generate a `.gitignore` from detected ecosystems, set the initial branch, and add remotes. Runs fully offline and never creates the first commit - **AI-Powered Generation**: Generate commits, tags, and changelogs using LLM APIs (Ollama, OpenAI, Anthropic, Kimi, DeepSeek, OpenRouter) or local models - **Conventional Commits**: Full support for Conventional Commits and commitlint formats - **Profile Management**: Manage multiple Git identities with SSH keys and GPG signing support @@ -48,6 +49,28 @@ Requirements: Rust 1.70+, Git 2.0+ ## Quick Start +### Initialize a Git Repository + +```bash +# Bootstrap the current directory as a Git repository +quicommit ginit + +# Specify the initial branch (default: init.defaultBranch, then main) +quicommit ginit -b dev + +# Add remotes, repeatable: --add or --add = +quicommit ginit --add https://github.com/user/repo.git +quicommit ginit --add upstream=git@github.com:user/repo.git + +# Apply an existing Git profile to the new repository +quicommit ginit --profile work + +# Preview only, write nothing +quicommit ginit --dry-run +``` + +`ginit` runs fully offline and is safe to re-run: it never creates the first commit and never overwrites an existing `README.md` or `.gitignore`. + ### Initialize ```bash @@ -390,6 +413,8 @@ quicommit config reset --force ## Configuration File +> For a complete categorized reference — quick setup, every field, provider defaults, recipes, and troubleshooting — see [docs/configuration-guide.en.md](docs/configuration-guide.en.md). + Location: - Linux: `~/.config/quicommit/config.toml` - macOS: `~/Library/Application Support/quicommit/config.toml` @@ -564,6 +589,7 @@ src/ │ ├── changelog.rs │ ├── profile.rs │ ├── config.rs +│ ├── ginit.rs │ └── init.rs ├── config/ # Configuration management │ ├── manager.rs @@ -572,7 +598,8 @@ src/ ├── git/ # Git operations │ ├── commit.rs │ ├── tag.rs -│ └── changelog.rs +│ ├── changelog.rs +│ └── init.rs ├── llm/ # LLM integration (rig-core based) │ ├── mod.rs │ ├── prompts.rs diff --git a/docs/configuration-guide.en.md b/docs/configuration-guide.en.md new file mode 100644 index 0000000..bc799d2 --- /dev/null +++ b/docs/configuration-guide.en.md @@ -0,0 +1,695 @@ +# QuiCommit Configuration Guide + +English | [简体中文](configuration-guide.md) + +This guide is for readers who want a complete command of QuiCommit's configuration. It covers: + +- **Quick setup**: get from "create a repo → configure an LLM → first commit" in three minutes +- **Detailed settings by category**: every field in the config file, its meaning, accepted values, and default +- **Command reference**: full tables for the `config` / `profile` subcommands +- **Environment variables and global options** +- **Common recipes** and **troubleshooting** + +> For a feature overview, see [README.md](../README.md) (Chinese: [readme_zh.md](../readme_zh.md)). +> Definitions of configuration terms (Repo init, Config init, Initial branch, …) live in [CONTEXT.md](../CONTEXT.md). + +--- + +## Table of Contents + +1. [Quick Setup](#1-quick-setup) +2. [Config File Location and Precedence](#2-config-file-location-and-precedence) +3. [Detailed Settings by Category](#3-detailed-settings-by-category) + - [3.1 Application Metadata (version / default_profile)](#31-application-metadata-version--default_profile) + - [3.2 LLM and AI Generation ([llm])](#32-llm-and-ai-generation-llm) + - [3.3 Git Identities (profiles.*)](#33-git-identities-profiles) + - [3.4 Repository-to-Profile Mapping (repo_profiles)](#34-repository-to-profile-mapping-repo_profiles) + - [3.5 Commit Settings ([commit])](#35-commit-settings-commit) + - [3.6 Tag Settings ([tag])](#36-tag-settings-tag) + - [3.7 Changelog Settings ([changelog])](#37-changelog-settings-changelog) + - [3.8 Language Settings ([language])](#38-language-settings-language) + - [3.9 Output Settings ([output])](#39-output-settings-output) +4. [Config Command Reference (quicommit config)](#4-config-command-reference-quicommit-config) +5. [Profile Command Reference (quicommit profile)](#5-profile-command-reference-quicommit-profile) +6. [Tokens and Credentials](#6-tokens-and-credentials) +7. [Environment Variables](#7-environment-variables) +8. [Global Options](#8-global-options) +9. [Full Configuration Example](#9-full-configuration-example) +10. [Common Recipes](#10-common-recipes) +11. [Troubleshooting](#11-troubleshooting) + +--- + +## 1. Quick Setup + +### Prerequisites + +| Requirement | Notes | +| --- | --- | +| Git | Any version works (repo initialization uses libgit2, so it does not rely on `git init -b`) | +| Rust / an installed `quicommit` | See the [README install section](../README.md#installation) | +| System keyring (recommended) | Windows Credential Manager / macOS Keychain / Linux Secret Service. Used to store API keys and PATs securely. Check with `quicommit config check-keyring` | + +### Path A: Interactive wizard (recommended for first-time use) + +```bash +quicommit init +``` + +The wizard asks, in order: output language → your first Git Profile (name / user name / email / description / work flag) → optional SSH → optional GPG → LLM provider → model → API key (hidden input, stored in the keyring). This is what CONTEXT.md calls **Config init** — it only creates QuiCommit's own config file and never touches a Git repository. + +Skip every prompt and generate a minimal config from your local Git identity: + +```bash +quicommit init --yes +``` + +### Path B: Bootstrap a repo + configure the LLM manually + +```bash +# 1. Turn the current directory into a Git repository +# (creates .git, writes README, generates .gitignore, sets the initial branch) +quicommit ginit + +# 2. Choose an LLM provider (interactive when no provider is given) +quicommit config set-llm deepseek + +# 3. Set the API key (omit the value for hidden input; a literal value leaks into shell history) +quicommit config set-api-key + +# 4. Verify connectivity +quicommit config test-llm + +# 5. First commit +quicommit commit +``` + +### Verify the current configuration + +```bash +quicommit config show # summarized view of all effective settings +quicommit config path # print the config file path +quicommit config get llm.provider +quicommit config check-keyring # check the keyring and related environment variables +``` + +--- + +## 2. Config File Location and Precedence + +The configuration is a single TOML file whose default location is determined by the OS config directory: + +| Platform | Default path | +| --- | --- | +| Linux | `~/.config/quicommit/config.toml` | +| macOS | `~/Library/Application Support/quicommit/config.toml` | +| Windows | `%APPDATA%\quicommit\config.toml` | + +### Specifying a custom path + +Precedence (highest to lowest): + +1. The global CLI option `-c` / `--config ` +2. The environment variable `QUICOMMIT_CONFIG` +3. The platform default path above + +```bash +quicommit -c ./my-config.toml config show +# or +QUICOMMIT_CONFIG=./my-config.toml quicommit config show +``` + +> This path is shared by every subcommand (`commit`, `tag`, `changelog`, `profile`, `ginit`, …). +> With a custom path, keyring entries are still keyed by provider / profile, independent of the config file path. + +### Where each value comes from + +| Setting | Precedence (high → low) | +| --- | --- | +| Config file path | `-c/--config` > `QUICOMMIT_CONFIG` > platform default | +| API key | Environment variable (`QUICOMMIT_API_KEY`, always first within a process) > keyring (default storage) > `llm.api_key` in the config file (only when `api_key_storage = "config"`) | +| Emoji decorations | `--no-color` (disables) > `--no-emoji` / `--emoji` > `output.emoji` config > on by default | +| Log level | `RUST_LOG` > number of `-v` flags | +| Initial branch (`ginit`) | `-b/--branch` > global `init.defaultBranch` > `main` | + +--- + +## 3. Detailed Settings by Category + +Each top-level table of the config file is documented field by field below. Every field lists **key / type / default**. + +### 3.1 Application Metadata (version / default_profile) + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `version` | string | `"1"` | Config schema version, used for future migrations; normally left alone | +| `default_profile` | string (optional) | none | Default Git identity. Used when `profile apply` is called without a name and by `profile show` without a name | + +### 3.2 LLM and AI Generation ([llm]) + +QuiCommit talks to six providers through [rig-core](https://github.com/0xPlaygrounds/rig): `ollama`, `openai`, `anthropic`, `kimi`, `deepseek`, `openrouter`. + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `provider` | string | `"ollama"` | Provider name, see the table below | +| `model` | string | `"llama2"` | Model name. When switching providers, if the current model is empty or still `llama2` it is replaced by that provider's default model | +| `base_url` | string (optional) | none (provider default) | Custom API base URL, for proxies, self-hosting, or regional endpoints | +| `max_tokens` | integer | `500` | Maximum output tokens per generation | +| `temperature` | float | `0.6` | Sampling temperature. Some providers override it (see "Temperature and thinking mode") | +| `timeout` | integer (seconds) | `30` | HTTP request timeout | +| `api_key_storage` | string | `"keyring"` | API key storage: `keyring` / `config` / `environment` | +| `api_key` | string (optional) | none | Only effective when `api_key_storage = "config"`; stored in plain text | +| `thinking_enabled` | bool | `false` | Whether thinking/reasoning mode is on by default (`--think` on `commit`/`tag`/`changelog` overrides it per run) | +| `thinking_budget_tokens` | integer (optional) | none (treated as `1024` at runtime) | Anthropic only: thinking budget in tokens | + +#### Provider defaults at a glance + +| provider | Default `base_url` | Default `model` | Needs an API key? | +| --- | --- | --- | --- | +| `ollama` | `http://localhost:11434` | `llama2` | No | +| `openai` | `https://api.openai.com/v1` | `gpt-4` | Yes | +| `anthropic` | `https://api.anthropic.com/v1` | `claude-3-sonnet-20240229` | Yes | +| `kimi` | `https://api.moonshot.cn/v1` | `kimi-k2.6` | Yes | +| `deepseek` | `https://api.deepseek.com` | `deepseek-v4-flash` | Yes | +| `openrouter` | `https://openrouter.ai/api/v1` | `openai/gpt-3.5-turbo` | Yes | + +> `quicommit config list-models` prints a set of example model names for the current provider (for Ollama it tries to call the local `ollama list`). + +#### The three API key storage modes + +- `keyring` (default, recommended): stored in the system keyring; no plain text appears in `config.toml`. If the keyring is unavailable, `set-api-key` fails and suggests using an environment variable or `config`. +- `config`: written in plain text to `llm.api_key` in `config.toml`. Convenient but insecure; `set-api-key` prints a plain-text warning. +- `environment`: nothing is stored; you must set the environment variable yourself. + +Setting and deleting: + +```bash +# Option 1: interactively choose provider / model / base_url / API key +quicommit config set-llm deepseek + +# Option 2: non-interactive, pass values directly +# (--api-key lands in shell history; prefer it only for CI) +quicommit config set-llm openai --model gpt-4o --base-url https://api.openai.com/v1 + +# Set/delete the API key on its own (omit the value for hidden input) +quicommit config set-api-key +quicommit config delete-api-key +``` + +#### Temperature and thinking mode + +`--think` (or `thinking_enabled = true`) takes effect only on `deepseek`, `kimi`, `anthropic`, and `openai`; other providers silently fall back to normal generation. Per-provider parameter handling: + +| provider | Normal mode | Thinking mode | +| --- | --- | --- | +| `ollama` | Uses `temperature` / `max_tokens` | Not supported, falls back | +| `deepseek` | Uses `temperature`; sends `thinking: disabled` explicitly | Omits temperature, streams | +| `kimi` | Forces `temperature = 0.6` (ignores config) | Forces `temperature = 1.0`, streams | +| `anthropic` | Uses `temperature` | Omits temperature; raises `max_tokens` to at least `thinking_budget_tokens + 100` (budget defaults to `1024`); streams | +| `openai` | Uses `temperature`; `o*` models explicitly disable reasoning | Omits temperature, streams | +| `openrouter` | Uses `temperature` / `max_tokens` | Not supported, falls back | + +> CLI switches: `commit --think`, `tag --think`, `changelog --think`. + +### 3.3 Git Identities (profiles.*) + +Each profile is a set of Git identity + authentication settings you can switch on independently. Create them with `quicommit profile add` (interactive) or by editing the config file directly. + +Top-level fields: + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `name` | string | none | Profile name; must match the TOML table name. Letters, digits, `-`, `_` only, max 50 chars | +| `user_name` | string | none | Written to `user.name` | +| `user_email` | string | none | Written to `user.email`; must be a valid email address | +| `description` | string (optional) | none | Free-form note | +| `is_work` | bool | `false` | Whether this is a work identity (a display/filter flag only) | +| `organization` | string (optional) | none | Organization name (meaningful when `is_work = true`) | +| `signing_key` | string (optional) | none | Explicit signing key; falls back to `gpg.key_id` when unset | + +#### `[profiles..settings]` — behavioral preferences + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `auto_sign_commits` | bool | `false` | When the profile is applied, write `commit.gpgsign = true` | +| `auto_sign_tags` | bool | `false` | When the profile is applied, write `tag.gpgsign = true` | +| `default_commit_format` | string (optional) | none | Preferred commit format for this profile: `conventional` / `commitlint` | +| `repo_patterns` | array of strings | `[]` | Path fragments used to match repositories to this profile | +| `llm_provider` | string (optional) | none | Preferred LLM provider for this profile (metadata, reserved) | +| `commit_template` | string (optional) | none | Custom commit message template | + +#### `[profiles..ssh]` — SSH settings (optional) + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `private_key_path` | path (optional) | none | Path to the SSH private key (existence is validated) | +| `public_key_path` | path (optional) | none | Public key path; derived as `.pub` from the private key when unset | +| `passphrase` | string (optional) | none | Key passphrase (stored encrypted) | +| `agent_forwarding` | bool | `false` | Whether to add `-A` | +| `ssh_command` | string (optional) | none | Fully custom SSH command; overrides the other fields when set | +| `known_hosts_file` | path (optional) | none | Adds `-o UserKnownHostsFile=` | + +Applying writes `core.sshCommand` into the local Git config. Command assembly: `ssh` + (`-A`) + (`-i `) + (`-o UserKnownHostsFile=`); if `ssh_command` is set, it is used as-is. + +#### `[profiles..gpg]` — GPG settings (optional) + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `key_id` | string | none | GPG Key ID, 16–40 uppercase hex characters | +| `program` | string | Windows: `gpg.exe`; otherwise: `gpg` | Written to `gpg.program` | +| `home_dir` | path (optional) | none | GPG home directory | +| `passphrase` | string (optional) | none | Passphrase (stored encrypted) | +| `use_agent` | bool | `true` | Whether to use gpg-agent | + +Applying writes `gpg.program`, `user.signingkey`, and — per `settings.auto_sign_commits` / `settings.auto_sign_tags` — `commit.gpgsign` / `tag.gpgsign` into the local Git config. + +#### Applying (writing to Git) and display + +`profile apply` / `profile set-repo` / `profile switch` write the profile into Git config: + +- Repo-level: `user.name`, `user.email`, plus the SSH / GPG keys noted above +- Global (`profile apply --global`): written into the global Git config + +> Applying a profile first clears "managed" keys that the new profile will not set (`core.sshCommand`, `user.signingkey`, `commit.gpgsign`, `tag.gpgsign`, `gpg.program`) so stale identities do not linger. + +### 3.4 Repository-to-Profile Mapping (repo_profiles) + +Records "repository absolute path → profile name" so commands such as `profile show` can tell which identity a repository should use. It is written automatically by `profile set-repo` or `ginit --profile`; hand-editing is rarely needed. + +```toml +[repo_profiles] +"/home/me/work/project" = "work" +"/home/me/personal/project" = "personal" +``` + +### 3.5 Commit Settings ([commit]) + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `format` | string | `"conventional"` | Commit format: `conventional` or `commitlint` | +| `auto_generate` | bool | `true` | Whether to generate commit messages with AI by default (`commit --manual` turns it off per run) | + +Format differences (see [validators.rs](../src/utils/validators.rs)): + +- `conventional`: `[scope][!]: `, where type is one of 11 (feat, fix, docs, style, refactor, perf, test, build, ci, chore, revert). +- `commitlint`: extends the conventional types (adds wip, init, update, remove, security) and additionally requires the subject not to start with an uppercase letter and not to end with a period. + +```bash +quicommit config set commit.format conventional +quicommit config set-commit-format commitlint +quicommit config set commit.auto_generate false +``` + +### 3.6 Tag Settings ([tag]) + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `version_prefix` | string | `"v"` | Tag version prefix, e.g. `v1.2.3` | +| `auto_generate` | bool | `true` | Whether to generate tag messages with AI by default | + +```bash +quicommit config set tag.version_prefix v +quicommit config set-version-prefix v +``` + +### 3.7 Changelog Settings ([changelog]) + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `path` | string | `"CHANGELOG.md"` | Changelog file path | +| `auto_generate` | bool | `true` | Whether to generate changelogs with AI by default (`--no-generate` turns it off per run, using the template instead) | + +```bash +quicommit config set changelog.path CHANGELOG.md +quicommit config set-changelog-path CHANGELOG.md +``` + +### 3.8 Language Settings ([language]) + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `output_language` | string | `"en"` | Language for UI and generated text | +| `keep_types_english` | bool | `true` | Whether commit types (feat, fix, …) stay in English | +| `keep_changelog_types_english` | bool | `true` | Whether changelog categories (Added, Fixed, …) stay in English | + +Supported language codes: `en`, `zh` (including `zh-cn` / `zh-tw`), `ja`, `ko`, `es`, `fr`, `de` (full names such as `english`, `chinese` are also accepted). An invalid code silently falls back to English. + +```bash +quicommit config set-language zh # omit the argument for an interactive picker +quicommit config set language.output_language zh +quicommit config set-keep-types-english true +quicommit config set-keep-changelog-types-english true +``` + +### 3.9 Output Settings ([output]) + +| Key | Type | Default | Description | +| --- | --- | --- | --- | +| `emoji` | bool | `true` | Whether to show decorations such as ✓ / ✗ / ⚠ / → | + +```bash +quicommit config set output.emoji false +``` + +CLI overrides: `--no-color` disables colors and decorations together; `--emoji` / `--no-emoji` control decorations alone. + +--- + +## 4. Config Command Reference (quicommit config) + +Alias: `quicommit cfg`. With no subcommand it behaves like `config show`. + +| Subcommand | Description | +| --- | --- | +| `config show` | Summarized view of current settings (general / LLM / commit / tag / language / changelog / security) | +| `config path` | Print the config file path | +| `config edit` | Open the config file in `$EDITOR` (or `$VISUAL`) | +| `config get ` | Read a single setting | +| `config set ` | Write a single setting (see the key table below) | +| `config set-llm [provider]` | Configure the LLM interactively; accepts `--model` / `--base-url` / `--api-key` | +| `config set-api-key [key]` | Set the current provider's API key (hidden input when omitted) | +| `config delete-api-key` | Delete the API key from the current storage backend | +| `config set-commit-format ` | Set `conventional` / `commitlint` | +| `config set-version-prefix ` | Set the tag version prefix | +| `config set-changelog-path ` | Set the changelog path | +| `config set-language [code]` | Set the output language (interactive when omitted) | +| `config set-keep-types-english ` | Keep commit types in English | +| `config set-keep-changelog-types-english ` | Keep changelog categories in English | +| `config list-models` | List example/installed models for the current provider | +| `config test-llm` | Send a test request to verify provider connectivity | +| `config check-keyring` | Check keyring availability and related environment variables | +| `config export -o [--password]` | Export the config (optionally encrypted) | +| `config import -i [--password]` | Import a config | +| `config reset [--force]` | Reset to defaults | + +### Keys accepted by `config set` / `config get` + +| Key | Values | +| --- | --- | +| `llm.provider` | `ollama` / `openai` / `anthropic` / `kimi` / `deepseek` / `openrouter` | +| `llm.model` | any model name | +| `llm.base_url` | a URL | +| `llm.max_tokens` | integer | +| `llm.temperature` | float | +| `llm.timeout` | integer (seconds) | +| `llm.thinking_enabled` | `true` / `false` | +| `llm.thinking_budget_tokens` | integer | +| `llm.api_key_storage` | `keyring` / `config` / `environment` | +| `commit.format` | `conventional` / `commitlint` | +| `commit.auto_generate` | `true` / `false` | +| `tag.version_prefix` | string | +| `tag.auto_generate` | `true` / `false` | +| `changelog.path` | path string | +| `changelog.auto_generate` | `true` / `false` | +| `language.output_language` | language code | +| `language.keep_types_english` | `true` / `false` | +| `language.keep_changelog_types_english` | `true` / `false` | +| `output.emoji` | `true` / `false` | + +> `config set` accepts only the keys above; anything else reports an "unknown config key" error. +> **The API key is not among them** — use `config set-api-key` / `config delete-api-key`. +> Boolean keys accept only the literals `true` / `false`. + +--- + +## 5. Profile Command Reference (quicommit profile) + +Alias: `quicommit p`. With no subcommand it behaves like `profile list`. + +| Subcommand | Description | +| --- | --- | +| `profile add` | Create a profile interactively (name / user name / email / description / work flag / SSH / GPG / tokens) | +| `profile list` | List all profiles (the default is marked `●`) | +| `profile show [name]` | Show the current repo's Git config, the matched profile, and details | +| `profile edit ` | Edit interactively, with SSH / GPG / signing / tokens submenus | +| `profile copy ` | Duplicate a profile (usage stats are not copied) | +| `profile remove ` | Delete a profile (also clears its keyring PATs) | +| `profile set-default ` | Set the default profile | +| `profile set-repo ` | Record the mapping for the current repo and apply it immediately | +| `profile switch` | Switch the default profile interactively, optionally applying it to the current repo | +| `profile apply [name] [--global]` | Apply a profile (defaults to `default`) to the current repo or the global Git config | +| `profile check [name]` | Compare a profile against the current repo's Git config | +| `profile stats [name]` | Show usage statistics | +| `profile token add ` | Add a service token (stored in the keyring) | +| `profile token remove ` | Remove a service token | +| `profile token list ` | List tokens and their storage status | + +--- + +## 6. Tokens and Credentials + +### PAT (Personal Access Token) + +PATs are used to push to private repositories on GitHub / GitLab and similar platforms. They are stored in the system keyring keyed by **profile + service name** (`config.toml` only records metadata such as type, description, and whether it is stored). + +```bash +quicommit profile token add personal github +quicommit profile token list personal +quicommit profile token remove personal github +``` + +The service name is free-form (`github`, `gitlab`, `bitbucket`, …). + +### Git Credential Helper + +QuiCommit can act as a Git credential helper; once registered, Git asks it for the PAT during a push: + +```bash +git config --global credential.helper quicommit +# or limit it to one host + +git config --global credential.https://github.com.helper quicommit +``` + +`credential get|store|erase` is invoked automatically by Git and hidden from `--help`. To delete a stored credential: + +```bash +echo "protocol=https +host=github.com" | git credential reject +``` + +### Import, export, and backup + +```bash +# Plain-text export (PATs in the keyring are not included) +quicommit config export -o config-backup.toml + +# Encrypted export (profile PATs are encrypted and bundled too) +quicommit config export -o config-backup.enc --password + +# Import +quicommit config import -i config-backup.toml +quicommit config import -i config-backup.enc --password +``` + +> The encrypted export uses AES-GCM + Argon2; the file is prefixed with `ENCRYPTED:`. If a target config holds PATs but encryption is not enabled, import/export prints a plain-text warning. + +--- + +## 7. Environment Variables + +| Variable | Description | +| --- | --- | +| `QUICOMMIT_CONFIG` | Config file path (equivalent to `-c/--config`) | +| `QUICOMMIT_API_KEY` | API key for any provider; **always first within the process**, ahead of the keyring and the config file | +| `QUICOMMIT__API_KEY` | Provider-specific API key (e.g. `QUICOMMIT_OPENAI_API_KEY`). Detected by the interactive `init` and shown by `config check-keyring` | +| `EDITOR` / `VISUAL` | Editor used by `config edit` (`EDITOR` wins) | +| `NO_COLOR` | Setting any value disables colors and emoji decorations | +| `RUST_LOG` | Overrides `-v` log filtering, e.g. `RUST_LOG=debug` | + +> Note: the key resolution path used for real generation requests is `QUICOMMIT_API_KEY` → keyring → (when `api_key_storage = "config"`) the config file. +> The provider-specific `QUICOMMIT__API_KEY` is currently used only by `init`'s detection and the `config check-keyring` display; to have it feed generation, set `QUICOMMIT_API_KEY` instead. + +--- + +## 8. Global Options + +All subcommands share these global options: + +| Option | Description | +| --- | --- | +| `-v, --verbose` (repeatable) | `-v` info, `-vv` debug, `-vvv` trace | +| `-c, --config ` | Config file path | +| `--no-color` | Disable colors **and** emoji decorations (highest priority) | +| `--emoji` / `--no-emoji` | Force emoji decorations on/off, overriding `output.emoji` | + +--- + +## 9. Full Configuration Example + +```toml +version = "1" +default_profile = "personal" + +# -- LLM ------------------------------------------------------------ +[llm] +provider = "deepseek" +model = "deepseek-v4-flash" +# base_url = "https://api.deepseek.com" # omit to use the provider default +max_tokens = 500 +temperature = 0.6 +timeout = 30 +api_key_storage = "keyring" +thinking_enabled = false +# thinking_budget_tokens = 1024 # Anthropic only + +# -- Commit / tag / changelog -------------------------------------- +[commit] +format = "conventional" +auto_generate = true + +[tag] +version_prefix = "v" +auto_generate = true + +[changelog] +path = "CHANGELOG.md" +auto_generate = true + +# -- Language and output ------------------------------------------- +[language] +output_language = "en" +keep_types_english = true +keep_changelog_types_english = true + +[output] +emoji = true + +# -- Personal identity --------------------------------------------- +[profiles.personal] +name = "personal" +user_name = "Your Name" +user_email = "you@example.com" +description = "Personal projects" +is_work = false + +[profiles.personal.settings] +auto_sign_commits = false +auto_sign_tags = false +repo_patterns = [] + +# -- Work identity (with SSH + GPG) -------------------------------- +[profiles.work] +name = "work" +user_name = "Your Name" +user_email = "you@company.com" +description = "Work projects" +is_work = true +organization = "Your Company" + +[profiles.work.settings] +auto_sign_commits = true +auto_sign_tags = true +default_commit_format = "conventional" +repo_patterns = ["/work/"] + +[profiles.work.ssh] +private_key_path = "/home/user/.ssh/id_ed25519_work" +agent_forwarding = true + +[profiles.work.gpg] +key_id = "0123456789ABCDEF" +program = "gpg" +use_agent = true + +# -- Repo -> identity mapping -------------------------------------- +[repo_profiles] +"/home/user/work/project" = "work" +"/home/user/personal/project" = "personal" +``` + +--- + +## 10. Common Recipes + +### Local Ollama (no API key) + +```bash +quicommit config set-llm ollama --base-url http://localhost:11434 --model llama2 +quicommit config test-llm +``` + +### DeepSeek + +```bash +quicommit config set-llm deepseek --model deepseek-v4-flash +quicommit config set-api-key # hidden input +# or in one shot: quicommit config set-llm deepseek --api-key +``` + +### Dual work / personal identities + +```bash +quicommit profile add # create "personal" +quicommit profile add # create "work" (optionally with SSH/GPG) +quicommit profile set-default personal + +cd ~/work/project +quicommit profile set-repo work # record the mapping and apply it immediately +quicommit profile check work # verify it matches the repo's Git config +``` + +### In CI (no keyring) + +```bash +export QUICOMMIT_API_KEY= # the environment variable always wins +export QUICOMMIT_CONFIG=./ci-config.toml +quicommit commit --yes +``` + +### Enabling thinking mode + +```bash +# Just this commit +quicommit commit --think + +# On by default (takes effect for deepseek/kimi/anthropic/openai) +quicommit config set llm.thinking_enabled true +``` + +### Headless Linux (no Secret Service) + +```bash +# Option 1: use an environment variable +export QUICOMMIT_API_KEY= + +# Option 2: store it in the config file (plain text; mind the file permissions) +quicommit config set llm.api_key_storage config +quicommit config set-api-key +``` + +--- + +## 11. Troubleshooting + +### Corrupted config or an incompatible upgrade + +```bash +quicommit config reset --force # reset to defaults +quicommit init # reconfigure +``` + +### API key errors + +```bash +quicommit config check-keyring # is the keyring available, are env vars picked up? +quicommit config show # confirm provider and key mask status +quicommit config test-llm # end-to-end connectivity +``` + +- "keyring is not available": the system has no Secret Service (common on headless Linux). Use an environment variable or `api_key_storage = config`. +- "API key not configured": `set-api-key` did not take effect, or the environment variable is unset. +- A provider reports "not available": usually a `base_url` or credential problem. DeepSeek's default URL is `https://api.deepseek.com` (**without** `/v1`); if a legacy config explicitly wrote `/v1` and validation now fails, re-run `quicommit config set-llm deepseek`. + +### Changes do not take effect + +- Confirm you edited the effective config file: `quicommit config path` (remember `-c` / `QUICOMMIT_CONFIG` may change the path). +- Check whether a global option overrides the config: `--emoji`, `--no-emoji`, `--think`. +- Check environment-variable precedence: `QUICOMMIT_API_KEY`, `RUST_LOG`. + +### Opening the config file + +```bash +quicommit config edit # uses $EDITOR / $VISUAL +quicommit config show # read-only view +``` diff --git a/docs/configuration-guide.md b/docs/configuration-guide.md new file mode 100644 index 0000000..02f481a --- /dev/null +++ b/docs/configuration-guide.md @@ -0,0 +1,693 @@ +# QuiCommit 配置指南 + +[English](configuration-guide.en.md) | 简体中文 + +本指南面向希望完整掌握 QuiCommit 配置的读者,覆盖: + +- **快速设置**:三分钟跑通「建仓库 → 配 LLM → 第一次提交」 +- **分类详细设置**:逐项说明配置文件里每个字段的含义、取值与默认值 +- **命令参考**:`config` / `profile` 子命令全表 +- **环境变量与全局选项** +- **常见场景配方**与**故障排除** + +> 想先看功能全貌,请阅读 [README](../README.md)(中文版 [readme_zh.md](../readme_zh.md))。 +> 配置术语(Repo init、Config init、Initial branch 等)的定义见 [CONTEXT.md](../CONTEXT.md)。 + +--- + +## 目录 + +1. [快速设置](#1-快速设置) +2. [配置文件位置与优先级](#2-配置文件位置与优先级) +3. [分类详细设置](#3-分类详细设置) + - [3.1 应用元信息(version / default_profile)](#31-应用元信息version--default_profile) + - [3.2 LLM 与 AI 生成(`[llm]`)](#32-llm-与-ai-生成llm) + - [3.3 Git 身份配置(`[profiles.*]`)](#33-git-身份配置profiles) + - [3.4 仓库到身份映射(`[repo_profiles]`)](#34-仓库到身份映射repo_profiles) + - [3.5 提交配置(`[commit]`)](#35-提交配置commit) + - [3.6 标签配置(`[tag]`)](#36-标签配置tag) + - [3.7 变更日志配置(`[changelog]`)](#37-变更日志配置changelog) + - [3.8 语言配置(`[language]`)](#38-语言配置language) + - [3.9 输出配置(`[output]`)](#39-输出配置output) +4. [配置命令参考(`quicommit config`)](#4-配置命令参考quicommit-config) +5. [身份配置命令参考(`quicommit profile`)](#5-身份配置命令参考quicommit-profile) +6. [令牌与凭据](#6-令牌与凭据) +7. [环境变量](#7-环境变量) +8. [全局选项](#8-全局选项) +9. [完整配置示例](#9-完整配置示例) +10. [常见场景配方](#10-常见场景配方) +11. [故障排除](#11-故障排除) + +--- + +## 1. 快速设置 + +### 前置条件 + +| 依赖 | 说明 | +| --- | --- | +| Git | 任意版本均可(仓库初始化走 libgit2,不依赖 `git init -b`) | +| Rust / 已安装的 `quicommit` | 见 [README 安装章节](../README.md#installation) | +| 系统密钥环(推荐) | Windows 凭据管理器 / macOS Keychain / Linux Secret Service。用于安全存放 API Key 与 PAT。用 `quicommit config check-keyring` 检查 | + +### 路线 A:交互式向导(推荐首次使用) + +```bash +quicommit init +``` + +向导依次询问:输出语言 → 第一个 Git Profile(名称 / 用户名 / 邮箱 / 描述 / 是否工作身份)→ 可选 SSH → 可选 GPG → LLM provider → 模型 → API Key(隐藏输入,存入密钥环)。这与 CONTEXT.md 所说的 **Config init** 对应——只创建 QuiCommit 自己的配置文件,不碰 Git 仓库。 + +跳过所有提问、使用本机 Git 身份生成一份最小配置: + +```bash +quicommit init --yes +``` + +### 路线 B:仓库起步 + 手动配 LLM + +```bash +# ① 把当前目录变成 Git 仓库(建库、写 README、生成 .gitignore、定初始分支) +quicommit ginit + +# ② 选择 LLM provider(无参数时进入交互选择) +quicommit config set-llm deepseek + +# ③ 设置 API Key(省略值可隐藏输入;已带值时注意 shell 历史泄露) +quicommit config set-api-key + +# ④ 验证连通性 +quicommit config test-llm + +# ⑤ 第一次提交 +quicommit commit +``` + +### 验证当前配置 + +```bash +quicommit config show # 汇总展示所有生效配置 +quicommit config path # 打印配置文件路径 +quicommit config get llm.provider +quicommit config check-keyring # 检查密钥环与相关环境变量 +``` + +--- + +## 2. 配置文件位置与优先级 + +配置文件是单个 TOML 文件,默认位置由操作系统的配置目录决定: + +| 平台 | 默认路径 | +| --- | --- | +| Linux | `~/.config/quicommit/config.toml` | +| macOS | `~/Library/Application Support/quicommit/config.toml` | +| Windows | `%APPDATA%\quicommit\config.toml` | + +### 指定自定义路径 + +优先级(从高到低): + +1. 命令行全局选项 `-c` / `--config ` +2. 环境变量 `QUICOMMIT_CONFIG` +3. 上述平台默认路径 + +```bash +quicommit -c ./my-config.toml config show +# 或 +QUICOMMIT_CONFIG=./my-config.toml quicommit config show +``` + +> 该路径会被所有子命令共享(`commit`、`tag`、`changelog`、`profile`、`ginit` 等)。 +> 用自定义路径时,密钥环条目仍按 provider / profile 维度存取,与配置文件路径无关。 + +### 配置来源优先级汇总 + +| 配置项 | 优先级(高 → 低) | +| --- | --- | +| 配置文件路径 | `-c/--config` > `QUICOMMIT_CONFIG` > 平台默认 | +| API Key | 环境变量(`QUICOMMIT_API_KEY`,进程内始终优先) > 密钥环(默认存储方式) > 配置文件内 `llm.api_key`(仅当 `api_key_storage = "config"`) | +| Emoji 装饰 | `--no-color`(关闭) > `--no-emoji` / `--emoji` > 配置 `output.emoji` > 默认开启 | +| 日志级别 | `RUST_LOG` > `-v` 次数 | +| Initial branch(`ginit`) | `-b/--branch` > 全局 `init.defaultBranch` > `main` | + +--- + +## 3. 分类详细设置 + +下面按配置文件的顶层表(table)逐项说明。每个字段都给出 **键名 / 类型 / 默认值**。 + +### 3.1 应用元信息(version / default_profile) + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `version` | string | `"1"` | 配置结构版本,用于未来迁移,一般不手动改动 | +| `default_profile` | string(可省略) | 无 | 默认 Git 身份名。`profile apply` 不带参数、`profile show` 不带参数时使用它 | + +### 3.2 LLM 与 AI 生成(`[llm]`) + +QuiCommit 通过 [rig-core](https://github.com/0xPlaygrounds/rig) 统一对接六家 provider:`ollama`、`openai`、`anthropic`、`kimi`、`deepseek`、`openrouter`。 + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `provider` | string | `"ollama"` | provider 名称,见下表 | +| `model` | string | `"llama2"` | 模型名。切换 provider 时若当前模型为空或仍是 `llama2`,会自动替换为该 provider 的默认模型 | +| `base_url` | string(可省略) | 无(用 provider 默认) | 自定义 API 地址,用于代理、私有部署或国内镜像 | +| `max_tokens` | 整数 | `500` | 单次生成的最大输出 token 数 | +| `temperature` | 浮点 | `0.6` | 采样温度。部分 provider 会覆盖它(见「温度与思考模式」) | +| `timeout` | 整数(秒) | `30` | HTTP 请求超时 | +| `api_key_storage` | string | `"keyring"` | API Key 存储方式:`keyring` / `config` / `environment` | +| `api_key` | string(可省略) | 无 | 仅当 `api_key_storage = "config"` 时生效,明文存于配置文件 | +| `thinking_enabled` | 布尔 | `false` | 默认是否启用思考/推理模式(`commit`/`tag`/`changelog` 的 `--think` 可临时覆盖) | +| `thinking_budget_tokens` | 整数(可省略) | 无(运行期按 `1024` 处理) | 仅 Anthropic 使用:思考预算 token | + +#### Provider 默认值速查 + +| provider | 默认 `base_url` | 默认 `model` | 是否需要 API Key | +| --- | --- | --- | --- | +| `ollama` | `http://localhost:11434` | `llama2` | 否 | +| `openai` | `https://api.openai.com/v1` | `gpt-4` | 是 | +| `anthropic` | `https://api.anthropic.com/v1` | `claude-3-sonnet-20240229` | 是 | +| `kimi` | `https://api.moonshot.cn/v1` | `kimi-k2.6` | 是 | +| `deepseek` | `https://api.deepseek.com` | `deepseek-v4-flash` | 是 | +| `openrouter` | `https://openrouter.ai/api/v1` | `openai/gpt-3.5-turbo` | 是 | + +> `quicommit config list-models` 会按当前 provider 打印一批示例模型名(Ollama 会尝试直接调用本机 `ollama list`)。 + +#### API Key 的三种存储方式 + +- `keyring`(默认,推荐):存入系统密钥环,`config.toml` 中不出现明文。密钥环不可用时 `set-api-key` 会报错并提示改用环境变量或 `config`。 +- `config`:明文写入 `config.toml` 的 `llm.api_key`。方便但不安全,`set-api-key` 会给出明文告警。 +- `environment`:不存储,要求你自行设置环境变量。 + +设置与删除: + +```bash +# 方式一:交互式选择 provider / 模型 / base_url / API Key +quicommit config set-llm deepseek + +# 方式二:非交互,直接给出参数(--api-key 会进入 shell 历史,建议仅用于 CI) +quicommit config set-llm openai --model gpt-4o --base-url https://api.openai.com/v1 + +# 单独设置/删除 API Key(省略值则隐藏输入) +quicommit config set-api-key +quicommit config delete-api-key +``` + +#### 温度与思考模式 + +`--think`(或配置 `thinking_enabled = true`)只在 `deepseek`、`kimi`、`anthropic`、`openai` 上生效;其余 provider 会自动降级为普通生成。各 provider 的参数处理如下: + +| provider | 普通模式 | 思考模式 | +| --- | --- | --- | +| `ollama` | 使用 `temperature` / `max_tokens` | 不支持,降级 | +| `deepseek` | 使用 `temperature`;显式传 `thinking: disabled` | 省略 temperature,走流式 | +| `kimi` | 强制 `temperature = 0.6`(忽略配置) | 强制 `temperature = 1.0`,走流式 | +| `anthropic` | 使用 `temperature` | 省略 temperature;`max_tokens` 提升到至少 `thinking_budget_tokens + 100`,预算缺省 `1024`;走流式 | +| `openai` | 使用 `temperature`;`o*` 系列模型显式关闭推理 | 省略 temperature,走流式 | +| `openrouter` | 使用 `temperature` / `max_tokens` | 不支持,降级 | + +> 命令层开关:`commit --think`、`tag --think`、`changelog --think`。 + +### 3.3 Git 身份配置(`[profiles.*]`) + +每个 profile 是一组可独立启用的 Git 身份 + 认证设置。用 `quicommit profile add`(交互式)创建,或直接编辑配置文件。 + +顶层字段: + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `name` | string | 无 | profile 名,须与 TOML 表名一致。只允许字母、数字、`-`、`_`,最长 50 字符 | +| `user_name` | string | 无 | 写入 `user.name` | +| `user_email` | string | 无 | 写入 `user.email`,须符合邮箱格式 | +| `description` | string(可省略) | 无 | 备注 | +| `is_work` | 布尔 | `false` | 是否工作身份(仅作展示/筛选标记) | +| `organization` | string(可省略) | 无 | 组织名(`is_work = true` 时有意义) | +| `signing_key` | string(可省略) | 无 | 直接指定签名 key;未设置时回退到 `gpg.key_id` | + +#### `[profiles..settings]` — 行为偏好 + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `auto_sign_commits` | 布尔 | `false` | 应用该 profile 时是否写入 `commit.gpgsign = true` | +| `auto_sign_tags` | 布尔 | `false` | 应用该 profile 时是否写入 `tag.gpgsign = true` | +| `default_commit_format` | string(可省略) | 无 | 该 profile 偏好的提交格式:`conventional` / `commitlint` | +| `repo_patterns` | 字符串数组 | `[]` | 用于把仓库路径匹配到该 profile 的路径片段 | +| `llm_provider` | string(可省略) | 无 | 该 profile 偏好的 LLM provider(元数据,供未来使用) | +| `commit_template` | string(可省略) | 无 | 自定义提交信息模板 | + +#### `[profiles..ssh]` — SSH 配置(可选) + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `private_key_path` | 路径(可省略) | 无 | SSH 私钥路径(校验存在性) | +| `public_key_path` | 路径(可省略) | 无 | 公钥路径;未设置时按私钥推导 `.pub` | +| `passphrase` | string(可省略) | 无 | 私钥口令(加密存储) | +| `agent_forwarding` | 布尔 | `false` | 是否加 `-A` | +| `ssh_command` | string(可省略) | 无 | 完全自定义的 SSH 命令;设置后覆盖其他字段 | +| `known_hosts_file` | 路径(可省略) | 无 | 追加 `-o UserKnownHostsFile=` | + +应用时写入 Git 本地配置 `core.sshCommand`。命令拼接规则:`ssh` +(`-A`)+(`-i <私钥>`)+(`-o UserKnownHostsFile=<文件>`);若 `ssh_command` 有值则直接使用它。 + +#### `[profiles..gpg]` — GPG 配置(可选) + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `key_id` | string | 无 | GPG Key ID,须为 16–40 位十六进制大写字符 | +| `program` | string | Windows:`gpg.exe`;其他:`gpg` | 写入 `gpg.program` | +| `home_dir` | 路径(可省略) | 无 | GPG home 目录 | +| `passphrase` | string(可省略) | 无 | 口令(加密存储) | +| `use_agent` | 布尔 | `true` | 是否使用 gpg-agent | + +应用时写入 Git 本地配置 `gpg.program`、`user.signingkey`,并按 `settings.auto_sign_commits` / `auto_sign_tags` 写入 `commit.gpgsign` / `tag.gpgsign`。 + +#### 应用(写出到 Git)与展示 + +`profile apply` / `profile set-repo` / `profile switch` 会把 profile 写入 Git 配置: + +- 仓库级:`user.name`、`user.email`,以及上面提到的 SSH / GPG 相关键 +- 全局(`profile apply --global`):写入全局 Git 配置 + +> 应用 profile 时会先清理「新 profile 不再设置」的受管键(`core.sshCommand`、`user.signingkey`、`commit.gpgsign`、`tag.gpgsign`、`gpg.program`),避免残留旧身份。 + +### 3.4 仓库到身份映射(`[repo_profiles]`) + +把「仓库绝对路径 → profile 名」记录下来,供 `profile show` 等命令识别当前仓库应使用哪个身份。由 `profile set-repo` 或 `ginit --profile` 自动写入,一般无需手改。 + +```toml +[repo_profiles] +"/home/me/work/project" = "work" +"/home/me/personal/project" = "personal" +``` + +### 3.5 提交配置(`[commit]`) + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `format` | string | `"conventional"` | 提交格式:`conventional` 或 `commitlint` | +| `auto_generate` | 布尔 | `true` | 是否默认用 AI 生成提交信息(`commit --manual` 可临时关闭) | + +格式差异(见 [validators.rs](../src/utils/validators.rs)): + +- `conventional`:`[scope][!]: `,type 取自 11 种(feat、fix、docs、style、refactor、perf、test、build、ci、chore、revert)。 +- `commitlint`:在 conventional 基础上扩展 type(额外支持 wip、init、update、remove、security),并额外校验主题不以大写字母开头、不以句点结尾。 + +```bash +quicommit config set commit.format conventional +quicommit config set-commit-format commitlint +quicommit config set commit.auto_generate false +``` + +### 3.6 标签配置(`[tag]`) + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `version_prefix` | string | `"v"` | tag 版本前缀,如 `v1.2.3` | +| `auto_generate` | 布尔 | `true` | 是否默认用 AI 生成 tag message | + +```bash +quicommit config set tag.version_prefix v +quicommit config set-version-prefix v +``` + +### 3.7 变更日志配置(`[changelog]`) + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `path` | string | `"CHANGELOG.md"` | 变更日志文件路径 | +| `auto_generate` | 布尔 | `true` | 是否默认用 AI 生成变更日志(`--no-generate` 可临时关闭,改用模版) | + +```bash +quicommit config set changelog.path CHANGELOG.md +quicommit config set-changelog-path CHANGELOG.md +``` + +### 3.8 语言配置(`[language]`) + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `output_language` | string | `"en"` | 界面/生成文案语言 | +| `keep_types_english` | 布尔 | `true` | 提交类型(feat、fix…)是否保持英文 | +| `keep_changelog_types_english` | 布尔 | `true` | 变更日志分类(Added、Fixed…)是否保持英文 | + +支持的语言代码:`en`、`zh`(含 `zh-cn` / `zh-tw`)、`ja`、`ko`、`es`、`fr`、`de`(也接受 `english`、`chinese` 等全称)。无效代码会静默回退为英文。 + +```bash +quicommit config set-language zh # 省略参数则交互式选择 +quicommit config set language.output_language zh +quicommit config set-keep-types-english true +quicommit config set-keep-changelog-types-english true +``` + +### 3.9 输出配置(`[output]`) + +| 键 | 类型 | 默认值 | 说明 | +| --- | --- | --- | --- | +| `emoji` | 布尔 | `true` | 是否显示 ✓ / ✗ / ⚠ / → 等装饰符号 | + +```bash +quicommit config set output.emoji false +``` + +命令行覆盖:`--no-color` 会同时关闭颜色与装饰;`--emoji` / `--no-emoji` 单独控制装饰。 + +--- + +## 4. 配置命令参考(`quicommit config`) + +别名:`quicommit cfg`。不带子命令时等价于 `config show`。 + +| 子命令 | 说明 | +| --- | --- | +| `config show` | 汇总展示当前配置(通用 / LLM / 提交 / 标签 / 语言 / 变更日志 / 安全) | +| `config path` | 打印配置文件路径 | +| `config edit` | 用 `$EDITOR`(或 `$VISUAL`)打开配置文件 | +| `config get ` | 读取单个配置项 | +| `config set ` | 写入单个配置项(见下方键表) | +| `config set-llm [provider]` | 交互式配置 LLM;可带 `--model` / `--base-url` / `--api-key` | +| `config set-api-key [key]` | 设置当前 provider 的 API Key(省略则隐藏输入) | +| `config delete-api-key` | 从当前存储方式中删除 API Key | +| `config set-commit-format ` | 设置 `conventional` / `commitlint` | +| `config set-version-prefix ` | 设置 tag 版本前缀 | +| `config set-changelog-path ` | 设置变更日志路径 | +| `config set-language [code]` | 设置输出语言(省略则交互式选择) | +| `config set-keep-types-english ` | 提交类型是否保持英文 | +| `config set-keep-changelog-types-english ` | 变更日志分类是否保持英文 | +| `config list-models` | 按当前 provider 列出示例/已安装模型 | +| `config test-llm` | 发送一次测试请求,验证 provider 连通性 | +| `config check-keyring` | 检查密钥环可用性与相关环境变量 | +| `config export -o [--password]` | 导出配置(可选加密) | +| `config import -i [--password]` | 导入配置 | +| `config reset [--force]` | 重置为默认配置 | + +### `config set` / `config get` 支持的键 + +| 键 | 取值 | +| --- | --- | +| `llm.provider` | `ollama` / `openai` / `anthropic` / `kimi` / `deepseek` / `openrouter` | +| `llm.model` | 任意模型名 | +| `llm.base_url` | URL | +| `llm.max_tokens` | 整数 | +| `llm.temperature` | 浮点 | +| `llm.timeout` | 整数(秒) | +| `llm.thinking_enabled` | `true` / `false` | +| `llm.thinking_budget_tokens` | 整数 | +| `llm.api_key_storage` | `keyring` / `config` / `environment` | +| `commit.format` | `conventional` / `commitlint` | +| `commit.auto_generate` | `true` / `false` | +| `tag.version_prefix` | 字符串 | +| `tag.auto_generate` | `true` / `false` | +| `changelog.path` | 路径字符串 | +| `changelog.auto_generate` | `true` / `false` | +| `language.output_language` | 语言代码 | +| `language.keep_types_english` | `true` / `false` | +| `language.keep_changelog_types_english` | `true` / `false` | +| `output.emoji` | `true` / `false` | + +> `config set` 只接受上表键名,其他键会报「未知配置键」。 +> **API Key 不在其中**——请用 `config set-api-key` / `config delete-api-key`。 +> 布尔键只接受字面 `true` / `false`。 + +--- + +## 5. 身份配置命令参考(`quicommit profile`) + +别名:`quicommit p`。不带子命令时等价于 `profile list`。 + +| 子命令 | 说明 | +| --- | --- | +| `profile add` | 交互式新建 profile(名称 / 用户名 / 邮箱 / 描述 / 工作标记 / SSH / GPG / 令牌) | +| `profile list` | 列出所有 profile(默认项标 `●`) | +| `profile show [name]` | 展示当前仓库 Git 配置、匹配到的 profile 及详情 | +| `profile edit ` | 交互式编辑,含 SSH / GPG / 签名偏好 / 令牌子菜单 | +| `profile copy ` | 复制 profile(不复制使用统计) | +| `profile remove ` | 删除 profile(同时清理其密钥环 PAT) | +| `profile set-default ` | 设置默认 profile | +| `profile set-repo ` | 为当前仓库记录映射并立即应用 | +| `profile switch` | 交互式切换默认 profile,可选是否应用到当前仓库 | +| `profile apply [name] [--global]` | 把 profile(默认取 default)应用到当前仓库或全局 Git 配置 | +| `profile check [name]` | 对比 profile 与当前仓库 Git 配置的差异 | +| `profile stats [name]` | 查看使用统计 | +| `profile token add ` | 添加服务令牌(存入密钥环) | +| `profile token remove ` | 移除服务令牌 | +| `profile token list ` | 列出令牌及其存储状态 | + +--- + +## 6. 令牌与凭据 + +### PAT(Personal Access Token) + +PAT 用于把私有仓库推送到 GitHub / GitLab 等平台,按 **profile + 服务名** 维度存入系统密钥环(`config.toml` 中只记录元信息如类型、描述、是否已存储)。 + +```bash +quicommit profile token add personal github +quicommit profile token list personal +quicommit profile token remove personal github +``` + +服务名可自由填写(`github`、`gitlab`、`bitbucket` 等)。 + +### Git Credential Helper + +QuiCommit 可作为 Git 凭据助手,注册后 Git 推送时会自动向它索取 PAT: + +```bash +git config --global credential.helper quicommit +# 或限定主机 + +git config --global credential.https://github.com.helper quicommit +``` + +`credential get|store|erase` 由 Git 自动调用,命令隐藏在 `--help` 之外。删除已存凭据: + +```bash +echo "protocol=https +host=github.com" | git credential reject +``` + +### 导入导出与备份 + +```bash +# 明文导出(不含密钥环中的 PAT) +quicommit config export -o config-backup.toml + +# 加密导出(把 profile 的 PAT 一并加密打包) +quicommit config export -o config-backup.enc --password + +# 导入 +quicommit config import -i config-backup.toml +quicommit config import -i config-backup.enc --password +``` + +> 加密导出使用 AES-GCM + Argon2;导出文件以 `ENCRYPTED:` 前缀标识。若目标配置含有 PAT 却未启用加密,导入/导出会给出明文告警。 + +--- + +## 7. 环境变量 + +| 变量 | 说明 | +| --- | --- | +| `QUICOMMIT_CONFIG` | 配置文件路径(等价于 `-c/--config`) | +| `QUICOMMIT_API_KEY` | 任意 provider 的 API Key,**进程内始终优先**于密钥环与配置文件 | +| `QUICOMMIT__API_KEY` | provider 专属 API Key(如 `QUICOMMIT_OPENAI_API_KEY`)。交互式 `init` 会检测它,`config check-keyring` 会展示它 | +| `EDITOR` / `VISUAL` | `config edit` 使用的编辑器(`EDITOR` 优先) | +| `NO_COLOR` | 设置任意值即关闭彩色与 Emoji 装饰 | +| `RUST_LOG` | 覆盖 `-v` 的日志过滤,如 `RUST_LOG=debug` | + +> 注意:真正参与生成请求的 Key 解析路径是 `QUICOMMIT_API_KEY` → 密钥环 →(`api_key_storage = "config"` 时)配置文件。 +> provider 专属的 `QUICOMMIT__API_KEY` 目前仅用于 `init` 的检测与 `config check-keyring` 的展示;若要让它生效参与生成,请改设 `QUICOMMIT_API_KEY`。 + +--- + +## 8. 全局选项 + +所有子命令共享以下全局选项: + +| 选项 | 说明 | +| --- | --- | +| `-v, --verbose`(可叠加) | `-v` info、`-vv` debug、`-vvv` trace | +| `-c, --config ` | 配置文件路径 | +| `--no-color` | 关闭颜色**与** Emoji 装饰(最高优先级) | +| `--emoji` / `--no-emoji` | 强制开启/关闭 Emoji 装饰,覆盖 `output.emoji` | + +--- + +## 9. 完整配置示例 + +```toml +version = "1" +default_profile = "personal" + +# ── LLM ───────────────────────────────────────────────────────────── +[llm] +provider = "deepseek" +model = "deepseek-v4-flash" +# base_url = "https://api.deepseek.com" # 省略则用 provider 默认 +max_tokens = 500 +temperature = 0.6 +timeout = 30 +api_key_storage = "keyring" +thinking_enabled = false +# thinking_budget_tokens = 1024 # 仅 Anthropic 使用 + +# ── 提交 / 标签 / 变更日志 ────────────────────────────────────────── +[commit] +format = "conventional" +auto_generate = true + +[tag] +version_prefix = "v" +auto_generate = true + +[changelog] +path = "CHANGELOG.md" +auto_generate = true + +# ── 语言与输出 ────────────────────────────────────────────────────── +[language] +output_language = "zh" +keep_types_english = true +keep_changelog_types_english = true + +[output] +emoji = true + +# ── 个人身份 ──────────────────────────────────────────────────────── +[profiles.personal] +name = "personal" +user_name = "Your Name" +user_email = "you@example.com" +description = "个人项目" +is_work = false + +[profiles.personal.settings] +auto_sign_commits = false +auto_sign_tags = false +repo_patterns = [] + +# ── 工作身份(含 SSH + GPG) ─────────────────────────────────────── +[profiles.work] +name = "work" +user_name = "Your Name" +user_email = "you@company.com" +description = "工作项目" +is_work = true +organization = "Your Company" + +[profiles.work.settings] +auto_sign_commits = true +auto_sign_tags = true +default_commit_format = "conventional" +repo_patterns = ["/work/"] + +[profiles.work.ssh] +private_key_path = "/home/user/.ssh/id_ed25519_work" +agent_forwarding = true + +[profiles.work.gpg] +key_id = "0123456789ABCDEF" +program = "gpg" +use_agent = true + +# ── 仓库 → 身份映射 ──────────────────────────────────────────────── +[repo_profiles] +"/home/user/work/project" = "work" +"/home/user/personal/project" = "personal" +``` + +--- + +## 10. 常见场景配方 + +### 用本地 Ollama(无需 API Key) + +```bash +quicommit config set-llm ollama --base-url http://localhost:11434 --model llama2 +quicommit config test-llm +``` + +### 用 DeepSeek + +```bash +quicommit config set-llm deepseek --model deepseek-v4-flash +quicommit config set-api-key # 隐藏输入 +# 或一次性:quicommit config set-llm deepseek --api-key +``` + +### 工作 / 个人双身份 + +```bash +quicommit profile add # 建 personal +quicommit profile add # 再建 work(可配 SSH/GPG) +quicommit profile set-default personal + +cd ~/work/project +quicommit profile set-repo work # 记录映射并立即应用到本仓库 +quicommit profile check work # 校验是否与仓库 Git 配置一致 +``` + +### 在 CI 中使用(无密钥环) + +```bash +export QUICOMMIT_API_KEY= # 环境变量始终优先 +export QUICOMMIT_CONFIG=./ci-config.toml +quicommit commit --yes +``` + +### 启用思考模式 + +```bash +# 仅本次提交 +quicommit commit --think + +# 全局默认开启(对 deepseek/kimi/anthropic/openai 生效) +quicommit config set llm.thinking_enabled true +``` + +### Linux 无桌面环境(无 Secret Service) + +```bash +# 方案一:改用环境变量 +export QUICOMMIT_API_KEY= + +# 方案二:改存配置文件(明文,注意权限) +quicommit config set llm.api_key_storage config +quicommit config set-api-key +``` + +--- + +## 11. 故障排除 + +### 配置损坏或旧版本不兼容 + +```bash +quicommit config reset --force # 重置为默认 +quicommit init # 重新配置 +``` + +### API Key 相关报错 + +```bash +quicommit config check-keyring # 确认密钥环是否可用、环境变量是否被识别 +quicommit config show # 确认 provider 与 Key 掩码状态 +quicommit config test-llm # 端到端连通性 +``` + +- 「keyring is not available」:系统无 Secret Service(常见于无桌面的 Linux)。改用环境变量或 `api_key_storage = config`。 +- 「API key not configured」:`set-api-key` 未生效或环境变量未设置。 +- provider 报「not available」:多为 `base_url` 或凭据问题。DeepSeek 的默认地址是 `https://api.deepseek.com`(**不带** `/v1`);若历史配置里显式写过 `/v1` 导致校验失败,请重新执行 `quicommit config set-llm deepseek`。 + +### 改了配置但行为没变 + +- 确认改的是生效的配置文件:`quicommit config path`(注意 `-c` / `QUICOMMIT_CONFIG` 可能改变了路径)。 +- 检查全局选项是否覆盖了配置:`--emoji`、`--no-emoji`、`--think`。 +- 检查环境变量优先级:`QUICOMMIT_API_KEY`、`RUST_LOG`。 + +### 打开配置文件 + +```bash +quicommit config edit # 使用 $EDITOR / $VISUAL +quicommit config show # 只读查看 +``` diff --git a/readme_zh.md b/readme_zh.md index 935f689..7918875 100644 --- a/readme_zh.md +++ b/readme_zh.md @@ -14,6 +14,7 @@ ## 主要功能 +- **仓库初始化**:用 `quicommit ginit` 一键起步本地 Git 仓库——建库、写最简 `README.md`、按识别出的生态生成 `.gitignore`、确立初始分支、添加远程。全程离线,不创建首个提交 - **AI智能生成**:使用LLM API(Ollama本地、OpenAI、Anthropic Claude、Kimi、DeepSeek、OpenRouter)生成提交信息、标签和变更日志 - **规范化提交**:支持Conventional Commits和commitlint格式规范 - **多配置管理**:为不同场景管理多个Git身份,支持SSH密钥和GPG签名配置 @@ -47,6 +48,28 @@ cargo install --path . ## 快速开始 +### 初始化 Git 仓库 + +```bash +# 把当前目录初始化为 Git 仓库 +quicommit ginit + +# 指定初始分支(默认取全局 init.defaultBranch,缺省为 main) +quicommit ginit -b dev + +# 添加远程,可重复传入:--add 或 --add <名称>= +quicommit ginit --add https://github.com/user/repo.git +quicommit ginit --add upstream=git@github.com:user/repo.git + +# 把已有 Git 配置套用到新仓库 +quicommit ginit --profile work + +# 只预览,不写任何内容 +quicommit ginit --dry-run +``` + +`ginit` 全程离线且可重复执行:不创建首个提交,也不覆盖已存在的 `README.md` 与 `.gitignore`。 + ### 初始化配置 ```bash @@ -384,6 +407,8 @@ quicommit config reset --force ## 配置文件 +> 完整的分类配置说明(快速设置、逐字段详解、provider 默认值、常见配方与故障排除)见 [docs/configuration-guide.md](docs/configuration-guide.md)。 + 配置文件位置: - Linux: `~/.config/quicommit/config.toml` - macOS: `~/Library/Application Support/quicommit/config.toml` @@ -558,6 +583,7 @@ src/ │ ├── changelog.rs │ ├── profile.rs │ ├── config.rs +│ ├── ginit.rs │ └── init.rs ├── config/ # 配置管理 │ ├── manager.rs @@ -566,7 +592,8 @@ src/ ├── git/ # Git操作封装 │ ├── commit.rs │ ├── tag.rs -│ └── changelog.rs +│ ├── changelog.rs +│ └── init.rs ├── llm/ # LLM 集成(基于 rig-core) │ ├── mod.rs │ ├── prompts.rs