---
name: guancli
description: 当用户要分析观远 BI / Guandata 的 ETL、数据集、页面/仪表板、卡片、血缘、节点 SQL、资源树、目录、表单填报数据、指标 metric、公共维度 public dimension、指标树归因 metric_attribution、指标泛化查询参数，或给出 ETL ID、dsId、page ID、card ID、metric ID、metric tree ID、公共维度 ID 想看现有内容/查询数据时，主动使用这个 skill。用户要创建、新建、编辑、删除指标或公共维度，尤其是“创建原子指标”“创建复合指标”“创建衍生指标”“新增 metric”“基于数据集建指标”“用两个指标算一个指标”“做同比/环比/最近N天/累计/期末值指标”“新建公共维度”“把几个数据集字段关联成公共维度”时，也要使用这个 skill 并读取对应写操作指引。即使用户只说"看一下这个 page""贴一下这个 ETL 的 SQL""搜个叫 X 的数据集""这个数据集长啥样""页面卡片用了哪些 ds""帮我查这个指标""生成指标泛化查询命令""帮我创建一个原子指标""帮我创建一个复合指标""帮我创建一个同比指标""帮我创建一个公共维度"，也要触发。它直接调用 BI HTTP API 拉数据并整理成 AI 友好的中文结论，定位是 BI 查询分析 + 表单填报 CRUD + 指标/公共维度写操作引导。修改 ETL 走 guanetl；新建/改 Card/Page 走 guanvis；数据源/数据集 CRUD/增量/调度走 guands；页面 PNG 视觉验证走 guanvis screenshot；管理员级 SVC SQL / 动态码走 guanadmin。若用户希望直接分析 BI 项目而不是手工点页面，或希望直接通过 ChatBI 进行主题问数/洞察分析，也应优先使用这个 skill。
compatibility: Requires Node.js 14+. Install via npm install -g @guandata/guancli.
---

# guancli

## 何时优先使用

- 用户希望分析观远 BI 项目的 ETL 逻辑、数据集结构、页面/仪表板内容。
- 用户提供了 BI 系统 URL，需要连接并获取数据。
- 用户要快速拿到 ETL 清单、节点 SQL、输入输出数据集血缘。
- 用户在排查 BI 资源配置、页面卡片定义、接口返回或 lineage 关系。
- 用户需要对表单填报(Form)数据进行 CRUD 操作（查询/插入/更新/删除）。
- 用户要直接用 ChatBI 主题做 L1 问数或 L2 洞察，而不是打开网页手工操作。
- 用户要搜索指标、获取指标详情、查询指标数据、查看指标目录、执行指标树归因，或让你生成/解释指标泛化查询命令。
- 用户给出数据集 ID，想查看该数据集创建或影响到的所有指标，包括直接原子指标以及下游复合指标、衍生指标。
- 用户要创建、新建、编辑或删除指标；当前指标写操作指引先覆盖原子指标、复合指标、衍生指标的创建和编辑前校验。
- 用户要查询、新建、编辑、转移责任人或删除指标公共维度。

如果用户只想生成页面 PNG 截图成品，不要用本 skill，改用 `guanvis screenshot`。页面截图不要再走 `guanexport`；移动端页面/卡片导出仍暂用 `guanexport` legacy 功能。

## 数据获取方式

通过保存的认证信息直接调用 BI HTTP API。

ChatBI 同样复用 `guancli/config.json` 中当前 profile 的认证信息。

## 首次配置（认证）

### 方式一：用户名密码登录（推荐）

```bash
guancli auth login
```

交互式输入：
1. 环境名称（默认 `default`，可自定义如 `staging`、`prod`）
2. BI 系统 URL（如 `https://bi.example.com`）
3. 选择登录方式：`1` 用户名密码
4. Domain（如 `demo`）
5. 用户名（邮箱）
6. 密码

登录成功后 Token 自动保存在系统标准配置目录下的 `guancli/config.json`。密码方式支持 Token 过期后自动刷新。

### 方式二：直接输入 Token

