# Butler-Shell

基于 LLM 与 tmux 的持久化 Shell 助手，通过 Telegram / QQ 接收自然语言指令，在远程服务器上执行命令并返回总结。

## 架构

```
Telegram Bot ──┐                    ┌── Telegram reply
               ├── _process_message ─┤
QQ (NapCat) ───┘   (共享逻辑)       └── NapCat send_private_msg
```

- **Gateway 层**：多通道抽象，当前支持 Telegram 和 NapCatQQ
- **Agent 层**：LLM 理解自然语言意图，生成命令，总结输出
- **Session 层**：tmux 管理持久化 Shell 会话，自动检测交互模式
- **Security 层**：用户白名单、危险命令审批、敏感信息过滤

## 快速开始

### 1. 配置

```bash
cp .env.example .env
# 编辑 .env，填入：
# - ANTHROPIC_API_KEY (必需，LLM 推理)
# - ANTHROPIC_BASE_URL (如用代理)
# - ANTHROPIC_MODEL (模型名称)
# - TELEGRAM_BOT_TOKEN (通过 @BotFather 创建 Bot 获取)
```

### 2. 安装

```bash
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```

### 3. 启动

```bash
python -m butler.main
```

服务运行在 `http://0.0.0.0:9600`。

### 4. 测试

```bash
# 健康检查
curl http://localhost:9600/health

# Mock 测试（不需要 Telegram/QQ）
python scripts/mock_test.py 当前目录有多少个文件
python scripts/mock_test.py 看下磁盘空间

# 查看原始输出日志
python scripts/mock_test.py raw
```

### 5. Telegram 对话

在 Telegram 给你的 Bot 发消息即可，支持自然语言：

- "查看当前目录"
- "看下磁盘空间"
- "系统负载怎么样"
- "当前目录有多少个文件"

## 项目结构

```
src/butler/
├── main.py                 # FastAPI 入口 + GatewayManager
├── config.py               # 配置管理 (pydantic-settings)
├── agent/
│   └── __init__.py         # LLM Agent (自然语言理解 + 输出总结)
├── gateway/
│   ├── base.py             # Gateway 抽象基类
│   ├── telegram.py         # Telegram Bot Gateway
│   └── napcat.py           # NapCatQQ WebSocket Gateway
├── session/
│   ├── state.py            # 数据模型 (SessionState, NapCatEvent)
│   └── wrapper.py          # TmuxWrapper (tmux 会话管理)
├── security/
│   ├── auth.py             # 用户认证授权
│   ├── guardrail.py        # 危险命令检测
│   └── sanitizer.py        # 敏感信息过滤
├── skills/
│   ├── base.py             # Skill 基类和注册表
│   ├── log_skill.py        # 日志 Skill (SQLite)
│   └── system_skill.py     # 系统信息 Skill
└── workflows/
    ├── handle_message.py   # Inngest 消息处理工作流
    └── guardrail.py        # Inngest 审批工作流
```

## 交互流程

1. 用户通过 Telegram/QQ 发送自然语言消息
2. Gateway 收到消息，调用 `_process_message()`
3. Agent (LLM) 理解意图，生成 shell 命令
4. 危险命令检查（rm -rf, sudo 等需审批）
5. 通过 tmux 执行命令
6. Agent 总结输出为自然语言
7. 通过原通道回复用户

## API 端点

| 端点 | 方法 | 说明 |
|------|------|------|
| `/health` | GET | 存活检查 |
| `/ready` | GET | 就绪检查（含 tmux/通道状态） |
| `/api/mock/message` | POST | Mock 测试端点（开发用） |
| `/api/raw-output` | GET | 查看原始命令输出日志 |
| `/api/approval` | POST | 危险命令审批 |
| `/api/inngest` | POST | Inngest 工作流入口 |

## 配置项

| 变量 | 说明 | 默认值 |
|------|------|--------|
| `ANTHROPIC_API_KEY` | LLM API Key | (必填) |
| `ANTHROPIC_BASE_URL` | API 代理地址 | (空) |
| `ANTHROPIC_MODEL` | 模型名称 | claude-sonnet-4-20250514 |
| `TELEGRAM_BOT_TOKEN` | Telegram Bot Token | (空) |
| `BUTLER_ALLOWED_USERS` | 用户白名单 (JSON) | [] (全部允许) |
| `BUTLER_GUARDRAIL_ENABLED` | 危险命令审批 | true |

## 添加新通道

1. 在 `src/butler/gateway/` 创建新文件，继承 `BaseGateway`
2. 实现 `start()`, `stop()`, `send_message()` 方法
3. 在 `_build_gateways()` 中注册
4. 在 `.env` 添加对应配置

## Docker 部署

```bash
docker-compose up -d
```

## 测试

```bash
pytest tests/ -v        # 运行测试
ruff check src/         # 代码格式
mypy src/               # 类型检查
```
