<h1 align="center">
  <img src="public/logo.png" alt="difit" width="260">
</h1>

<p align="center">
  <a href="./README.md">English</a> | <a href="./README.ja.md">日本語</a> | 简体中文 | <a href="./README.ko.md">한국어</a>
</p>

![difit screenshot](docs/images/screenshot.png)

**difit** 是一个让你使用 GitHub 风格查看器查看和审查本地 git 差异的 CLI 工具。除了清晰的视觉效果外，评论还可以作为 AI 提示进行复制。AI 时代的本地代码审查工具！

## ⚡ 快速开始

先试用一下

```bash
npx difit  # 在 WebUI 中查看最新提交的差异
```

安装后使用

```bash
npm install -g difit
difit  # 在 WebUI 中查看最新提交的差异
```

使其可供 AI 代理使用

```bash
npx skills add yoshiko-pg/difit # 为代理添加 Skills
```

安装后包含的主要 Skill：

- `difit`：在代码修改后通过 difit 向用户请求审查
- `difit-review`：审查特定 diff 或 PR，并启动一个已预载评论或说明的 difit

## 🚀 使用方法

### 基本用法

```bash
difit <target>                    # 查看单个提交差异
difit <target> [compare-with]     # 比较两个提交/分支
```

### 单个提交审查

```bash
difit          # HEAD（最新）提交
difit 6f4a9b7  # 特定提交
difit feature  # feature 分支上的最新提交
```

### 比较两个提交

```bash
difit @ main         # 与 main 分支比较（@ 是 HEAD 的别名）
difit feature main   # 比较分支
difit . origin/main  # 比较工作目录与远程 main
```

### 特殊参数

difit 支持常见差异场景的特殊关键字：

```bash
difit .        # 所有未提交的更改（暂存区 + 未暂存）
difit staged   # 暂存区更改
difit working  # 仅未暂存的更改
```

### GitHub PR

```bash
difit --pr https://github.com/owner/repo/pull/123
```

`--pr` 模式会在内部执行 `gh pr diff --patch` 来获取补丁。
同时还会导入 PR 中未解决的 inline review thread，并在 difit 中作为启动评论显示出来。

认证由 GitHub CLI 处理：

1. **先登录一次**（推荐）：`gh auth login`
2. **令牌认证**（CI/非交互环境）：设置 `GH_TOKEN` 或 `GITHUB_TOKEN`

#### GitHub Enterprise Server

对于 Enterprise Server PR，请先让 GitHub CLI 认证到 Enterprise 主机：

1. `gh auth login --hostname YOUR-ENTERPRISE-SERVER`
2. 或设置 `GH_HOST=YOUR-ENTERPRISE-SERVER`，并配置 `GH_TOKEN` / `GITHUB_TOKEN`

### 启动时注入评论

你可以在启动 difit 时注入初始审查评论：

```bash
difit --comment '{"type":"thread","filePath":"src/example.ts","position":{"side":"new","line":10},"body":"这次修改的背景是……"}'
```

`--comment` 可重复指定，同时接受单个 JSON object 或 JSON array。支持的类型如下：

- `thread`：在指定 diff 位置创建新的 thread
- `reply`：向相同 diff 位置上最新的现有 thread 添加 reply

如果相同评论已经存在，difit 会跳过导入。

### 标准输入

通过使用管道通过标准输入传递统一差异，您可以使用 difit 查看来自任何工具的差异。

```bash
# 查看来自其他工具的差异
diff -u file1.txt file2.txt | difit

# 审查保存的补丁
cat changes.patch | difit

# 与合并基础比较
git diff --merge-base main feature | difit

# 将整个现有文件视为新添加进行审查
git diff -- /dev/null path/to/file | difit

# 显式标准输入模式
git diff --cached | difit -
```

标准输入模式按“意图优先”规则选择：

- `-` 会显式启用标准输入模式
- 当提供 positional 参数（`<target>` / `[compare-with]`）或 `--pr` 时，difit 会按 Git/PR 模式处理，不会自动读取 stdin
- 只有在未显式选择模式且 stdin 为 pipe/file/socket 时，才会自动进入标准输入模式

## ⚙️ CLI 选项

| 标志                  | 默认值         | 描述                                                                              |
| --------------------- | -------------- | --------------------------------------------------------------------------------- |
| `<target>`            | HEAD           | 提交哈希、标签、HEAD~n、分支或特殊参数                                            |
| `[compare-with]`      | -              | 要比较的可选第二个提交（显示两者之间的差异）                                      |
| `--merge-base`        | false          | 在 diff 前先用 `git merge-base` 解析基准 revision（仅限 Git revision 模式）       |
| `--pr <url>`          | -              | 要审查的 GitHub PR URL（例如：https://github.com/owner/repo/pull/123）            |
| `--comment <json>`    | -              | 注入初始评论（可重复指定；接受 JSON object 或 array）                             |
| `--port`              | 4966           | 首选端口；如果被占用则回退到 +1                                                   |
| `--host`              | 127.0.0.1      | 绑定服务器的主机地址（使用 0.0.0.0 进行外部访问）                                 |
| `--no-open`           | false          | 不自动打开浏览器                                                                  |
| `--clean`             | false          | 启动时清除所有现有评论和已查看的文件                                              |
| `--include-untracked` | false          | 自动将 untracked 文件包含在 diff 中（仅在 `.` 或 `working` 时有效）               |
| `--keep-alive`        | false          | 浏览器断开后保持服务器运行（使用 Ctrl+C 手动停止）                                |
| `--background`        | false          | 在后台保持服务器运行，并输出 JSON 连接信息                                        |
| `--context <lines>`   | Git 默认值 (3) | 限制每处变更周围的上下文行数（`0` 仅显示变更行；不可与 `--pr` 或 stdin 一起使用） |