```bash
guancli auth login
```

选择登录方式 `2`，直接粘贴已有的 Auth Token。适用于已从 Web 界面或其他途径获取 Token 的场景。

### 多环境管理

```bash
guancli auth login --profile staging            # 添加 staging 环境
guancli auth login --profile prod --default     # 添加 prod 并设为默认
guancli auth list                                # 列出所有环境
guancli auth status                              # 查看当前认证状态
guancli auth use staging                         # 切换默认环境为 staging
guancli auth remove staging                      # 删除 staging 环境
```

使用特定环境（不切换默认）：

```bash
guancli --profile staging etl tree
guancli --profile staging chatbi list-theme
```

### ChatBI 配置

ChatBI 统一复用当前 profile 的 `base_url` 和 `uIdToken`。

- 不需要单独配置 ChatBI URL
- 不需要第二套 token / cookie
- `guancli` 会在内部自动推导并探测可用的 ChatBI Public API 地址，默认优先尝试同域名下的 `/api/chat/public-api`

## 能力边界

guancli 是 BI 资源的**查询分析入口**，并支持少量明确边界的写操作（Form 表单填报 CRUD、指标写操作引导）。其他写入类任务由专用 skill 负责：

| 任务 | 应使用的工具 |
|------|-------------|
| ETL 新建 / 编辑 / 保存 / 执行 | `guanetl` |
| 数据源 / 数据集 CRUD / 增量 / 调度 | `guands` |
| 看板 / 卡片构建 / 页面发布 / 截图 | `guanvis` |

> guancli 能显示 ETL 的节点定义和 SQL，但 ETL 的新建、修改、保存、执行闭环应通过 `guanetl` 完成。

## 先做判断

1. 先用 `auth status` 确认认证是否有效。
2. 如果 Token 过期，密码登录方式会自动刷新；Token 方式需重新登录。
3. 先判断资源类型：ETL 用 `etl`，数据集用 `ds`，页面/仪表板用 `page`，表单填报用 `form`。
4. 信息不全时先 `tree` 或 `search`，拿到 ID 后再 `get`。
5. `tree` 和 `search` 语义不同：目录名能出现在 `ds tree`，不代表同词一定能命中 `ds search`。

## 指标命令参考

当任务涉及指标、指标树归因、`metric query`、泛化查询、同比/环比、XTD、最近 N 周期、占比、Top N 排名或 `adv-calc-json` 时，先按需读取引用文件，避免把全部命令塞进主 skill：

- 指标与指标树全量命令：`references/metric-commands.md`
- 指标泛化查询参数与示例：`references/metric-generic-query.md`
- 指标新建 / 编辑 / 删除入口：`references/metric-mutation.md`
- 指标通用写入配置：`references/metric-common-fields.md`
- 指标表达式 / 计算公式支持范围：`references/metric-expression-rules.md`
- 原子指标写入细节：`references/metric-atomic-mutation.md`
- 复合指标写入细节：`references/metric-composite-mutation.md`
- 衍生指标写入细节：`references/metric-derived-mutation.md`
- 指标删除细节：`references/metric-delete-mutation.md`
- 公共维度查询与写入：`references/metric-public-dimension.md`

关键规则：

