feat: 持久对话 MCP 插件 v1.6.37 · Hub + Panel + MCP 三形态部署

- 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 插件,可同时跑
This commit is contained in:
卡若AI
2026-06-26 13:01:08 +08:00
commit 62577508c9
19 changed files with 10493 additions and 0 deletions

340
docs/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,340 @@
# 架构ARCHITECTURE.md
> 持久对话 MCP 插件的完整技术架构
---
## 1. 整体拓扑
```
┌────────────────────┐
│ Trae / Cursor │ IDESOLO Agent 窗口)
│ (MCP client) │
└─────────┬──────────┘
│ stdio JSON-RPC
│ 4 tools: init / select / wait / merge
┌────────────────────┐
│ ensure-hub.sh │ stdio → HTTP 桥接
│ (MCP server) │
└─────────┬──────────┘
│ HTTP (13458)
┌────────────────────┐
│ hub.js (主) │ ┌─ 远端: 192.168.110.101:13458
│ Node 22 + HTTP │ └─ 本地: 127.0.0.1:13458
└─────────┬──────────┘
│ 短轮询10s
┌────────────────────┐
│ sessions.json │ 持久化层
│ bindings.json │ - sessions: ct_xxx → 状态
│ plan-bindings │ - bindings: workspace::title@ip → ct_
│ thread-bindings/ │ - plan: planName → ct_
└────────────────────┘ - thread: threadId → ct_
↓ 周期同步(可选)
┌────────────────────┐
│ MongoDB │ 远端数据库
│ karuo_site │ (port 27017)
└────────────────────┘
```
---
## 2. 核心数据流
### 2.1 初始化
```
Agent → init_conversation(cursorTitle=标签, newPlan=true, planLabel=xxx)
→ ensure-hub.sh → POST /api/init
→ hub.js 创建 sessionct_xxx
→ 写入 sessions.json
→ 写 bindingworkspace::title@ip → ct_xxx
→ 返回 { token: ct_xxx, status: holding }
```
### 2.2 选择已有
```
Agent → select_conversation(token=ct_xxx, cursorTitle=标签)
→ ensure-hub.sh → POST /api/select
→ hub.js 验证垂直绑定workspace::title@ip 三件指纹)
→ 不匹配 → 403 BINDING_REJECTED
→ 匹配 → 复用 session
```
### 2.3 真挂起
```
Agent → wait_for_user_input(token, message, timeout)
→ ensure-hub.sh → POST /api/wait/register
→ hub.js 设置 session.status = "waiting"
→ 注册到 pendingWaits[token]
→ 长连接(短轮询 10s 续约)
→ 收到 reply
a. 用户发消息 → deliverReply → 返回
b. timedReply 触发10s 间隔)→ deliverReply("保活续跑") → 返回
c. POLL_TIMEOUT_MS=10s → renewal → 继续轮询
→ Agent 端按 status 决定:
- "replied" → 返回 text
- "renewal" → 继续 poll
- "gone" → 重新 register
```
### 2.4 合并
```
Agent → merge_conversation(fromToken, toToken, cursorTitle)
→ ensure-hub.sh → POST /api/merge
→ hub.js 把 fromToken 的 messages 追加到 toToken
→ fromToken 标记 archived
→ 增量保存 sessions.json
```
---
## 3. 垂直绑定
### 3.1 绑定指纹
```
bindingKey = `${workspace}::${cursorTitle}@${hostIp}`
```
示例:
```
/Users/karuo/Documents/个人::持久对话永久续跑-20260626@192.168.3.1
```
### 3.2 验证时机
| 触发 | 验证 |
|:---|:---|
| `select_conversation` | 严校验(必须完全匹配) |
| `init_conversation` | 宽校验(可换 title 重新绑定) |
| `wait_for_user_input` | 中校验(容许 title 改名) |
| `merge_conversation` | 严校验(不匹配拒绝) |
### 3.3 改标签自动迁移
```javascript
// 用户在 Trae 改了标签 "A" → "B"
// wait 时传入新 title "B"
// hub.js 检测到旧 binding 有 token旧 bindingKey 不匹配
// 允许迁移:把 bindingKey 改成新值token 复用
```
---
## 4. session 状态机
```
init
holding ──────┐
│ │ (每 10s 续约 / 接收新消息)
│ │
▼ │
waiting ───────┤
│ │
│ (用户发消息)│
▼ │
replied ───────┘
│ (autoStreak 累加)
running
│ (merge / 结束持久对话)
merged / archived
```
---
## 5. autoStreak 与 keepAlive
### 5.1 概念
- `autoStreak`:连续"用户不发消息"的轮次计数
- `keepAlive`Hub 在 autoStreak 超阈值时主动推"保活续跑"消息
### 5.2 真挂起模式(推荐)
```json
POST /api/session/config
{
"sessionAutoContinue": false,
"timedReplyEnabled": false,
"timedReplyIntervalMs": 0
}
```
**效果**
- 关闭 timedReply → 不会主动推"保活续跑"
- 关闭 autoContinue → 不会因为 idle 触发续跑
- wait 唯一返回源 = 用户真消息
- MCP 工具调用一直阻塞agent turn 不会结束
### 5.3 自动模式(不推荐,会顶回 wait
```json
{
"sessionAutoContinue": true,
"timedReplyEnabled": true,
"timedReplyIntervalMs": 10000
}
```
**效果**
- 每 10s 推"保活续跑"
- wait 立即返回
- agent turn 结束UI 显示"任务完成"
---
## 6. 短轮询 vs 长连接
| 方案 | 优点 | 缺点 | 采用 |
|:---|:---|:---|:---|
| 短轮询10s | 简单、跨网段友好、稳 | 续约频繁 | ✅ |
| WebSocket | 实时、省资源 | 需配 wss、断线重连复杂 | ❌ |
| Server-Sent Events | 单向实时 | 不支持双向 | ❌ |
| Long Polling | 接近实时 | 服务器维护成本 | ❌(短轮询已够) |
短轮询间隔:`POLL_TIMEOUT_MS = 10000`10s可在 `hub.js` 改。
---
## 7. 数据持久化
### 7.1 文件布局
```
~/.persistent-chat-local/
├── sessions.json # 主 session 数据
├── bindings.json # workspace::title@ip → ct_
├── plan-bindings.json # planName → ct_
├── thread-bindings/ # threadId → ct_ (mkdir)
├── archive/ # 归档 session
│ └── 2026-06/
│ └── ct_xxx.json
├── replies/ # 历史用户回复缓存
├── logs/
│ ├── hub.log # Hub 主日志
│ ├── launchd.log # macOS launchd 日志
│ └── launchd.err
├── templates/ # 面板模板
├── server.js # MCP server41KB
├── hub.js # Hub 主服务89KB
├── panel.html # 浏览器面板84KB
├── cursor-title.js # 标签解析器4KB
├── ensure-hub.sh # 启动器
└── mongo_sync.py # → MongoDB 同步
```
### 7.2 sessions.json 格式
```json
{
"ct_xxxx": {
"token": "ct_xxxx",
"title": "永久续跑三段式",
"displayTitle": "",
"status": "holding",
"workspace": "/Users/karuo/Documents/个人",
"createdAt": 1782448693854,
"lastActiveAt": 1782449356228,
"msgCount": 10,
"autoStreak": 1,
"bindingKey": "/Users/karuo/Documents/个人::标签@192.168.3.1",
"hostIp": "192.168.3.1",
"hub": "192.168.110.101:13458",
"bindingCheckCount": 17,
"continueMode": "optimize",
"sessionAutoContinue": false,
"timedReplyEnabled": false,
"timedReplyIntervalMs": 0,
"messages": [
{ "role": "user", "content": "...", "at": 1782448794716, "auto": false },
{ "role": "assistant", "content": "...", "at": 1782449116363, "auto": false }
],
"lastReview": {
"hasReview": false,
"completionPct": null,
"nextStep": "",
"isIdleNext": true
}
}
}
```
### 7.3 周期保存
- 每次 register / deliverReply / merge 后 `saveSessions()`
- 写盘:原子 rename先写 .tmp再 rename
- 加载:启动时一次 loadSessions(),之后只内存操作
---
## 8. 与 MongoDB 同步(可选)
`mongo_sync.py` 把 sessions.json 周期同步到 MongoDB `karuo_site.sessions`
```python
# 触发
python3 mongo_sync.py
# 或 cron 每 5 分钟
*/5 * * * * cd ~/.persistent-chat-local && python3 mongo_sync.py
```
用途:
- 多机同步(局域网内多 Hub
- 长期归档(超过 1000 个 session 不卡)
- 跨平台Mac / NAS / Linux
---
## 9. 安全性
| 维度 | 措施 |
|:---|:---|
| 端口 | 13458 默认仅 LAN 监听,不暴露公网 |
| 鉴权 | 垂直绑定(三件指纹),无 token → 拒绝 |
| 数据 | sessions.json 落在 ~/.persistent-chat-local/,权限 600 |
| 跨网段 | 靠 SSH 隧道 / VPN |
| 日志 | 不记录用户隐私内容(只记 metadata |
| 卡密激活 | **已删除**v1.6.37 不再有 license 校验) |
---
## 10. 性能
| 指标 | 值 |
|:---|:---|
| Hub 内存 | ~50MB1000 个 session |
| Hub CPU | < 1%空闲 |
| session 占内存 | ~5KB metadata |
| 单消息占内存 | ~1KB |
| 短轮询带宽 | ~1KB/10s/session |
| 启动时间 | < 1sNode 22 |
| sessions.json 加载 | 10000 session < 500ms |
---
## 11. 版本演进
| 版本 | 日期 | 关键变化 |
|:---|:---|:---|
| v1.1 | 2025-12 | 初版 hub.js |
| v1.5 | 2026-03 | server.js / MCP 4 工具 |
| v1.6.30 | 2026-05 | autoStreak / timedReply |
| v1.6.37 | 2026-06-07 | **删除卡密激活** / MongoDB 同步 |
| v1.6.68 | 2026-06-20 | 本地增强VSIX 4.6 兼容 |
---
> 最后更新2026-06-26 · 卡若AI

281
docs/DEPLOY.md Normal file
View File

@@ -0,0 +1,281 @@
# 部署文档DEPLOY.md
> 三种部署形态 + 完整运维手册
> 适用版本v1.6.372026-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` |
| 端口 | 13458HTTP |
| 用户 | `fnvtk`SSH |
| 数据目录 | `/volume1/homes/fnvtk/.persistent-chat-local/` |
### 部署步骤
```bash
# 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
```bash
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
1. DSM 控制面板 → 任务计划
2. 新增 → 触发的任务 → 用户自定义脚本
3. **事件**:开机 / 启动
4. **用户**root
5. **脚本**
```bash
#!/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 守护(推荐)
```bash
# 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
```
### 启停命令
```bash
# 启动
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
```
---
## 形态 CTrae / Cursor 插件stdio MCP
### 适用场景
- 直接在 IDE 里用
- 与 Hub 通过 stdio 通信ensure-hub.sh 桥接)
### 部署步骤
```bash
# 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` 环境变量切换。
---
## 验证清单
部署完后挨个跑:
```bash
# 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 三步
```
---
## 升级流程
```bash
# 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 / 云盘。
```bash
# 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
---
## 监控
```bash
# 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

189
docs/INSTALL.md Normal file
View File

@@ -0,0 +1,189 @@
# 安装文档INSTALL.md
> 完整安装步骤 · 三种形态
---
## 前置条件
| 项 | 要求 | 验证 |
|:---|:---|:---|
| macOS | 13+ | `sw_vers` |
| Node | v22 | `node --version` |
| Git | 2.30+ | `git --version` |
| 网络 | 能访问 192.168.110.101 | `ping -c1 192.168.110.101` |
---
## 安装形态 A远端 NAS公司 13458
### 步骤 1准备目录
```bash
ssh fnvtk@192.168.110.101
mkdir -p /volume1/homes/fnvtk/.persistent-chat-local
cd /volume1/homes/fnvtk/.persistent-chat-local
```
### 步骤 2上传文件
从本地 git 仓库:
```bash
# 本地
scp src/{server.js,hub.js,cursor-title.js} \
web/panel.html \
scripts/{ensure-hub.sh,mongo_sync.py} \
fnvtk@192.168.110.101:/volume1/homes/fnvtk/.persistent-chat-local/
```
### 步骤 3安装依赖
无第三方依赖(纯 Node 22 标准库)。
### 步骤 4启动
```bash
# 远端
ssh fnvtk@192.168.110.101
cd /volume1/homes/fnvtk/.persistent-chat-local
chmod +x ensure-hub.sh
nohup /usr/local/opt/node@22/bin/node hub.js > logs/hub.log 2>&1 &
```
### 步骤 5验证
```bash
curl http://192.168.110.101:13458/api/health
# 期望:{"ok":true,"pid":<X>,"panelVersion":"1.6.37"}
```
---
## 安装形态 B本地备份launchd
### 步骤 1建目录
```bash
mkdir -p ~/.persistent-chat-local
```
### 步骤 2拷文件
```bash
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写 launchd plist
```bash
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
```
### 步骤 4加载
```bash
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.karuo.persistent-chat-hub.plist
```
### 步骤 5验证
```bash
launchctl print gui/$UID/com.karuo.persistent-chat-hub | head -5
curl http://127.0.0.1:13458/api/health
```
---
## 安装形态 CTrae/Cursor MCP 插件
### 步骤 1复制 mcp.json
```bash
# Trae
cp mcp-config/trae.mcp.json ~/.trae/mcp.json
# Cursor
cp mcp-config/cursor.mcp.json ~/Documents/个人/.cursor/mcp.json
```
### 步骤 2完全退出 IDE
- Trae: `Cmd+Q`
- Cursor: `Cmd+Q`
### 步骤 3重开 IDE
### 步骤 4验证
在 Trae / Cursor 看到 `persistent-chat` MCP server 绿色点。
---
## 升级
```bash
# 1. 拉新代码
cd /Users/karuo/Documents/个人/persistent-chat-plugin
git pull
# 2. 备份
cp -r ~/.persistent-chat-local ~/.persistent-chat-local.bak.$(date +%Y%m%d)
# 3. 覆盖核心(不动 data/
cp src/* ~/.persistent-chat-local/
cp web/panel.html ~/.persistent-chat-local/
# 4. 重启 Hub
launchctl bootout gui/$UID/com.karuo.persistent-chat-hub
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.karuo.persistent-chat-hub.plist
# 5. Trae Cmd+Q 重开
```
---
## 卸载
```bash
# 1. 停止 launchd
launchctl bootout gui/$UID/com.karuo.persistent-chat-hub
# 2. 删除文件
rm -rf ~/.persistent-chat-local
rm ~/Library/LaunchAgents/com.karuo.persistent-chat-hub.plist
# 3. 删除 MCP 配置
# Trae: 编辑 ~/.trae/mcp.json 删 persistent-chat 段
# Cursor: 编辑 ~/Documents/个人/.cursor/mcp.json 删 persistent-chat 段
# 4. 远端 NAS
ssh fnvtk@192.168.110.101
pkill -f "node hub.js"
# 不删数据可保留 ~/.persistent-chat-local 目录
```
---
> 最后更新2026-06-26 · 卡若AI