## 💬 评论系统

difit 包含一个审查评论系统，便于向 AI 编码代理提供反馈：

1. **添加评论**：单击任何差异行上的评论按钮或拖动选择范围
2. **编辑评论**：使用编辑按钮编辑现有评论
3. **生成提示**：评论包含"复制提示"按钮，可为 AI 编码代理格式化上下文
4. **复制全部**：使用"复制所有提示"以结构化格式复制所有评论
5. **持久存储**：评论按每个提交保存在浏览器 localStorage 中

### 评论提示格式

```sh
src/components/Button.tsx:L42   # 此行自动添加
使此变量名更具描述性
```

对于范围选择：

```sh
src/components/Button.tsx:L42-L48   # 此行自动添加
此部分是不必要的
```

## 🤖 从代理调用

你可以通过以下命令安装这些 Skill，以便从 AI 代理中使用 difit：

```sh
npx skills add yoshiko-pg/difit
```

安装后包含的主要 Skill：

- `difit`：在代码修改后通过 difit 向用户请求审查
- `difit-review`：审查特定 diff 或 PR，并启动一个已预载评论或说明的 difit

在代码修改后或自动审查时，代理可以根据目的使用对应的 Skill 来启动 difit 服务器。

## 🎨 语法高亮语言

- **JavaScript/TypeScript**：`.js`, `.jsx`, `.ts`, `.tsx`, `.svelte`
- **Web 技术**：HTML, CSS, JSON, XML, Markdown
- **Shell 脚本**：`.sh`, `.bash`, `.zsh`, `.fish`
- **后端语言**：PHP, SQL, Ruby, Java, Scala, Perl, Elixir, Haskell, Clojure
- **系统语言**：C, C++, C#, Rust, Go
- **移动语言**：Swift, Kotlin, Dart
- **基础设施即代码**：Terraform (HCL), Nix
- **其他**：Python, Protobuf, YAML, Solidity, Vim Script, GDScript

## 🔍 自动折叠文件

difit 自动识别并折叠某些文件以保持视图整洁：

- **已删除文件**：已删除的文件不需要详细审查，因此自动折叠
- **自动生成文件**：自动生成的代码默认折叠。这包括：
  - 锁定文件 (`package-lock.json`, `go.sum`, `Cargo.lock`, `Gemfile.lock` 等)
  - 压缩文件 (`*.min.js`, `*.min.css`)
  - 源映射 (`*.map`)
  - 生成的代码:
    - Orval (`*.msw.ts`, `*.zod.ts`, `*.api.ts`)
    - Dart (`*.g.dart`, `*.freezed.dart`)
    - C# (`*.g.cs`, `*.designer.cs`)
    - Protobuf (`*.pb.go`, `*.pb.cc`, `*.pb.h`)
  - 框架:
    - Ruby on Rails (`db/schema.rb`)
    - Laravel (`_ide_helper.php`)
    - Gradle (`gradle.lockfile`)
    - Python (`uv.lock`, `pdm.lock`)
  - 通用生成文件 (`*.generated.cs`, `*.generated.ts`, `*.generated.js`)
  - 基于内容的检测:
    - 包含 `@generated` 标记的文件
    - 包含 `DO NOT EDIT` 标头的文件
    - 特定语言的生成标头 (Go, Python 等)

## 🛠️ 开发

```bash
# 安装依赖
pnpm install

# 启动开发服务器（带热重载）
# 这会同时运行 Vite 开发服务器和 CLI，NODE_ENV=development
pnpm run dev

# 构建并启动生产服务器
pnpm run start <target>

# 构建生产版本
pnpm run build

# 运行测试
pnpm test

# 运行 typecheck、lint 和格式化
pnpm run check
pnpm run format
```

### 开发工作流程

- **`pnpm run dev`**：同时启动 Vite 开发服务器（带热重载）和 CLI 服务器
- **`pnpm run start <target>`**：构建所有内容并启动生产服务器（用于测试最终构建）
- **开发模式**：使用 Vite 的开发服务器进行热重载和快速开发
- **生产模式**：提供构建的静态文件（供 npx 和生产构建使用）

## 🏗️ 架构

- **CLI**：使用 Commander.js 进行参数解析，具有全面的验证
- **后端**：Express 服务器配合 simple-git 进行差异处理
- **GitHub 集成**：使用 GitHub CLI（`gh pr diff --patch`）获取 PR 补丁
- **前端**：React 18 + TypeScript + Vite
- **样式**：Tailwind CSS v4，带有类似 GitHub 的深色主题
- **语法高亮**：Prism.js 带动态语言加载
- **测试**：Vitest 用于单元测试，测试文件与源代码放在一起
- **质量**：oxlint、oxfmt、lefthook 预提交钩子

## 📋 要求

- Node.js ≥ 21.0.0
- 包含要审查的提交的 Git 仓库
- 使用 `--pr` 模式时需要 GitHub CLI（`gh`）

## 📄 许可证

MIT