- 普通指标数据查询用 `guancli metric query <metric_id>`，可加 `--dim`、`--filter`、排序、列筛选、输出格式等。
- 按数据集反查指标用 `guancli metric by-dataset <ds_id>`；新版 BI 会走后端批量接口直接返回直接指标和下游指标，旧版 BI 会兼容回退为先定位使用该数据集的原子指标、再沿指标下游血缘展开复合指标和衍生指标。适合回答“这个数据集关联了哪些指标 / 改这个数据集会影响哪些指标”。如果已知指标主题，可加 `-d <metric_topic_id>` 缩小范围；需要结构化结果时用 `-f json`。
- 只要传入 `--compare`、`--compare-value`、`--xtd`、`--last`、`--recent`、`--recent-base`、`--percentage`、`--percentage-dim`、`--rank-top`、`--rank-order`、`--rank-dim`、`--adv-calc-json` 任一参数，就进入指标泛化查询模式。
- 泛化查询要求 BI 版本 `>= 8.2.1`；如需确认环境版本，先执行 `guancli server-version --profile <profile>`。
- 当用户要创建或编辑原子指标、复合指标、衍生指标时，先读取 `references/metric-mutation.md` 判断类型，再读取 `references/metric-common-fields.md`，最后只读取对应类型文件：原子指标读 `references/metric-atomic-mutation.md`，复合指标读 `references/metric-composite-mutation.md`，衍生指标读 `references/metric-derived-mutation.md`。如果涉及原子指标表达式 `formulaField.fdFormula`、复合指标 `formula` 或组合衍生 `deriveSetting.formula`，必须同时读取 `references/metric-expression-rules.md`，按当前前后端支持的表达式形态生成。默认使用当前已登录环境，不询问 profile；按必填项、数据格式 `format` 和启用的指标业务属性配置逐步查询/确认，生成 JSON 文件并先做 dry-run/人工摘要。用户确认后仍需按 Web 同款保存前校验执行：原子指标上线前跑 save-precheck，编辑态跑 validate-update-impact；复合指标和衍生指标编辑态跑 validate-update-impact。校验通过或二次确认后才真实提交。
- 当用户要删除指标时，读取 `references/metric-delete-mutation.md`。删除必须先跑 `validate-delete-impact`；如果存在下游指标或卡片，按 Web 行为阻断删除并展示影响资源；只有无影响且用户明确确认后，才执行真实删除。
- 当用户要查询、新建、编辑或删除公共维度时，读取 `references/metric-public-dimension.md`。公共维度写入字段为 `name`、`businessOwner`、`relatedFields[{dsId,fdId}]`；关联字段必须同类型。删除前先跑 depend-check，若已有指标使用，需要提示会影响指标计算准确性，用户明确确认后才删除。

## 标准分析流程

### 1. 拉取目录树

```bash
guancli etl tree
guancli ds tree
guancli page tree
```

### 2. 搜索资源

```bash
guancli etl search                     # 搜索所有 ETL
guancli etl search 关键词              # 按关键词搜索
guancli etl search 关键词 -d <dir_id>  # 在指定目录中搜索
guancli ds search 关键词               # 搜索数据集
guancli ds search --limit 500 --offset 500  # 分页扫描数据集
guancli ds search --id <dsId>          # 按数据集 ID 精确查找并返回单个数据集详情
guancli ds search 关键词 --id <dsId>   # 按名称 + ID 组合查找
guancli page search 关键词             # 搜索页面
```

`ds search` 默认返回前 500 条，环境数据集较多时用 `--limit` 和 `--offset` 分页扫描；`ds search --id` 会直接按数据集 ID 获取单个数据集详情，`--limit` 和 `--offset` 在 `--id` 模式下忽略。

### 3. 获取详情（含血缘）

```bash
guancli etl get <resource_id>          # ETL 详情（含节点、SQL、血缘）
guancli ds get <resource_id>           # 数据集详情（含字段结构、血缘）
guancli ds get <resource_id> --brief   # 数据集轻量输出（省略 Malloy、血缘、公式详情，节省 token）
guancli ds get <resource_id> --assoc   # 附加显示关联关系摘要（ETL、融合等）
guancli page get <resource_id>         # 页面详情（含卡片列表、血缘）
```

**`--brief` 模式**：省略 Malloy 数据源定义、血缘关系、计算字段公式等高 token 内容，只保留基本信息和字段名/类型列表。适合 AI 在上下文受限时快速了解数据集结构。所有 `get` 子命令均支持此选项。

**`--assoc` 模式**（仅 `ds get`）：在详情末尾追加数据集关联关系摘要，显示关联的 ETL、数据融合等资源。

### 4. 预览数据集数据

