feat: skills - upgrade auto-tmux automation

This commit is contained in:
tukuaiai
2026-05-19 02:12:30 +08:00
parent 7beaadb4fc
commit 49137b80d8
15 changed files with 721 additions and 38 deletions
+2 -2
View File
@@ -166,7 +166,7 @@ git push origin develop
│ ├── README.md # skills 总览与索引
│ ├── AGENTS.md # skills/ 目录规则
│ ├── auto-skill/ # 元技能核心
│ ├── auto-tmux/ # tmux 自动化操控与多终端协作
│ ├── auto-tmux/ # tmux 自动化脚本、pane 巡检、救援与多终端协作
│ └── claude-official-skills/ # Claude 官方 skills 软链接入口
├── assets/ # 静态资产与外部资源入口
@@ -239,7 +239,7 @@ git push origin develop
- `docs/references/README.md#reference-engineering-practice` - 项目架构、代码组织、开发经验、底层程序逻辑、AI 编程质量门禁与常见坑的统一入口
- `docs/references/README.md#reference-technology-stack` - 常见软件系统技术栈、选型维度、组合案例与初学者学习路径
- `skills/auto-skill/` - Skills 生成、重构与校验的元技能
- `skills/auto-tmux/` - tmux 自动化操控、pane 巡检、按键注入与多终端协作技能
- `skills/auto-tmux/` - tmux 自动化操控、脚本化 pane 巡检、按键注入、日志录制与多终端协作技能
### docs README 结构契约
+2 -2
View File
@@ -501,7 +501,7 @@ pip install -r tools/prompts-library/scripts/requirements.txt
* [**Skills 制作器**](https://github.com/yusufkaraaslan/Skill_Seekers): 可根据需求生成定制化 Skills 的工具。
* [**元提示词**](https://docs.google.com/spreadsheets/d/1Ifk_dLF25ULSxcfGem1hXzJsi7_RBUNAki8SBCuvkJA/edit?gid=1254297203#gid=1254297203): 用于生成提示词的高级提示词。
* [**元技能:Auto Skill**](./skills/auto-skill/SKILL.md): 用于生成、重构与校验 Skills 的元技能。
* [**auto-tmux**](./skills/auto-tmux/SKILL.md): tmux 自动化操控、pane 巡检、按键注入与多终端协作技能。
* [**auto-tmux**](./skills/auto-tmux/SKILL.md): tmux 自动化操控、脚本化 pane 巡检、按键注入、日志录制与多终端协作技能。
* [**Mermaid Chart**](https://www.mermaidchart.com/): 用于将文本描述转换为架构图、序列图等可视化图表。
* [**NotebookLM**](https://notebooklm.google.com/): 一款用于 AI 解读资料、音频和生成思维导图的工具。
* [**Zread**](https://zread.ai/): AI 驱动的 GitHub 仓库阅读工具,有助于快速理解项目代码。
@@ -587,7 +587,7 @@ pip install -r tools/prompts-library/scripts/requirements.txt
├── prompts/ # 提示词库入口(指向云端表格)
├── skills/ # 技能库入口
│ ├── auto-skill/ # 元技能核心
│ ├── auto-tmux/ # tmux 自动化操控与多终端协作
│ ├── auto-tmux/ # tmux 自动化脚本、pane 巡检、救援与多终端协作
│ └── claude-official-skills/ # Claude 官方 skills 软链接入口
├── tools/ # 辅助工具、外部仓库与工具配置
├── scripts/ # 自动化脚本
+2 -2
View File
@@ -15,7 +15,7 @@ skills/
│ ├── assets/ # (可选) 模板/样例/静态资源
│ └── agents/ # (可选) Agent 元数据(如 openai.yaml
├── auto-skill/ # 元技能:生成/校验/脚手架化其它技能
└── auto-tmux/ # tmux 自动化操控、pane 巡检与多终端协作
└── auto-tmux/ # tmux 自动化脚本、pane 巡检、救援与多终端协作
```
## 外部仓库引用(约定)
@@ -47,6 +47,6 @@ skills/
## 快速定位(常用技能)
- `skills/auto-skill/`:元技能(技能生成/校验/脚手架)
- `skills/auto-tmux/`tmux 自动化技能;通过 `assets/` 软链接复用 `tools/external/.tmux``tools/external/tmux`
- `skills/auto-tmux/`tmux 自动化技能;通过 `scripts/auto-tmux.sh` 提供安全执行层,并通过 `assets/` 软链接复用 `tools/external/.tmux``tools/external/tmux`
- `skills/claude-official-skills/`Claude 官方 skills 仓库(Anthropic)的软链接入口
- `skills/auto-skill/scripts/Skill_Seekers-development`Skill Seekers submodule 的软链接入口
+3 -3
View File
@@ -7,13 +7,13 @@
| 技能 | 说明 |
|:---|:---|
| [auto-skill](./auto-skill/SKILL.md) | 生成、重构与校验 Skills 的元技能 |
| [auto-tmux](./auto-tmux/SKILL.md) | tmux 自动化操控、pane 巡检、按键注入、蜂群协作和 oh-my-tmux 参考入口 |
| [auto-tmux](./auto-tmux/SKILL.md) | tmux 自动化操控、脚本化 pane 巡检、按键注入、日志录制、蜂群协作和 oh-my-tmux 参考入口 |
| [claude-official-skills](./claude-official-skills/) | Claude 官方 skills 仓库的软链接入口,事实来源在 `tools/external/claude-official-skills/` |
## 维护口径
- `auto-skill/` 是本仓库的 Skill 生产与升级入口,继续保留。
- `auto-tmux/` 是 tmux 自动化与多 AI 终端协作入口,通过软链接复用 `tools/external/.tmux``tools/external/tmux`
- `auto-tmux/` 是 tmux 自动化与多 AI 终端协作入口,包含 `scripts/auto-tmux.sh` 执行层,并通过软链接复用 `tools/external/.tmux``tools/external/tmux`
- `claude-official-skills/` 是外部官方仓库展示入口,通过 submodule 管理事实来源。
- 领域型/工具型 Skill 如交易、数据库、代理、Telegram、EPUB 等不在主仓库维护;如需引入,优先使用独立仓库、submodule 或重新生成的方式。
@@ -51,6 +51,6 @@ git submodule update --init --recursive
## 相关资源
- [元技能文件](./auto-skill/SKILL.md) - 生成、重构与校验 Skills
- [auto-tmux](./auto-tmux/SKILL.md) - tmux 自动化操控与多终端协作
- [auto-tmux](./auto-tmux/SKILL.md) - tmux 自动化操控、脚本化巡检与多终端协作
- [提示词库](../prompts/) - 更细粒度的提示词集合
- [文档库](../docs/) - 方法论与开发经验
+7
View File
@@ -11,10 +11,15 @@ skills/auto-tmux/
├── assets/ # 外部 tmux 相关仓库的只读软链接入口
│ ├── oh-my-tmux -> ../../../tools/external/.tmux
│ └── tmux-src -> ../../../tools/external/tmux
├── scripts/ # 安全封装的 tmux 自动化脚本
│ ├── auto-tmux.sh
│ ├── README.md
│ └── AGENTS.md
└── references/ # 长文档、示例与故障排查
├── index.md
├── getting_started.md
├── api.md
├── automation.md
├── examples.md
└── troubleshooting.md
```
@@ -23,6 +28,7 @@ skills/auto-tmux/
- `assets/oh-my-tmux` 只暴露 gpakosz/oh-my-tmux submodule,不在技能目录内复制配置源码。
- `assets/tmux-src` 只暴露 tmux/tmux submodule,供需要查看源码或上游文档时定位。
- `scripts/auto-tmux.sh` 是技能执行层,封装 topology/capture/send/scan/rescue/record/hub/wait。
- 技能文档可以引用软链接入口;更新上游内容必须通过 `tools/external/` 下的 submodule 指针完成。
- 不在本目录直接修改 submodule 内容;如需改造,先 fork 上游并更新 submodule 来源。
@@ -31,3 +37,4 @@ skills/auto-tmux/
- 上游来源:`tools/external/.tmux``tools/external/tmux`
- 下游使用:`SKILL.md``references/` 中的命令示例。
- 验证入口:`skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict`
- 脚本验证:`bash -n skills/auto-tmux/scripts/auto-tmux.sh`
+5 -1
View File
@@ -5,6 +5,7 @@
## 入口
- [SKILL.md](./SKILL.md) - 技能触发条件、命令片段、规则和质量门禁。
- [scripts/](./scripts/) - 安全封装的 tmux 自动化脚本。
- [references/](./references/) - tmux / oh-my-tmux 参考、示例和故障排查。
- [assets/](./assets/) - 指向仓库外部 submodule 的只读软链接入口。
@@ -18,12 +19,15 @@
## 快速验证
```bash
bash -n skills/auto-tmux/scripts/auto-tmux.sh
skills/auto-tmux/scripts/auto-tmux.sh help
skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict
```
## 使用边界
- 发送按键前必须先 `capture-pane` 复核目标上下文
- 优先使用 `scripts/auto-tmux.sh`,需要低层调试时再直接使用 tmux 原生命令
- 发送按键前必须先 `capture-pane` 复核目标上下文;脚本会默认打印最近上下文。
- 批量操作前必须先列出 session/window/pane 白名单。
- 不在未知 pane 中发送破坏性命令。
- 不在本目录复制或修改上游 tmux / oh-my-tmux 源码。
+59 -27
View File
@@ -1,11 +1,11 @@
---
name: auto-tmux
description: "tmux 自动化操控:读取/广播/救援 session|window|pane,基于 oh-my-tmux 配置安全地让 AI 自控/互控终端。触发:需要 capture-pane/send-keys、批量巡检、蜂群 AI 协作、卡死救援或快速查看快捷键。"
description: "tmux 自动化操控:用 scripts/auto-tmux.sh 安全读取、发送、巡检、救援、录制 session|window|pane基于 oh-my-tmux 组织多 AI 终端协作。触发:capture-panesend-keys、批量巡检、蜂群 AI 协作、卡死救援、tmux 工作台初始化。"
---
# auto-tmux Skill
让 AI 像熟练运维一样操作 tmux:读取终端输出、发送按键、批量巡检、协作/救援其他终端默认兼容 `tools/external/.tmux`gpakosz/oh-my-tmux),并在本技能内通过 `assets/oh-my-tmux``assets/tmux-src` 暴露上游 submodule。
让 AI 像熟练运维一样操作 tmux:优先使用 `scripts/auto-tmux.sh` 安全封装读取终端输出、发送按键、批量巡检、协作/救援其他终端;必要时再回退到 tmux 原生命令。默认兼容 `tools/external/.tmux`gpakosz/oh-my-tmux),并在本技能内通过 `assets/oh-my-tmux``assets/tmux-src` 暴露上游 submodule。
## When to Use This Skill
@@ -13,6 +13,7 @@ description: "tmux 自动化操控:读取/广播/救援 session|window|pane
- 需要远程读取/复制某个 tmux pane 的最新输出(日志、提示、错误)。
- 需要向指定 pane 发送按键/命令(确认 `y``Enter``Ctrl+C`、广播同一窗口)。
- 需要批量巡检/接管多 AI 终端(蜂群协作、自动救援卡死任务)。
- 需要初始化 AI 多终端工作台、等待输出 pattern、录制 pane 日志或保存巡检证据。
- 需要快速回忆 oh-my-tmux 快捷键、前缀或同步面板操作。
- 需要在当前仓库复用 `tools/external/.tmux` 配置并避免修改主配置。
- 需要从技能目录内快速查看 oh-my-tmux 配置或 tmux 上游源码入口。
@@ -22,30 +23,54 @@ description: "tmux 自动化操控:读取/广播/救援 session|window|pane
- 不用于执行非 tmux 环境(目标不存在时先创建 session/window/pane)。
- 不直接编辑 `~/.tmux.conf` / `.tmux.conf`(遵循 oh-my-tmux:修改请放到 `.tmux.conf.local`)。
- 不盲发破坏性按键:`kill-server``rm -rf` 等必须先 capture-pane 确认目标上下文。
- 不把脚本当成权限绕过器;敏感会话、密码输入、生产数据库操作仍需人工确认。
- 如果 tmux 版本 < 2.6,需先升级再使用本技能的命令组合。
## Quick Reference
### 常用模式(≤20 条,直接复制即用)
**脚本帮助与语法检查**
```bash
bash -n skills/auto-tmux/scripts/auto-tmux.sh
skills/auto-tmux/scripts/auto-tmux.sh help
```
**查看快捷键帮助**oh-my-tmux 双前缀:主 `C-a`,备用 `C-b`,前缀后按 `?`
```text
[按] <prefix> ?
```
**枚举拓扑(session/window/pane**
**枚举拓扑(脚本优先**
```bash
skills/auto-tmux/scripts/auto-tmux.sh topology
skills/auto-tmux/scripts/auto-tmux.sh topology --session ai-hub
```
**枚举拓扑(原生命令兜底)**
```bash
tmux list-sessions
tmux list-windows -a -F '#S:#I:#W#F'
tmux list-panes -a -F '#S:#I.#P #{pane_current_command} #{pane_title}'
```
**读取指定 pane 最近 120 行**
**读取指定 pane 最近输出**
```bash
skills/auto-tmux/scripts/auto-tmux.sh capture -t <session>:<window>.<pane> -n 120
```
**原生读取指定 pane 最近 120 行**
```bash
tmux capture-pane -t <session>:<window>.<pane> -p -S -120
```
**向指定 pane 发送确认键**
**向指定 pane 发送命令或确认键**
```bash
skills/auto-tmux/scripts/auto-tmux.sh send -t <session>:<window>.<pane> --text "make test" --enter
skills/auto-tmux/scripts/auto-tmux.sh rescue -t <session>:<window>.<pane> --pattern "(y/n)" --reply y
```
**原生发送确认键**
```bash
tmux send-keys -t <session>:<window>.<pane> "y" Enter
```
@@ -61,27 +86,23 @@ tmux set-window-option synchronize-panes on
tmux set-window-option synchronize-panes off
```
**一次扫描全部窗口并截取最近输出(蜂群巡检骨架**
**一次扫描全部窗口并截取最近输出(蜂群巡检)**
```bash
for w in $(tmux list-windows -a -F '#S:#I'); do
tmux capture-pane -t "$w" -p -S -80 | sed "s/^/[$w] /";
done
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub -n 80
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback" --save-dir /tmp/auto-tmux-scan
```
**远程救援:发现等待输入即发送 y**
```bash
target="0:3.0" # 示例
tmux capture-pane -t "$target" -p -S -50 | grep -qi "(y/n)" && \
tmux send-keys -t "$target" "y" Enter
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
skills/auto-tmux/scripts/auto-tmux.sh rescue -t "$target" --pattern "(y/n)" --reply y --dry-run
skills/auto-tmux/scripts/auto-tmux.sh rescue -t "$target" --pattern "(y/n)" --reply y
```
**新建 AI 蜂群工作台(1 指挥 + 3 工人)**
```bash
tmux new-session -d -s ai-hub -n commander 'bash'
tmux new-window -t ai-hub -n worker1 'kiro-cli chat'
tmux new-window -t ai-hub -n worker2 'kiro-cli chat'
tmux new-window -t ai-hub -n worker3 'kiro-cli chat'
tmux attach -t ai-hub
skills/auto-tmux/scripts/auto-tmux.sh hub --session ai-hub --workers 3 --cmd "codex"
skills/auto-tmux/scripts/auto-tmux.sh topology --session ai-hub
```
**启用 oh-my-tmux 配置(仓库内版本)**
@@ -93,11 +114,18 @@ cp -n "$repo_root/skills/auto-tmux/assets/oh-my-tmux/.tmux.conf.local" ~/.tmux.c
**记录 pane 输出到文件**
```bash
tmux pipe-pane -t <session>:<window>.<pane> -o 'cat >> /tmp/tmux-<session>-<window>-<pane>.log'
skills/auto-tmux/scripts/auto-tmux.sh record start -t <session>:<window>.<pane> --dir /tmp/auto-tmux-records
skills/auto-tmux/scripts/auto-tmux.sh record stop -t <session>:<window>.<pane>
```
**等待 pane 出现完成信号**
```bash
skills/auto-tmux/scripts/auto-tmux.sh wait -t <session>:<window>.<pane> --pattern "Tests passed|BUILD SUCCESS" --timeout 300
```
## Rules & Constraints
- MUST:优先使用 `scripts/auto-tmux.sh`;直接使用 tmux 原生命令时必须保留同等安全约束。
- MUST:在发送按键前用 `capture-pane` 复核目标上下文;按键操作必须带 `<session>:<window>.<pane>` 绝对定位。
- MUST:遵循 oh-my-tmux 约定,不修改主配置文件;自定义写入 `~/.tmux.conf.local`
- MUST:批量操作前先 `list-windows`/`list-panes` 建立白名单,避免误控用户窗口。
@@ -110,17 +138,18 @@ tmux pipe-pane -t <session>:<window>.<pane> -o 'cat >> /tmp/tmux-<session>-<wind
## Examples
### Example 1:自动给卡住的安装脚本回车确认
- 输入:安装脚本停在 `Proceed? (y/n)`位置在 `0:3.0`
- 输入:安装脚本停在 `Proceed? (y/n)`先用 `topology` 找到真实 target
- 步骤:
1) `tmux capture-pane -t 0:3.0 -p -S -50 | grep -qi "(y/n)"` 确认等待输入
2) `tmux send-keys -t 0:3.0 "y" Enter` 发送确认
1) `skills/auto-tmux/scripts/auto-tmux.sh topology` 找到目标 `<session>:<window>.<pane>`
2) `skills/auto-tmux/scripts/auto-tmux.sh rescue -t <target> --pattern "(y/n)" --reply y --dry-run` 确认命中
3) `skills/auto-tmux/scripts/auto-tmux.sh rescue -t <target> --pattern "(y/n)" --reply y` 发送确认。
- 验收:脚本继续运行,无额外多余输入。
### Example 2:蜂群巡检 + 自动救援
- 输入:4 个 AI 终端分布在 session `ai-hub` 的多个窗口。
- 步骤:
1) 运行 Quick Reference 巡检循环收集最近 80 行并观察状态。
2) 对匹配 `"(y/n)"` 的 pane 触发「远程救援」片段自动发 `y`
1) `skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub -n 80 --save-dir /tmp/auto-tmux-scan` 收集状态。
2) 对匹配 `"(y/n)"` 的 pane 运行 `rescue --dry-run`,确认后再真实发送
3) 对输出包含 `Traceback``ERROR` 的 pane,先 `capture-pane` 记录再人工介入。
- 验收:等待确认的终端恢复,未误伤正常任务;巡检日志保存在本地。
@@ -128,8 +157,8 @@ tmux pipe-pane -t <session>:<window>.<pane> -o 'cat >> /tmp/tmux-<session>-<wind
- 输入:需要 1 个指挥 + 3 个 worker,并使用仓库内 oh-my-tmux 配置。
- 步骤:
1) 运行「启用 oh-my-tmux 配置」片段完成软链和本地副本(若已存在跳过)。
2) 运行「新建 AI 蜂群工作台」片段创建 session 并 attach
3) 在 commander pane 使用「枚举拓扑」确认 worker 窗口存在。
2) `skills/auto-tmux/scripts/auto-tmux.sh hub --session ai-hub --workers 3 --cmd "codex"` 创建 session。
3) `skills/auto-tmux/scripts/auto-tmux.sh topology --session ai-hub` 确认 worker 窗口存在。
- 验收:前缀键为 `C-a`,状态栏正常;4 个窗口可互相捕获/发送按键。
## FAQ
@@ -153,15 +182,17 @@ tmux pipe-pane -t <session>:<window>.<pane> -o 'cat >> /tmp/tmux-<session>-<wind
- `references/index.md`: 导航与文件速览
- `references/getting_started.md`: 术语、oh-my-tmux 最小接入步骤
- `references/api.md`: tmux/oh-my-tmux 常用命令、选项与 gpakosz 特色键位
- `references/automation.md`: `scripts/auto-tmux.sh` 子命令、安全模型与 AI 蜂群协作流程
- `references/examples.md`: 蜂群协议脚本与长示例
- `references/troubleshooting.md`: 典型故障到修复路径
- `scripts/auto-tmux.sh`: 安全封装的 tmux 自动化脚本入口
- `assets/oh-my-tmux`: gpakosz/oh-my-tmux submodule 的相对软链接入口
- `assets/tmux-src`: tmux/tmux submodule 的相对软链接入口
## Maintenance
- Sources: `skills/auto-tmux/assets/oh-my-tmux``skills/auto-tmux/assets/tmux-src`、蜂群实战提示词、Skill Seeker 生成的抓取材料(如需扩展自动化)。
- Last updated: 2026-04-28
- Last updated: 2026-05-19
- Known limits: 未涵盖 tmux 插件管理(tpm)及多用户共享权限配置;需时再补充。
## Quality Gate
@@ -173,4 +204,5 @@ tmux pipe-pane -t <session>:<window>.<pane> -o 'cat >> /tmp/tmux-<session>-<wind
4. ≥3 个端到端示例,含输入/步骤/验收。
5. 长文档放在 `references/` 并可导航;无文档堆砌。
6. 不确定项给出验证路径;禁止虚构 tmux 行为。
7. 运行 `skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux` 通过。
7. `bash -n skills/auto-tmux/scripts/auto-tmux.sh` 通过。
8. 运行 `skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict` 通过。
+1
View File
@@ -7,4 +7,5 @@
- 参考资料只能引用仓库相对路径,不写个人机器绝对路径。
- 上游来源统一写为 `tools/external/.tmux``tools/external/tmux``tools/external/Skill_Seekers-development`
- 示例命令必须优先使用可复制的占位符或 `git rev-parse --show-toplevel` 动态定位仓库根目录。
- 脚本类说明优先引用 `skills/auto-tmux/scripts/auto-tmux.sh`,再给原生命令兜底。
- 不确定的 tmux 行为必须给出验证命令,不编造。
+1
View File
@@ -7,5 +7,6 @@
| [index.md](./index.md) | 参考资料索引 |
| [getting_started.md](./getting_started.md) | 术语、最短路径和工作姿势 |
| [api.md](./api.md) | tmux / oh-my-tmux 常用命令与配置速查 |
| [automation.md](./automation.md) | `auto-tmux.sh` 脚本子命令、安全模型和 AI 蜂群协作流程 |
| [examples.md](./examples.md) | 巡检、救援、审计和多 AI 工作台示例 |
| [troubleshooting.md](./troubleshooting.md) | 常见故障与修复路径 |
+133
View File
@@ -0,0 +1,133 @@
# auto-tmux Script Automation
`scripts/auto-tmux.sh``auto-tmux` 的安全执行层:把高频 tmux 操作封装为可审计命令,减少手写 `capture-pane` / `send-keys` 时的误控风险。
## 设计目标
- **先观察再控制**:所有发送动作都要求目标 pane 存在,并优先输出最近上下文。
- **默认脱敏**:读取 pane 输出时自动遮蔽常见 token、API key、password、Bearer token。
- **拒绝危险动作**`rm -rf``git reset --hard``git clean -fd``tmux kill-server` 等命令默认拒绝,必须显式 `--force`
- **批量动作可解释**scan/rescue 都基于明确 session、pane、pattern 和 reply,不做无条件广播。
- **不改用户配置**:脚本只操作 tmux server,不写 `~/.tmux.conf`oh-my-tmux 配置仍走 `assets/oh-my-tmux` 参考入口。
## 子命令总览
| 子命令 | 用途 | 风险控制 |
|:---|:---|:---|
| `topology` | 列出 session/window/pane 拓扑 | 只读 |
| `capture` | 读取指定 pane 最近输出 | 默认脱敏,可保存到文件 |
| `send` | 向指定 pane 发送文本或按键 | 先打印上下文,危险文本需 `--force` |
| `rescue` | pattern 命中后发送确认 | 不命中不发送 |
| `scan` | 批量巡检 pane 输出 | 可按 session 限定范围 |
| `record` | 开启/停止 pane 输出审计日志 | 文件写入到显式目录 |
| `hub` | 初始化 AI 多终端工作台 | 已存在 session 不覆盖 |
| `wait` | 等待 pane 输出出现某个 pattern | 超时失败 |
## 典型流程
### 1. 建立 AI 工作台
```bash
skills/auto-tmux/scripts/auto-tmux.sh hub --session ai-hub --workers 3 --cmd "codex"
```
验收:
```bash
skills/auto-tmux/scripts/auto-tmux.sh topology --session ai-hub
```
### 2. 巡检全部 worker
```bash
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub -n 100
```
只看错误:
```bash
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback|failed"
```
保存巡检日志:
```bash
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --save-dir /tmp/auto-tmux-scan
```
### 3. 安全发送命令
```bash
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
skills/auto-tmux/scripts/auto-tmux.sh send -t "$target" --text "make test" --enter
```
如果要清空当前输入行后发送:
```bash
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
skills/auto-tmux/scripts/auto-tmux.sh send -t "$target" --clear --text "make lint" --enter
```
### 4. 自动救援等待确认的 pane
```bash
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
skills/auto-tmux/scripts/auto-tmux.sh rescue -t "$target" --pattern "(y/n)" --reply y
```
先演练不发送:
```bash
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
skills/auto-tmux/scripts/auto-tmux.sh rescue -t "$target" --pattern "(y/n)" --reply y --dry-run
```
### 5. 等待任务完成信号
```bash
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
skills/auto-tmux/scripts/auto-tmux.sh wait -t "$target" --pattern "BUILD SUCCESS|Tests passed" --timeout 300
```
### 6. 开启审计日志
```bash
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
skills/auto-tmux/scripts/auto-tmux.sh record start -t "$target" --dir /tmp/auto-tmux-records
```
停止:
```bash
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
skills/auto-tmux/scripts/auto-tmux.sh record stop -t "$target"
```
## AI 蜂群协作建议
推荐结构:
```text
ai-hub
├── commander # 人类或主 Agent:分配任务、巡检、验收、回收证据
├── worker1 # 子任务 1
├── worker2 # 子任务 2
└── worker3 # 子任务 3
```
最小协议:
1. commander 只通过明确 pane 目标发送任务,不盲发广播。
2. worker 输出完成状态、失败原因、修改文件和验证结果。
3. commander 用 `scan` 收集状态,用 `capture` 保留证据。
4. 需要确认输入时,用 `rescue --dry-run` 先验证 pattern,再真实发送。
5. 长任务用 `record start` 留日志,结束后 `record stop`
## 验证命令
```bash
bash -n skills/auto-tmux/scripts/auto-tmux.sh
skills/auto-tmux/scripts/auto-tmux.sh help
skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict
```
+21 -1
View File
@@ -1,5 +1,25 @@
# Long Examples
## 用例 0:使用脚本入口完成巡检、发送和救援
```bash
# 查看拓扑
skills/auto-tmux/scripts/auto-tmux.sh topology --session ai-hub
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
# 读取 worker 输出
skills/auto-tmux/scripts/auto-tmux.sh capture -t "$target" -n 100
# 发送测试命令
skills/auto-tmux/scripts/auto-tmux.sh send -t "$target" --text "make test" --enter
# 对等待确认的 pane 执行救援
skills/auto-tmux/scripts/auto-tmux.sh rescue -t "$target" --pattern "(y/n)" --reply y
```
- 推荐优先使用脚本入口;下面的 Bash 片段保留为理解 tmux 原生命令的参考。
## 用例 1:巡检 + 自动救援脚本(bash)
```bash
@@ -11,7 +31,7 @@ for w in $(tmux list-windows -a -F '#S:#I'); do
panes=$(tmux list-panes -t "$w" -F '#S:#I.#P')
for p in $panes; do
log=$(tmux capture-pane -t "$p" -p -S -80)
printf '--- [%s] ---\n%s\n' "$p" "$log"
printf -- '--- [%s] ---\n%s\n' "$p" "$log"
if echo "$log" | grep -qi "(y/n)"; then
tmux send-keys -t "$p" "y" Enter
echo "[action] sent y to $p"
+2
View File
@@ -4,11 +4,13 @@
- `getting_started.md`:术语、最小安装、前缀说明
- `api.md`tmux/oh-my-tmux 常用命令、同步广播、安全写法
- `automation.md``scripts/auto-tmux.sh` 子命令、安全模型与 AI 蜂群协作流程
- `examples.md`:蜂群巡检脚本、自动救援脚本、Skill Seeker 抓取示例
- `troubleshooting.md`:常见报错与修复路径
## Notes
- 长文档、脚本细节放这里,`SKILL.md` 只保留可立即执行的片段。
- 脚本入口统一为 `skills/auto-tmux/scripts/auto-tmux.sh`,原生命令作为兜底参考。
- 配置来源:仓库内 `tools/external/.tmux`gpakosz/oh-my-tmux)。
- 大规模文档抓取/刷新可用 `tools/external/Skill_Seekers-development`,示例见 `examples.md`
+20
View File
@@ -0,0 +1,20 @@
# skills/auto-tmux/scripts
本目录承载 `auto-tmux` 的可执行脚本层。脚本必须安全封装 tmux 常用操作,减少手写 `capture-pane` / `send-keys` 时的误控风险。
## 目录结构
```text
scripts/
├── AGENTS.md # 本文件:脚本维护规则
├── README.md # 面向人类的脚本入口说明
└── auto-tmux.sh # 统一 tmux 自动化命令入口
```
## 维护规则
- 脚本必须使用 Bash 标准能力,不引入额外运行时依赖。
- 发送按键类功能必须先验证目标 pane 存在,并优先打印上下文。
- 捕获输出默认脱敏;只有显式 `--no-redact` 才允许输出原文。
- 批量救援必须通过 pattern 匹配触发,不允许无条件向所有 pane 发送输入。
- 新增脚本后必须更新 `README.md``SKILL.md``references/index.md`,并运行 `bash -n` 与 skill strict 校验。
+35
View File
@@ -0,0 +1,35 @@
# auto-tmux scripts
`scripts/` 存放 `auto-tmux` 的可执行辅助脚本,把常见 tmux 操作封装成安全、可复用、可审计的命令。
## 入口
- [`auto-tmux.sh`](./auto-tmux.sh) - 统一命令入口,支持拓扑、读取、发送、巡检、救援、录制、等待和 AI 工作台初始化。
## 常用命令
```bash
# 查看帮助
skills/auto-tmux/scripts/auto-tmux.sh help
# 查看 tmux 拓扑
skills/auto-tmux/scripts/auto-tmux.sh topology
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
# 读取指定 pane 最近 80 行
skills/auto-tmux/scripts/auto-tmux.sh capture -t "$target" -n 80
# 发送命令并回车
skills/auto-tmux/scripts/auto-tmux.sh send -t "$target" --text "make test" --enter
# 扫描某个 session 的错误
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback"
```
## 安全约束
- 默认对捕获输出做密钥脱敏。
- `send` 会先打印目标 pane 最近上下文,再发送按键。
- 危险命令默认拒绝,必须显式 `--force`
- 批量操作必须使用明确的 session/window/pane 目标。
+428
View File
@@ -0,0 +1,428 @@
#!/usr/bin/env bash
# auto-tmux: safe tmux automation wrapper for Codex/AI operator workflows.
set -euo pipefail
PROG="${0##*/}"
DEFAULT_LINES=120
DEFAULT_RESCUE_PATTERN='(\(y/n\)|\[y/N\]|\[Y/n\]|continue\?|proceed\?|confirm|确认|是否继续)'
DANGEROUS_PATTERN='(^|[[:space:];|&])(rm[[:space:]]+-rf|mkfs|dd[[:space:]]+if=|shutdown|reboot|halt|poweroff|tmux[[:space:]]+kill-server|git[[:space:]]+reset[[:space:]]+--hard|git[[:space:]]+clean[[:space:]]+-fd|DROP[[:space:]]+(DATABASE|TABLE))'
usage() {
cat <<'EOF'
auto-tmux: safe tmux automation wrapper
Usage:
auto-tmux.sh help
auto-tmux.sh topology [--session NAME]
auto-tmux.sh capture -t TARGET [-n LINES] [--save FILE] [--no-redact]
auto-tmux.sh send -t TARGET (--text TEXT | --key KEY) [--enter] [--clear] [--force] [--dry-run]
auto-tmux.sh rescue -t TARGET [--pattern REGEX] [--reply TEXT] [-n LINES] [--force] [--dry-run]
auto-tmux.sh scan [--session NAME] [-n LINES] [--pattern REGEX] [--rescue] [--reply TEXT] [--save-dir DIR]
auto-tmux.sh record start -t TARGET [--dir DIR]
auto-tmux.sh record stop -t TARGET
auto-tmux.sh hub [--session NAME] [--workers N] [--cmd CMD] [--commander-cmd CMD] [--attach]
auto-tmux.sh wait -t TARGET --pattern REGEX [--timeout SEC] [--interval SEC] [-n LINES]
Target format:
<session>:<window>.<pane>
Examples:
auto-tmux.sh topology
auto-tmux.sh capture -t <target-from-topology> -n 80
auto-tmux.sh send -t <target-from-topology> --text "make test" --enter
auto-tmux.sh rescue -t <target-from-topology> --pattern "(y/n)" --reply y
auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback"
auto-tmux.sh hub --session ai-hub --workers 3 --cmd "codex"
EOF
}
die() {
printf 'error: %s\n' "$*" >&2
exit 1
}
warn() {
printf 'warn: %s\n' "$*" >&2
}
require_tmux() {
command -v tmux >/dev/null 2>&1 || die "tmux is not installed or not in PATH"
tmux list-sessions >/dev/null 2>&1 || die "no tmux server/session found"
}
target_exists() {
local target="$1"
tmux display-message -pt "$target" '#{pane_id}' >/dev/null 2>&1
}
require_target() {
local target="$1"
[[ -n "$target" ]] || die "missing -t TARGET"
target_exists "$target" || die "tmux target not found: $target"
}
redact() {
sed -E \
-e 's/(OPENAI_API_KEY|ANTHROPIC_API_KEY|GITHUB_TOKEN|GH_TOKEN|API_KEY|TOKEN|PASSWORD|SECRET)=([^[:space:]]+)/\1=<redacted>/g' \
-e 's/(Bearer[[:space:]]+)[A-Za-z0-9._~+\/=-]+/\1<redacted>/g' \
-e 's/(sk-[A-Za-z0-9_-]{12,})/<redacted-openai-key>/g'
}
capture_raw() {
local target="$1"
local lines="$2"
tmux capture-pane -t "$target" -p -S "-$lines"
}
capture_print() {
local target="$1"
local lines="$2"
local no_redact="$3"
if [[ "$no_redact" == "1" ]]; then
capture_raw "$target" "$lines"
else
capture_raw "$target" "$lines" | redact
fi
}
is_dangerous_text() {
local text="$1"
echo "$text" | grep -Eiq "$DANGEROUS_PATTERN"
}
cancel_copy_mode_if_needed() {
local target="$1"
local in_mode
in_mode="$(tmux display-message -pt "$target" '#{pane_in_mode}' 2>/dev/null || echo 0)"
if [[ "$in_mode" == "1" ]]; then
tmux send-keys -t "$target" -X cancel
fi
}
pane_list() {
local session="$1"
if [[ -n "$session" ]]; then
tmux list-panes -a -F '#S:#I.#P' | awk -F: -v s="$session" '$1 == s {print}'
else
tmux list-panes -a -F '#S:#I.#P'
fi
}
cmd_topology() {
local session=""
while [[ $# -gt 0 ]]; do
case "$1" in
--session) session="${2:-}"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown topology option: $1" ;;
esac
done
require_tmux
if [[ -n "$session" ]]; then
tmux has-session -t "$session" 2>/dev/null || die "session not found: $session"
printf 'session: %s\n' "$session"
tmux list-windows -t "$session" -F ' window #{window_index}: #{window_name} #{window_flags}'
tmux list-panes -a -F '#S #S:#{window_index}.#{pane_index} #{pane_current_command} #{pane_current_path}' |
awk -v s="$session" '$1 == s {print " pane target=" $2 " cmd=" $3 " path=" $4}'
else
tmux list-sessions -F 'session: #{session_name} windows=#{session_windows} attached=#{session_attached}'
tmux list-windows -a -F ' window #S:#{window_index}: #{window_name} #{window_flags}'
tmux list-panes -a -F ' pane #S:#{window_index}.#{pane_index} cmd=#{pane_current_command} path=#{pane_current_path}'
fi
}
cmd_capture() {
local target=""
local lines="$DEFAULT_LINES"
local save_file=""
local no_redact="0"
while [[ $# -gt 0 ]]; do
case "$1" in
-t|--target) target="${2:-}"; shift 2 ;;
-n|--lines) lines="${2:-}"; shift 2 ;;
--save) save_file="${2:-}"; shift 2 ;;
--no-redact) no_redact="1"; shift ;;
-h|--help) usage; exit 0 ;;
*) die "unknown capture option: $1" ;;
esac
done
require_tmux
require_target "$target"
if [[ -n "$save_file" ]]; then
mkdir -p "$(dirname "$save_file")"
capture_print "$target" "$lines" "$no_redact" | tee "$save_file"
else
capture_print "$target" "$lines" "$no_redact"
fi
}
cmd_send() {
local target=""
local text=""
local key=""
local enter="0"
local clear="0"
local force="0"
local dry_run="0"
while [[ $# -gt 0 ]]; do
case "$1" in
-t|--target) target="${2:-}"; shift 2 ;;
--text) text="${2:-}"; shift 2 ;;
--key) key="${2:-}"; shift 2 ;;
--enter) enter="1"; shift ;;
--clear) clear="1"; shift ;;
--force) force="1"; shift ;;
--dry-run) dry_run="1"; shift ;;
-h|--help) usage; exit 0 ;;
*) die "unknown send option: $1" ;;
esac
done
require_tmux
require_target "$target"
[[ -n "$text" || -n "$key" ]] || die "send requires --text TEXT or --key KEY"
[[ -z "$text" || -z "$key" ]] || die "send accepts only one of --text or --key"
printf -- '--- current context: %s ---\n' "$target" >&2
capture_print "$target" 40 0 >&2 || true
if [[ -n "$text" && "$force" != "1" ]] && is_dangerous_text "$text"; then
die "refusing dangerous text without --force: $text"
fi
if [[ "$dry_run" == "1" ]]; then
printf '[dry-run] target=%s clear=%s text=%q key=%q enter=%s\n' "$target" "$clear" "$text" "$key" "$enter"
return 0
fi
cancel_copy_mode_if_needed "$target"
if [[ "$clear" == "1" ]]; then
tmux send-keys -t "$target" C-u
fi
if [[ -n "$text" ]]; then
tmux send-keys -t "$target" -l "$text"
else
tmux send-keys -t "$target" "$key"
fi
if [[ "$enter" == "1" ]]; then
tmux send-keys -t "$target" Enter
fi
}
cmd_rescue() {
local target=""
local pattern="$DEFAULT_RESCUE_PATTERN"
local reply="y"
local lines=80
local force="0"
local dry_run="0"
while [[ $# -gt 0 ]]; do
case "$1" in
-t|--target) target="${2:-}"; shift 2 ;;
--pattern) pattern="${2:-}"; shift 2 ;;
--reply) reply="${2:-}"; shift 2 ;;
-n|--lines) lines="${2:-}"; shift 2 ;;
--force) force="1"; shift ;;
--dry-run) dry_run="1"; shift ;;
-h|--help) usage; exit 0 ;;
*) die "unknown rescue option: $1" ;;
esac
done
require_tmux
require_target "$target"
local output
output="$(capture_raw "$target" "$lines")"
printf '%s\n' "$output" | redact
if printf '%s\n' "$output" | grep -Eiq "$pattern"; then
printf '[match] target=%s pattern=%s reply=%q\n' "$target" "$pattern" "$reply" >&2
if [[ "$dry_run" == "1" ]]; then
printf '[dry-run] would send reply to %s\n' "$target"
else
if [[ "$force" == "1" ]]; then
cmd_send -t "$target" --text "$reply" --enter --force
else
cmd_send -t "$target" --text "$reply" --enter
fi
fi
else
printf '[skip] no rescue pattern matched for %s\n' "$target" >&2
fi
}
cmd_scan() {
local session=""
local lines=80
local pattern=""
local rescue="0"
local reply="y"
local save_dir=""
while [[ $# -gt 0 ]]; do
case "$1" in
--session) session="${2:-}"; shift 2 ;;
-n|--lines) lines="${2:-}"; shift 2 ;;
--pattern) pattern="${2:-}"; shift 2 ;;
--rescue) rescue="1"; shift ;;
--reply) reply="${2:-}"; shift 2 ;;
--save-dir) save_dir="${2:-}"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown scan option: $1" ;;
esac
done
require_tmux
if [[ -n "$save_dir" ]]; then
mkdir -p "$save_dir"
fi
local pane output safe_name
while IFS= read -r pane; do
[[ -n "$pane" ]] || continue
printf '\n===== [%s] =====\n' "$pane"
output="$(capture_raw "$pane" "$lines")"
printf '%s\n' "$output" | redact
if [[ -n "$save_dir" ]]; then
safe_name="${pane//[:.]/-}.log"
printf '%s\n' "$output" | redact > "$save_dir/$safe_name"
fi
if [[ -n "$pattern" ]] && printf '%s\n' "$output" | grep -Eiq "$pattern"; then
printf '[match] %s matched %s\n' "$pane" "$pattern" >&2
if [[ "$rescue" == "1" ]]; then
cmd_send -t "$pane" --text "$reply" --enter
fi
fi
done < <(pane_list "$session")
}
cmd_record() {
local action="${1:-}"
[[ -n "$action" ]] || die "record requires start or stop"
shift || true
local target=""
local dir="/tmp/auto-tmux-records"
while [[ $# -gt 0 ]]; do
case "$1" in
-t|--target) target="${2:-}"; shift 2 ;;
--dir) dir="${2:-}"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown record option: $1" ;;
esac
done
require_tmux
require_target "$target"
case "$action" in
start)
mkdir -p "$dir"
local safe_name="${target//[:.]/-}.log"
local file="$dir/$safe_name"
tmux pipe-pane -t "$target" -o "cat >> '$file'"
printf 'recording %s -> %s\n' "$target" "$file"
;;
stop)
tmux pipe-pane -t "$target"
printf 'recording stopped for %s\n' "$target"
;;
*)
die "record action must be start or stop"
;;
esac
}
cmd_hub() {
local session="ai-hub"
local workers=3
local worker_cmd="bash"
local commander_cmd="bash"
local attach="0"
while [[ $# -gt 0 ]]; do
case "$1" in
--session) session="${2:-}"; shift 2 ;;
--workers) workers="${2:-}"; shift 2 ;;
--cmd) worker_cmd="${2:-}"; shift 2 ;;
--commander-cmd) commander_cmd="${2:-}"; shift 2 ;;
--attach) attach="1"; shift ;;
-h|--help) usage; exit 0 ;;
*) die "unknown hub option: $1" ;;
esac
done
command -v tmux >/dev/null 2>&1 || die "tmux is not installed or not in PATH"
if tmux has-session -t "$session" 2>/dev/null; then
warn "session already exists: $session"
tmux list-windows -t "$session" -F '#S:#I #{window_name}'
else
tmux new-session -d -s "$session" -n commander "$commander_cmd"
local i
for i in $(seq 1 "$workers"); do
tmux new-window -t "$session" -n "worker$i" "$worker_cmd"
done
tmux select-window -t "$session:commander"
printf 'created tmux AI hub: %s workers=%s cmd=%q\n' "$session" "$workers" "$worker_cmd"
fi
if [[ "$attach" == "1" ]]; then
tmux attach -t "$session"
fi
}
cmd_wait() {
local target=""
local pattern=""
local timeout=60
local interval=2
local lines=80
while [[ $# -gt 0 ]]; do
case "$1" in
-t|--target) target="${2:-}"; shift 2 ;;
--pattern) pattern="${2:-}"; shift 2 ;;
--timeout) timeout="${2:-}"; shift 2 ;;
--interval) interval="${2:-}"; shift 2 ;;
-n|--lines) lines="${2:-}"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) die "unknown wait option: $1" ;;
esac
done
require_tmux
require_target "$target"
[[ -n "$pattern" ]] || die "wait requires --pattern REGEX"
local start now output
start="$(date +%s)"
while true; do
output="$(capture_raw "$target" "$lines")"
if printf '%s\n' "$output" | grep -Eiq "$pattern"; then
printf '%s\n' "$output" | redact
printf '[matched] target=%s pattern=%s\n' "$target" "$pattern" >&2
return 0
fi
now="$(date +%s)"
if (( now - start >= timeout )); then
printf '%s\n' "$output" | redact
die "timeout waiting for pattern: $pattern"
fi
sleep "$interval"
done
}
main() {
local cmd="${1:-help}"
shift || true
case "$cmd" in
help|-h|--help) usage ;;
topology) cmd_topology "$@" ;;
capture) cmd_capture "$@" ;;
send) cmd_send "$@" ;;
rescue) cmd_rescue "$@" ;;
scan) cmd_scan "$@" ;;
record) cmd_record "$@" ;;
hub) cmd_hub "$@" ;;
wait) cmd_wait "$@" ;;
*) die "unknown command: $cmd" ;;
esac
}
main "$@"