Files
team/scripts/tmux-msg-log.sh
arno d9f1990884
All checks were successful
CI / lint (push) Successful in 6s
功能: 添加 tmux 消息通知与日志脚本
2026-04-19 22:23:34 +08:00

290 lines
8.4 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-msg-log.sh — 消息日志查询工具
#
# 用法:
# tmux-msg-log.sh recent [--count 20]
# tmux-msg-log.sh by-pane <pane_id>
# tmux-msg-log.sh show <msg_id>
# tmux-msg-log.sh stats
# tmux-msg-log.sh log <msg_id> "<status_note>"
#
# 示例:
# tmux-msg-log.sh recent
# tmux-msg-log.sh by-pane %2
# tmux-msg-log.sh show msg-20260419-142357-a1b2
# tmux-msg-log.sh stats
set -euo pipefail
MSG_DIR="${TMUX_MSG_DIR:-/workspace/.tmux-messages}"
INDEX_FILE="${MSG_DIR}/index.jsonl"
# ─── 颜色 ───
GREEN='\033[32m'
RED='\033[31m'
YELLOW='\033[33m'
CYAN='\033[36m'
BOLD='\033[1m'
RESET='\033[0m'
read_envelope() {
local msg_id="$1"
find "$MSG_DIR" -name "${msg_id}.json" -type f 2>/dev/null | head -1
}
# ─── recent 子命令 ───
cmd_recent() {
local count="${1:-20}"
if [[ ! -f "$INDEX_FILE" ]]; then
echo "暂无消息记录"
return
fi
echo -e "${BOLD}══ 最近 ${count} 条消息 ══${RESET}"
echo ""
tail -n "$count" "$INDEX_FILE" | while IFS= read -r line; do
[[ -z "$line" ]] && continue
echo "$line" | python3 -c "
import sys, json
d = json.loads(sys.stdin.read())
direction = d.get('direction', '?')
status = d.get('status', '?')
msg_id = d.get('msg_id', '?')
from_p = d.get('from', '?')
to_p = d.get('to', '?')
summary = d.get('summary', '')[:50]
ts = d.get('ts', '?')
# 状态颜色
if status in ('completed', 'delivered', 'replied'):
color = '\033[32m'
elif status in ('failed', 'send_failed', 'reply_failed'):
color = '\033[31m'
else:
color = '\033[33m'
direction_icon = '→' if direction == 'request' else '←'
print(f' {color}{status:12}\033[0m {msg_id} {direction_icon} {from_p}→{to_p}')
print(f' {summary}')
print(f' {ts}')
print()
" 2>/dev/null
done
}
# ─── by-pane 子命令 ───
cmd_by_pane() {
local pane_id="${1:?用法: tmux-msg-log.sh by-pane <pane_id>}"
if [[ ! -f "$INDEX_FILE" ]]; then
echo "暂无消息记录"
return
fi
echo -e "${BOLD}══ Pane ${pane_id} 的消息 ══${RESET}"
local count=0
while IFS= read -r line; do
[[ -z "$line" ]] && continue
local match
match=$(echo "$line" | python3 -c "
import sys, json
d = json.loads(sys.stdin.read())
if d.get('from') == '${pane_id}' or d.get('to') == '${pane_id}':
print('yes')
else:
print('no')
" 2>/dev/null)
[[ "$match" != "yes" ]] && continue
count=$((count + 1))
echo "$line" | python3 -c "
import sys, json
d = json.loads(sys.stdin.read())
direction = d.get('direction', '?')
status = d.get('status', '?')
msg_id = d.get('msg_id', '?')
from_p = d.get('from', '?')
to_p = d.get('to', '?')
summary = d.get('summary', '')[:50]
role = '发送' if d.get('from') == '${pane_id}' else '接收'
print(f' [{role}] {status:12} {msg_id} {summary}')
" 2>/dev/null
done < "$INDEX_FILE"
echo ""
echo "${count} 条消息"
}
# ─── show 子命令 ───
cmd_show() {
local msg_id="${1:?用法: tmux-msg-log.sh show <msg_id>}"
local envelope_path
envelope_path=$(read_envelope "$msg_id")
if [[ -z "$envelope_path" ]]; then
echo "错误: 未找到消息 ${msg_id}" >&2
exit 1
fi
python3 -c "
import sys, json
with open('${envelope_path}') as f:
d = json.load(f)
print('══ 消息详情 ══')
print(f'消息ID: {d[\"msg_id\"]}')
print(f'方向: {d[\"direction\"]}')
if d.get('in_reply_to'):
print(f'回复消息: {d[\"in_reply_to\"]}')
print(f'来源: {d[\"from_title\"]} ({d[\"from_pane\"]})')
print(f'目标: {d[\"to_title\"]} ({d[\"to_pane\"]})')
print(f'状态: {d[\"status\"]}')
if d.get('task_summary'):
print(f'任务摘要: {d[\"task_summary\"]}')
if d.get('task_file'):
print(f'任务文件: {d[\"task_file\"]}')
print(f'创建时间: {d[\"created_at\"]}')
if d.get('delivered_at'):
print(f'送达时间: {d[\"delivered_at\"]}')
if d.get('replied_at'):
print(f'回复时间: {d[\"replied_at\"]}')
print(f'回复摘要: {d.get(\"reply_summary\", \"\")}')
if d.get('error'):
print(f'错误: {d[\"error\"]}')
" 2>/dev/null
}
# ─── stats 子命令 ───
cmd_stats() {
if [[ ! -f "$INDEX_FILE" ]]; then
echo "暂无消息记录"
return
fi
local total=0 requests=0 replies=0
local completed=0 pending=0 failed=0
declare -A pane_counts
while IFS= read -r line; do
[[ -z "$line" ]] && continue
total=$((total + 1))
local direction status from to
direction=$(echo "$line" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('direction','?'))" 2>/dev/null)
status=$(echo "$line" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('status','?'))" 2>/dev/null)
from=$(echo "$line" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('from','?'))" 2>/dev/null)
to=$(echo "$line" | python3 -c "import sys,json; print(json.loads(sys.stdin.read()).get('to','?'))" 2>/dev/null)
[[ "$direction" == "request" ]] && requests=$((requests + 1))
[[ "$direction" == "reply" ]] && replies=$((replies + 1))
case "$status" in
completed|delivered|replied) completed=$((completed + 1)) ;;
created|sent|pending) pending=$((pending + 1)) ;;
failed|send_failed|reply_failed) failed=$((failed + 1)) ;;
esac
pane_counts["$from"]=$(( ${pane_counts["$from"]:-0} + 1 ))
pane_counts["$to"]=$(( ${pane_counts["$to"]:-0} + 1 ))
done < "$INDEX_FILE"
echo -e "${BOLD}══ 消息统计 ══${RESET}"
echo ""
echo " 总计: ${total}"
echo " 请求: ${requests}"
echo " 回复: ${replies}"
echo ""
echo -e " ${GREEN}完成: ${completed}${RESET} ${YELLOW}待处理: ${pending}${RESET} ${RED}失败: ${failed}${RESET}"
echo ""
echo "各面板活跃度:"
for pane in "${!pane_counts[@]}"; do
printf " %-6s %d 条\n" "$pane" "${pane_counts[$pane]}"
done
}
# ─── 主入口 ───
# ─── list 子命令 ───
cmd_list() {
local filter_from='' filter_to='' filter_status=''
while [[ $# -gt 0 ]]; do
case "$1" in
--from) filter_from="$2"; shift 2 ;;
--to) filter_to="$2"; shift 2 ;;
--status) filter_status="$2"; shift 2 ;;
*) shift ;;
esac
done
if [[ ! -f "$INDEX_FILE" ]]; then
echo "暂无消息记录"
return
fi
local count=0
while IFS= read -r line; do
[[ -z "$line" ]] && continue
if [[ -n "$filter_from" ]]; then
local from
from=$(echo "$line" | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['from'])" 2>/dev/null)
[[ "$from" != "$filter_from" ]] && continue
fi
if [[ -n "$filter_to" ]]; then
local to
to=$(echo "$line" | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['to'])" 2>/dev/null)
[[ "$to" != "$filter_to" ]] && continue
fi
if [[ -n "$filter_status" ]]; then
local st
st=$(echo "$line" | python3 -c "import sys,json; print(json.loads(sys.stdin.read())['status'])" 2>/dev/null)
[[ "$st" != "$filter_status" ]] && continue
fi
count=$((count + 1))
echo "$line" | python3 -c "
import sys, json
d = json.loads(sys.stdin.read())
print(f'{d[\"msg_id\"]} {d[\"status\"]:12} {d[\"from\"]}→{d[\"to\"]} {d.get(\"summary\",\"\")[:50]}')
" 2>/dev/null
done < "$INDEX_FILE"
echo ""
echo "${count} 条消息"
}
# ─── 主入口 ───
cmd="${1:-help}"
shift || true
case "$cmd" in
recent) cmd_recent "$@" ;;
by-pane) cmd_by_pane "$@" ;;
show) cmd_show "$@" ;;
stats) cmd_stats ;;
list) cmd_list "$@" ;;
help|--help|-h)
echo "用法: tmux-msg-log.sh <command> [options]"
echo ""
echo "命令:"
echo " recent [--count N] 最近 N 条消息(默认 20"
echo " by-pane <pane_id> 指定面板的消息"
echo " show <msg_id> 消息详情"
echo " list [--from <p>] [--to <p>] [--status <s>]"
echo " 列出消息(可过滤)"
echo " stats 统计摘要"
;;
*)
echo "错误: 未知命令 '$cmd'" >&2
exit 1
;;
esac