```bash
guancli ds preview <ds_id>              # 预览数据集数据 (表格格式)
guancli ds preview <ds_id> --limit 20   # 限制预览行数
guancli ds preview <ds_id> --raw        # 输出原始 JSON
guancli ds execute-sql -inputs <ds_id> -sql 'SELECT * FROM `数据集名称` LIMIT 20'  # 用 SQL 查询数据集（需目标 BI 满足 8.2.0-hf12+，并在 BI 管理后台 - 域设置打开高级 SQL 查询开关）
# SQL 中请使用数据集名称作为临时表名；名称包含中文、空格或特殊字符时，请使用反引号包裹。可先执行 `ds get <ds_id> --brief` 查看数据集名称和字段列表。
`execute-sql` 的旧版 public-api fallback 不支持 disable-cache；`--limit` 在非 raw 输出渲染前本地截断，`--raw` 保持后端原始响应。
```

数据集 ID (dsId) 可通过 `ds tree` 或 `ds search` 获取。

如果用户给的是业务目录名而不是数据集名，优先先 `ds tree` 定位目录，再在目录内按真实表名搜索，或从已有 `page/card` 反查 `dsId`。

#### 带筛选条件预览

通过 `--filter` 参数传入筛选条件，每个 `--filter` 值的格式为 `"列名 操作符 [值]"`。
列名中包含空格时无需特殊处理，解析器会智能定位操作符。

```bash
guancli ds preview <ds_id> --filter "name EQ 张三"
guancli ds preview <ds_id> --filter "age GT 18" --filter "city IN 北京,上海,广州"
guancli ds preview <ds_id> --filter "score BT 60,100"
guancli ds preview <ds_id> --filter "status IS_NULL"
guancli ds preview <ds_id> --filter "销售 金额 GT 100" --combine-type OR
```

支持的操作符：
- 比较：`EQ`（等于）、`NE`（不等于）、`LT`（小于）、`LE`（小于等于）、`GT`（大于）、`GE`（大于等于）
- 区间：`BT`（between，两个值逗号分隔）
- 集合：`IN`（多值逗号分隔）
- 空值：`IS_NULL`、`NOT_NULL`
- 字符串：`CONTAINS`、`NOT_CONTAINS`、`STARTSWITH`、`NOT_STARTSWITH`、`ENDSWITH`、`NOT_ENDSWITH`

`--combine-type` 控制多条件组合方式，默认 `AND`，可设为 `OR`。
字段类型会自动从数据集 schema 推断，无需手动指定。

#### 日期粒度筛选（SUB_DATE）

对 DATE/TIMESTAMP 字段，可用 `toYear`/`toQuarter`/`toMonth`/`toWeek`/`toDate` 修饰符按粒度筛选。
语法：`"列名 toGranularity OPERATOR value"`，值使用标准格式，CLI 自动转换为 BI API 格式。

```bash
guancli card preview <cd_id> --filter "日期字段 toQuarter IN 2026-Q1"
guancli card preview <cd_id> --filter "日期字段 toQuarter IN 2026-Q1,2026-Q2"
guancli card preview <cd_id> --filter "日期字段 toYear EQ 2026"
guancli card preview <cd_id> --filter "日期字段 toMonth EQ 2026-01"
guancli card preview <cd_id> --filter "日期字段 toWeek EQ 2026-W01"
guancli card preview <cd_id> --filter "日期字段 toDate EQ 2026-01-15"
```

值格式规范：

| 粒度 | 修饰符 | 值格式 | 示例 |
|------|--------|--------|------|
| 年 | `toYear` | `YYYY` | `2026` |
| 季度 | `toQuarter` | `YYYY-QN` | `2026-Q1` |
| 月 | `toMonth` | `YYYY-MM` | `2026-01` |
| 周 | `toWeek` | `YYYY-WNN` 或 `YYYY WNN` | `2026-W01` |
| 日期 | `toDate` | `YYYY-MM-DD` | `2026-01-15` |

可配合 `--filter "维度字段 EQ 值"` 同时使用多个筛选条件。

#### 排序和列筛选

所有 preview 命令（ds/card）都支持排序和列筛选：

