mirror of
https://github.com/tradecatlabs/vibe-coding-cn.git
synced 2026-08-18 21:38:05 +00:00
feat: skills - deepen auto-tmux swarm tooling
This commit is contained in:
@@ -13,6 +13,8 @@ skills/auto-tmux/
|
|||||||
│ └── tmux-src -> ../../../tools/external/tmux
|
│ └── tmux-src -> ../../../tools/external/tmux
|
||||||
├── scripts/ # 安全封装的 tmux 自动化脚本
|
├── scripts/ # 安全封装的 tmux 自动化脚本
|
||||||
│ ├── auto-tmux.sh
|
│ ├── auto-tmux.sh
|
||||||
|
│ ├── swarm-state.sh
|
||||||
|
│ ├── auto-tmux-smoke-test.sh
|
||||||
│ ├── README.md
|
│ ├── README.md
|
||||||
│ └── AGENTS.md
|
│ └── AGENTS.md
|
||||||
└── references/ # 长文档、示例与故障排查
|
└── references/ # 长文档、示例与故障排查
|
||||||
@@ -20,6 +22,7 @@ skills/auto-tmux/
|
|||||||
├── getting_started.md
|
├── getting_started.md
|
||||||
├── api.md
|
├── api.md
|
||||||
├── automation.md
|
├── automation.md
|
||||||
|
├── swarm-state.md
|
||||||
├── ai-swarm-collaboration.md
|
├── ai-swarm-collaboration.md
|
||||||
├── examples.md
|
├── examples.md
|
||||||
└── troubleshooting.md
|
└── troubleshooting.md
|
||||||
@@ -29,7 +32,8 @@ skills/auto-tmux/
|
|||||||
|
|
||||||
- `assets/oh-my-tmux` 只暴露 gpakosz/oh-my-tmux submodule,不在技能目录内复制配置源码。
|
- `assets/oh-my-tmux` 只暴露 gpakosz/oh-my-tmux submodule,不在技能目录内复制配置源码。
|
||||||
- `assets/tmux-src` 只暴露 tmux/tmux submodule,供需要查看源码或上游文档时定位。
|
- `assets/tmux-src` 只暴露 tmux/tmux submodule,供需要查看源码或上游文档时定位。
|
||||||
- `scripts/auto-tmux.sh` 是技能执行层,封装 topology/capture/send/scan/rescue/record/hub/wait。
|
- `scripts/auto-tmux.sh` 是技能执行层,封装 topology/capture/send/scan/rescue/record/snapshot/hub/wait。
|
||||||
|
- `scripts/swarm-state.sh` 是蜂群协作状态层,管理任务、锁、状态日志和结果报告。
|
||||||
- 技能文档可以引用软链接入口;更新上游内容必须通过 `tools/external/` 下的 submodule 指针完成。
|
- 技能文档可以引用软链接入口;更新上游内容必须通过 `tools/external/` 下的 submodule 指针完成。
|
||||||
- 不在本目录直接修改 submodule 内容;如需改造,先 fork 上游并更新 submodule 来源。
|
- 不在本目录直接修改 submodule 内容;如需改造,先 fork 上游并更新 submodule 来源。
|
||||||
|
|
||||||
@@ -38,4 +42,4 @@ skills/auto-tmux/
|
|||||||
- 上游来源:`tools/external/.tmux` 与 `tools/external/tmux`。
|
- 上游来源:`tools/external/.tmux` 与 `tools/external/tmux`。
|
||||||
- 下游使用:`SKILL.md` 和 `references/` 中的命令示例。
|
- 下游使用:`SKILL.md` 和 `references/` 中的命令示例。
|
||||||
- 验证入口:`skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict`。
|
- 验证入口:`skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict`。
|
||||||
- 脚本验证:`bash -n skills/auto-tmux/scripts/auto-tmux.sh`。
|
- 脚本验证:`bash -n skills/auto-tmux/scripts/auto-tmux.sh`、`bash -n skills/auto-tmux/scripts/swarm-state.sh`、`skills/auto-tmux/scripts/auto-tmux-smoke-test.sh`。
|
||||||
|
|||||||
@@ -20,7 +20,10 @@
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash -n skills/auto-tmux/scripts/auto-tmux.sh
|
bash -n skills/auto-tmux/scripts/auto-tmux.sh
|
||||||
|
bash -n skills/auto-tmux/scripts/swarm-state.sh
|
||||||
skills/auto-tmux/scripts/auto-tmux.sh help
|
skills/auto-tmux/scripts/auto-tmux.sh help
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh help
|
||||||
|
skills/auto-tmux/scripts/auto-tmux-smoke-test.sh
|
||||||
skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict
|
skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -29,5 +32,6 @@ skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict
|
|||||||
- 优先使用 `scripts/auto-tmux.sh`,需要低层调试时再直接使用 tmux 原生命令。
|
- 优先使用 `scripts/auto-tmux.sh`,需要低层调试时再直接使用 tmux 原生命令。
|
||||||
- 发送按键前必须先 `capture-pane` 复核目标上下文;脚本会默认打印最近上下文。
|
- 发送按键前必须先 `capture-pane` 复核目标上下文;脚本会默认打印最近上下文。
|
||||||
- 批量操作前必须先列出 session/window/pane 白名单。
|
- 批量操作前必须先列出 session/window/pane 白名单。
|
||||||
|
- 多 worker 并发前用 `swarm-state.sh` 管理任务、锁和状态,避免重复修改同一资源。
|
||||||
- 不在未知 pane 中发送破坏性命令。
|
- 不在未知 pane 中发送破坏性命令。
|
||||||
- 不在本目录复制或修改上游 tmux / oh-my-tmux 源码。
|
- 不在本目录复制或修改上游 tmux / oh-my-tmux 源码。
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
name: auto-tmux
|
name: auto-tmux
|
||||||
description: "tmux 自动化操控:用 scripts/auto-tmux.sh 安全读取、发送、巡检、救援、录制 session|window|pane,并基于 oh-my-tmux 组织多 AI 终端协作。触发:capture-pane、send-keys、批量巡检、蜂群 AI 协作、卡死救援、tmux 工作台初始化。"
|
description: "tmux 自动化操控:用 scripts/auto-tmux.sh 安全读取、发送、巡检、救援、录制 session|window|pane,用 swarm-state.sh 管理蜂群任务/锁/状态,并基于 oh-my-tmux 组织多 AI 终端协作。触发:capture-pane、send-keys、批量巡检、蜂群 AI 协作、卡死救援、tmux 工作台初始化。"
|
||||||
---
|
---
|
||||||
|
|
||||||
# auto-tmux Skill
|
# auto-tmux Skill
|
||||||
|
|
||||||
让 AI 像熟练运维一样操作 tmux:优先使用 `scripts/auto-tmux.sh` 安全封装读取终端输出、发送按键、批量巡检、协作/救援其他终端;必要时再回退到 tmux 原生命令。默认兼容 `tools/external/.tmux`(gpakosz/oh-my-tmux),并在本技能内通过 `assets/oh-my-tmux` 与 `assets/tmux-src` 暴露上游 submodule。
|
让 AI 像熟练运维一样操作 tmux:优先使用 `scripts/auto-tmux.sh` 安全封装读取终端输出、发送按键、批量巡检、协作/救援其他终端;使用 `scripts/swarm-state.sh` 管理蜂群任务、锁、状态和结果;必要时再回退到 tmux 原生命令。默认兼容 `tools/external/.tmux`(gpakosz/oh-my-tmux),并在本技能内通过 `assets/oh-my-tmux` 与 `assets/tmux-src` 暴露上游 submodule。
|
||||||
|
|
||||||
## When to Use This Skill
|
## When to Use This Skill
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@ description: "tmux 自动化操控:用 scripts/auto-tmux.sh 安全读取、发
|
|||||||
- 需要向指定 pane 发送按键/命令(确认 `y`、`Enter`、`Ctrl+C`、广播同一窗口)。
|
- 需要向指定 pane 发送按键/命令(确认 `y`、`Enter`、`Ctrl+C`、广播同一窗口)。
|
||||||
- 需要批量巡检/接管多 AI 终端(蜂群协作、自动救援卡死任务)。
|
- 需要批量巡检/接管多 AI 终端(蜂群协作、自动救援卡死任务)。
|
||||||
- 需要初始化 AI 多终端工作台、等待输出 pattern、录制 pane 日志或保存巡检证据。
|
- 需要初始化 AI 多终端工作台、等待输出 pattern、录制 pane 日志或保存巡检证据。
|
||||||
|
- 需要给 tmux 蜂群建立任务队列、状态日志、文件锁和结果报告。
|
||||||
- 需要快速回忆 oh-my-tmux 快捷键、前缀或同步面板操作。
|
- 需要快速回忆 oh-my-tmux 快捷键、前缀或同步面板操作。
|
||||||
- 需要在当前仓库复用 `tools/external/.tmux` 配置并避免修改主配置。
|
- 需要在当前仓库复用 `tools/external/.tmux` 配置并避免修改主配置。
|
||||||
- 需要从技能目录内快速查看 oh-my-tmux 配置或 tmux 上游源码入口。
|
- 需要从技能目录内快速查看 oh-my-tmux 配置或 tmux 上游源码入口。
|
||||||
@@ -33,7 +34,9 @@ description: "tmux 自动化操控:用 scripts/auto-tmux.sh 安全读取、发
|
|||||||
**脚本帮助与语法检查**
|
**脚本帮助与语法检查**
|
||||||
```bash
|
```bash
|
||||||
bash -n skills/auto-tmux/scripts/auto-tmux.sh
|
bash -n skills/auto-tmux/scripts/auto-tmux.sh
|
||||||
|
bash -n skills/auto-tmux/scripts/swarm-state.sh
|
||||||
skills/auto-tmux/scripts/auto-tmux.sh help
|
skills/auto-tmux/scripts/auto-tmux.sh help
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh help
|
||||||
```
|
```
|
||||||
|
|
||||||
**查看快捷键帮助**(oh-my-tmux 双前缀:主 `C-a`,备用 `C-b`,前缀后按 `?`)
|
**查看快捷键帮助**(oh-my-tmux 双前缀:主 `C-a`,备用 `C-b`,前缀后按 `?`)
|
||||||
@@ -92,6 +95,11 @@ 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
|
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback" --save-dir /tmp/auto-tmux-scan
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**生成证据快照**
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/auto-tmux.sh snapshot --session ai-hub --dir /tmp/auto-tmux-snapshot -n 120
|
||||||
|
```
|
||||||
|
|
||||||
**远程救援:发现等待输入即发送 y**
|
**远程救援:发现等待输入即发送 y**
|
||||||
```bash
|
```bash
|
||||||
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
|
target="$(tmux list-panes -t ai-hub:worker1 -F '#S:#I.#P' | head -n 1)"
|
||||||
@@ -123,6 +131,19 @@ skills/auto-tmux/scripts/auto-tmux.sh record stop -t <session>:<window>.<pane>
|
|||||||
skills/auto-tmux/scripts/auto-tmux.sh wait -t <session>:<window>.<pane> --pattern "Tests passed|BUILD SUCCESS" --timeout 300
|
skills/auto-tmux/scripts/auto-tmux.sh wait -t <session>:<window>.<pane> --pattern "Tests passed|BUILD SUCCESS" --timeout 300
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**初始化蜂群状态、任务和锁**
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh init --dir /tmp/ai_swarm
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-add --id task-001 --text "检查 README 链接"
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh lock-acquire --name README.md --owner <session>:<window>.<pane>
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh report --dir /tmp/ai_swarm
|
||||||
|
```
|
||||||
|
|
||||||
|
**脚本端到端自测**
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/auto-tmux-smoke-test.sh
|
||||||
|
```
|
||||||
|
|
||||||
## Rules & Constraints
|
## Rules & Constraints
|
||||||
|
|
||||||
- MUST:优先使用 `scripts/auto-tmux.sh`;直接使用 tmux 原生命令时必须保留同等安全约束。
|
- MUST:优先使用 `scripts/auto-tmux.sh`;直接使用 tmux 原生命令时必须保留同等安全约束。
|
||||||
@@ -133,6 +154,7 @@ skills/auto-tmux/scripts/auto-tmux.sh wait -t <session>:<window>.<pane> --patter
|
|||||||
- SHOULD:发送完整命令行时避免先发 `Escape`;先 `C-c` 中断、`C-u` 清行,再用 `send-keys -l` 逐字发送完整命令。
|
- SHOULD:发送完整命令行时避免先发 `Escape`;先 `C-c` 中断、`C-u` 清行,再用 `send-keys -l` 逐字发送完整命令。
|
||||||
- SHOULD:pane 处在 Codex UI 时,先发送 `/exit` 回到 shell 再执行命令。
|
- SHOULD:pane 处在 Codex UI 时,先发送 `/exit` 回到 shell 再执行命令。
|
||||||
- SHOULD:长任务开启 `pipe-pane` 记录审计;广播完成后立即 `synchronize-panes off`。
|
- SHOULD:长任务开启 `pipe-pane` 记录审计;广播完成后立即 `synchronize-panes off`。
|
||||||
|
- SHOULD:多 worker 修改同一文件、目录或服务前,先用 `swarm-state.sh lock-acquire` 声明锁。
|
||||||
- NEVER:在未知 pane 发送破坏性命令;NEVER 在 root 会话不经确认发送 `Ctrl+C`/`Ctrl+D`。
|
- NEVER:在未知 pane 发送破坏性命令;NEVER 在 root 会话不经确认发送 `Ctrl+C`/`Ctrl+D`。
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
@@ -183,10 +205,13 @@ skills/auto-tmux/scripts/auto-tmux.sh wait -t <session>:<window>.<pane> --patter
|
|||||||
- `references/getting_started.md`: 术语、oh-my-tmux 最小接入步骤
|
- `references/getting_started.md`: 术语、oh-my-tmux 最小接入步骤
|
||||||
- `references/api.md`: tmux/oh-my-tmux 常用命令、选项与 gpakosz 特色键位
|
- `references/api.md`: tmux/oh-my-tmux 常用命令、选项与 gpakosz 特色键位
|
||||||
- `references/automation.md`: `scripts/auto-tmux.sh` 子命令、安全模型与 AI 蜂群协作流程
|
- `references/automation.md`: `scripts/auto-tmux.sh` 子命令、安全模型与 AI 蜂群协作流程
|
||||||
|
- `references/swarm-state.md`: 蜂群状态、任务、锁和报告协议
|
||||||
- `references/ai-swarm-collaboration.md`: tmux 蜂群协作历史文档、架构模式、协议、案例和风险限制
|
- `references/ai-swarm-collaboration.md`: tmux 蜂群协作历史文档、架构模式、协议、案例和风险限制
|
||||||
- `references/examples.md`: 蜂群协议脚本与长示例
|
- `references/examples.md`: 蜂群协议脚本与长示例
|
||||||
- `references/troubleshooting.md`: 典型故障到修复路径
|
- `references/troubleshooting.md`: 典型故障到修复路径
|
||||||
- `scripts/auto-tmux.sh`: 安全封装的 tmux 自动化脚本入口
|
- `scripts/auto-tmux.sh`: 安全封装的 tmux 自动化脚本入口
|
||||||
|
- `scripts/swarm-state.sh`: 蜂群任务、锁、状态和报告脚本
|
||||||
|
- `scripts/auto-tmux-smoke-test.sh`: tmux 自动化脚本端到端自测
|
||||||
- `assets/oh-my-tmux`: gpakosz/oh-my-tmux submodule 的相对软链接入口
|
- `assets/oh-my-tmux`: gpakosz/oh-my-tmux submodule 的相对软链接入口
|
||||||
- `assets/tmux-src`: tmux/tmux submodule 的相对软链接入口
|
- `assets/tmux-src`: tmux/tmux submodule 的相对软链接入口
|
||||||
|
|
||||||
@@ -205,5 +230,6 @@ skills/auto-tmux/scripts/auto-tmux.sh wait -t <session>:<window>.<pane> --patter
|
|||||||
4. ≥3 个端到端示例,含输入/步骤/验收。
|
4. ≥3 个端到端示例,含输入/步骤/验收。
|
||||||
5. 长文档放在 `references/` 并可导航;无文档堆砌。
|
5. 长文档放在 `references/` 并可导航;无文档堆砌。
|
||||||
6. 不确定项给出验证路径;禁止虚构 tmux 行为。
|
6. 不确定项给出验证路径;禁止虚构 tmux 行为。
|
||||||
7. `bash -n skills/auto-tmux/scripts/auto-tmux.sh` 通过。
|
7. `bash -n skills/auto-tmux/scripts/auto-tmux.sh` 与 `bash -n skills/auto-tmux/scripts/swarm-state.sh` 通过。
|
||||||
8. 运行 `skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict` 通过。
|
8. `skills/auto-tmux/scripts/auto-tmux-smoke-test.sh` 通过或在无 tmux 环境下明确跳过。
|
||||||
|
9. 运行 `skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict` 通过。
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
| [getting_started.md](./getting_started.md) | 术语、最短路径和工作姿势 |
|
| [getting_started.md](./getting_started.md) | 术语、最短路径和工作姿势 |
|
||||||
| [api.md](./api.md) | tmux / oh-my-tmux 常用命令与配置速查 |
|
| [api.md](./api.md) | tmux / oh-my-tmux 常用命令与配置速查 |
|
||||||
| [automation.md](./automation.md) | `auto-tmux.sh` 脚本子命令、安全模型和 AI 蜂群协作流程 |
|
| [automation.md](./automation.md) | `auto-tmux.sh` 脚本子命令、安全模型和 AI 蜂群协作流程 |
|
||||||
|
| [swarm-state.md](./swarm-state.md) | 蜂群状态、任务、锁和报告协议 |
|
||||||
| [ai-swarm-collaboration.md](./ai-swarm-collaboration.md) | tmux 蜂群协作完整说明、架构模式、协议、案例和风险限制 |
|
| [ai-swarm-collaboration.md](./ai-swarm-collaboration.md) | tmux 蜂群协作完整说明、架构模式、协议、案例和风险限制 |
|
||||||
| [examples.md](./examples.md) | 巡检、救援、审计和多 AI 工作台示例 |
|
| [examples.md](./examples.md) | 巡检、救援、审计和多 AI 工作台示例 |
|
||||||
| [troubleshooting.md](./troubleshooting.md) | 常见故障与修复路径 |
|
| [troubleshooting.md](./troubleshooting.md) | 常见故障与修复路径 |
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ tmux 蜂群协作的核心是:让 AI 不再只是孤立会话,而是通过 t
|
|||||||
| 巡检 | `auto-tmux.sh scan` | 批量检查多个 pane 状态 |
|
| 巡检 | `auto-tmux.sh scan` | 批量检查多个 pane 状态 |
|
||||||
| 救援 | `auto-tmux.sh rescue` | 对等待确认、卡住或异常的 pane 做最小干预 |
|
| 救援 | `auto-tmux.sh rescue` | 对等待确认、卡住或异常的 pane 做最小干预 |
|
||||||
| 记录 | `pipe-pane` / `auto-tmux.sh record` | 保留长任务审计日志 |
|
| 记录 | `pipe-pane` / `auto-tmux.sh record` | 保留长任务审计日志 |
|
||||||
| 协调 | 共享状态文件 + 明确 target | 任务同步、分工、避免冲突 |
|
| 协调 | `swarm-state.sh` + 明确 target | 任务同步、分工、加锁、避免冲突 |
|
||||||
|
|
||||||
```text
|
```text
|
||||||
传统模式: 人 <-> AI1, 人 <-> AI2, 人 <-> AI3
|
传统模式: 人 <-> AI1, 人 <-> AI2, 人 <-> AI3
|
||||||
@@ -108,7 +108,13 @@ skills/auto-tmux/scripts/auto-tmux.sh wait -t "$target" --pattern "done|完成|T
|
|||||||
|
|
||||||
### 4.2 状态目录
|
### 4.2 状态目录
|
||||||
|
|
||||||
可选共享状态目录:
|
推荐使用 `scripts/swarm-state.sh` 初始化共享状态目录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh init --dir /tmp/ai_swarm
|
||||||
|
```
|
||||||
|
|
||||||
|
默认共享状态目录:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
/tmp/ai_swarm/
|
/tmp/ai_swarm/
|
||||||
@@ -145,6 +151,33 @@ skills/auto-tmux/scripts/auto-tmux.sh wait -t "$target" --pattern "done|完成|T
|
|||||||
6. **保留证据**:长任务开启 `record`,关键检查保存 scan 日志。
|
6. **保留证据**:长任务开启 `record`,关键检查保存 scan 日志。
|
||||||
7. **人工兜底**:危险操作、敏感凭证、生产环境变更必须人工确认。
|
7. **人工兜底**:危险操作、敏感凭证、生产环境变更必须人工确认。
|
||||||
|
|
||||||
|
### 4.4 任务与锁
|
||||||
|
|
||||||
|
添加任务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-add --id task-001 --text "检查 README 链接"
|
||||||
|
```
|
||||||
|
|
||||||
|
worker 认领任务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-claim --id task-001 --owner "ai-hub:2.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
修改文件前获取锁:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh lock-acquire --name README.md --owner "ai-hub:2.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
完成后释放锁并记录结果:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh lock-release --name README.md --owner "ai-hub:2.1"
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-done --id task-001 --owner "ai-hub:2.1" --result "make test passed"
|
||||||
|
```
|
||||||
|
|
||||||
## 5. 架构模式
|
## 5. 架构模式
|
||||||
|
|
||||||
### 5.1 P2P 对等模式
|
### 5.1 P2P 对等模式
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
| `rescue` | pattern 命中后发送确认 | 不命中不发送 |
|
| `rescue` | pattern 命中后发送确认 | 不命中不发送 |
|
||||||
| `scan` | 批量巡检 pane 输出 | 可按 session 限定范围 |
|
| `scan` | 批量巡检 pane 输出 | 可按 session 限定范围 |
|
||||||
| `record` | 开启/停止 pane 输出审计日志 | 文件写入到显式目录 |
|
| `record` | 开启/停止 pane 输出审计日志 | 文件写入到显式目录 |
|
||||||
|
| `snapshot` | 导出拓扑和 pane 输出证据包 | 默认脱敏,写入显式目录 |
|
||||||
| `hub` | 初始化 AI 多终端工作台 | 已存在 session 不覆盖 |
|
| `hub` | 初始化 AI 多终端工作台 | 已存在 session 不覆盖 |
|
||||||
| `wait` | 等待 pane 输出出现某个 pattern | 超时失败 |
|
| `wait` | 等待 pane 输出出现某个 pattern | 超时失败 |
|
||||||
|
|
||||||
@@ -55,6 +56,12 @@ skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --pattern "ERROR|Tra
|
|||||||
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --save-dir /tmp/auto-tmux-scan
|
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --save-dir /tmp/auto-tmux-scan
|
||||||
```
|
```
|
||||||
|
|
||||||
|
生成完整证据快照:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/auto-tmux.sh snapshot --session ai-hub --dir /tmp/auto-tmux-snapshot -n 120
|
||||||
|
```
|
||||||
|
|
||||||
### 3. 安全发送命令
|
### 3. 安全发送命令
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -123,11 +130,43 @@ ai-hub
|
|||||||
3. commander 用 `scan` 收集状态,用 `capture` 保留证据。
|
3. commander 用 `scan` 收集状态,用 `capture` 保留证据。
|
||||||
4. 需要确认输入时,用 `rescue --dry-run` 先验证 pattern,再真实发送。
|
4. 需要确认输入时,用 `rescue --dry-run` 先验证 pattern,再真实发送。
|
||||||
5. 长任务用 `record start` 留日志,结束后 `record stop`。
|
5. 长任务用 `record start` 留日志,结束后 `record stop`。
|
||||||
|
6. 多 worker 修改同一文件、目录或服务前,用 `swarm-state.sh lock-acquire` 声明锁。
|
||||||
|
|
||||||
|
## 状态与锁脚本
|
||||||
|
|
||||||
|
初始化状态目录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh init --dir /tmp/ai_swarm
|
||||||
|
```
|
||||||
|
|
||||||
|
添加并认领任务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-add --id task-001 --text "检查 README 链接"
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-claim --id task-001 --owner "ai-hub:2.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
获取文件锁:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh lock-acquire --name README.md --owner "ai-hub:2.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
完成任务并生成报告:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-done --id task-001 --owner "ai-hub:2.1" --result "make test passed"
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh report
|
||||||
|
```
|
||||||
|
|
||||||
## 验证命令
|
## 验证命令
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
bash -n skills/auto-tmux/scripts/auto-tmux.sh
|
bash -n skills/auto-tmux/scripts/auto-tmux.sh
|
||||||
|
bash -n skills/auto-tmux/scripts/swarm-state.sh
|
||||||
skills/auto-tmux/scripts/auto-tmux.sh help
|
skills/auto-tmux/scripts/auto-tmux.sh help
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh help
|
||||||
|
skills/auto-tmux/scripts/auto-tmux-smoke-test.sh
|
||||||
skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict
|
skills/auto-skill/scripts/validate-skill.sh skills/auto-tmux --strict
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
- `getting_started.md`:术语、最小安装、前缀说明
|
- `getting_started.md`:术语、最小安装、前缀说明
|
||||||
- `api.md`:tmux/oh-my-tmux 常用命令、同步广播、安全写法
|
- `api.md`:tmux/oh-my-tmux 常用命令、同步广播、安全写法
|
||||||
- `automation.md`:`scripts/auto-tmux.sh` 子命令、安全模型与 AI 蜂群协作流程
|
- `automation.md`:`scripts/auto-tmux.sh` 子命令、安全模型与 AI 蜂群协作流程
|
||||||
|
- `swarm-state.md`:蜂群状态、任务、锁和报告协议
|
||||||
- `ai-swarm-collaboration.md`:tmux 蜂群协作完整说明、架构模式、协议、案例和风险限制
|
- `ai-swarm-collaboration.md`:tmux 蜂群协作完整说明、架构模式、协议、案例和风险限制
|
||||||
- `examples.md`:蜂群巡检脚本、自动救援脚本、Skill Seeker 抓取示例
|
- `examples.md`:蜂群巡检脚本、自动救援脚本、Skill Seeker 抓取示例
|
||||||
- `troubleshooting.md`:常见报错与修复路径
|
- `troubleshooting.md`:常见报错与修复路径
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
# Swarm State and Lock Protocol
|
||||||
|
|
||||||
|
`scripts/swarm-state.sh` 是 `auto-tmux` 的最小蜂群状态管理脚本,用于在 tmux 多 AI 协作时记录状态、分配任务、声明锁和汇总报告。
|
||||||
|
|
||||||
|
它不依赖数据库、`jq` 或后台服务,默认把状态写入 `/tmp/ai_swarm`。需要隔离不同项目时,用 `--dir DIR` 或环境变量 `AUTO_TMUX_SWARM_DIR` 指定目录。
|
||||||
|
|
||||||
|
## 文件结构
|
||||||
|
|
||||||
|
```text
|
||||||
|
/tmp/ai_swarm/
|
||||||
|
├── status.log
|
||||||
|
├── tasks.tsv
|
||||||
|
├── locks/
|
||||||
|
│ └── <name>.lock.d/
|
||||||
|
│ ├── owner
|
||||||
|
│ └── created_at
|
||||||
|
└── results/
|
||||||
|
└── <task-id>.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## 初始化
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh init
|
||||||
|
```
|
||||||
|
|
||||||
|
指定目录:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh init --dir /tmp/my-ai-swarm
|
||||||
|
```
|
||||||
|
|
||||||
|
## 状态日志
|
||||||
|
|
||||||
|
写入状态:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh log \
|
||||||
|
--target "ai-hub:2.1" \
|
||||||
|
--status START \
|
||||||
|
--message "开始执行 make test"
|
||||||
|
```
|
||||||
|
|
||||||
|
查看最近状态:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh status -n 20
|
||||||
|
```
|
||||||
|
|
||||||
|
状态建议:
|
||||||
|
|
||||||
|
| 状态 | 含义 |
|
||||||
|
|:---|:---|
|
||||||
|
| `START` | 开始任务 |
|
||||||
|
| `DONE` | 完成任务 |
|
||||||
|
| `WAIT` | 等待依赖、输入或门禁 |
|
||||||
|
| `ERROR` | 出现错误 |
|
||||||
|
| `HELP` | 请求帮助 |
|
||||||
|
| `SKIP` | 跳过,已有其他 worker 处理 |
|
||||||
|
| `LOCK` | 获取锁 |
|
||||||
|
| `UNLOCK` | 释放锁 |
|
||||||
|
|
||||||
|
## 任务管理
|
||||||
|
|
||||||
|
新增任务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-add --id task-001 --text "检查 README 链接"
|
||||||
|
```
|
||||||
|
|
||||||
|
认领任务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-claim --id task-001 --owner "ai-hub:2.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
完成任务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-done \
|
||||||
|
--id task-001 \
|
||||||
|
--owner "ai-hub:2.1" \
|
||||||
|
--result "make test passed"
|
||||||
|
```
|
||||||
|
|
||||||
|
查看任务:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-list
|
||||||
|
```
|
||||||
|
|
||||||
|
## 锁管理
|
||||||
|
|
||||||
|
锁用于避免多个 worker 同时修改同一文件、目录或服务。
|
||||||
|
|
||||||
|
获取锁:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh lock-acquire \
|
||||||
|
--name "README.md" \
|
||||||
|
--owner "ai-hub:2.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
释放锁:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh lock-release \
|
||||||
|
--name "README.md" \
|
||||||
|
--owner "ai-hub:2.1"
|
||||||
|
```
|
||||||
|
|
||||||
|
查看锁:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh lock-list
|
||||||
|
```
|
||||||
|
|
||||||
|
锁使用 `mkdir` 创建目录,具备基本原子性。若锁归属不匹配,默认拒绝释放;确需人工回收时才使用 `--force`。
|
||||||
|
|
||||||
|
## 报告
|
||||||
|
|
||||||
|
生成汇总报告:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh report
|
||||||
|
```
|
||||||
|
|
||||||
|
报告包含:
|
||||||
|
|
||||||
|
- 任务列表。
|
||||||
|
- 当前锁。
|
||||||
|
- 最近状态日志。
|
||||||
|
|
||||||
|
## 推荐协作流
|
||||||
|
|
||||||
|
1. commander 初始化状态目录。
|
||||||
|
2. commander 将任务写入 `tasks.tsv`。
|
||||||
|
3. worker 获取文件或服务锁。
|
||||||
|
4. worker 认领任务并写入 `START`。
|
||||||
|
5. worker 执行任务,必要时用 `auto-tmux.sh record` 保留日志。
|
||||||
|
6. worker 完成后写入 `DONE` 和结果。
|
||||||
|
7. commander 用 `report` 汇总状态,再用测试、diff、日志做验收。
|
||||||
|
|
||||||
|
## 安全边界
|
||||||
|
|
||||||
|
- `swarm-state.sh` 只管理状态,不直接控制 tmux pane。
|
||||||
|
- 真实发送命令仍必须走 `auto-tmux.sh send` 或 `auto-tmux.sh rescue`。
|
||||||
|
- 状态文件默认在 `/tmp`,不保存密钥、Token、密码或私密项目内容。
|
||||||
|
- 锁只能降低冲突概率,不能替代 Git diff、测试和人工验收。
|
||||||
@@ -8,7 +8,9 @@
|
|||||||
scripts/
|
scripts/
|
||||||
├── AGENTS.md # 本文件:脚本维护规则
|
├── AGENTS.md # 本文件:脚本维护规则
|
||||||
├── README.md # 面向人类的脚本入口说明
|
├── README.md # 面向人类的脚本入口说明
|
||||||
└── auto-tmux.sh # 统一 tmux 自动化命令入口
|
├── auto-tmux.sh # 统一 tmux 自动化命令入口
|
||||||
|
├── swarm-state.sh # 蜂群状态、任务、锁和报告管理
|
||||||
|
└── auto-tmux-smoke-test.sh # 临时 tmux 会话端到端自测
|
||||||
```
|
```
|
||||||
|
|
||||||
## 维护规则
|
## 维护规则
|
||||||
@@ -17,4 +19,6 @@ scripts/
|
|||||||
- 发送按键类功能必须先验证目标 pane 存在,并优先打印上下文。
|
- 发送按键类功能必须先验证目标 pane 存在,并优先打印上下文。
|
||||||
- 捕获输出默认脱敏;只有显式 `--no-redact` 才允许输出原文。
|
- 捕获输出默认脱敏;只有显式 `--no-redact` 才允许输出原文。
|
||||||
- 批量救援必须通过 pattern 匹配触发,不允许无条件向所有 pane 发送输入。
|
- 批量救援必须通过 pattern 匹配触发,不允许无条件向所有 pane 发送输入。
|
||||||
|
- 状态脚本只能写入显式状态目录,不保存密钥、Token、密码或私密项目内容。
|
||||||
|
- 自测脚本必须创建独立临时 tmux session,并在退出时清理。
|
||||||
- 新增脚本后必须更新 `README.md`、`SKILL.md`、`references/index.md`,并运行 `bash -n` 与 skill strict 校验。
|
- 新增脚本后必须更新 `README.md`、`SKILL.md`、`references/index.md`,并运行 `bash -n` 与 skill strict 校验。
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
## 入口
|
## 入口
|
||||||
|
|
||||||
- [`auto-tmux.sh`](./auto-tmux.sh) - 统一命令入口,支持拓扑、读取、发送、巡检、救援、录制、等待和 AI 工作台初始化。
|
- [`auto-tmux.sh`](./auto-tmux.sh) - 统一命令入口,支持拓扑、读取、发送、巡检、救援、录制、等待和 AI 工作台初始化。
|
||||||
|
- [`swarm-state.sh`](./swarm-state.sh) - 蜂群状态、任务、锁和报告管理。
|
||||||
|
- [`auto-tmux-smoke-test.sh`](./auto-tmux-smoke-test.sh) - 创建临时 tmux 会话,端到端验证脚本能力。
|
||||||
|
|
||||||
## 常用命令
|
## 常用命令
|
||||||
|
|
||||||
@@ -25,6 +27,17 @@ skills/auto-tmux/scripts/auto-tmux.sh send -t "$target" --text "make test" --ent
|
|||||||
|
|
||||||
# 扫描某个 session 的错误
|
# 扫描某个 session 的错误
|
||||||
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback"
|
skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback"
|
||||||
|
|
||||||
|
# 生成证据快照
|
||||||
|
skills/auto-tmux/scripts/auto-tmux.sh snapshot --session ai-hub --dir /tmp/auto-tmux-snapshot
|
||||||
|
|
||||||
|
# 初始化蜂群状态并添加任务
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh init --dir /tmp/ai_swarm
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh task-add --id task-001 --text "检查 README 链接"
|
||||||
|
skills/auto-tmux/scripts/swarm-state.sh report --dir /tmp/ai_swarm
|
||||||
|
|
||||||
|
# 端到端自测
|
||||||
|
skills/auto-tmux/scripts/auto-tmux-smoke-test.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## 安全约束
|
## 安全约束
|
||||||
@@ -33,3 +46,4 @@ skills/auto-tmux/scripts/auto-tmux.sh scan --session ai-hub --pattern "ERROR|Tra
|
|||||||
- `send` 会先打印目标 pane 最近上下文,再发送按键。
|
- `send` 会先打印目标 pane 最近上下文,再发送按键。
|
||||||
- 危险命令默认拒绝,必须显式 `--force`。
|
- 危险命令默认拒绝,必须显式 `--force`。
|
||||||
- 批量操作必须使用明确的 session/window/pane 目标。
|
- 批量操作必须使用明确的 session/window/pane 目标。
|
||||||
|
- 多 worker 协作时用 `swarm-state.sh lock-acquire` 声明文件、目录或服务锁。
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Smoke-test auto-tmux scripts without touching user tmux sessions.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
AUTO_TMUX="$SCRIPT_DIR/auto-tmux.sh"
|
||||||
|
SWARM_STATE="$SCRIPT_DIR/swarm-state.sh"
|
||||||
|
SESSION="auto-tmux-smoke-$$"
|
||||||
|
SWARM_DIR="/tmp/auto-tmux-smoke-swarm-$$"
|
||||||
|
SNAPSHOT_DIR="/tmp/auto-tmux-smoke-snapshot-$$"
|
||||||
|
RECORD_DIR="/tmp/auto-tmux-smoke-record-$$"
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
tmux kill-session -t "$SESSION" 2>/dev/null || true
|
||||||
|
rm -rf "$SWARM_DIR" "$SNAPSHOT_DIR" "$RECORD_DIR"
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
command -v tmux >/dev/null 2>&1 || {
|
||||||
|
echo "SKIP: tmux is not installed"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
bash -n "$AUTO_TMUX"
|
||||||
|
bash -n "$SWARM_STATE"
|
||||||
|
|
||||||
|
"$AUTO_TMUX" hub --session "$SESSION" --workers 1 --cmd bash
|
||||||
|
"$AUTO_TMUX" topology --session "$SESSION" >/tmp/auto-tmux-smoke-topology.txt
|
||||||
|
|
||||||
|
commander_target="$(tmux list-panes -t "$SESSION:commander" -F '#S:#I.#P' | head -n 1)"
|
||||||
|
worker_target="$(tmux list-panes -t "$SESSION:worker1" -F '#S:#I.#P' | head -n 1)"
|
||||||
|
|
||||||
|
"$AUTO_TMUX" capture -t "$commander_target" -n 10 >/tmp/auto-tmux-smoke-capture.txt
|
||||||
|
"$AUTO_TMUX" send -t "$worker_target" --text "echo AUTO_TMUX_SMOKE_OK" --enter
|
||||||
|
"$AUTO_TMUX" wait -t "$worker_target" --pattern "AUTO_TMUX_SMOKE_OK" --timeout 10 >/tmp/auto-tmux-smoke-wait.txt
|
||||||
|
"$AUTO_TMUX" snapshot --session "$SESSION" --dir "$SNAPSHOT_DIR" -n 20 >/tmp/auto-tmux-smoke-snapshot.txt
|
||||||
|
test -s "$SNAPSHOT_DIR/topology.txt"
|
||||||
|
|
||||||
|
"$AUTO_TMUX" record start -t "$worker_target" --dir "$RECORD_DIR" >/tmp/auto-tmux-smoke-record-start.txt
|
||||||
|
"$AUTO_TMUX" record stop -t "$worker_target" >/tmp/auto-tmux-smoke-record-stop.txt
|
||||||
|
|
||||||
|
"$SWARM_STATE" init --dir "$SWARM_DIR" >/tmp/auto-tmux-smoke-swarm-init.txt
|
||||||
|
"$SWARM_STATE" task-add --dir "$SWARM_DIR" --id smoke-task --text "run smoke task" >/tmp/auto-tmux-smoke-task-add.txt
|
||||||
|
"$SWARM_STATE" task-claim --dir "$SWARM_DIR" --id smoke-task --owner "$worker_target"
|
||||||
|
"$SWARM_STATE" lock-acquire --dir "$SWARM_DIR" --name smoke-file --owner "$worker_target" >/tmp/auto-tmux-smoke-lock.txt
|
||||||
|
"$SWARM_STATE" lock-release --dir "$SWARM_DIR" --name smoke-file --owner "$worker_target" >/tmp/auto-tmux-smoke-unlock.txt
|
||||||
|
"$SWARM_STATE" task-done --dir "$SWARM_DIR" --id smoke-task --owner "$worker_target" --result "ok"
|
||||||
|
"$SWARM_STATE" report --dir "$SWARM_DIR" >/tmp/auto-tmux-smoke-report.txt
|
||||||
|
grep -q 'smoke-task' /tmp/auto-tmux-smoke-report.txt
|
||||||
|
|
||||||
|
printf 'auto-tmux smoke test ok: session=%s worker=%s\n' "$SESSION" "$worker_target"
|
||||||
@@ -20,6 +20,7 @@ Usage:
|
|||||||
auto-tmux.sh scan [--session NAME] [-n LINES] [--pattern REGEX] [--rescue] [--reply TEXT] [--save-dir DIR]
|
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 start -t TARGET [--dir DIR]
|
||||||
auto-tmux.sh record stop -t TARGET
|
auto-tmux.sh record stop -t TARGET
|
||||||
|
auto-tmux.sh snapshot [--session NAME] [--dir DIR] [-n LINES]
|
||||||
auto-tmux.sh hub [--session NAME] [--workers N] [--cmd CMD] [--commander-cmd CMD] [--attach]
|
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]
|
auto-tmux.sh wait -t TARGET --pattern REGEX [--timeout SEC] [--interval SEC] [-n LINES]
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ Examples:
|
|||||||
auto-tmux.sh send -t <target-from-topology> --text "make test" --enter
|
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 rescue -t <target-from-topology> --pattern "(y/n)" --reply y
|
||||||
auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback"
|
auto-tmux.sh scan --session ai-hub --pattern "ERROR|Traceback"
|
||||||
|
auto-tmux.sh snapshot --session ai-hub --dir /tmp/auto-tmux-snapshot
|
||||||
auto-tmux.sh hub --session ai-hub --workers 3 --cmd "codex"
|
auto-tmux.sh hub --session ai-hub --workers 3 --cmd "codex"
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@@ -332,6 +334,39 @@ cmd_record() {
|
|||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cmd_snapshot() {
|
||||||
|
local session=""
|
||||||
|
local dir="/tmp/auto-tmux-snapshot-$(date +%Y%m%d-%H%M%S)"
|
||||||
|
local lines=120
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--session) session="${2:-}"; shift 2 ;;
|
||||||
|
--dir) dir="${2:-}"; shift 2 ;;
|
||||||
|
-n|--lines) lines="${2:-}"; shift 2 ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) die "unknown snapshot option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
require_tmux
|
||||||
|
mkdir -p "$dir/panes"
|
||||||
|
{
|
||||||
|
printf 'auto-tmux snapshot\n'
|
||||||
|
printf 'created_at=%s\n' "$(date -Is)"
|
||||||
|
printf 'session=%s\n\n' "${session:-<all>}"
|
||||||
|
cmd_topology ${session:+--session "$session"}
|
||||||
|
} > "$dir/topology.txt"
|
||||||
|
|
||||||
|
local pane safe_name
|
||||||
|
while IFS= read -r pane; do
|
||||||
|
[[ -n "$pane" ]] || continue
|
||||||
|
safe_name="${pane//[:.]/-}.log"
|
||||||
|
capture_print "$pane" "$lines" 0 > "$dir/panes/$safe_name"
|
||||||
|
done < <(pane_list "$session")
|
||||||
|
|
||||||
|
printf 'snapshot written: %s\n' "$dir"
|
||||||
|
}
|
||||||
|
|
||||||
cmd_hub() {
|
cmd_hub() {
|
||||||
local session="ai-hub"
|
local session="ai-hub"
|
||||||
local workers=3
|
local workers=3
|
||||||
@@ -419,6 +454,7 @@ main() {
|
|||||||
rescue) cmd_rescue "$@" ;;
|
rescue) cmd_rescue "$@" ;;
|
||||||
scan) cmd_scan "$@" ;;
|
scan) cmd_scan "$@" ;;
|
||||||
record) cmd_record "$@" ;;
|
record) cmd_record "$@" ;;
|
||||||
|
snapshot) cmd_snapshot "$@" ;;
|
||||||
hub) cmd_hub "$@" ;;
|
hub) cmd_hub "$@" ;;
|
||||||
wait) cmd_wait "$@" ;;
|
wait) cmd_wait "$@" ;;
|
||||||
*) die "unknown command: $cmd" ;;
|
*) die "unknown command: $cmd" ;;
|
||||||
|
|||||||
Executable
+303
@@ -0,0 +1,303 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# swarm-state: minimal state, task and lock manager for tmux AI swarm workflows.
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SWARM_DIR="${AUTO_TMUX_SWARM_DIR:-/tmp/ai_swarm}"
|
||||||
|
STATUS_LOG="$SWARM_DIR/status.log"
|
||||||
|
TASKS_TSV="$SWARM_DIR/tasks.tsv"
|
||||||
|
LOCKS_DIR="$SWARM_DIR/locks"
|
||||||
|
RESULTS_DIR="$SWARM_DIR/results"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
swarm-state: tmux AI swarm state/task/lock helper
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
swarm-state.sh init [--dir DIR]
|
||||||
|
swarm-state.sh log --target TARGET --status STATUS --message TEXT [--dir DIR]
|
||||||
|
swarm-state.sh status [--dir DIR]
|
||||||
|
swarm-state.sh task-add --text TEXT [--id ID] [--dir DIR]
|
||||||
|
swarm-state.sh task-list [--dir DIR]
|
||||||
|
swarm-state.sh task-claim --id ID --owner TARGET [--dir DIR]
|
||||||
|
swarm-state.sh task-done --id ID --owner TARGET [--result TEXT] [--dir DIR]
|
||||||
|
swarm-state.sh lock-acquire --name NAME --owner TARGET [--dir DIR]
|
||||||
|
swarm-state.sh lock-release --name NAME --owner TARGET [--dir DIR] [--force]
|
||||||
|
swarm-state.sh lock-list [--dir DIR]
|
||||||
|
swarm-state.sh report [--dir DIR]
|
||||||
|
|
||||||
|
Environment:
|
||||||
|
AUTO_TMUX_SWARM_DIR overrides the default /tmp/ai_swarm.
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
printf 'error: %s\n' "$*" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
sanitize() {
|
||||||
|
tr '\t\r\n' ' ' | sed -E 's/[[:space:]]+/ /g; s/^ //; s/ $//'
|
||||||
|
}
|
||||||
|
|
||||||
|
set_dir() {
|
||||||
|
local dir="$1"
|
||||||
|
SWARM_DIR="$dir"
|
||||||
|
STATUS_LOG="$SWARM_DIR/status.log"
|
||||||
|
TASKS_TSV="$SWARM_DIR/tasks.tsv"
|
||||||
|
LOCKS_DIR="$SWARM_DIR/locks"
|
||||||
|
RESULTS_DIR="$SWARM_DIR/results"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_init() {
|
||||||
|
mkdir -p "$LOCKS_DIR" "$RESULTS_DIR"
|
||||||
|
touch "$STATUS_LOG" "$TASKS_TSV"
|
||||||
|
if [[ ! -s "$TASKS_TSV" ]]; then
|
||||||
|
printf 'id\tstatus\towner\ttext\tresult\n' > "$TASKS_TSV"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_init() {
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown init option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
ensure_init
|
||||||
|
printf 'swarm initialized: %s\n' "$SWARM_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_log() {
|
||||||
|
local target="" status="" message=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
--target) target="${2:-}"; shift 2 ;;
|
||||||
|
--status) status="${2:-}"; shift 2 ;;
|
||||||
|
--message) message="${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown log option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ -n "$target" ]] || die "missing --target"
|
||||||
|
[[ -n "$status" ]] || die "missing --status"
|
||||||
|
[[ -n "$message" ]] || die "missing --message"
|
||||||
|
ensure_init
|
||||||
|
message="$(printf '%s' "$message" | sanitize)"
|
||||||
|
printf '[%s] [%s] [%s] %s\n' "$(date +%H:%M:%S)" "$target" "$status" "$message" >> "$STATUS_LOG"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_status() {
|
||||||
|
local lines=30
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
-n|--lines) lines="${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown status option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
ensure_init
|
||||||
|
tail -n "$lines" "$STATUS_LOG"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_task_add() {
|
||||||
|
local id="" text=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
--id) id="${2:-}"; shift 2 ;;
|
||||||
|
--text) text="${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown task-add option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ -n "$text" ]] || die "missing --text"
|
||||||
|
ensure_init
|
||||||
|
if [[ -z "$id" ]]; then
|
||||||
|
id="task-$(date +%Y%m%d%H%M%S)-$$"
|
||||||
|
fi
|
||||||
|
text="$(printf '%s' "$text" | sanitize)"
|
||||||
|
printf '%s\tTODO\t-\t%s\t-\n' "$id" "$text" >> "$TASKS_TSV"
|
||||||
|
printf 'task added: %s\n' "$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_task_list() {
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown task-list option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
ensure_init
|
||||||
|
column -t -s $'\t' "$TASKS_TSV" 2>/dev/null || cat "$TASKS_TSV"
|
||||||
|
}
|
||||||
|
|
||||||
|
update_task() {
|
||||||
|
local id="$1" status="$2" owner="$3" result="$4"
|
||||||
|
local tmp
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
awk -F '\t' -v OFS='\t' -v id="$id" -v status="$status" -v owner="$owner" -v result="$result" '
|
||||||
|
NR == 1 {print; next}
|
||||||
|
$1 == id {$2 = status; $3 = owner; if (result != "") $5 = result; found = 1}
|
||||||
|
{print}
|
||||||
|
END {if (!found) exit 42}
|
||||||
|
' "$TASKS_TSV" > "$tmp" || {
|
||||||
|
local code=$?
|
||||||
|
rm -f "$tmp"
|
||||||
|
if [[ "$code" == "42" ]]; then
|
||||||
|
die "task not found: $id"
|
||||||
|
fi
|
||||||
|
exit "$code"
|
||||||
|
}
|
||||||
|
mv "$tmp" "$TASKS_TSV"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_task_claim() {
|
||||||
|
local id="" owner=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
--id) id="${2:-}"; shift 2 ;;
|
||||||
|
--owner) owner="${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown task-claim option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ -n "$id" ]] || die "missing --id"
|
||||||
|
[[ -n "$owner" ]] || die "missing --owner"
|
||||||
|
ensure_init
|
||||||
|
update_task "$id" "DOING" "$owner" ""
|
||||||
|
cmd_log --target "$owner" --status "START" --message "claimed $id"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_task_done() {
|
||||||
|
local id="" owner="" result="done"
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
--id) id="${2:-}"; shift 2 ;;
|
||||||
|
--owner) owner="${2:-}"; shift 2 ;;
|
||||||
|
--result) result="${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown task-done option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ -n "$id" ]] || die "missing --id"
|
||||||
|
[[ -n "$owner" ]] || die "missing --owner"
|
||||||
|
ensure_init
|
||||||
|
result="$(printf '%s' "$result" | sanitize)"
|
||||||
|
update_task "$id" "DONE" "$owner" "$result"
|
||||||
|
printf '%s\n' "$result" > "$RESULTS_DIR/$id.txt"
|
||||||
|
cmd_log --target "$owner" --status "DONE" --message "$id $result"
|
||||||
|
}
|
||||||
|
|
||||||
|
lock_path() {
|
||||||
|
local name="$1"
|
||||||
|
name="$(printf '%s' "$name" | sed -E 's#[^A-Za-z0-9_.-]+#_#g')"
|
||||||
|
printf '%s/%s.lock.d' "$LOCKS_DIR" "$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_lock_acquire() {
|
||||||
|
local name="" owner=""
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
--name) name="${2:-}"; shift 2 ;;
|
||||||
|
--owner) owner="${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown lock-acquire option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ -n "$name" ]] || die "missing --name"
|
||||||
|
[[ -n "$owner" ]] || die "missing --owner"
|
||||||
|
ensure_init
|
||||||
|
local path
|
||||||
|
path="$(lock_path "$name")"
|
||||||
|
if mkdir "$path" 2>/dev/null; then
|
||||||
|
printf '%s\n' "$owner" > "$path/owner"
|
||||||
|
printf '%s\n' "$(date -Is)" > "$path/created_at"
|
||||||
|
cmd_log --target "$owner" --status "LOCK" --message "acquired $name"
|
||||||
|
printf 'lock acquired: %s\n' "$name"
|
||||||
|
else
|
||||||
|
printf 'lock busy: %s owner=' "$name" >&2
|
||||||
|
cat "$path/owner" >&2 2>/dev/null || printf 'unknown\n' >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_lock_release() {
|
||||||
|
local name="" owner="" force="0"
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
--name) name="${2:-}"; shift 2 ;;
|
||||||
|
--owner) owner="${2:-}"; shift 2 ;;
|
||||||
|
--force) force="1"; shift ;;
|
||||||
|
*) die "unknown lock-release option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[[ -n "$name" ]] || die "missing --name"
|
||||||
|
[[ -n "$owner" ]] || die "missing --owner"
|
||||||
|
ensure_init
|
||||||
|
local path current_owner
|
||||||
|
path="$(lock_path "$name")"
|
||||||
|
[[ -d "$path" ]] || die "lock not found: $name"
|
||||||
|
current_owner="$(cat "$path/owner" 2>/dev/null || true)"
|
||||||
|
if [[ "$force" != "1" && "$current_owner" != "$owner" ]]; then
|
||||||
|
die "lock owner mismatch: current=$current_owner requested=$owner"
|
||||||
|
fi
|
||||||
|
rm -rf "$path"
|
||||||
|
cmd_log --target "$owner" --status "UNLOCK" --message "released $name"
|
||||||
|
printf 'lock released: %s\n' "$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_lock_list() {
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown lock-list option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
ensure_init
|
||||||
|
find "$LOCKS_DIR" -mindepth 1 -maxdepth 1 -type d -name '*.lock.d' -print | sort | while read -r path; do
|
||||||
|
printf '%s\towner=%s\tcreated_at=%s\n' \
|
||||||
|
"$(basename "$path" .lock.d)" \
|
||||||
|
"$(cat "$path/owner" 2>/dev/null || printf unknown)" \
|
||||||
|
"$(cat "$path/created_at" 2>/dev/null || printf unknown)"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_report() {
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||||
|
*) die "unknown report option: $1" ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
ensure_init
|
||||||
|
printf '# swarm report\n\n'
|
||||||
|
printf 'dir: %s\n\n' "$SWARM_DIR"
|
||||||
|
printf '## tasks\n\n'
|
||||||
|
cmd_task_list
|
||||||
|
printf '\n## locks\n\n'
|
||||||
|
cmd_lock_list || true
|
||||||
|
printf '\n## recent status\n\n'
|
||||||
|
cmd_status -n 20
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local cmd="${1:-help}"
|
||||||
|
shift || true
|
||||||
|
case "$cmd" in
|
||||||
|
help|-h|--help) usage ;;
|
||||||
|
init) cmd_init "$@" ;;
|
||||||
|
log) cmd_log "$@" ;;
|
||||||
|
status) cmd_status "$@" ;;
|
||||||
|
task-add) cmd_task_add "$@" ;;
|
||||||
|
task-list) cmd_task_list "$@" ;;
|
||||||
|
task-claim) cmd_task_claim "$@" ;;
|
||||||
|
task-done) cmd_task_done "$@" ;;
|
||||||
|
lock-acquire) cmd_lock_acquire "$@" ;;
|
||||||
|
lock-release) cmd_lock_release "$@" ;;
|
||||||
|
lock-list) cmd_lock_list "$@" ;;
|
||||||
|
report) cmd_report "$@" ;;
|
||||||
|
*) die "unknown command: $cmd" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
Reference in New Issue
Block a user