Files
team/scripts/tmux-send-prompt.sh
2026-04-19 22:23:34 +08:00

155 lines
4.8 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# tmux-send-prompt.sh — 可靠地向 tmux pane 中的 cc 发送提示词
#
# 解决的问题:
# 1. 发送长文本后 Enter 可能未被正确接收
# 2. 前一个命令还没执行完就发送新命令
# 3. 无法确认命令是否已成功提交
# 4. 文件内容过长时 send-keys 不可靠
#
# 用法:
# tmux-send-prompt.sh <pane_id> <text_string|text_file> [options]
#
# 选项:
# --submit-delay <seconds> 发送文本后等待多久再按 Enter(默认 1)
# --from <pane_id> 发送方 pane ID(用于日志)
# --no-verify 跳过提交验证(非阻塞模式)
#
# 行为:
# - 文本字符串: 直接发送
# - 文件路径: 发送简短指令,让 cc 自己读取文件并执行
#
# 示例:
# tmux-send-prompt.sh %1 "短文本提示"
# tmux-send-prompt.sh %1 /path/to/prompt.md
# tmux-send-prompt.sh %1 "文本" --submit-delay 2
# tmux-send-prompt.sh %1 "文本" --from %2 --no-verify
set -euo pipefail
# ─── 参数解析 ───
PANE_ID=''
TEXT_OR_FILE=''
SUBMIT_DELAY=1
FROM_PANE=''
NO_VERIFY=false
while [[ $# -gt 0 ]]; do
case "$1" in
--submit-delay)
SUBMIT_DELAY="${2:?--submit-delay 需要一个数值参数}"
shift 2
;;
--from)
FROM_PANE="${2:?--from 需要一个 pane ID}"
shift 2
;;
--no-verify)
NO_VERIFY=true
shift
;;
-*)
echo "错误: 未知选项 $1" >&2
exit 1
;;
*)
if [[ -z "$PANE_ID" ]]; then
PANE_ID="$1"
elif [[ -z "$TEXT_OR_FILE" ]]; then
TEXT_OR_FILE="$1"
elif [[ "$1" =~ ^[0-9]+$ ]]; then
# 向后兼容: 第三个位置参数为数字时视为 submit-delay
SUBMIT_DELAY="$1"
else
echo "错误: 多余参数 '$1'" >&2
exit 1
fi
shift
;;
esac
done
if [[ -z "$PANE_ID" ]]; then
echo "用法: tmux-send-prompt.sh <pane_id> <text|file> [options]" >&2
exit 1
fi
if [[ -z "$TEXT_OR_FILE" ]]; then
echo "错误: 需要提供文本或文件路径" >&2
exit 1
fi
# ─── 日志函数 ───
LOG_FILE="${TMUX_SEND_LOG:-/workspace/.tmux-send-prompt.log}"
log_call() {
local status="$1" detail="${2:-}"
local ts
ts=$(date -Iseconds)
local from_field="${FROM_PANE:-null}"
local text_len=${#TEXT_OR_FILE}
printf '{"ts":"%s","from":"%s","to":"%s","text_len":%d,"status":"%s","detail":"%s"}\n' \
"$ts" "$from_field" "$PANE_ID" "$text_len" "$status" "$detail" \
>> "$LOG_FILE" 2>/dev/null || true
}
# ─── 构建发送内容 ───
if [[ -f "$TEXT_OR_FILE" ]]; then
FILE_PATH=$(realpath "$TEXT_OR_FILE")
TEXT="请读取 ${FILE_PATH} 并执行其中的内容"
echo "[tmux-send] 检测到文件: ${FILE_PATH},将指示 cc 自行读取"
else
TEXT="$TEXT_OR_FILE"
fi
# ─── 步骤1: 等待 cc 的 prompt 出现(❯ 字符)───
# cc 状态栏在 ❯ 下方占 3 行,需要 tail -6 才能捕获
echo "[tmux-send] 等待 cc 的 prompt 就绪..."
for i in $(seq 1 30); do
LAST_LINE=$(tmux capture-pane -t "$PANE_ID" -p 2>/dev/null | tail -6 | grep -c '' || true)
if [[ "$LAST_LINE" -ge 1 ]]; then
echo "[tmux-send] cc 已就绪 (等待 ${i}s)"
break
fi
if [[ "$i" -eq 30 ]]; then
echo "[tmux-send] 警告: 30s 内未检测到 prompt,尝试发送"
log_call "timeout_wait" "prompt_not_found"
fi
sleep 1
done
# ─── 步骤2: 发送文本(不带 Enter)───
tmux send-keys -t "$PANE_ID" "$TEXT"
sleep "${SUBMIT_DELAY}"
# ─── 步骤3: 单独发送 Enter ───
tmux send-keys -t "$PANE_ID" Enter
sleep 2
# ─── 步骤4: 验证(可选)───
# cc 的 ❯ 始终在底部,无法通过 ❯ 消失判断提交成功。
# 改为:对比发送前后 pane 内容,若内容变化则说明已提交。
if [[ "$NO_VERIFY" == true ]]; then
echo "[tmux-send] 跳过验证(--no-verify"
log_call "sent_no_verify"
exit 0
fi
BEFORE_HASH=$(tmux capture-pane -t "$PANE_ID" -p 2>/dev/null | md5sum | cut -d' ' -f1)
for i in $(seq 1 3); do
sleep 3
AFTER_HASH=$(tmux capture-pane -t "$PANE_ID" -p 2>/dev/null | md5sum | cut -d' ' -f1)
if [[ "$BEFORE_HASH" != "$AFTER_HASH" ]]; then
echo "[tmux-send] 命令已成功提交 (第 $i 次检查,内容已变化)"
log_call "success" "content_changed_on_attempt_$i"
exit 0
fi
# 内容未变化,可能 Enter 未生效,重试一次
echo "[tmux-send] 内容未变化,重试 Enter 第 $i 次..."
tmux send-keys -t "$PANE_ID" Enter
done
log_call "failed" "content_unchanged_after_3_retries"
echo "[tmux-send] 警告: 3次重试后内容仍未变化,请手动检查"
exit 1