```bash
guancli ds preview <ds_id> --sort-asc name                    # 按 name 升序 (API 层面排序)
guancli ds preview <ds_id> --sort-desc id                     # 按 id 降序 (API 层面排序)
guancli ds preview <ds_id> --columns "id,name,status"         # 只显示指定列
guancli ds preview <ds_id> --filter "status EQ FAILED" --sort-desc id --columns "id,task_name"
```

- `--sort-asc` / `--sort-desc`: 互斥，只能指定一个列。ds preview 的排序通过 API 在数据库层面执行；card preview 的排序在 Go 端对本次取数范围执行，排序取数下限为 10000 行，若卡片总行数超过本次取数范围，不承诺全量 Top N。
- `--columns`: 逗号分隔的列名列表，只显示指定列（Go 端执行）。

### 5. 获取卡片数据

```bash
guancli card get <cd_id>                # 获取卡片元信息
guancli card preview <cd_id>            # 预览卡片数据 (图表默认最多 10000 行；选择器未排序时保留服务端默认)
guancli card preview <cd_id> --limit 20 # 限制预览行数
guancli card preview <cd_id> -f csv     # 导出 CSV 到 stdout
guancli card preview <cd_id> -f csv -o card.csv # 导出 CSV 到文件
guancli card preview <cd_id> -f excel -o card.xls # 导出 Excel 可打开文件
guancli card preview <cd_id> --value-format raw -f csv # 保留原始数值，适合 AI 后续计算
```

卡片 ID (cdId) 可通过 `page get` 命令查看页面详情获取。
图表卡片内部会按 BI 预览接口的分页能力自动取数；选择器/树状选择器仍使用服务端单次返回。图表卡片数值默认使用 `--value-format formatted`，按卡片返回的数值格式输出（小数位、千分位、货币、百分比、单位等）；需要保留原始数值用于 AI 后续计算时，使用 `--value-format raw`。无卡片格式时 `--precision` 作为兜底最大精度，默认 6 位。任意卡片预览结果在未指定 `-o/--output` 且超过 1000 行时，默认写入 `card_<cdId>_<timestamp>.<ext>` 文件，避免把大结果直接塞入上下文。该能力不对接 BI 导出任务接口。

复杂报表 Pro 卡片会自动切换为 xlsx 下载模式，只支持写入文件，不支持 `--raw`、`-f/--format`、`--limit`、排序、列筛选、精度、数值输出格式、动态参数和动态维度。未指定 `-o/--output` 时默认写入 `complex_report_pro_<cdId>_<timestamp>.xlsx`。

#### 带筛选条件预览卡片

卡片 preview 同样支持 `--filter` 参数，语法与数据集 preview 一致（含日期粒度筛选）。
筛选条件会通过 API 传递给后端，适用于 CHART、SELECTOR、TREE_SELECTOR 三种卡片类型。复杂报表 Pro 首版也使用 `--filter`，CLI 会基于页面普通选择器的 `asFilter.columnMappings` 自动映射为子卡 `childFilters`；映射不唯一、树/组合筛选器、动态参数 target 等复杂情况会直接报错。

```bash
guancli card preview <cd_id> --filter "name EQ 张三"
guancli card preview <cd_id> --filter "age GT 18" --filter "city IN 北京,上海"
guancli card preview <cd_id> --filter "利润中心 EQ 华南" --filter "季度(日期) toQuarter IN 2026-Q1"
guancli card preview <complex_report_pro_cd_id> --filter "周 toWeek EQ 2026-W01" -o report.xlsx
```

字段类型会自动从卡片关联的数据集 schema 推断。日期粒度筛选需配合 `card get` 查看字段配置中的筛选器字段名和粒度。

#### 带动态参数预览图表卡片

图表卡片 preview 支持通过 `--dynamic-param` 覆盖 BI 全局动态参数，格式为 `参数名=值` 或 `dpId=值`，可多次指定。
CLI 会查询 `/api/dynamic-parameter/query` 补全参数元数据，并把完整 `dynamicParams` 传给 `/api/card/{cdId}/data`。
该能力仅支持 CHART 图表卡片；数据集 preview 当前后端接口不消费动态参数，暂不支持。
多选参数值沿用 BI 前端约定，使用英文逗号拼接成一个字符串传入。