294
docs/MCP_SETUP.md Normal file
View File

@@ -0,0 +1,294 @@
# MCP 配置MCP_SETUP.md
> Trae / Cursor 接入持久对话 MCP 插件的完整配置
---
## 1. Trae CNmacOS
### 配置文件位置
```
~/.trae/mcp.json
```
### 完整配置
```json
{
"mcpServers": {
"persistent-chat": {
"type": "stdio",
"command": "/Users/karuo/.persistent-chat-local/ensure-hub.sh",
"args": [
"--workspace=${workspaceFolder}"
],
"env": {
"PCHAT_HTTP_PORT": "13458",
"PCHAT_NODE": "/usr/local/opt/node@22/bin/node",
"PCHAT_HUB_HOST": "192.168.110.101",
"NO_PROXY": "192.168.110.101,127.0.0.1,localhost"
},
"disabled": false,
"autoApprove": [
"wait_for_user_input",
"init_conversation",
"merge_conversation",
"select_conversation"
]
}
}
}
```
### 关键字段
| 字段 | 值 | 说明 |
|:---|:---|:---|
| `command` | `~/.persistent-chat-local/ensure-hub.sh` | 启动器,桥接 stdio ↔ HTTP |
| `PCHAT_HUB_HOST` | `192.168.110.101` | 远端 NAS IP |
| `PCHAT_HTTP_PORT` | `13458` | Hub 端口 |
| `PCHAT_NODE` | `/usr/local/opt/node@22/bin/node` | Node 22 路径 |
| `NO_PROXY` | `192.168.110.101,127.0.0.1,localhost` | 绕过代理直连 |
| `autoApprove` | 4 个工具全开 | 不弹确认框 |
### 加载步骤
1. 写入 `~/.trae/mcp.json`
2. **Trae 必须 `Cmd+Q` 完全退出**(不是关窗)
3. 重新打开 Trae
4. 看 SOLO Agent 窗口的工具列表 → 出现 `persistent-chat` 4 个工具
### 验证
```bash
# 1. 看 Trae 进程里是否有 server.js
ps aux | grep "persistent-chat-local/server.js" | grep -v grep
# 期望:看到 1 个进程env 含 PCHAT_HUB_HOST=192.168.110.101
# 2. 在 Trae 里发:"开始测试"
# 期望4 工具出现 + 拿到 ct_ 开头的 token
```
---
## 2. Cursor
### 配置文件位置
```
~/Documents/个人/.cursor/mcp.json
```
### 完整配置(与 Trae 相同)
```json
{
"mcpServers": {
"persistent-chat": {
"type": "stdio",
"command": "/Users/karuo/.persistent-chat-local/ensure-hub.sh",
"args": ["--workspace=${workspaceFolder}"],
"env": {
"PCHAT_HTTP_PORT": "13458",
"PCHAT_NODE": "/usr/local/opt/node@22/bin/node",
"PCHAT_HUB_HOST": "192.168.110.101",
"NO_PROXY": "192.168.110.101,127.0.0.1,localhost"
},
"disabled": false,
"autoApprove": [
"wait_for_user_input",
"init_conversation",
"merge_conversation",
"select_conversation"
]
}
}
}
```
### 加载步骤
1. 写入 `~/Documents/个人/.cursor/mcp.json`
2. Cursor → 设置 → MCP → Refresh
3.`persistent-chat` 是否绿色点
4. 面板访问Ctrl+L → 输入 `/mcp`
---
## 3. 多 IDE 共存
### 场景
- 同时开 Trae 和 Cursor都想用持久对话
- 共享同一个 Hub远端 NAS
### 配置要点
**两边的 mcp.json 保持一致**,都指向同一个 Hub
```json
"PCHAT_HUB_HOST": "192.168.110.101"
```
**垂直绑定隔离**
- 不同工作区 → 不同 session
- 不同 Cursor 标签 → 不同 session
- 同工作区 + 同标签 → 复用 session
**冲突场景**
- Trae 标签 = "学习" + Cursor 标签 = "学习" → 互窜(不推荐)
- 建议Trae 用 "Trae_xxx"Cursor 用 "Cursor_xxx"
---
## 4. 双 Hub 配置(远端 + 本地)
### 场景
- 远端 NAS 24×7 在
- 本地 launchd 守护备份
- 远端挂时自动 fallback
### 方案:脚本切换
**ensure-hub.sh 增强版**(可加 fallback
```bash
#!/bin/bash
# /Users/karuo/.persistent-chat-local/ensure-hub.sh
HUB_HOST="${PCHAT_HUB_HOST:-127.0.0.1}"
# 测试主 Hub
if ! curl -sf "http://${HUB_HOST}:13458/api/health" -m 2 > /dev/null; then
# 失败fallback 到本地
HUB_HOST="127.0.0.1"
fi
export PCHAT_HUB_HOST="$HUB_HOST"
exec /usr/local/opt/node@22/bin/node \
/Users/karuo/.persistent-chat-local/server.js \
--workspace="${1#--workspace=}"
```
这样远端挂时自动回退到本地launchd 守护一直跑)。
---
## 5. 工具参数详解
### 5.1 init_conversation
```typescript
{
token?: string; // 已有 tokenmerge 用)
cursorTitle: string; // 必填Cursor 标签
newPlan?: boolean; // true=换计划,归档旧 ct_
planLabel?: string; // 计划名newPlan 时必填)
workspace?: string; // 工作区路径
}
```
**返回**
```json
{
"Conversation initialized. pchat-token: ct_xxxx"
"🆕 新计划线程ct_xxxx"
"[BINDING_AUTO_NEW] 新对话已自动绑定"
}
```
### 5.2 select_conversation
```typescript
{
token: string; // 必填:要复用的 ct_
cursorTitle: string; // 必填:当前 Cursor 标签
}
```
**返回**
```json
{
"[BINDING_REUSE]"
"🔄 恢复对话: ct_xxxx"
}
```
### 5.3 wait_for_user_input
```typescript
{
token: string; // 必填
message: string; // 提示用户的话
timeout?: number; // 最长等多久ms默认 60000
renewalOnly?: boolean; // true=只续约不等消息
}
```
**返回**
```json
{
"<用户发的消息 或 '保活续跑' 默认文本>"
"[pchat-token: ct_xxxx]"
"校验#N"
}
```
### 5.4 merge_conversation
```typescript
{
fromToken: string; // 源 token
toToken: string; // 目标 token
cursorTitle: string; // 当前标签
}
```
**用途**:把两个 plan 的上下文合并。
---
## 6. 完整对话循环示例
```javascript
// 1. 起新计划
const init = await mcp.call('init_conversation', {
cursorTitle: '持久对话永久续跑-20260626',
newPlan: true,
planLabel: '永久续跑三段式',
});
const token = extractToken(init); // ct_xxxx
// 2. 干活(可任意调用其他工具)
// ...
// 3. 真挂起等用户
const reply = await mcp.call('wait_for_user_input', {
token,
message: '【真挂起】请发任务或"继续"',
timeout: 1800000, // 30 分钟
});
// 收到用户消息 → reply.text
// 4. 复用旧 session
await mcp.call('select_conversation', {
token,
cursorTitle: '持久对话永久续跑-20260626',
});
// 5. 循环到用户说"结束持久对话"
```
---
## 7. 常见配置错误
| 错误 | 现象 | 修复 |
|:---|:---|:---|
| `PCHAT_NODE` 路径错 | `node not found` | `which node` 改 |
| `PCHAT_HUB_HOST` 用 0.0.0.0 | 端口冲突 | 改成具体 IP |
| `NO_PROXY` 缺 | 代理拦截 | 加 `192.168.110.101` |
| `autoApprove` 缺 | 每次弹窗 | 加 4 个工具名 |
| Trae 没重启 | MCP 不加载 | `Cmd+Q` 退出 |
| Cursor 没 refresh | 看不到 | 设置 → MCP → Refresh |
---
> 最后更新2026-06-26 · 卡若AI

