- 新增命令: lark-delegate(跨项目委派)、lark-inbox(收件箱)、lark-me(自发送)、stop(任务收尾) - 新增工具: lark-consumer/consumer-ensure/inbox-check(飞书事件实时消费与会话隔离)、tmux-monitor(监控面板) - runcc.sh 增加 --list/--kill/--send 操作模式与多会话自增命名 - CLAUDE.md 增加强制要求(汇报格式、收尾通知、上下文压缩)
87 lines
3.5 KiB
Bash
Executable File
87 lines
3.5 KiB
Bash
Executable File
#!/bin/bash
|
||
# ============================================================================
|
||
# SessionStart Hook — 飞书收件箱检查
|
||
# 检查实时事件日志中是否有金鹏新发送给 bot 的消息
|
||
#
|
||
# 多 Session 隔离:每个 tmux session 使用独立的时间戳文件,
|
||
# 通过 tmux session name 区分不同 session,互不干扰。
|
||
# tmux session name 比 PPID 更稳定——即使 Claude Code 重启,同一 tmux 窗口仍复用同一时间戳。
|
||
#
|
||
# 环境变量:
|
||
# LARK_INBOX_NDJSON_PATH - inbox ndjson 相对路径(必需)
|
||
# LARK_BOT_NAME - bot 显示名称(默认 "bot")
|
||
# ============================================================================
|
||
set -euo pipefail
|
||
|
||
PROJECT_ROOT="${PWD}"
|
||
INBOX_FILE="${PROJECT_ROOT}/${LARK_INBOX_NDJSON_PATH:-01-输入/lark-inbox.ndjson}"
|
||
CHECK_DIR="${PROJECT_ROOT}/.claude/.lark-inbox-checks"
|
||
BOT_NAME="${LARK_BOT_NAME:-bot}"
|
||
|
||
# ── 确保检查目录存在 & 清理过期 session 文件 ─────────────────
|
||
mkdir -p "${CHECK_DIR}"
|
||
find "${CHECK_DIR}" -type f -mtime +7 -delete 2>/dev/null || true
|
||
|
||
# ── 会话标识 & 专属时间戳文件 ──────────────────────────────────
|
||
# 使用 tmux session name 作为稳定标识,非 tmux 环境回退到 PPID
|
||
if [ -n "${TMUX:-}" ]; then
|
||
SESSION_ID="tmux-$(tmux display-message -p '#S' 2>/dev/null || echo "unknown")"
|
||
else
|
||
SESSION_ID="notmux-${PPID}"
|
||
fi
|
||
SESSION_FILE="${CHECK_DIR}/${SESSION_ID}"
|
||
|
||
# ── 获取本 session 的上次检查时间戳 ──────────────────────────
|
||
if [ -f "${SESSION_FILE}" ]; then
|
||
LAST_TS=$(cat "${SESSION_FILE}")
|
||
else
|
||
LAST_TS=0
|
||
fi
|
||
|
||
# ── 检查 ndjson 文件 ───────────────────────────────────────────
|
||
if [ ! -s "${INBOX_FILE}" ]; then
|
||
exit 0
|
||
fi
|
||
|
||
# ── 提取新消息 ─────────────────────────────────────────────────
|
||
NEW_MSGS=$(python3 -c "
|
||
import json, sys
|
||
from datetime import datetime
|
||
|
||
last_ts = ${LAST_TS}
|
||
new_msgs = []
|
||
|
||
with open('${INBOX_FILE}') as f:
|
||
for line in f:
|
||
line = line.strip()
|
||
if not line:
|
||
continue
|
||
try:
|
||
d = json.loads(line)
|
||
ts = int(d['time'])
|
||
if ts > last_ts:
|
||
dt = datetime.fromtimestamp(ts / 1000).strftime('%H:%M')
|
||
new_msgs.append(f'[{dt}] {d[\"msg\"]}')
|
||
except:
|
||
pass
|
||
|
||
if new_msgs:
|
||
print('\n'.join(new_msgs[-5:])) # 最多显示最近5条
|
||
" 2>/dev/null)
|
||
|
||
# ── 更新本 session 的时间戳(毫秒)─────────────────────────────
|
||
date +%s%3N > "${SESSION_FILE}"
|
||
|
||
# ── 无新消息则退出 ─────────────────────────────────────────────
|
||
if [ -z "${NEW_MSGS}" ]; then
|
||
exit 0
|
||
fi
|
||
|
||
# ── 输出模式:--text 纯文本(供 skill 调用),默认 hook JSON ────
|
||
if [ "${1:-}" = "--text" ]; then
|
||
printf '%s\n' "${NEW_MSGS}"
|
||
else
|
||
ESCAPED=$(printf '📬 飞书收件箱有新消息(金鹏→%s):\n%s\n\n请在简报末尾简要列出这些新消息。' "${BOT_NAME}" "${NEW_MSGS}" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()))")
|
||
printf '{"hookSpecificOutput":{"hookEventName":"SessionStart","additionalContext":%s}}\n' "${ESCAPED}"
|
||
fi
|