```bash
guancli card preview <cd_id> --dynamic-param "结束时间={{{today}}}"
guancli card preview <cd_id> --dynamic-param "11=999" --raw
guancli card preview <cd_id> --dynamic-param "品类=鞋,服,包"
guancli card preview <cd_id> --dynamic-param "DATE_RANGE_PARAM_LEFT=2026-05-01" --dynamic-param "DATE_RANGE_PARAM_RIGHT={{{today}}}"
```

#### 带动态维度预览图表卡片

图表卡片 preview 支持通过 `--dynamic-field` 覆盖当前卡片自身的动态维度选择；参数名沿用历史/API 命名，语义上表示动态维度。
格式为 `动态维度名=字段名`、`dzId=fdId`、`dzId=key`，也兼容旧写法 `dzId:key`。
动态维度名、dzId、字段名、fdId、key 先用 `card get <cd_id>` 查看；如果动态维度没有配置名称，只能使用 dzId。
单选动态维度只能指定一个字段；`multiSelect: true` 的动态维度可用英文逗号传多个字段，或重复指定同一个动态维度，CLI 会合并去重。
字段名本身包含英文逗号时，CLI 会优先按完整字段名匹配；也可用 CSV 引号写法，例如 `"维度=\"门店,二店\""`。
该能力仅支持当前卡片自身的动态维度，不支持带 `sourceDzIds` 的来源动态维度；参数只影响本次运行态取数，不修改卡片配置。

```bash
guancli card get <cd_id> # 查看动态维度配置、dzId、可选字段、fdId、key
guancli card preview <cd_id> --dynamic-field "维度=区域"
guancli card preview <cd_id> --dynamic-field "维度=区域,门店" --dynamic-field "数值=销售额,利润"
guancli card preview <cd_id> --dynamic-field "维度=区域" --dynamic-field "维度=门店"
guancli card preview <cd_id> --dynamic-field "dz_region=province_fd,city_fd"
guancli card preview <cd_id> --dynamic-field "dz_region=province_key,city_key"
guancli card preview <cd_id> --dynamic-field "dz_region:city_key"
```

### 6. 表单填报操作 (Form CRUD)

类似 Airtable 风格的表单数据 CRUD，用户始终用**字段名**操作，CLI 内部自动映射到 fdId。

#### 列出表单

```bash
guancli form list                       # 列出所有表单
guancli form list 关键词                # 搜索表单
guancli form list --tree                # 目录树形式展示
```

#### 查看表单结构

```bash
guancli form schema <fmId>              # 查看字段结构（LLM 消费核心）
guancli form schema <fmId> -f json      # JSON 格式
```

#### 查询数据

```bash
guancli form query <fmId>                          # 查询数据（默认 50 行）
guancli form query <fmId> --limit 100              # 指定行数
guancli form query <fmId> --filter "姓名 EQ 张三"  # 筛选
guancli form query <fmId> --sort-asc 值            # 按值升序
guancli form query <fmId> --columns "姓名,值"      # 只显示指定列
guancli form query <fmId> -f json                  # JSON 格式（rowId 完整）
guancli form query <fmId> -f expanded              # PG 风格竖排
```

筛选操作符：`EQ`（等于）、`CONTAINS`（包含）、`STARTSWITH`、`ENDSWITH`、`IS_NULL`、`NOT_NULL`。

**重要**：`rowId` 在 auto 表格格式中可能被截断，使用 `-f json` 或 `-f expanded` 获取完整 rowId。

#### 插入数据

```bash
guancli form add <fmId> --data '{"字段名": "值", "数字字段": 42}'
guancli form add <fmId> --set "字段名=值" --set "数字字段=42"
echo '[{"字段名":"a"},{"字段名":"b"}]' | guancli form add <fmId> --stdin
```

#### 更新数据

