# 为什么 PIG 保持扁平的 Cobra 命令层

> 一个顶层命令对应 cmd 中一个文件，具体行为进入 cli 与 internal 包的源码布局决策。

---

LLMS 索引： [llms.txt](/zh/llms.txt)

---

> **决策日期：** 2026-06-30<br>
> **状态：** 当前仍在执行的仓库架构。<br>
> **当前参考：** [`pig` 命令总览](/zh/cmd/)与[源码仓库](https://github.com/pgsty/pig)<br>
> **范围：** Go 源码归属与命令注册方式，而不是公开命令分类本身。

## 决策 {#decision}

`cmd` 包保持扁平。一个顶层命令对应一个顶层 Go 文件：`pg.go`、`pb.go`、`pt.go`、
`pe.go`、`sty.go`、`do.go`、`repo.go` 等。即使命令树很复杂，也继续留在这个入口文件中，
除非另有明确的布局决策。

文件可以很长，但只应包含 Cobra 关注点：名称、别名、注解、参数、实参校验、帮助、注册和选项映射。
具体工作放入 `cli/*`、`internal/*` 或其它实现包。

## 背景 {#context}

早期命令增长产生了很多以子命令命名的小文件，也出现了多套确认、结构化输出、计划渲染和旧接口包装实现。
一些简单问题因此难以回答：顶层命令在哪里注册，某个别名由谁拥有，两段辅助代码是否在执行同一策略？

PIG 的命令族很大，但它们的公开语法是一个整体。把语法集中在一个位置更容易审查冲突，
实现包则继续按职责拆分。

## 考虑过的方案 {#alternatives}

- **在 `cmd` 下为每个命令建目录。** 普通命令不采用，因为一个公开语法会散落在多个包中，也容易把业务逻辑放到 Cobra 附近。
- **每个子命令一个文件。** 注册、别名和继承参数将难以作为整体审阅。
- **把所有逻辑都放进 `cmd`。** 操作逻辑依赖 Cobra 状态后，测试与复用都会变差。
- **抽象每一行重复代码。** 猜测式框架会遮蔽命令语法；只有已经稳定、跨命令复用的胶水才应共享。

## 契约 {#contract}

- `cmd/root.go` 负责根命令、全局参数和顶层注册；
- `cmd/utils.go` 负责共享的命令层辅助函数；
- 每个普通顶层命令有一个对应的顶层源码文件，可以配一个同名测试文件；
- Cobra 层校验语法和映射选项，但不执行具体操作；
- 确认、注解、结构化输出与计划辅助逻辑只有一套实现；
- 实现包接收普通选项并返回类型化结果或错误，不依赖 Cobra 全局状态。

## 影响 {#impact}

部分命令文件会有意保持较长。这个取舍是可接受的，因为公开接口可以作为整体审阅，而实现仍然在下层拆分。
规则也减少了别名或参数移动时的文件震荡，为 Agent 提供确定的阅读起点。

边界是架构性的，不是外观性的：把业务逻辑藏在闭包里的短 `cmd` 文件仍然违规；
只包含声明式命令胶水的长文件则没有问题。

## 验证与演进 {#verification}

约定记录在 [`9eb70db`](https://github.com/pgsty/pig/commit/9eb70db)，
随后由大型命令面整合提交 [`fb93602`](https://github.com/pgsty/pig/commit/fb93602) 落实。
Guard 测试检查别名冲突与命令注册，实现层行为则由各包测试验证。

## 当前状态 {#status}

这仍是新工作的仓库规则。公开命令文档统一放在本站；源码布局约束继续靠近代码保留，
确保贡献者与编码 Agent 在修改前就能看到。
