# 架构(ARCHITECTURE.md) > 持久对话 MCP 插件的完整技术架构 --- ## 1. 整体拓扑 ``` ┌────────────────────┐ │ Trae / Cursor │ IDE(SOLO 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 创建 session(ct_xxx) → 写入 sessions.json → 写 binding:workspace::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}` ``` 示例(默认公示用主链 IP): ``` /Users/karuo/Documents/个人::持久对话永久续跑-20260626@192.168.110.101 ``` ### 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 server(41KB) ├── 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.110.101", "hostIp": "192.168.110.101", "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 内存 | ~50MB(1000 个 session) | | Hub CPU | < 1%(空闲) | | 单 session 占内存 | ~5KB(仅 metadata) | | 单消息占内存 | ~1KB | | 短轮询带宽 | ~1KB/10s/session | | 启动时间 | < 1s(Node 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