```bash
guancli form update <fmId> <rowId> --data '{"字段名": "新值"}'
guancli form update <fmId> <rowId> --set "字段名=新值"
```

`rowId` 通过 `form query` 获取。

#### 删除数据

```bash
guancli form delete <fmId> <rowId>                 # 删除单行
guancli form delete <fmId> <rowId1> <rowId2>       # 删除多行
guancli form delete <fmId> --all --yes             # 删除全部（需确认）
```

#### 子表操作

主表中 `TABLE` / `MATRIX_TABLE` 类型字段对应子表。子表有独立的 `subFmId`，可以用 `schema` 查看其字段结构。

```bash
# 1. 查看主表 schema，找到 TABLE 字段的 subFmId
guancli form schema <mainFmId>
# 输出中 TABLE 字段的备注列显示 "子表 subFmId=..."

# 2. 查看子表字段结构
guancli form schema <subFmId>

# 3. 查询子表数据（返回结果包含主表字段，rowId 为主表行 ID，subId 为子行 ID）
guancli form query <subFmId>

# 4. 向子表插入行（需指定主表行的 rowId）
guancli form add <subFmId> --parent-row <主表rowId> --set "字段名=值"

# 5. 更新子表行（使用 subId 作为 rowId）
guancli form update <subFmId> <subId> --set "字段名=新值"

# 6. 删除子表行
guancli form delete <subFmId> <subId>
```

**子表 ID 映射规则**（AI 调用时注意区分）：

| 操作 | fmId 参数 | 行 ID 参数 | 额外参数 |
|------|-----------|-----------|---------|
| schema | subFmId | - | - |
| query | subFmId | - | 返回 rowId(主表行) + subId(子行) |
| add | subFmId | - | `--parent-row <主表rowId>` |
| update | subFmId | **subId** (作为 rowId 位置参数) | - |
| delete | subFmId | **subId** (作为 rowId 位置参数) | - |

**注意**：
- 子表 add 内部通过主表 update API 间接完成（后端限制），CLI 自动保留已有子行
- add 需全量读取子表以保留已有行，子表总行数上限 10000；非并发安全
- `--stdin` 批量插入部分失败时 CLI 返回非零退出码，summary 中显示成功/失败计数

#### 典型工作流

```bash
# 1. 找到表单
guancli form list 测试

# 2. 查看结构
guancli form schema <fmId>

# 3. 插入数据
guancli form add <fmId> --data '{"测试1": "hello", "值": 42}'

# 4. 查询并获取 rowId
guancli form query <fmId> -f json

# 5. 更新
guancli form update <fmId> <rowId> --set "值=99"

# 6. 删除
guancli form delete <fmId> <rowId>
```

### 7. ChatBI 主题问数 / 洞察

先列主题，再执行问数或洞察；如果用户没有指定主题，不要猜。

```bash
guancli chatbi list-theme
guancli chatbi list-theme --insight
guancli chatbi query --theme-name "经营主题" --message "最近30天营业收入是多少？"
guancli chatbi query --theme-id "<theme_id>" --message "最近30天营业收入是多少？"
guancli chatbi insight --theme-name "经营主题" --message "分析最近30天营业收入变化原因"
guancli chatbi insight --theme-id "<theme_id>" --message "分析最近30天营业收入变化原因" --agent-mode single_agent
```

规则：

- `list-theme` 输出 markdown 表格
- `list-theme --insight` 可列出仅用于洞察的主题
- `query` 输出 L1 markdown，包含解释和结果表格
- `insight` 输出 L2 markdown；如返回 `GuanViz.json`，CLI 会自动降级成 markdown 表格
- ChatBI 命令复用当前 profile 的 `uIdToken`
- 默认超时 300 秒、轮询间隔 2 秒；必要时可传 `--timeout-ms` / `--poll-interval-ms`

### 8. 输出格式控制

`--format` / `-f` 控制 preview 命令的输出格式：

