- src/: server.js (MCP 4 工具) + hub.js (HTTP Hub) + cursor-title.js - web/: panel.html (主面板) + panel.remote.html (远端 1637) - scripts/: ensure-hub.sh (stdio→http 桥) + mongo_sync.py - mcp-config/: trae.mcp.json + cursor.mcp.json - docs/: INSTALL / DEPLOY / MCP_SETUP / ARCHITECTURE / QUICKSTART - ZIP 原始安装包备查 关键机制: - 4 MCP 工具:init / select / wait / merge - 垂直绑定:workspace::cursorTitle@hostIp 三件指纹 - 真挂起:关闭 timedReply 后 wait 真正阻塞,agent turn 不结束 - 双 Hub 部署:远端 NAS 24×7 + 本地 launchd 守护备份 - 三形态组合:远端 + 本地 + Trae 插件,可同时跑
7.5 KiB
7.5 KiB
部署文档(DEPLOY.md)
三种部署形态 + 完整运维手册
适用版本:v1.6.37(2026-06-07)
形态 A:远端 NAS(推荐 · 公司 13458)
适用场景
- 多人 / 跨机 / 跨网段访问
- 24×7 在线(NAS 不关机)
- 唯一权威 Hub,所有 IDE 共享
前置条件
| 项 | 要求 |
|---|---|
| NAS IP | 192.168.110.101(公司)/ 192.168.1.201(公司 LAN) |
| Node | v22(路径 /usr/local/opt/node@22/bin/node) |
| 端口 | 13458(HTTP) |
| 用户 | fnvtk(SSH) |
| 数据目录 | /volume1/homes/fnvtk/.persistent-chat-local/ |
部署步骤
# 1. SSH 登录 NAS
ssh fnvtk@192.168.110.101
# 2. 创建部署目录
mkdir -p /volume1/homes/fnvtk/.persistent-chat-local
cd /volume1/homes/fnvtk/.persistent-chat-local
# 3. 上传 6 个核心文件
# (用 scp / git pull / rsync 任一方式)
# 必需文件:server.js / hub.js / panel.html / ensure-hub.sh / mongo_sync.py / cursor-title.js
# 4. 设置权限
chmod +x ensure-hub.sh
# 5. 启动 Hub(前台调试用)
/usr/local/opt/node@22/bin/node hub.js &
# 6. 验证
curl http://192.168.110.101:13458/api/health
# 期望:{"ok":true,"pid":<X>,"panelVersion":"1.6.37"}
后台守护(用 nohup)
cd /volume1/homes/fnvtk/.persistent-chat-local
nohup /usr/local/opt/node@22/bin/node hub.js > logs/hub.log 2>&1 &
disown
echo $! > /tmp/pchat-hub.pid
系统级守护(Synology Task Scheduler)
- DSM 控制面板 → 任务计划
- 新增 → 触发的任务 → 用户自定义脚本
- 事件:开机 / 启动
- 用户:root
- 脚本:
#!/bin/bash cd /volume1/homes/fnvtk/.persistent-chat-local /usr/local/opt/node@22/bin/node hub.js >> /volume1/homes/fnvtk/.persistent-chat-local/logs/hub.log 2>&1 &
形态 B:本地备份(127.0.0.1:13458)
适用场景
- 单机 fallback(远端挂时自动接上)
- 开发调试(启停方便)
- 离线工作
macOS launchd 守护(推荐)
# 1. 写 plist
cat > ~/Library/LaunchAgents/com.karuo.persistent-chat-hub.plist <<'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.karuo.persistent-chat-hub</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/opt/node@22/bin/node</string>
<string>/Users/karuo/.persistent-chat-local/hub.js</string>
</array>
<key>WorkingDirectory</key><string>/Users/karuo/.persistent-chat-local</string>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
<key>StandardOutPath</key><string>/Users/karuo/.persistent-chat-local/logs/launchd.log</string>
<key>StandardErrorPath</key><string>/Users/karuo/.persistent-chat-local/logs/launchd.err</string>
</dict>
</plist>
EOF
# 2. 加载
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.karuo.persistent-chat-hub.plist
# 3. 验证
launchctl print gui/$UID/com.karuo.persistent-chat-hub | head -10
curl http://127.0.0.1:13458/api/health
启停命令
# 启动
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.karuo.persistent-chat-hub.plist
# 停止
launchctl bootout gui/$UID ~/Library/LaunchAgents/com.karuo.persistent-chat-hub.plist
# 状态
launchctl print gui/$UID/com.karuo.persistent-chat-hub
# 日志
tail -f /Users/karuo/.persistent-chat-local/logs/launchd.log
形态 C:Trae / Cursor 插件(stdio MCP)
适用场景
- 直接在 IDE 里用
- 与 Hub 通过 stdio 通信(ensure-hub.sh 桥接)
部署步骤
# 1. 创建本地目录
mkdir -p ~/.persistent-chat-local
# 2. 拷贝核心文件
cp src/server.js src/hub.js src/cursor-title.js ~/.persistent-chat-local/
cp web/panel.html ~/.persistent-chat-local/panel.html
cp scripts/ensure-hub.sh ~/.persistent-chat-local/
chmod +x ~/.persistent-chat-local/ensure-hub.sh
# 3. 编辑 MCP 配置(见 mcp-config/trae.mcp.json)
ensure-hub.sh 原理
MCP stdio ←→ ensure-hub.sh ←→ Hub HTTP (13458)
- 收到 MCP 调用 → 转发到 Hub HTTP
- Hub 持久挂着,session 不丢
- IDE 重启不影响 Hub 状态
三形态组合
推荐:远端 NAS 为主(24×7),本地为备份(断网续命),Trae 插件为入口。
Trae ←stdio→ ensure-hub.sh ←HTTP→ [本地 13458] (fallback)
↑
[远端 192.168.110.101:13458] (主)
通过 PCHAT_HUB_HOST 环境变量切换。
验证清单
部署完后挨个跑:
# 1. 健康
curl http://192.168.110.101:13458/api/health
curl http://127.0.0.1:13458/api/health
# 2. session list
curl http://192.168.110.101:13458/api/state | python3 -m json.tool
# 3. 面板可访问
open http://192.168.110.101:13458/
open http://127.0.0.1:13458/
# 4. Trae 插件已加载
ps aux | grep "server.js" | grep -v grep
# 期望:看到 /Users/karuo/.persistent-chat-local/server.js
# 5. 跑 init + select + wait 三步
升级流程
# 1. 备份
cp -r ~/.persistent-chat-local ~/.persistent-chat-local.bak.$(date +%Y%m%d)
ssh fnvtk@192.168.110.101 "cp -r /volume1/homes/fnvtk/.persistent-chat-local /volume1/homes/fnvtk/.persistent-chat-local.bak.\$(date +%Y%m%d)"
# 2. 拉新代码
cd /Users/karuo/Documents/个人/persistent-chat-plugin
git pull
# 3. 覆盖核心文件(不动 data/)
cp src/* ~/.persistent-chat-local/
cp web/panel.html ~/.persistent-chat-local/
# 4. 远端同步
scp src/* fnvtk@192.168.110.101:/volume1/homes/fnvtk/.persistent-chat-local/
scp web/panel.html fnvtk@192.168.110.101:/volume1/homes/fnvtk/.persistent-chat-local/
# 5. 重启 Hub(不影响 session 文件)
launchctl bootout gui/$UID/com.karuo.persistent-chat-hub
launchctl bootstrap gui/$UID/com.karuo.persistent-chat-hub.plist
ssh fnvtk@192.168.110.101 "pkill -f 'node hub.js' ; cd /volume1/homes/fnvtk/.persistent-chat-local && nohup /usr/local/opt/node@22/bin/node hub.js > logs/hub.log 2>&1 &"
# 6. Trae Cmd+Q 重开
数据备份
sessions.json(远端/本地):所有 session 状态bindings.json:工作区→token 绑定plan-bindings.json:计划→token 绑定thread-bindings/:线程→token 绑定logs/:运行日志
建议:每天 cron 备份整个 .persistent-chat-local 目录到 NAS / 云盘。
# cron 任务:每天 02:00 备份
0 2 * * * tar czf ~/backups/pchat-$(date +\%Y\%m\%d).tar.gz ~/.persistent-chat-local
故障排查
| 症状 | 原因 | 处理 |
|---|---|---|
| 面板打不开 | Hub 未启动 | launchctl print gui/$UID/com.karuo.persistent-chat-hub |
Token未获取 |
Trae 未重启 | Cmd+Q 完全退出重开 |
| session 串台 | 多用户同 IP | 加 hostIp 区分 / 改 cursorTitle |
| Hub 占 CPU | 短轮询频繁 | 改 POLL_TIMEOUT_MS 到 30000 |
| 数据丢失 | 没备份 | 立刻 cron 跑起来 |
安全注意
- 13458 端口默认仅监听 LAN IP,不暴露公网
- 跨网段访问靠 SSH 隧道或 VPN
- 永远不要把
127.0.0.1:13458暴露到 0.0.0.0
监控
# Hub 状态
watch -n 5 'curl -s http://192.168.110.101:13458/api/health | python3 -c "import json,sys;d=json.load(sys.stdin);print(d.get(\"panelVersion\"),d.get(\"pid\"),\"sessions=\"+str(len(json.load(open(\"/dev/null\")))))" 2>/dev/null'
# session 数量
curl -s http://192.168.110.101:13458/api/state | python3 -c "import json,sys;print(len(json.load(sys.stdin)['sessions']))"
最后更新:2026-06-26 · 卡若AI