161
docs/QUICKSTART.md Normal file
View File

@@ -0,0 +1,161 @@
# 5 分钟上手QUICKSTART.md
> 假设你的工作环境是 macOS + Trae CN + 公司 NAS192.168.110.101
> 跟着抄5 分钟内跑起来。
---
## Step 1 · 装到本地30s
```bash
mkdir -p ~/.persistent-chat-local
# 从仓库拷核心文件
git clone http://192.168.110.101:3000/fnvtk/persistent-chat-plugin.git /tmp/pchat
cp /tmp/pchat/src/* ~/.persistent-chat-local/
cp /tmp/pchat/web/panel.html ~/.persistent-chat-local/
cp /tmp/pchat/scripts/ensure-hub.sh ~/.persistent-chat-local/
chmod +x ~/.persistent-chat-local/ensure-hub.sh
```
## Step 2 · 写 MCP 配置30s
```bash
cat > ~/.trae/mcp.json <<'EOF'
{
"mcpServers": {
"persistent-chat": {
"type": "stdio",
"command": "/Users/karuo/.persistent-chat-local/ensure-hub.sh",
"args": ["--workspace=${workspaceFolder}"],
"env": {
"PCHAT_HTTP_PORT": "13458",
"PCHAT_NODE": "/usr/local/opt/node@22/bin/node",
"PCHAT_HUB_HOST": "192.168.110.101",
"NO_PROXY": "192.168.110.101,127.0.0.1,localhost"
},
"disabled": false,
"autoApprove": [
"wait_for_user_input",
"init_conversation",
"merge_conversation",
"select_conversation"
]
}
}
}
EOF
```
## Step 3 · 配 Hub远端 NAS已有则跳过
在 NAS 上ssh fnvtk@192.168.110.101
```bash
mkdir -p /volume1/homes/fnvtk/.persistent-chat-local
cd /volume1/homes/fnvtk/.persistent-chat-local
# scp 把 src/* + web/panel.html 拷过来
chmod +x ensure-hub.sh
# 启动
nohup /usr/local/opt/node@22/bin/node hub.js > logs/hub.log 2>&1 &
disown
```
## Step 4 · 配本地备份 Hub30s
```bash
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
launchctl bootstrap gui/$UID ~/Library/LaunchAgents/com.karuo.persistent-chat-hub.plist
```
## Step 5 · Trae Cmd+Q 重开10s
完全退出 Trae不是关窗重开。
## Step 6 · 验证30s
打开 Trae → SOLO Agent 窗口 → 看到 4 个工具:
```
✓ init_conversation
✓ select_conversation
✓ wait_for_user_input
✓ merge_conversation
```
发:"**开始测试**"
期望:
1. 看到 `init_conversation` 调出
2. 拿到 `ct_xxxx` 的 token
3. 收到 [卡若复盘] 格式回复
4. Agent 继续 wait
## Step 7 · 跑三段式(持续)
每次用户发新消息:
```
1. select_conversation(token=ct_xxx) ← 接回旧 session
2. 执行用户任务
3. 写 [卡若复盘] 🎯📌💡📝▶
4. wait_for_user_input(token=ct_xxx, message=提示)
5. 循环
```
## Step 8 · 结束(仅在用户说"结束持久对话"时)
```javascript
// 用户说"结束持久对话"后
await mcp.call('merge_conversation', {
fromToken: 'ct_xxx',
toToken: 'ct_归档', // 或留空 = 纯归档
cursorTitle: '当前标签',
});
```
---
## 🎉 完成
你现在有:
- ✅ 远端 NAS Hub 24×7 在
- ✅ 本地备份 Hub挂了自动起
- ✅ Trae 插件 4 工具全可用
- ✅ 持久对话循环(不主动结束)
---
## 🆘 卡住看这里
| 现象 | 一行修 |
|:---|:---|
| Trae 看不到 4 工具 | `Cmd+Q` 重开 |
| Hub 启动失败 | `node hub.js` 前台跑看错 |
| 提示 Token未获取 | Trae 没重启 |
| 任务完成 = 对话死 | 不是Hub 仍 holding下一条进来自动续 |
| wait 不返回 | 真挂起模式生效,等你发消息 |
---
> 详细见 [DEPLOY.md](DEPLOY.md) / [MCP_SETUP.md](MCP_SETUP.md) / [ARCHITECTURE.md](ARCHITECTURE.md)