```bash
guancli ds preview <ds_id>                 # auto: 对齐表格，列>10 或行>20 时自动截断
guancli ds preview <ds_id> -f csv           # CSV 格式
guancli ds preview <ds_id> -f excel         # Excel 2003 XML 格式
guancli ds preview <ds_id> -f expanded      # PG 风格竖排
guancli ds preview <ds_id> -f table         # 对齐表格
guancli ds preview <ds_id> -f json          # JSON 行记录数组
guancli ds preview <ds_id> -f json | jq '.[0]'  # 配合 jq
```

`--raw` 输出 API 原始 JSON（不经过解析）：

```bash
guancli --raw etl tree
guancli --raw etl get <id>
```

## Token 管理

- 密码登录方式：Token 过期后自动调用 sign-in API 刷新。
- 每次 API 响应中如果包含新 Token，且距上次签发超过可配置间隔（默认 10 分钟），会自动更新缓存。
- Token 的签发时间和过期时间记录在配置文件中。
- 可通过修改 `config.json` 中的 `token_refresh_interval_seconds` 调整刷新间隔。

## 输出说明

- **目录树**：树形结构（├── └──），包含名称和 ID
- **搜索结果**：表格式列表，包含名称、ID、状态、路径、调度信息、时间
- **ETL 详情**：流程摘要 + 节点详细信息（含 Sources/UsedBy 引用）+ 等价 SQL + 血缘关系
- **数据集详情**：基本信息 + 字段结构（维度/度量/计算字段分类）+ Malloy source 定义 + 血缘关系
- **页面详情**：页面信息 + 卡片列表（含筛选器配置、交互联动、Malloy 查询）+ 血缘关系
- **数据集预览**：表格格式预览（列名 + 数据行），显示数据集基本信息和行列统计
- **卡片数据**：表格格式预览（维度 + 度量），自动检测卡片类型（图表/筛选器/树状筛选器）
- **表单列表**：表格式列表，包含 fmId、名称、类型、创建者、更新时间
- **表单结构**：字段定义表格，包含 fdId、名称、类型、必填/可编辑、选项（LLM 消费核心）；TABLE 类型字段显示 subFmId
- **表单数据**：表格格式，首列为 rowId（用于 update/delete），后续为字段列；子表查询结果额外包含 `subId` 列（子行主键，update/delete 时用作 rowId 参数）
- **表单写操作**（add/update/delete）：默认输出 `✓ ...` 文本；`-f json` 时输出结构化 JSON：`{"ok":true,"action":"add","rowId":"...","count":N,"total":N,"failed":N}`。批量插入部分失败时 `ok=false` 且 exit code 非零
- **ChatBI 主题列表**：markdown 表格，包含 `theme_id`、`theme_name`
- **ChatBI 问数/洞察**：markdown 文本；图表块会被自动转成表格，便于继续总结

## 回答风格要求

- 用中文输出，优先给"可执行结论"。
- 不只贴原始命令结果，必须做逻辑归纳（按链路/主题）。
- 涉及时间相关信息时给出明确日期。
- 如果用户给的是模糊对象名，先说明你是如何定位到具体资源 ID 的。

## 故障排查

### ETL preview 返回 0 行

0 行是合法结果，不一定是错误。排查顺序：
1. 确认输入数据集有数据：`guancli ds preview <dsId> --limit 5`
2. 如果节点有 FILTER_ROWS 或 WHERE 条件，临时简化后再 preview

### Token 过期 / API 401

密码登录方式会自动刷新。如果仍然失败，重新登录：

```bash
guancli auth login
```

## 配置文件位置

- macOS: `~/Library/Application Support/guancli/config.json`
- Linux: `~/.config/guancli/config.json`
- Windows: `%AppData%\\guancli\\config.json`

```json
{
  "profiles": {
    "default": {
      "name": "default",
      "base_url": "https://bi.example.com",
      "domain": "demo",
      "login_id": "user@example.com",
      "password": "yourpassword",
      "auth_method": "password",
      "token": "...",
      "issued_at": 1711234567,
      "expires_at": 0,
      "is_default": true
    }
  },
  "token_refresh_interval_seconds": 600
}
```
