2026-06-21 21:23:50 +08:00
|
|
|
|
# cc-hook
|
|
|
|
|
|
|
2026-06-21 21:49:51 +08:00
|
|
|
|
🤗 Claude Code 钩子服务,将 Claude Code 事件转发至 Gotify 推送通知。
|
|
|
|
|
|
|
|
|
|
|
|
## 功能特性
|
|
|
|
|
|
|
|
|
|
|
|
- **实时通知**:当 Claude Code 需要关注时,立即收到手机推送
|
2026-06-21 22:46:20 +08:00
|
|
|
|
- **多事件支持**:Notification(权限请求、等待输入等)、Stop(任务完成)、PreToolUse(提问通知)
|
2026-06-21 21:49:51 +08:00
|
|
|
|
- **轻量部署**:单个 Docker 容器,资源占用极低
|
|
|
|
|
|
- **灵活配置**:通过环境变量自定义 Gotify 服务器和 Token
|
|
|
|
|
|
|
|
|
|
|
|
## 架构概览
|
|
|
|
|
|
|
|
|
|
|
|
```mermaid
|
|
|
|
|
|
graph LR
|
|
|
|
|
|
A[Claude Code] -->|POST /hooks| B[cc-hook]
|
|
|
|
|
|
B -->|POST /message| C[Gotify]
|
|
|
|
|
|
C -->|推送通知| D[手机/客户端]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 前置条件
|
|
|
|
|
|
|
|
|
|
|
|
- Docker 和 Docker Compose
|
|
|
|
|
|
- Claude Code 已安装
|
|
|
|
|
|
- Gotify 服务器(自建或公共)
|
|
|
|
|
|
|
|
|
|
|
|
## 快速开始
|
|
|
|
|
|
|
|
|
|
|
|
### 1. 克隆项目
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
git clone <your-repo-url> cc-hook
|
|
|
|
|
|
cd cc-hook
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. 配置环境变量
|
|
|
|
|
|
|
2026-06-21 22:01:38 +08:00
|
|
|
|
复制 `.env.example` 并填写实际配置:
|
2026-06-21 21:49:51 +08:00
|
|
|
|
|
2026-06-21 22:01:38 +08:00
|
|
|
|
```bash
|
|
|
|
|
|
cp .env.example .env
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
编辑 `.env`:
|
|
|
|
|
|
|
|
|
|
|
|
```env
|
|
|
|
|
|
GOTIFY_URL=http://your-gotify-server:port # Gotify 服务器地址
|
|
|
|
|
|
GOTIFY_TOKEN=your-token-here # Gotify 应用 Token
|
|
|
|
|
|
PORT=:8082 # 服务监听端口(默认 8082)
|
2026-06-21 21:49:51 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. 启动服务
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker-compose up -d
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 4. 配置 Claude Code
|
|
|
|
|
|
|
|
|
|
|
|
将以下内容添加到 `~/.claude/settings.json`:
|
|
|
|
|
|
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"hooks": {
|
|
|
|
|
|
"Notification": [
|
|
|
|
|
|
{
|
2026-06-23 21:27:55 +08:00
|
|
|
|
"matcher": "",
|
|
|
|
|
|
"hooks": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "http",
|
|
|
|
|
|
"url": "http://47.121.181.112:8082/hooks"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
2026-06-21 21:49:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
],
|
|
|
|
|
|
"Stop": [
|
|
|
|
|
|
{
|
2026-06-23 21:27:55 +08:00
|
|
|
|
"hooks": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "http",
|
|
|
|
|
|
"url": "http://47.121.181.112:8082/hooks"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
2026-06-21 21:49:51 +08:00
|
|
|
|
}
|
2026-06-21 22:46:20 +08:00
|
|
|
|
],
|
|
|
|
|
|
"PreToolUse": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"matcher": "AskUserQuestion",
|
|
|
|
|
|
"hooks": [
|
|
|
|
|
|
{
|
2026-06-23 21:27:55 +08:00
|
|
|
|
"type": "http",
|
|
|
|
|
|
"url": "http://47.121.181.112:8082/hooks"
|
2026-06-21 22:46:20 +08:00
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
2026-06-25 23:52:42 +08:00
|
|
|
|
],
|
|
|
|
|
|
"UserPromptSubmit": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"hooks": [
|
|
|
|
|
|
{
|
|
|
|
|
|
"type": "http",
|
|
|
|
|
|
"url": "http://47.121.181.112:8082/hooks"
|
|
|
|
|
|
}
|
|
|
|
|
|
]
|
|
|
|
|
|
}
|
2026-06-21 21:49:51 +08:00
|
|
|
|
]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 支持的事件
|
|
|
|
|
|
|
|
|
|
|
|
### Notification 事件
|
|
|
|
|
|
|
|
|
|
|
|
| Matcher | 标题 | 优先级 | 说明 |
|
|
|
|
|
|
|---------|------|--------|------|
|
|
|
|
|
|
| `permission_prompt` | 需要权限 | 7 | Claude 需要你批准一个操作 |
|
|
|
|
|
|
| `idle_prompt` | 等待输入 | 5 | Claude 完成工作,等待下一步指令 |
|
|
|
|
|
|
| `auth_success` | 认证成功 | 3 | 身份验证完成 |
|
|
|
|
|
|
| 其他 | 通知 | 5 | 默认通知 |
|
|
|
|
|
|
|
|
|
|
|
|
### Stop 事件
|
|
|
|
|
|
|
|
|
|
|
|
| 条件 | 标题 | 优先级 | 说明 |
|
|
|
|
|
|
|------|------|--------|------|
|
|
|
|
|
|
| 正常完成 | 任务完成 | 5 | Claude 完成了本轮回复 |
|
|
|
|
|
|
| 循环检测 | 循环停止 | 8 | Stop hook 连续触发多次,已自动停止 |
|
|
|
|
|
|
|
2026-06-21 22:46:20 +08:00
|
|
|
|
### PreToolUse 事件
|
|
|
|
|
|
|
|
|
|
|
|
| 工具名称 | 标题 | 优先级 | 说明 |
|
|
|
|
|
|
|----------|------|--------|------|
|
|
|
|
|
|
| `AskUserQuestion` | 等待回答 | 6 | Claude 向你提问,等待回答 |
|
|
|
|
|
|
| 其他工具 | 工具调用 | 4 | Claude 正在使用工具 |
|
|
|
|
|
|
|
2026-06-25 23:52:42 +08:00
|
|
|
|
### UserPromptSubmit 事件
|
|
|
|
|
|
|
|
|
|
|
|
| 行为 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| 记录 Prompt | 将用户提交的 prompt 存入 MySQL 数据库,便于复盘提示词质量 |
|
|
|
|
|
|
|
|
|
|
|
|
> ⚠️ 需要配置 `MYSQL_DSN` 环境变量才会启用数据库记录,否则仅打印日志。
|
|
|
|
|
|
|
|
|
|
|
|
#### 数据库表结构
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
CREATE TABLE prompts (
|
|
|
|
|
|
id BIGINT AUTO_INCREMENT PRIMARY KEY,
|
|
|
|
|
|
session_id VARCHAR(128) NOT NULL, -- Claude Code 会话 ID
|
|
|
|
|
|
project_name VARCHAR(255) NOT NULL, -- 项目名称(从 cwd 自动提取)
|
|
|
|
|
|
prompt TEXT NOT NULL, -- 用户提交的 prompt
|
|
|
|
|
|
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
|
|
|
|
INDEX idx_session_id (session_id),
|
|
|
|
|
|
INDEX idx_project_name (project_name),
|
|
|
|
|
|
INDEX idx_created_at (created_at)
|
|
|
|
|
|
);
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
- `session_id`:用于关联同一会话的多条 prompt
|
|
|
|
|
|
- `project_name`:从工作目录自动提取(如 `/home/user/my-app` → `my-app`),便于按项目筛选
|
|
|
|
|
|
|
2026-06-21 21:49:51 +08:00
|
|
|
|
## 配置说明
|
|
|
|
|
|
|
2026-06-21 22:01:38 +08:00
|
|
|
|
| 环境变量 | 必填 | 说明 |
|
|
|
|
|
|
|----------|------|------|
|
|
|
|
|
|
| `GOTIFY_URL` | 是 | Gotify 服务器地址 |
|
|
|
|
|
|
| `GOTIFY_TOKEN` | 是 | Gotify 应用 Token |
|
|
|
|
|
|
| `PORT` | 否 | 服务监听端口(默认 `:8082`) |
|
2026-06-25 23:52:42 +08:00
|
|
|
|
| `MYSQL_DSN` | 否 | MySQL 连接串,留空则不记录 prompt(格式: `user:password@tcp(host:port)/dbname?parseTime=true`) |
|
2026-06-21 21:49:51 +08:00
|
|
|
|
|
|
|
|
|
|
## API 端点
|
|
|
|
|
|
|
|
|
|
|
|
### POST /hooks
|
|
|
|
|
|
|
|
|
|
|
|
接收 Claude Code Hook 事件并转发至 Gotify。
|
|
|
|
|
|
|
|
|
|
|
|
**请求体示例:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{
|
|
|
|
|
|
"session_id": "abc123",
|
|
|
|
|
|
"cwd": "/home/user/project",
|
|
|
|
|
|
"hook_event_name": "Notification",
|
|
|
|
|
|
"matcher": "permission_prompt"
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**响应:**
|
|
|
|
|
|
- 成功:`{"status":"ok"}`
|
|
|
|
|
|
- 忽略:`{"status":"ignored"}`
|
|
|
|
|
|
- 错误:HTTP 500
|
|
|
|
|
|
|
|
|
|
|
|
### GET /health
|
|
|
|
|
|
|
|
|
|
|
|
健康检查端点。
|
|
|
|
|
|
|
|
|
|
|
|
**响应:**
|
|
|
|
|
|
```json
|
|
|
|
|
|
{"status":"ok"}
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 本地开发
|
|
|
|
|
|
|
|
|
|
|
|
### 直接运行
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 安装依赖
|
|
|
|
|
|
go mod tidy
|
|
|
|
|
|
|
2026-06-21 22:01:38 +08:00
|
|
|
|
# 复制并编辑配置
|
|
|
|
|
|
cp .env.example .env
|
2026-06-21 21:49:51 +08:00
|
|
|
|
|
2026-06-21 22:01:38 +08:00
|
|
|
|
# 运行(自动加载 .env)
|
2026-06-21 21:49:51 +08:00
|
|
|
|
go run .
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 测试
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 健康检查
|
2026-06-21 22:01:38 +08:00
|
|
|
|
curl http://47.121.181.112:8082/health
|
2026-06-21 21:49:51 +08:00
|
|
|
|
|
|
|
|
|
|
# 模拟 Notification 事件
|
2026-06-21 22:01:38 +08:00
|
|
|
|
curl -X POST http://47.121.181.112:8082/hooks \
|
2026-06-21 21:49:51 +08:00
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
|
-d '{"session_id":"test","cwd":"/tmp","hook_event_name":"Notification","matcher":"permission_prompt"}'
|
|
|
|
|
|
|
|
|
|
|
|
# 模拟 Stop 事件
|
2026-06-21 22:01:38 +08:00
|
|
|
|
curl -X POST http://47.121.181.112:8082/hooks \
|
2026-06-21 21:49:51 +08:00
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
|
-d '{"session_id":"test","cwd":"/tmp","hook_event_name":"Stop"}'
|
2026-06-21 22:46:20 +08:00
|
|
|
|
|
|
|
|
|
|
# 模拟 AskUserQuestion 事件
|
|
|
|
|
|
curl -X POST http://47.121.181.112:8082/hooks \
|
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
|
-d '{"session_id":"test","cwd":"/tmp","hook_event_name":"PreToolUse","tool_name":"AskUserQuestion","tool_input":{"question":"你想使用哪种数据库?"}}'
|
2026-06-25 23:52:42 +08:00
|
|
|
|
|
|
|
|
|
|
# 模拟 UserPromptSubmit 事件(记录 prompt 到 MySQL)
|
|
|
|
|
|
curl -X POST http://47.121.181.112:8082/hooks \
|
|
|
|
|
|
-H 'Content-Type: application/json' \
|
|
|
|
|
|
-d '{"session_id":"test","cwd":"/tmp","hook_event_name":"UserPromptSubmit","tool_input":{"prompt":"帮我写一个 Hello World 程序"}}'
|
2026-06-21 21:49:51 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 项目结构
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
cc-hook/
|
2026-06-21 22:01:38 +08:00
|
|
|
|
├── .env.example # 环境变量示例
|
|
|
|
|
|
├── .gitignore # Git 忽略规则
|
2026-06-21 21:49:51 +08:00
|
|
|
|
├── config.go # 配置管理(环境变量读取)
|
2026-06-25 23:52:42 +08:00
|
|
|
|
├── db.go # MySQL 连接与 prompt 存储
|
2026-06-21 21:49:51 +08:00
|
|
|
|
├── gotify.go # Gotify HTTP 客户端
|
|
|
|
|
|
├── handler.go # Hook 事件处理器
|
|
|
|
|
|
├── main.go # HTTP 服务入口
|
|
|
|
|
|
├── Dockerfile # 多阶段 Docker 构建
|
|
|
|
|
|
├── docker-compose.yml # Docker Compose 部署配置
|
|
|
|
|
|
└── go.mod # Go 模块定义
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## 扩展计划
|
|
|
|
|
|
|
2026-06-25 23:52:42 +08:00
|
|
|
|
- [x] 数据库记录:将 UserPromptSubmit 的 prompt 写入 MySQL,便于复盘提示词质量
|
2026-06-21 22:46:20 +08:00
|
|
|
|
- [x] 更多事件支持:PreToolUse(AskUserQuestion 提问通知)
|
2026-06-21 21:49:51 +08:00
|
|
|
|
|
|
|
|
|
|
## License
|
|
|
|
|
|
|
|
|
|
|
|
MIT
|