# `libtv group` — 普通分组

对画布的**普通分组**（画布上可承载一组子节点的 group 节点）做**列表 / 新建 / 查询或绑定子节点 / 目录级默认绑定**等操作。项目范围由 **`-p` / `--project`** 或当前目录 `.libtv/project.json` 中的 **`projectUuid`** 决定（见 [commands/project.md](./project.md)）。

管道、stdout/stderr 约定与嵌套 case 见 [../examples/pipes/README.md](../examples/pipes/README.md)。

## 子命令

| 子命令                                  | 作用                                                              |
| --------------------------------------- | ----------------------------------------------------------------- |
| **`libtv group list`**                  | 列出画布上所有**普通**分组（便于抄 `groupNodeKey` 或展示名）      |
| **`libtv group create <group>`**        | **仅新建**分组；已有同名**普通**分组则失败                        |
| **`libtv group use <group>` / `unuse`** | 将当前目录绑定 / 解绑到指定普通分组                               |
| **（默认）`libtv group "<显示名>"`**    | 「**已有就查询 / 绑定，没有就建并绑定**」的幂等接入；可选 `--run` |

### 共享选项与绑定来源

除 `list` / `unuse` 外，其它子命令共享以下概念；不重复定义。

**共享 flags**

| 选项                   | 必填 | 说明                                                                                                                                                                          |
| ---------------------- | ---- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-p, --project <uuid>` | 否   | 目标项目 UUID；缺省时使用目录绑定。                                                                                                                                           |
| `-g, --group <父组>`   | 否   | 父级**普通分组**；在其 `childNodeIds` 内解析分组名 / 子节点名，避免同名冲突。                                                                                                 |
| `-r, --run`            | 否   | 主流程成功后对**目标普通分组**做一次**整组按顺序执行**（与网页「整组执行」一致）。进度在 stderr 约每 3 分钟一条、前缀 `[run-group]`；成功结果在 stdout，管道下为单行 NDJSON。 |
| `--help`               | 否   | 打印该子命令帮助。                                                                                                                                                            |

**绑定来源**（`create` / 默认子命令共用）

| 来源              | 说明                                                                                             |
| ----------------- | ------------------------------------------------------------------------------------------------ |
| `--node <子节点>` | 子节点 **id 优先**，否则按展示名匹配（重名取第一个）；可重复指定。                               |
| 管道 stdin        | 每行一条 JSON，读取 `nodeKey` 或 `newNodeKey`（与 `libtv node` / `libtv upload` 成功输出一致）。 |

> 两来源合并时 **stdin 在前**，再整体去重。子节点若已在别的普通分组里，会先从原分组移除再挂到目标分组。

### `libtv group list`

用法骨架：`libtv group list [flags]`

**位置参数**：无。

**选项**：`-p, --project`（见共享）。

**输出**：stdout 为 JSON，含所有普通分组的 `groupNodeKey`、展示名、子节点数量等。

### `libtv group create <group>`

用法骨架：`libtv group create <group> [flags]`

**位置参数**

- **`<group>`**（必填）：新建分组的展示名。若该展示名（或在 `-g` 父组内的解析规则下）已对应**普通分组**节点，会报错并提示改用默认子命令 `libtv group <group>` 查询 / 绑定；若被**非普通分组**节点占用，也会报错退出。

**选项**：`-p` / `-g` / `-r`（见共享）；**绑定来源**：`--node` 与 stdin（见共享）。

**行为**

| 有无绑定来源（`--node` / stdin） | 结果                                                                                     |
| -------------------------------- | ---------------------------------------------------------------------------------------- |
| 无                               | 建空分组。stdout JSON 的 `action: "create_empty"`，含 `groupNodeKey` / `boundNodeKeys`。 |
| 有                               | 新建分组并绑定。`action: "create_bind"`。                                                |

### `libtv group use <group>` / `libtv group unuse`

用法骨架：

- `libtv group use <group> [flags]`
- `libtv group unuse [flags]`

**`use` 的含义**：把**当前工作目录**和画布上的**某一个普通分组**关联起来（持久化到 `.libtv/project.json` 的 **`groupNodeKey`**）。之后在同一目录下跑 `libtv node …`，只要**没有**再写 `-g/--group`，CLI 会把它当成已经传了「就是这一组」：**列表 / 按名解析 / 更新 / 删改 / 连线**等都只在**该分组的子节点**（`childNodeIds`）范围内进行；**新建节点**也会默认**挂到这个分组**下。需要临时换范围时，直接在对应 `libtv node` 命令上加 `-g/--group <其他组>` 即可覆盖。

**位置参数**

- **`<group>`**（`use` 必填；`unuse` 无位置参数）：分组节点的 **id** 或**展示名**；解析规则与默认子命令一致。

**选项**

| 选项                   | 作用范围        | 说明                                                                                                                               |
| ---------------------- | --------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `-p, --project <uuid>` | `use` / `unuse` | 缺省使用当前目录绑定；指定时须与写入的 `projectUuid` 一致。                                                                        |
| `-g, --group <父组>`   | 仅 `use`        | 仅在指定父级普通分组的 `childNodeIds` 内解析 `<group>`，消歧义；**不是** [`libtv node -g`](./node.md) 那条「覆盖 node 分组范围」。 |

**行为 / 输出**

| 子命令  | 成功输出（stdout JSON）                                                                         |
| ------- | ----------------------------------------------------------------------------------------------- |
| `use`   | 含 `ok` / `cwd` / `projectUuid` / `groupNodeKey` / `name`；目标不是**可绑定的普通分组**会报错。 |
| `unuse` | 含 `groupUnbound: true`；清除 `groupNodeKey`，**保留** `projectUuid`。                          |

### `libtv group "<分组显示名>"`（默认子命令）

用法骨架：`libtv group <group> [flags]`

**位置参数**

- **`<group>`**（必填）：分组展示名或 id。若画布上已执行 `libtv group use` 且省略位置参数，等同于使用目录默认分组（以 `--help` 为准）。

**选项**：`-p` / `-g` / `-r`（见共享）；**绑定来源**：`--node` 与 stdin（见共享）。

**行为**（按是否有同名普通分组 × 是否有绑定来源）

| 画布上是否已有同名**普通**分组 | 是否有绑定来源（`--node` 或 stdin）                      |
| ------------------------------ | -------------------------------------------------------- |
| 有                             | 无 → **查询**（`action: "query"`，含子节点、执行计划等） |
| 有                             | 有 → **绑定**（`action: "bind"`）                        |
| 无                             | 无 → **建空分组**（`action: "create_empty"`）            |
| 无                             | 有 → **新建分组并绑定**（`action: "create_bind"`）       |

若该显示名被**非普通分组**节点占用，会报错退出。

**与 `create` 的区别**：默认子命令在「无已有同名普通分组」时会**顺带新建**；**`create` 在已有同名普通分组时一律失败**，适合脚本里「必须保证是新建」的场景。

## 示例

```bash
# case 1: 列出画布上的所有普通分组
libtv group list

# case 2: 仅新建一个空分组（已有同名则报错）
libtv group create "本镜资源组"

# case 3: 新建并绑定子节点（--node 可重复）
libtv group create "本镜资源组" --node "图A" --node "图B"

# case 4: 幂等接入：有就查询/绑定，没有就建并绑定
libtv group "本镜资源组" --node "图A" --node "图B"

# case 5: 管道把多个上游 nodeKey 绑到同一分组（顺序执行，避免并行写管道）
(libtv node "图A" && libtv node "图B") | libtv group "本镜资源组"

# case 6: 建组绑定后整组执行
libtv group "本镜资源组" --node "图A" --node "图B" --run

# case 7: 把当前工作目录绑定到某个普通分组；之后 libtv node 默认限定在该组内
libtv group use "本镜资源组"

# case 8: 解除目录默认分组绑定（保留项目绑定）
libtv group unuse

# case 9: 父组下解析同名分组（消歧义）
libtv group use "子组A" -g "父组"
```

> 并行 `&` 多进程同时写同一条管道时，单行 JSON 可能被交错或截断，导致下游解析失败；重要流水线请 **`&&` 顺序执行** 或先写入临时文件再读取，见 [../examples/pipes/error-handling.md](../examples/pipes/error-handling.md)。
