feat: 根目录 AI 安装指引 AGENTS.md + install.sh 一键安装

AI 先读 AGENTS.md 自主完成安装/排错;install.sh 同步 Hub、部署 MCP、冒烟验收。
修复 sync_pchat_runtime 使用本仓库 lib/src/web 结构。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
卡若AI
2026-06-29 18:00:46 +08:00
parent 7bb771e9bc
commit ec540f6625
5 changed files with 328 additions and 163 deletions

168
AGENTS.md Normal file
View File

@@ -0,0 +1,168 @@
# AGENTS.md · Persistent Chat 插件
> **AI 第一入口**:收到「安装 pchat / Persistent Chat / 持久对话」类任务时,**先读本文件**再按步骤自主执行无需用户逐步确认sudo/W2 除外需用户输密码)。
**Gitea**http://192.168.110.101:3000/fnvtk/persistent-chat-plugin
**一键安装**`bash install.sh [工作区绝对路径]`
---
## 0. AI 必读顺序
| 顺序 | 文件 | 何时读 |
|:---:|:---|:---|
| 1 | **本文件 `AGENTS.md`** | 每次安装/排错起手 |
| 2 | `install.sh` | 执行一键安装 |
| 3 | `docs/prd/PersistentChat_经验汇总.md` | 某步失败时查现象→解法 |
| 4 | `docs/prd/PersistentChat_模块说明.md` | 需理解 API/架构时 |
| 5 | `docs/prd/PersistentChat_整合CO-Chat_需求PRD_v1.md` | 需求边界争议时 |
**禁止**:同时加载 `co-chat.mdc` + `persistent-chat.mdc`;禁止调用 `reset-cursor-env --quit-cursor` 强杀 Cursor。
---
## 1. 产品一句话
**Persistent Chatpchat** = VSIX + Hub `:13458` + MCP 4 工具(`init/select/wait/merge`)。模式 A 无限续跑(`wait_for_user_input`);模式 B Composer 增强(无 CO 卡密,`patchNativeOk`)。
---
## 2. 自主安装协议AI 逐步执行)
### Step 0 · 克隆(若未克隆)
```bash
git clone http://192.168.110.101:3000/fnvtk/persistent-chat-plugin.git
cd persistent-chat-plugin
```
### Step 1 · 一键安装
```bash
bash install.sh "/path/to/workspace"
```
**通过标准**:脚本末尾 `冒烟 fail=0``curl -sf http://127.0.0.1:13458/api/health`
### Step 2 · 验证AI 必须跑)
```bash
bash scripts/co-integration/pchat_smoke_test.sh
curl -sf http://127.0.0.1:13458/api/mode/check | python3 -m json.tool # conflict: false
curl -sf http://127.0.0.1:13458/api/enhance/diagnose | python3 -m json.tool # gatesPass: true
curl -sf http://127.0.0.1:13458/api/prd/progress | python3 -c "import sys,json; d=json.load(sys.stdin); assert d['percent']==100"
```
任一项失败 → 跳 **§4 排错**,修完从 Step 1 重跑 `sync` 或对应脚本。
### Step 3 · 增强向导gatesPass 为 false 时)
1. 打开 http://127.0.0.1:13458/enhance
2. **W2** 修权限(需用户 sudo 密码)
3. **W6** 修 Cursor 前置
4. 打开 **核心增强包 Toggle**
5.**① 诊断** → W8 应 **✅ 原生OK**
6. 再跑 Step 2 验证
### Step 4 · 告知用户
安装完成后 **必须** 提示:`Cmd+Q 完全退出 Cursor → 重开`MCP 配置生效)。
### Step 5 · VSIX若用户尚未安装
VSIX 不在本仓库需用户手动Cursor → Install from VSIX → `persistent-chat-4.6.0-4tools.vsix`。装完后重跑 Step 1。
---
## 3. 仓库根目录地图
```
persistent-chat-plugin/
├── AGENTS.md ← AI 读本文件(你在这里)
├── install.sh ← 人类/AI 一键安装
├── README.md ← 人类概览
├── cursor-config/ ← MCP + rules 真源 → deploy-cursor-config.sh
├── src/ hub.js · server.jsMCP
├── lib/ enhance · bridge · smoke · retire
├── web/ panel.html · panel-enhance.html
├── vendor/ cochat-engine 3.3.34
├── scripts/
│ ├── ensure-hub.sh MCP 启动器
│ └── co-integration/ 冒烟 · sync · retire 脚本
├── mcp-config/ MCP JSON 模板
└── docs/prd/ PRD · 经验 · 模块说明
```
**运行时目录**install 写入):`~/.persistent-chat-local/`
---
## 4. 排错决策树AI 自主修复)
| 现象 | 检测命令 | 修复动作 |
|:---|:---|:---|
| Hub 不通 | `curl :13458/api/health` | `bash scripts/co-integration/sync_pchat_runtime.sh` |
| 冒烟 fail | `bash scripts/co-integration/pchat_smoke_test.sh` | 看失败项;通常 Hub 未起或 lib 未同步 |
| MCP duplicate / Loading | Cursor Settings | 确认 `~/.cursor/mcp.json``{}`;项目级仅 persistent-chat+codegraph`bash cursor-config/deploy-cursor-config.sh "$WS"`Cmd+Q |
| conflict: true | `/api/mode/check` | `bash scripts/co-integration/pchat_retire_co_rule.sh "$WS"` |
| permOk false | `/api/enhance/diagnose` | Hub /enhance → W2`vendor/cochat-engine/scripts/cochat_fix_write_permission.sh` |
| Toggle 打不开 | diagnose | 先 W2+W6读经验汇总 §1.5 |
| W8 待重启 | diagnose | 点「诊断」→ patchNativeOk读经验汇总 §1.1 |
| co-chat 扩展仍在 | `ls ~/.cursor/extensions/co-chat*` | `bash scripts/co-integration/retire_cochat.sh`(需 gatesPass |
| patchOk false 但 patchNativeOk true | 正常 | **非阻塞**;增强包可用 |
| codegraph Error | 路径是否存在 | 检查 `cursor-config/mcp.project.json` 内 codegraph 脚本路径;或暂时 disabled |
详细根因:`docs/prd/PersistentChat_经验汇总.md`
---
## 5. MCP 配置真源(唯一一套)
| 层级 | 路径 | 内容 |
|:---|:---|:---|
| 项目 | `<workspace>/.cursor/mcp.json` | persistent-chatensure-hub+ codegraph |
| 用户 | `~/.cursor/mcp.json` | **`{}` 空**(防双载) |
| 规则 A | `.cursor/rules/persistent-chat.mdc` | wait 续跑 |
| 规则 B | `.cursor/rules/pchat-composer.mdc` | Composer 增强 |
部署:`bash cursor-config/deploy-cursor-config.sh "/path/to/workspace"`
**MCP 4 工具**`init_conversation` · `select_conversation` · `wait_for_user_input` · `merge_conversation`
---
## 6. Hub API 速查
| API | 用途 |
|:---|:---|
| `GET /api/health` | Hub 存活 |
| `GET /api/enhance/diagnose` | 三门禁 + gatesPass |
| `GET /api/enhance/status` | composer-enhance.json |
| `POST /api/smoke/run` | 9 项自动化验收 |
| `GET /api/mode/check` | 规则互斥 |
| `GET /api/prd/progress` | PRD 100% 进度 |
| `GET /enhance` | 增强向导 UI |
---
## 7. AI 执行铁律
1. **先跑命令再下结论** — 用 §2 Step 2 验证,不要猜状态
2. **失败查经验汇总** — 不要发明新解法
3. **只保留一套 MCP** — 禁止 co-mcp + persistent-chat 并存
4. **不强杀 Cursor** — W7 排队,用户手动 Cmd+Q
5. **W8 以 patchNativeOk 为准** — patchOk 可选
6. **安装完 push 不必** — 除非用户要求改仓库
7. **中文回复用户** — 步骤清晰、带验证结果
---
## 8. 验收完成标准100%
- [ ] `install.sh` 成功 + 冒烟 fail=0
- [ ] `/api/mode/check` → conflict: false
- [ ] `/api/enhance/diagnose` → gatesPass: true
- [ ] `/api/prd/progress` → percent: 100
- [ ] 用户已 Cmd+Q 重启 Cursor
全部满足 → 向用户报告「安装完成,可开 ct_ 续跑 + /enhance 增强」。

197
README.md
View File

@@ -1,169 +1,74 @@
# Cursor/Trae 持久对话 MCP 插件 v1.6.37
# Persistent Chat · 持久对话 MCP 插件
> **垂直绑定 · 真挂起 · 永不断开**
> 一个让 Cursor / Trae / VSCode 与 Agent 之间实现"可持续对话"的 MCP 插件。
> **AI 安装**:先读 **[AGENTS.md](AGENTS.md)** → 执行 **`bash install.sh [工作区路径]`**
> **人类安装**:同上,或看 `docs/prd/PersistentChat_安装说明.md`
[![Gitea](https://img.shields.io/badge/Gitea-fnvtK%2Fpersistent--chat--plugin-blue)](http://192.168.110.101:3000/fnvtk/persistent-chat-plugin)
[![Version](https://img.shields.io/badge/Version-v1.1--CO--integration-green)](#)
[![MCP](https://img.shields.io/badge/MCP-4--tools-orange)](#)
[![Hub](https://img.shields.io/badge/Hub-192.168.110.101%3A13458-purple)](#)
[![Gitea](https://img.shields.io/badge/Gitea-persistent--chat--plugin-blue)](http://192.168.110.101:3000/fnvtk/persistent-chat-plugin)
[![Version](https://img.shields.io/badge/Version-v1.1--CO-green)](#)
[![Hub](https://img.shields.io/badge/Hub-13458-purple)](#)
---
## 🎯 一句话描述
## 快速开始
普通 MCP 调一次就结束对话;本插件用 **4 个工具 + Hub 长连接**,让 agent 与用户的对话**永不中断**,适合长跑学习清单 / 跨天多计划 / 自动续跑任务。
```bash
git clone http://192.168.110.101:3000/fnvtk/persistent-chat-plugin.git
cd persistent-chat-plugin
bash install.sh /path/to/your/workspace
# Cmd+Q 重启 Cursor
```
| 入口 | URL |
|:---|:---|
| Hub 面板 | http://127.0.0.1:13458 |
| 增强向导 | http://127.0.0.1:13458/enhance |
---
## 📦 仓库内容
## 根目录指引AI / 人类)
| 文件 | 用途 |
|:---|:---|
| **[AGENTS.md](AGENTS.md)** | **AI 第一入口**:完整安装协议 + 排错决策树 |
| **[install.sh](install.sh)** | 一键安装 Hub + Cursor 配置 + 冒烟 |
| [cursor-config/](cursor-config/) | MCP / rules 真源 |
| [docs/prd/](docs/prd/) | PRD · 经验 · 模块说明 |
---
## 仓库结构
```
persistent-chat-plugin/
├── lib/ # CO-Chat 整合模块enhance/bridge/smoke/retire
├── vendor/ # cochat-engine 3.3.34(无卡密补丁引擎)
├── docs/prd/ # PRD + 安装说明 + 经验汇总 + 模块说明
├── scripts/co-integration/ # 冒烟 / 同步 / 退役脚本
│ ├── server.js (42KB) # MCP Server 端4 个工具入口
│ ├── hub.js (89KB) # Hub 主服务HTTP + WebSocket
│ └── cursor-title.js (4KB) # Cursor 标题解析器
── web/ # 持久对话面板(浏览器 UI
│ ├── panel.html (84KB) # 主面板 v1.6.37
│ ├── panel.remote.html # 远端 NAS 面板panel_remote_v1637
│ └── panel.html.local # 本地备份面板
├── scripts/ # 部署与运维脚本
│ ├── ensure-hub.sh # 启动器MCP stdio → http
│ ├── mongo_sync.py # 会话 → MongoDB 同步
│ └── (deploy scripts...)
├── mcp-config/ # MCP 配置模板
│ ├── trae.mcp.json # Trae CN 配法
│ └── cursor.mcp.json # Cursor 配法
├── docs/ # 完整文档
│ ├── INSTALL.md # 安装
│ ├── DEPLOY.md # 部署
│ ├── MCP_SETUP.md # MCP 配置
│ ├── ARCHITECTURE.md # 架构
│ └── QUICKSTART.md # 5 分钟上手
├── Cursor持久对话-安装包-v1.6.37_20260607.zip # 原始安装包(备查)
└── README.md # 本文件
├── AGENTS.md # AI 必读安装指引
├── install.sh # 一键安装
├── cursor-config/ # MCP + rules → deploy-cursor-config.sh
├── src/ # hub.js · server.js · cursor-title.js
├── lib/ # enhance · bridge · smoke · retire
├── web/ # panel.html · panel-enhance.html
├── vendor/ # cochat-engine 3.3.34
├── scripts/ # ensure-hub.sh · co-integration/
├── mcp-config/ # MCP JSON 模板
── docs/ # 架构 · 部署 · PRD
```
---
## ⚡ 三种部署形态
## MCP 工具4 个)
| 形态 | 端口 | 适用 | 关键 |
|:---|:---|:---|:---|
| **本地备份** | 127.0.0.1:13458 | 单机 | launchd 守护,挂了自动起 |
| **远端 NAS** | 192.168.110.101:13458 | 多人 / 跨机 | Node 守护,跨网段访问 |
| **Trae 插件** | MCP stdio | 与 IDE 集成 | ensure-hub.sh 起 4 工具 |
可同时跑,三者共享同一 Hub 协议。
---
## 🔧 MCP 工具
| # | 工具 | 用途 |
|:---:|:---|:---|
| 1 | `init_conversation` | 起新 session支持 `newPlan:true` 换计划) |
| 2 | `select_conversation` | 复用旧 session垂直绑定校验 |
| 3 | `wait_for_user_input` | 真挂起,等用户下一条 |
| 4 | `merge_conversation` | 合流两个 session 的上下文 |
| 5 | `quota_status` | 读取本地限额状态与阈值预警 |
| 6 | `prepare_continuity_handoff` | 生成续接摘要,保护连续线 |
**核心机制**Hub 把 session 存在内存 + 周期 savetoken (`ct_xxx`) 垂直绑定到「工作区 + Cursor 标签 + IP」三件指纹。
## 🛡 合法增强
- 本地 `quota-status.json` 可作为限额状态输入源
- 到阈值时只做预警和续接摘要,不自动重置
- 面板会提示先调用 `prepare_continuity_handoff`
---
## 🚀 5 分钟上手
```bash
# 1. 克隆
git clone http://192.168.110.101:3000/fnvtk/persistent-chat-plugin.git
cd persistent-chat-plugin
# 2. 部署到 ~/.persistent-chat-local
mkdir -p ~/.persistent-chat-local
cp src/* scripts/ensure-hub.sh ~/.persistent-chat-local/
cp web/panel.html ~/.persistent-chat-local/panel.html
# 3. 编辑 mcp.json填到 Trae/Cursor
cat mcp-config/trae.mcp.json
# 复制内容到 ~/.trae/mcp.json
# 4. Trae Cmd+Q 退出重开,让 MCP 重新加载
# 5. 在 SOLO Agent 窗口发"开始测试"或"继续"
```
详细见 [QUICKSTART.md](docs/QUICKSTART.md)。
---
## 🔒 垂直绑定
每个 session 用「工作区::Cursor 标签 @ IP」做绑定指纹
```
/Users/karuo/Documents/个人::持久对话永久续跑-20260626@192.168.110.101
```
换工作区 / 换标签 / 换 IP 都不会复用 session避免串台。
---
## 📊 核心指标
| 指标 | 值 |
| 工具 | 用途 |
|:---|:---|
| Hub 进程 | Node 22 (`/usr/local/opt/node@22/bin/node`) |
| 端口 | 13458 |
| 协议 | HTTP + 短轮询10s 续约) |
| 保活档 | 10s / 30s / 60s / 2min / 4min / 9min / 15min / 30min |
| 校验频率 | 每次 wait 触发一次 |
| 单 session 容量 | 无限制(内存 + JSON 周期 save |
| `init_conversation` | 新建 ct_ 会话 |
| `select_conversation` | 恢复会话 |
| `wait_for_user_input` | 真挂起续跑 |
| `merge_conversation` | 合流上下文 |
---
## 🆘 常见问题
## 链接
**Q: 提示"Token未获取, 未登录"**
A: Trae 需 `Cmd+Q` 完全退出重开,让 MCP 配置生效。
- **Gitea**http://192.168.110.101:3000/fnvtk/persistent-chat-plugin
- **PRD**`docs/prd/PersistentChat_整合CO-Chat_需求PRD_v1.md`
- **排错**`docs/prd/PersistentChat_经验汇总.md`
**Q: "任务完成" 是不是对话死了?**
A: 不是。Hub 上 session 仍 holding等用户下一条自动续跑。可在 http://192.168.110.101:13458/ 看到。
**Q: 如何真正关掉对话?**
A: 在对话里说"结束持久对话"agent 会主动 merge。
---
## 📜 许可证
私有项目 · 仅公司内部使用 © 2026 卡若AI
---
## 🔗 相关链接
- **默认主链**`http://192.168.110.101:13458/`
- **Gitea 仓库**http://192.168.110.101:3000/fnvtk/persistent-chat-plugin
- **增强向导**http://127.0.0.1:13458/enhance
- **PRD 真源**`docs/prd/PersistentChat_整合CO-Chat_需求PRD_v1.md`
- **远端主链面板**http://192.168.110.101:13458/
- **本地兜底面板**http://127.0.0.1:13458/
- **Trae 配置**`~/.trae/mcp.json`
- **Cursor 配置**`~/Documents/个人/.cursor/mcp.json`
私有项目 © 2026 卡若AI

View File

@@ -2,12 +2,26 @@
# 将 Gitea 仓库内 cursor-config 部署到本机 Cursorco-chat → pchat 唯一套)
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
WS="${1:-/Users/karuo/Documents/个人}"
WS="${1:-$PWD}"
echo "=== deploy cursor-config → $WS ==="
mkdir -p "$WS/.cursor/rules/_retired"
cp -f "$ROOT/cursor-config/mcp.project.json" "$WS/.cursor/mcp.json"
mkdir -p "$WS/.cursor/rules/_retired" "$WS/.cursor"
python3 -c "
import json, pathlib
src=pathlib.Path('$ROOT/cursor-config/mcp.project.json')
dst=pathlib.Path('$WS/.cursor/mcp.json')
data=json.loads(src.read_text())
pc=data.get('mcpServers',{}).get('persistent-chat',{})
if pc:
args=pc.get('args') or []
if args: args[0]='--workspace=$WS'
env=pc.get('env') or {}
env['PCHAT_WORKSPACE']='$WS'
pc['env']=env
pc['args']=args
dst.write_text(json.dumps(data, indent=2, ensure_ascii=False)+'\n')
"
cp -f "$ROOT/cursor-config/mcp.user.json" "$HOME/.cursor/mcp.json"
cp -f "$ROOT/cursor-config/rules/persistent-chat.mdc" "$WS/.cursor/rules/persistent-chat.mdc"
cp -f "$ROOT/cursor-config/rules/pchat-composer.mdc" "$WS/.cursor/rules/pchat-composer.mdc"
@@ -17,7 +31,6 @@ if [[ -f "$WS/.cursor/rules/co-chat.mdc" ]]; then
echo "co-chat.mdc → _retired"
fi
bash "$ROOT/scripts/co-integration/sync_pchat_runtime.sh" 2>/dev/null || \
bash "$WS/开发文档/脚本/sync_pchat_runtime.sh" 2>/dev/null || true
bash "$ROOT/scripts/co-integration/sync_pchat_runtime.sh"
echo "完成。请 Cmd+Q 重启 Cursor。"

76
install.sh Executable file
View File

@@ -0,0 +1,76 @@
#!/usr/bin/env bash
# Persistent Chat 一键安装Gitea 仓库根目录)
# 用法: bash install.sh [工作区路径]
set -euo pipefail
REPO="$(cd "$(dirname "$0")" && pwd)"
WS="${1:-$PWD}"
HUB="${PCHAT_HUB_URL:-http://127.0.0.1:13458}"
echo "╔══════════════════════════════════════════╗"
echo "║ Persistent Chat · 一键安装 ║"
echo "╚══════════════════════════════════════════╝"
echo "仓库: $REPO"
echo "工作区: $WS"
echo ""
# Phase 0: 前置
if ! command -v node >/dev/null 2>&1; then
echo "❌ 需要 Node.js 18+"; exit 1
fi
if [[ "$(uname)" != "Darwin" ]]; then
echo "⚠️ 当前脚本针对 macOS 优化;其他系统部分步骤需人工调整"
fi
# Phase 1: 运行时 Hub
echo "▶ [1/5] 同步 Hub 到 ~/.persistent-chat-local …"
bash "$REPO/scripts/co-integration/sync_pchat_runtime.sh"
# Phase 2: Cursor MCP + rules
echo "▶ [2/5] 部署 Cursor 配置pchat 唯一套)…"
bash "$REPO/cursor-config/deploy-cursor-config.sh" "$WS"
# Phase 3: 退役 co-chat 规则(扩展若存在则提示)
if ls "$HOME/.cursor/extensions"/co-chat.co-chat-panel-* >/dev/null 2>&1; then
echo "▶ [3/5] 检测到 co-chat 扩展,执行退役 …"
if [[ -f "$REPO/scripts/co-integration/retire_cochat.sh" ]]; then
bash "$REPO/scripts/co-integration/retire_cochat.sh" || echo "⚠️ 退役需 W2/W6/W8 门禁;可稍后在 Hub /enhance 完成后再跑"
fi
else
echo "▶ [3/5] co-chat 扩展未安装,跳过退役"
bash "$REPO/scripts/co-integration/pchat_retire_co_rule.sh" "$WS" 2>/dev/null || true
fi
# Phase 4: 冒烟
echo "▶ [4/5] 冒烟测试 …"
export PCHAT_HUB_URL="$HUB"
if bash "$REPO/scripts/co-integration/pchat_smoke_test.sh"; then
echo "✅ 冒烟 fail=0"
else
echo "❌ 冒烟失败AI 请读 AGENTS.md §排错"
exit 1
fi
# Phase 5: 增强门禁摘要
echo "▶ [5/5] 增强门禁 …"
curl -sf "$HUB/api/enhance/diagnose" 2>/dev/null | python3 -c "
import sys, json
try:
j=json.load(sys.stdin)
r=j.get('report',j)
s=r.get('state',{})
gp=r.get('gatesPass', False)
print(f' gatesPass={gp} permOk={s.get(\"permOk\")} cursorPrefOk={s.get(\"cursorPrefOk\")} patchNativeOk={s.get(\"patchNativeOk\")}')
if not gp:
print(' → 打开 $HUB/enhance 完成 W2/W6 并开启增强包,点「诊断」')
except Exception as e:
print(' (diagnose 暂不可用)', e)
" || true
echo ""
echo "══════════════════════════════════════════"
echo "✅ 安装完成"
echo " Hub: $HUB"
echo " 增强: $HUB/enhance"
echo " 下一步: Cmd+Q 重启 Cursor → 新建 Chat 测 wait 续跑"
echo " AI指引: 读本仓库 AGENTS.md"
echo "══════════════════════════════════════════"

27
scripts/co-integration/sync_pchat_runtime.sh Normal file → Executable file
View File

@@ -1,25 +1,28 @@
#!/usr/bin/env bash
# 将 .persistent-chat-v1.1/lib 同步到 ~/.persistent-chat-local/lib 并重启 Hub
# 将本仓库源码同步到 ~/.persistent-chat-local 并重启 Hub
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
REPO="$(cd "$(dirname "$0")/../.." && pwd)"
DST="$HOME/.persistent-chat-local"
SRC_LIB="$ROOT/.persistent-chat-v1.1/lib"
PORT="${PCHAT_HTTP_PORT:-13458}"
NODE="${PCHAT_NODE:-$(command -v node)}"
mkdir -p "$DST/lib"
rsync -a --delete "$SRC_LIB/" "$DST/lib/"
cp -f "$ROOT/.persistent-chat-v1.1/panel.html" "$DST/panel-enhance.html" 2>/dev/null || true
# hub.js 需已 patch 引入 lib/hub-routes-prd.js
if ! grep -q 'hub-routes-prd' "$DST/hub.js" 2>/dev/null; then
echo "WARN: hub.js 尚未引入 hub-routes-prd请手动 patch 或更新 hub.js"
fi
mkdir -p "$DST/lib" "$DST/logs"
rsync -a --delete "$REPO/lib/" "$DST/lib/"
cp -f "$REPO/src/hub.js" "$DST/hub.js"
cp -f "$REPO/src/server.js" "$DST/server.js"
cp -f "$REPO/src/cursor-title.js" "$DST/cursor-title.js" 2>/dev/null || true
cp -f "$REPO/scripts/ensure-hub.sh" "$DST/ensure-hub.sh"
cp -f "$REPO/scripts/mongo_sync.py" "$DST/mongo_sync.py" 2>/dev/null || true
cp -f "$REPO/web/panel.html" "$DST/panel.html"
cp -f "$REPO/web/panel-enhance.html" "$DST/panel-enhance.html" 2>/dev/null || \
cp -f "$REPO/web/panel.html" "$DST/panel-enhance.html"
chmod +x "$DST/ensure-hub.sh" 2>/dev/null || true
if lsof -ti ":$PORT" >/dev/null 2>&1; then
lsof -ti ":$PORT" | xargs kill 2>/dev/null || true
sleep 1
fi
nohup "${PCHAT_NODE:-node}" "$DST/hub.js" >> "$DST/logs/hub.stdout.log" 2>&1 &
nohup "$NODE" "$DST/hub.js" >> "$DST/logs/hub.stdout.log" 2>&1 &
for i in $(seq 1 40); do
curl -sf -m 2 "http://127.0.0.1:$PORT/api/health" >/dev/null && break
sleep 0.2