Files
cc-hook/README.md
T
wonder 717d2c70be feat: 支持 UserPromptSubmit 事件,将 prompt 存入 MySQL
- 新增 db.go:MySQL 连接管理、自动建表、兼容旧表 ALTER
- handler.go:处理 UserPromptSubmit,从 cwd 提取项目名称
- main.go:可选初始化 MySQL,优雅关闭释放连接
- config.go:新增 MYSQL_DSN 配置项
- 表结构:session_id + project_name + prompt + created_at
2026-06-25 23:52:42 +08:00

267 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# cc-hook
🤗 Claude Code 钩子服务,将 Claude Code 事件转发至 Gotify 推送通知。
## 功能特性
- **实时通知**:当 Claude Code 需要关注时,立即收到手机推送
- **多事件支持**:Notification(权限请求、等待输入等)、Stop(任务完成)、PreToolUse(提问通知)
- **轻量部署**:单个 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. 配置环境变量
复制 `.env.example` 并填写实际配置:
```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)
```
### 3. 启动服务
```bash
docker-compose up -d
```
### 4. 配置 Claude Code
将以下内容添加到 `~/.claude/settings.json`:
```json
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "http",
"url": "http://47.121.181.112:8082/hooks"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "http",
"url": "http://47.121.181.112:8082/hooks"
}
]
}
],
"PreToolUse": [
{
"matcher": "AskUserQuestion",
"hooks": [
{
"type": "http",
"url": "http://47.121.181.112:8082/hooks"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "http",
"url": "http://47.121.181.112:8082/hooks"
}
]
}
]
}
}
```
## 支持的事件
### Notification 事件
| Matcher | 标题 | 优先级 | 说明 |
|---------|------|--------|------|
| `permission_prompt` | 需要权限 | 7 | Claude 需要你批准一个操作 |
| `idle_prompt` | 等待输入 | 5 | Claude 完成工作,等待下一步指令 |
| `auth_success` | 认证成功 | 3 | 身份验证完成 |
| 其他 | 通知 | 5 | 默认通知 |
### Stop 事件
| 条件 | 标题 | 优先级 | 说明 |
|------|------|--------|------|
| 正常完成 | 任务完成 | 5 | Claude 完成了本轮回复 |
| 循环检测 | 循环停止 | 8 | Stop hook 连续触发多次,已自动停止 |
### PreToolUse 事件
| 工具名称 | 标题 | 优先级 | 说明 |
|----------|------|--------|------|
| `AskUserQuestion` | 等待回答 | 6 | Claude 向你提问,等待回答 |
| 其他工具 | 工具调用 | 4 | Claude 正在使用工具 |
### 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`),便于按项目筛选
## 配置说明
| 环境变量 | 必填 | 说明 |
|----------|------|------|
| `GOTIFY_URL` | 是 | Gotify 服务器地址 |
| `GOTIFY_TOKEN` | 是 | Gotify 应用 Token |
| `PORT` | 否 | 服务监听端口(默认 `:8082`) |
| `MYSQL_DSN` | 否 | MySQL 连接串,留空则不记录 prompt(格式: `user:password@tcp(host:port)/dbname?parseTime=true`) |
## 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
# 复制并编辑配置
cp .env.example .env
# 运行(自动加载 .env)
go run .
```
### 测试
```bash
# 健康检查
curl http://47.121.181.112:8082/health
# 模拟 Notification 事件
curl -X POST http://47.121.181.112:8082/hooks \
-H 'Content-Type: application/json' \
-d '{"session_id":"test","cwd":"/tmp","hook_event_name":"Notification","matcher":"permission_prompt"}'
# 模拟 Stop 事件
curl -X POST http://47.121.181.112:8082/hooks \
-H 'Content-Type: application/json' \
-d '{"session_id":"test","cwd":"/tmp","hook_event_name":"Stop"}'
# 模拟 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":"你想使用哪种数据库?"}}'
# 模拟 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 程序"}}'
```
## 项目结构
```
cc-hook/
├── .env.example # 环境变量示例
├── .gitignore # Git 忽略规则
├── config.go # 配置管理(环境变量读取)
├── db.go # MySQL 连接与 prompt 存储
├── gotify.go # Gotify HTTP 客户端
├── handler.go # Hook 事件处理器
├── main.go # HTTP 服务入口
├── Dockerfile # 多阶段 Docker 构建
├── docker-compose.yml # Docker Compose 部署配置
└── go.mod # Go 模块定义
```
## 扩展计划
- [x] 数据库记录:将 UserPromptSubmit 的 prompt 写入 MySQL,便于复盘提示词质量
- [x] 更多事件支持:PreToolUse(AskUserQuestion 提问通知)
## License
MIT