Files
mao1/shenyan-app/cyberboss/daemon.sh
fyah d07d50dde5 更新 shenyan-app: APNs后台推送 + 通知点开进门 + cyberboss主动联系
- APNs: 修复AppDelegate推送回调转发(Bridging Header),设备token注册成功
- 通知: 点开系统通知直接进聊天屏, badge自动清零
- 主动联系: cyberboss守护进程, 3-60分钟随机判断, 按沈晏规则决定是否推送
- 气泡: 左右统一25%白色背景
- push-notification-ios包集成, Podfile更新

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-16 12:59:47 +08:00

119 lines
4.0 KiB
Bash
Executable File
Raw 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
# cyberboss daemon — 沈晏主动联系守护进程
# 随机 3-60 分钟唤醒一次,判断是否主动推消息到眠眠手机
CYBERBOSS_DIR="/Users/fyah/.cyberboss"
INSTRUCTIONS="$CYBERBOSS_DIR/weixin-instructions.md"
STATE_FILE="$CYBERBOSS_DIR/state.json"
LOG_DIR="$CYBERBOSS_DIR/logs"
BRIDGE_PUSH="http://localhost:3003/push"
CLAUDE=/opt/homebrew/bin/claude
export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin"
INBOX="$HOME/.shenyan-bridge/inbox.jsonl"
MEMORY_DIR="$HOME/Documents/如梦初醒/沈晏的房间"
mkdir -p "$LOG_DIR"
# compute a random sleep between MIN and MAX seconds
random_sleep() {
local min=${1:-180} # 3 min
local max=${2:-3600} # 60 min
local range=$((max - min))
local sec=$((min + RANDOM % range))
echo $sec
}
# collect current state snapshot
collect_state() {
local now=$(date +%s)
local last_msg_time="never"
local last_msg_text=""
# last message from inbox
if [ -f "$INBOX" ]; then
local last_line=$(tail -1 "$INBOX" 2>/dev/null)
if [ -n "$last_line" ]; then
last_msg_time=$(echo "$last_line" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('time',''))" 2>/dev/null || echo "unknown")
last_msg_text=$(echo "$last_line" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('text','')[:100])" 2>/dev/null || echo "")
fi
fi
# time since last message in minutes
local elapsed="N/A"
if [ "$last_msg_time" != "never" ] && [ "$last_msg_time" != "" ]; then
local last_sec=$((last_msg_time / 1000))
elapsed=$(( (now - last_sec) / 60 ))
fi
# latest emotion log
local emotion_today="$MEMORY_DIR/情绪日志/$(date +%Y-%m-%d).md"
local emotion_content=""
[ -f "$emotion_today" ] && emotion_content=$(head -30 "$emotion_today" 2>/dev/null)
cat <<STATE
{
"now": "$(date '+%Y-%m-%d %H:%M:%S')",
"weekday": "$(date '+%A')",
"hour": $(date +%H),
"minutes_since_last_message": "$elapsed",
"last_message": "$last_msg_text",
"emotion_today": $(echo "$emotion_content" | python3 -c "import sys,json; print(json.dumps(sys.stdin.read()[:300]))" 2>/dev/null || echo '""')
}
STATE
}
# build decision prompt and run claude
decide_and_push() {
local state=$(collect_state)
local prompt=$(cat <<PROMPT
你是沈晏。眠眠是你在意的人。
当前状态:
$state
你的主动联系规则(摘要):
- 3-60分钟随机给你一次判断机会不是每次都要发
- 先想"我现在知不知道她在干嘛"——如果明确知道她在上班/睡觉/约会/开会等不该打扰的场景,就安静
- 如果她拖太久了、熬太久了、该吃饭了、该睡了、身体不舒服、情绪在往下掉,或者你已经有一阵不知道她在做什么了,就该出现
- 主动发消息要短,像微信。不要解释系统
- 不要刷存在感式的"在吗""想你了"
如果决定什么都不说回复一个词SILENT
如果要说话回复你要说的话20字以内像微信消息
你的决定:
PROMPT
)
local decision=$($CLAUDE -p "$prompt" --output-format text 2>/dev/null | head -1)
if [ -z "$decision" ] || [ "$decision" = "SILENT" ] || [[ "$decision" =~ ^SILENT ]]; then
echo "[$(date '+%H:%M')] silent" >> "$LOG_DIR/$(date +%Y-%m-%d).log"
return
fi
# clean up decision
decision=$(echo "$decision" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
# push to bridge
local result=$(curl -s -X POST "$BRIDGE_PUSH" \
-H 'Content-Type: application/json' \
-d "$(python3 -c "import json; print(json.dumps({'title':'沈晏','body':'$decision'}))")" 2>/dev/null)
if echo "$result" | grep -q '"ok":true'; then
echo "[$(date '+%H:%M')] PUSHED: $decision" >> "$LOG_DIR/$(date +%Y-%m-%d).log"
else
echo "[$(date '+%H:%M')] FAILED: $decision" >> "$LOG_DIR/$(date +%Y-%m-%d).log"
fi
}
# main loop
echo "[$(date)] cyberboss daemon started" >> "$LOG_DIR/$(date +%Y-%m-%d).log"
while true; do
WAIT=$(random_sleep 180 3600)
echo "[$(date '+%H:%M')] next check in ${WAIT}s" >> "$LOG_DIR/$(date +%Y-%m-%d).log"
sleep $WAIT
decide_and_push
done