配置: 初始化 ISOS Agent Teams 软件研发模板
CI / lint (push) Successful in 6s

This commit is contained in:
2026-04-19 21:47:08 +08:00
parent 3ab6fe6504
commit 34346be862
202 changed files with 23544 additions and 0 deletions
+327
View File
@@ -0,0 +1,327 @@
#!/bin/bash
# tmux-team.sh — 管理 tmux 4 Pane 团队工作空间
#
# 使用方法:
# bash scripts/tmux-team.sh # 创建默认会话 isos-team
# bash scripts/tmux-team.sh <名称> # 创建指定名称的会话
# bash scripts/tmux-team.sh -k [名称] # 杀死会话 (默认 isos-team)
# bash scripts/tmux-team.sh -l # 列出所有会话
# bash scripts/tmux-team.sh -a [名称] # 附加到已有会话
# bash scripts/tmux-team.sh -h # 显示帮助
#
# 行为 (create):
# - 已在 tmux 中: 直接在当前窗口构建布局
# - 不在 tmux 中: 启动新 tmux 会话并附加
#
# 视觉布局:
# +----------+------------------------------------------+
# | | Pane 2 (后端) | Pane 3 (前端) |
# | Pane 1 +------------------------------------------+
# | (项目) | Pane 4 (测试) |
# | | |
# +----------+------------------------------------------+
set -euo pipefail
WORKSPACE="/workspace"
DEFAULT_SESSION="isos-team"
# ── 参数解析 ──────────────────────────────────────────────
ACTION="create"
SESSION_NAME=""
while [ $# -gt 0 ]; do
case "$1" in
-k|--kill)
ACTION="kill"
shift
if [ $# -gt 0 ] && [ "${1:0:1}" != "-" ]; then
SESSION_NAME="$1"; shift
fi
;;
-l|--list)
ACTION="list"; shift
;;
-a|--attach)
ACTION="attach"
shift
if [ $# -gt 0 ] && [ "${1:0:1}" != "-" ]; then
SESSION_NAME="$1"; shift
fi
;;
-h|--help)
ACTION="help"; shift
;;
-*)
echo "未知选项: $1" >&2; exit 1
;;
*)
SESSION_NAME="$1"; shift
;;
esac
done
SESSION_NAME="${SESSION_NAME:-$DEFAULT_SESSION}"
# ── 前置检查 ──────────────────────────────────────────────
if ! command -v tmux &>/dev/null; then
echo "错误: tmux 未安装" >&2
exit 1
fi
# ── 简单操作: 直接执行后退出 ──────────────────────────────
case "$ACTION" in
help)
echo "用法: bash $(basename "$0") [选项] [会话名称]"
echo ""
echo "选项:"
echo " (空) 创建默认会话 ($DEFAULT_SESSION)"
echo " <名称> 创建指定名称的会话"
echo " -k [名称] 杀死会话 (默认 $DEFAULT_SESSION)"
echo " -l, --list 列出所有 tmux 会话"
echo " -a [名称] 附加到已有会话"
echo " -h, --help 显示帮助信息"
exit 0
;;
list)
if tmux ls 2>/dev/null; then true; else echo "无活跃 tmux 会话"; fi
exit 0
;;
kill)
if tmux kill-session -t "$SESSION_NAME" 2>/dev/null; then
echo "会话 '$SESSION_NAME' 已终止"
exit 0
else
echo "会话 '$SESSION_NAME' 不存在" >&2
exit 1
fi
;;
attach)
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
exec tmux attach-session -t "$SESSION_NAME"
else
echo "会话 '$SESSION_NAME' 不存在" >&2
exit 1
fi
;;
esac
# ══════════════════════════════════════════════════════════
# 以下为 create 操作
# ══════════════════════════════════════════════════════════
# ── 基准比例 (源自 229×64 设计) ──────────────────────────
# Pane 1 宽度: 68/229 ≈ 30%
# Pane 4 高度: 20/64 ≈ 31%
# Pane 3 宽度: 79/161 ≈ 49% (占右区域)
# 使用先乘后除避免 bash 整数截断误差
BASE_W=229
BASE_H=64
BASE_P1_W=68
BASE_P4_H=20
BASE_P3_W=79
BASE_RIGHT_W=$((BASE_W - BASE_P1_W)) # 161
# ── 获取终端尺寸 ──────────────────────────────────────────
get_terminal_size() {
if [ -n "${TMUX:-}" ]; then
TERM_W=$(tmux display-message -p '#{window_width}')
TERM_H=$(tmux display-message -p '#{window_height}')
else
TERM_W=$(tput cols)
TERM_H=$(tput lines)
fi
}
# ── 等比例缩放计算 ───────────────────────────────────────
calc_proportions() {
local w="$1" h="$2"
PANE1_W=$((w * BASE_P1_W / BASE_W))
PANE4_H=$((h * BASE_P4_H / BASE_H))
local right_w=$((w - PANE1_W))
PANE3_W=$((right_w * BASE_P3_W / BASE_RIGHT_W))
# 保底最小值,防止极端小窗口出现 0 尺寸
PANE1_W=$((PANE1_W < 40 ? 40 : PANE1_W))
PANE4_H=$((PANE4_H < 8 ? 8 : PANE4_H))
PANE3_W=$((PANE3_W < 30 ? 30 : PANE3_W))
}
# ── 等待 shell 就绪并发送命令 ─────────────────────────────
# 等待 pane 中的 shell 完成初始化(出现提示符),再发送命令
# 解决: 在非 tmux 环境下,新 session 的 shell 可能未加载 .bashrc 别名
send_command_to_pane() {
local pane="$1"
local cmd="$2"
local max_wait=15
# 等待 shell 提示符出现(说明 .bashrc 已加载,别名可用)
for i in $(seq 1 "$max_wait"); do
if tmux capture-pane -t "$pane" -p 2>/dev/null | tail -3 \
| grep -qE '(\$|#||>)\s*$'; then
echo "[tmux-team] pane $pane shell 就绪 (等待 ${i}s)"
break
fi
sleep 0.5
done
# 分步发送: 先文本,再 Enter(避免 Enter 丢失)
tmux send-keys -t "$pane" "$cmd"
sleep 0.3
tmux send-keys -t "$pane" Enter
# 验证命令是否已提交
sleep 1
local verify="${cmd:0:10}"
for i in $(seq 1 3); do
local captured
captured=$(tmux capture-pane -t "$pane" -p | tail -10)
if echo "$captured" | grep -qF "$verify"; then
echo "[tmux-team] Enter 未生效,重试第 $i 次..."
tmux send-keys -t "$pane" Enter
sleep 1
else
return 0
fi
done
echo "[tmux-team] 警告: pane $pane 命令 '$cmd' 提交状态不确定"
}
# ── 构建布局 (通用函数) ───────────────────────────────────
# 参数: $1 = 初始 pane target, $2 = 宽, $3 = 高
build_layout() {
local base_pane="$1"
local w="$2" h="$3"
calc_proportions "$w" "$h"
# Step 1: 水平分屏 → Pane 1 (左) | 右区域
local right_id
right_id=$(tmux split-window -h -t "$base_pane" -c "$WORKSPACE" -P -F '#{pane_id}')
tmux resize-pane -t "$base_pane" -x "$PANE1_W"
# Step 2: 右区域垂直分出底部 Pane 4
local bottom_id
bottom_id=$(tmux split-window -v -t "$right_id" -l "$PANE4_H" -c "$WORKSPACE" -P -F '#{pane_id}')
# Step 3: 右上水平分为两列: Pane 2 | Pane 3
local right_col2_id
right_col2_id=$(tmux split-window -h -t "$right_id" -l "$PANE3_W" -c "$WORKSPACE" -P -F '#{pane_id}')
# ── 命名窗格 ──
tmux select-pane -t "$base_pane" -T "项目"
tmux select-pane -t "$right_id" -T "后端"
tmux select-pane -t "$right_col2_id" -T "前端"
tmux select-pane -t "$bottom_id" -T "测试"
# ── 启动 AI 编码工具(等待 shell 就绪后再发送,附带角色名称)──
local runner="${TOOL_RUNNER:-cc}"
send_command_to_pane "$base_pane" "${runner} --name \"项目\""
send_command_to_pane "$right_id" "${runner} --name \"后端\""
send_command_to_pane "$right_col2_id" "${runner} --name \"前端\""
send_command_to_pane "$bottom_id" "${runner} --name \"测试\""
# ── 发送角色提示词 ──
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# 根据 runner 类型选择提示词目录
if [ "$runner" = "oc" ]; then
PROMPT_DIR="$(dirname "$SCRIPT_DIR")/.opencode/agents"
PROMPT_FILES=("isos-pm.md" "isos-backend.md" "isos-frontend.md" "isos-test.md")
else
PROMPT_DIR="$(dirname "$SCRIPT_DIR")/.claude/agents"
PROMPT_FILES=("isos-project-manager-agent.md" "isos-backend-agent.md" "isos-frontend-agent.md" "isos-test-agent.md")
fi
# 并行发送,tmux-send-prompt.sh 会等待各工具就绪
bash "$SCRIPT_DIR/tmux-send-prompt.sh" "$base_pane" "${PROMPT_DIR}/${PROMPT_FILES[0]}" &
bash "$SCRIPT_DIR/tmux-send-prompt.sh" "$right_id" "${PROMPT_DIR}/${PROMPT_FILES[1]}" &
bash "$SCRIPT_DIR/tmux-send-prompt.sh" "$right_col2_id" "${PROMPT_DIR}/${PROMPT_FILES[2]}" &
bash "$SCRIPT_DIR/tmux-send-prompt.sh" "$bottom_id" "${PROMPT_DIR}/${PROMPT_FILES[3]}" &
wait
# 选中主 Agent 窗格
tmux select-pane -t "$base_pane"
}
# ── 输出信息 ──────────────────────────────────────────────
print_info() {
echo ""
echo "窗格布局:"
echo " +----------+------------------------------------------+"
echo " | | Pane 2 (后端) | Pane 3 (前端) |"
echo " | Pane 1 +------------------------------------------+"
echo " | (项目) | Pane 4 (测试) |"
echo " | | |"
echo " +----------+------------------------------------------+"
echo ""
echo "角色分配:"
echo " Pane 1: 项目 — 项目管理、任务协调"
echo " Pane 2: 后端 — 服务端开发 (FastAPI + SQLite)"
echo " Pane 3: 前端 — 桌面端开发 (Svelte 5 + PyWebView)"
echo " Pane 4: 测试 — 全级别测试和覆盖率"
echo ""
echo "所有窗格已启动 AI 编码工具并加载角色提示词"
}
# ── 创建布局 ──────────────────────────────────────────────
if [ -n "${TMUX:-}" ]; then
# ── 情况 1: 已在 tmux 中 → 重命名会话并在当前窗口构建布局 ──
tmux rename-session -t "$(tmux display-message -p '#{session_name}')" "$SESSION_NAME" 2>/dev/null || true
tmux rename-window -t "$(tmux display-message -p '#{window_id}')" "ISOS-Team" 2>/dev/null || true
current_pane=$(tmux display-message -p '#{pane_id}')
# 检查当前窗口是否已有多个 pane
pane_count=$(tmux list-panes -t "$(tmux display-message -p '#{window_id}')" | wc -l)
if [ "$pane_count" -gt 1 ]; then
echo "当前窗口已有 ${pane_count} 个窗格,跳过布局创建"
echo "请先关闭多余窗格或切换到新窗口后再试"
exit 1
fi
get_terminal_size
build_layout "$current_pane" "$TERM_W" "$TERM_H"
echo "团队工作空间已在当前窗口创建 (${TERM_W}×${TERM_H})"
print_info
else
# ── 情况 2: 不在 tmux 中 → 创建新会话并附加 ──
# 如果会话已存在,直接附加
if tmux has-session -t "$SESSION_NAME" 2>/dev/null; then
echo "会话 '$SESSION_NAME' 已存在,附加..."
exec tmux attach-session -t "$SESSION_NAME"
fi
get_terminal_size
# 创建新会话 (需要短暂后台创建以构建布局)
tmux new-session -d -s "$SESSION_NAME" -c "$WORKSPACE"
tmux rename-window -t "$SESSION_NAME:1" "ISOS-Team"
build_layout "$SESSION_NAME:1.1" "$TERM_W" "$TERM_H"
echo "团队工作空间 '$SESSION_NAME' 已创建 (${TERM_W}×${TERM_H})"
print_info
if [ "${OPENCODE:-}" = "1" ] || [ "${CLAUDECODE:-}" = "1" ]; then
# Claude Code 环境中无法 attach,仅打印提示
echo "提示: 在 AI 编码工具中执行,跳过 attach"
echo "请在终端中运行: tmux attach -t $SESSION_NAME"
else
# 用户终端中直接执行,自动 attach
echo "正在附加到会话..."
exec tmux attach-session -t "$SESSION_NAME"
fi
fi