# feishu-operator

以 **个人身份** （`user_access_token`）操作飞书的 Python 工具库与 CLI。

支持：消息收发、文档与 Wiki、电子表格、多维表格、通讯录、云盘、日历、妙记、任务、邮箱。

---

## 安装

```bash
pip install feishu-operator
# 或使用 uv
uv add feishu-operator
```

---

## 快速开始

```bash
# 首次授权（打开浏览器完成飞书 OAuth）
feishu-operator auth login

# 查看授权状态
feishu-operator auth status

# 发送私信
feishu-operator message send --to ou_xxx --text "Hello!"

# 查看收件箱
feishu-operator mail list
```

---

## 环境变量

| 变量 | 说明 | 默认值 |
|---|---|---|
| `FEISHU_SERVICE_URL` | ChatGPT 服务端地址 | `https://it.kxxxl.com` |
| `FEISHU_TOKEN_DIR` | token 缓存目录 | `~/.config/feishu-operator` |
| `FEISHU_USER_TOKEN` | 直接传入 token，跳过本地缓存 | — |

> `FEISHU_APP_ID` / `FEISHU_APP_SECRET` **不在客户端配置** 。所有飞书 OAuth 凭证由服务端持有和管理，客户端零凭证。

---

## 认证流程

```mermaid
sequenceDiagram
    participant C as "客户端 (feishu-operator)"
    participant S as "服务端 (ChatGPT)"
    participant F as "飞书 OAuth"

    C->>S: POST /webhook/auth/session
    S-->>C: session_id + auth_url
    C->>F: 打开浏览器，用户授权
    F->>S: 回调 /webhook/oauth?code=xxx
    S->>F: 换取 user_access_token
    S-->>S: 存入 session（含 scopes）
    loop "轮询"
        C->>S: GET /webhook/auth/session/{id}
        S-->>C: status=done, token, scopes
    end
    C-->>C: 缓存至 credentials.json
```

token 缓存在本地 `~/.config/feishu-operator/credentials.json`（权限 0600）。临近过期自动刷新，无需重复授权。

---

## 功能一览

| 模块 | 已实现功能 | 所需权限 |
|---|---|---|
| **消息** | 发送、回复、撤回、获取单条、列出群聊、获取群信息、获取群成员、Pin/Unpin 消息、获取群聊历史 | `im:message` `im:chat:readonly` |
| **文档** | 创建、获取元信息、读取正文、获取全部 blocks、从 URL 解析 Wiki 节点 | `docx:document` `wiki:wiki` |
| **电子表格** | 获取元信息、列出工作表、创建表格、读/写/追加/清空、批量读/写、合并/取消合并单元格、新增/删除/复制工作表 | `drive:drive` `drive:file` |
| **多维表格** | 创建应用、获取应用、列出/创建/删除数据表、记录增删改查、列出/创建/删除字段、列出/创建/删除视图 | `bitable:app` |
| **通讯录** | 获取用户信息、获取部门成员 | `contact:user.base:readonly` |
| **云盘** | 列目录、上传、下载、移动、复制、删除、创建文件夹、批量获取文件元信息、搜索文件、设置权限 | `drive:drive` `drive:file` |
| **日历** | 获取主日历、列出日程、创建/更新/删除日程、添加/删除参与者、查询空闲忙碌 | `calendar:calendar` |
| **妙记** | 获取详情、获取转写文字、获取统计信息（只读） | `minutes:minutes:readonly` |
| **任务** | 列出清单、列出任务、创建/获取/更新/完成/删除任务 | `task:task:read` `task:task:write` |
| **邮箱** | 列出邮件、获取邮件、发送邮件 | `mail:user_mailbox.message:readonly` `mail:user_mailbox.message:send` |

---

## 已知限制

| 限制 | 原因 |
|---|---|
| 无法列出私聊（p2p）历史消息 | 飞书 API 不支持 user token 读取 p2p 消息列表 |
| 无法按姓名搜索用户 | `search/v1/user` 不支持 user token |
| 无法获取无权限的部门列表 | 需要管理员权限 |
| 妙记为只读 | 飞书不提供 user token 写入妙记的接口 |
| 日历为只读 | 应用后台仅开通 `calendar:calendar:readonly` |

---

## 模块结构

```
src/feishu_operator/
├── __init__.py          # 公开 API
├── _client.py           # lark.Client 单例
├── _credentials.py      # token 本地持久化
├── _scopes.py           # 权限定义与 InsufficientScopeError
├── _cli.py              # Click CLI 入口
├── auth.py              # OAuth 2.0 + PKCE 认证 & token 管理
├── message.py           # 消息操作
├── document.py          # 文档 & Wiki 操作（含 get_wiki_node_by_url / get_doc_blocks）
├── sheets.py            # 电子表格 CRUD（含 parse_composite_token）
├── bitable.py           # 多维表格操作
├── contact.py           # 通讯录操作
├── drive.py             # 云盘文件管理
├── calendar.py          # 日历 & 日程
├── minutes.py           # 妙记（只读）
├── task.py              # 任务 v2
└── mail.py              # 个人邮箱收发
```

---

## License

MIT
