# data-factory-sql

通过 [Kyuubi HTTP API](https://mi.feishu.cn/wiki/Svthwh7g9isyKbkIXO0czfX5nef) 在小米数据工场（[data.mioffice.cn](https://data.mioffice.cn/workspace)）执行 SQL 的 Claude Code / OpenCode skill。

**特点**：

- ✅ 纯 HTTP API，**无需浏览器/Chrome 扩展**
- ✅ 支持 `auto` / `presto` / `spark` / `doris` / `hologres` 多引擎
- ✅ 自动轮询 + URL 编码 + nextQueryId 跟踪 + 错误恢复
- ✅ 结果落 CSV，stdout 输出结构化 JSON 摘要供 agent 解析
- ✅ 跨平台（Windows / Mac / Linux），仅依赖 Python 3.8+ 与 `requests`

---

## 安装

### 1. clone 到 skill 目录

```bash
# Claude Code
git clone git@git.n.xiaomi.com:zhongsiyao/data-dactory-fetch-skill.git \
  ~/.claude/skills/data-factory-sql

# OpenCode 同理（路径替换为 ~/.config/opencode/skills/data-factory-sql 或对应位置）
```

> 关键：clone 时**目标目录名必须是 `data-factory-sql`**（与 SKILL.md frontmatter 里的 `name` 字段一致）。

### 2. 申请 Token

打开数据工场 → 空间配置 → Verification Token 列表 → **生成新的 Token**：

> https://data.mioffice.cn/workspace/?wid=<YOUR_WORKSPACE_ID>#/workspace/<YOUR_WORKSPACE_ID>/config?tab=tokenList

把上面 URL 里的 `<YOUR_WORKSPACE_ID>` 替换成你自己的 workspace id（在数据工场页面顶部可见）。

⚠️ **Token 与服务地址必须同集群**。本 skill 默认 `cnbj1`（中国北京），所以 token 必须也是 cnbj1 下生成的，否则会报"找不到元信息"。其他集群用 `--cluster cnbj2 / alsgp0 / ...`。

### 3. 配置 Token

按以下任一方式（优先级从高到低）：

```bash
# 方式 A：环境变量
export KYUUBI_TOKEN=<your_token>

# 方式 B：默认文件路径（Windows）
echo <your_token> > "C:\workspace\data-factory-token.txt"

# 方式 C：默认文件路径（Mac / Linux）
mkdir -p ~/.config/data-factory && echo <your_token> > ~/.config/data-factory/token

# 方式 D：每次调用时 --token 参数（不推荐，会出现在命令行历史）
```

### 4. 验证

```bash
python ~/.claude/skills/data-factory-sql/run_sql.py --print-config
python ~/.claude/skills/data-factory-sql/run_sql.py "SELECT 1 AS id, 'hello' AS msg"
```

成功输出：stderr 表格预览 + stdout 一行 JSON 摘要（含 queryId / engine / rows / cols / output 路径）。

---

## 快速开始

### 跑现成的 SQL

```bash
python ~/.claude/skills/data-factory-sql/run_sql.py "SELECT 1"
```

### 多行 SQL 用文件

```bash
python ~/.claude/skills/data-factory-sql/run_sql.py -f my_query.sql --engine spark
```

### 在 Claude Code / OpenCode 里调用

skill 已注册触发词：「跑个 SQL」「数据工场查一下」「跑一下这条 SQL」等。直接说自然语言或贴 SQL 即可，agent 会自动调用。

---

## 文件结构

```
data-factory-sql/
├── SKILL.md            # Agent 触发文档（含红线 / 工作流 / 错误码）
├── kyuubi_client.py    # Kyuubi HTTP API client（提交 → 轮询 → 拉结果 → 关闭）
├── run_sql.py          # CLI 入口
└── README.md           # 本文件
```

详细的 agent 行为规范、错误码、状态机说明见 [SKILL.md](./SKILL.md)。

---

## 与业务知识的边界

本仓库**只做通用 SQL 执行能力**（"工具"层），不包含：

- 业务表的字段含义 / 枚举值 / 取值约束
- 常用 JOIN / 过滤模板
- 业务指标的归因 SQL

这些"领域知识"会维护在独立仓库（**TODO：链接占位**）作为知识库，由本 skill 的"模式 B"消费。这种分离让工具能复用、知识库能独立演进，符合 AI Native 落地的工具/知识两层架构。

---

## 常见问题

| 现象 | 排查方向 |
|------|----------|
| `auth: HTTP 401` | token 失效 / 过期 / 错位（cnbj2 token 用在 cnbj1）|
| `query: errCode 4007499 ... do not have permission ...` | 用户没有该 catalog/table 的权限。**注意 `hive_*` 与 `iceberg_*` catalog 的权限可能不同**——优先尝试用户原 SQL 的 catalog |
| `query: errCode 4007402` | 工场认证异常，重新生成 token |
| `query: errCode 4007415` | queryId 编码错误。本 client 内部已修复（`requests` 的 `params` 自动编码，不要预编码） |
| 状态永远不到 FINISHED | 用户旧 demo 用的状态值是 `QUEUED/FAILED/CANCELLED`，**实际是 `PENDING/RUNNING/FINISHED/ERROR/TIMEOUT/CLOSED`** |

---

## License

内部使用。仅限小米员工。
