diff --git a/.claude/skills/portal-release/SKILL.md b/.claude/skills/portal-release/SKILL.md index aefb343..8b8e0ec 100644 --- a/.claude/skills/portal-release/SKILL.md +++ b/.claude/skills/portal-release/SKILL.md @@ -5,7 +5,7 @@ description: Package, deploy, verify, and roll back the Memind Portal runtime on # Portal 生产发布 / 验证 / 回滚 -103(`john@180.159.29.143`)是唯一生产 Portal 主机。这个 skill 是打包、发布、验证、回滚的**唯一入口**——不要现场发明新流程,不要直接 SSH 到 103 手改代码或手写文件到 `MindSpace/`。 +103(`john@114.85.107.50`)是唯一生产 Portal 主机。这个 skill 是打包、发布、验证、回滚的**唯一入口**——不要现场发明新流程,不要直接 SSH 到 103 手改代码或手写文件到 `MindSpace/`。 ## 0. 发布前置检查(必须) @@ -96,7 +96,7 @@ curl -k -i https://m.tkmind.cn/auth/login \ ### 3.2 Portal + 九个 goosed 实例(SSH 103) ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' printf "portal="; curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/api/status for p in $(seq 18006 18014); do printf "goosed_${p}=" @@ -113,7 +113,7 @@ ssh john@180.159.29.143 ' ### 3.3 日志关键词检查(SSH 103) ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' tail -200 ~/Library/Logs/memind-portal.log | egrep "User auth bootstrap failed|ER_PARSE_ERROR|Cannot find package|Failed to add extension|No such file|Unknown extension|Provider not set|not configured" || echo "no error keywords found" ' @@ -164,7 +164,7 @@ bash scripts/release-portal-runtime-prod.sh --skip-tests --yes **紧急方式**(本地仓库回不去、必须直接用远端备份时): ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' launchctl bootout gui/$(id -u)/cn.tkmind.memind-portal 2>/dev/null || true lsof -tiTCP:8081 -sTCP:LISTEN | xargs kill 2>/dev/null || true mv /Users/john/Project/Memind /Users/john/Project/Memind-bad-release-$(date +%s) diff --git a/docs/103-105-upgrade-runbook-2026-06-26.md b/docs/103-105-upgrade-runbook-2026-06-26.md index 39d5a45..7238855 100644 --- a/docs/103-105-upgrade-runbook-2026-06-26.md +++ b/docs/103-105-upgrade-runbook-2026-06-26.md @@ -15,7 +15,7 @@ ### 103 -- 主机:`john@180.159.29.143` +- 主机:`john@114.85.107.50` - 主运行根目录:`/Users/john/Project` - 当前业务目录: - `/Users/john/Project/Memind` diff --git a/docs/103-h5-rich-page-rollout-runbook-20260707.md b/docs/103-h5-rich-page-rollout-runbook-20260707.md index afd56ee..0cfb983 100644 --- a/docs/103-h5-rich-page-rollout-runbook-20260707.md +++ b/docs/103-h5-rich-page-rollout-runbook-20260707.md @@ -15,7 +15,7 @@ - Portal release: `20260707-154245-ea4c6b7` - Git commit: `ea4c6b707c2a95c5c63eed4ed5dc02f8a6f786bc` - Branch used for release: `release/rich-page-router-0707` -- Production host: `john@180.159.29.143` +- Production host: `john@114.85.107.50` ## 安全边界 @@ -60,7 +60,7 @@ MEMIND_SESSION_BROKER_METRICS=1 103 本机: ```bash -ssh john@180.159.29.143 'curl -fsS http://127.0.0.1:8081/api/status' +ssh john@114.85.107.50 'curl -fsS http://127.0.0.1:8081/api/status' ``` 外部入口: @@ -72,7 +72,7 @@ curl -ksS https://m.tkmind.cn/api/status Manifest: ```bash -ssh john@180.159.29.143 'cat /Users/john/Project/Memind/.release-manifest.txt' +ssh john@114.85.107.50 'cat /Users/john/Project/Memind/.release-manifest.txt' ``` ### 2. 账号级 smoke @@ -195,7 +195,7 @@ Portal runtime 发布会移动旧 live 目录到 archive,再展开新 runtime 确认命令: ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' /opt/homebrew/bin/docker exec goosed-prod-1 sh -lc "ls -l /Users/john/Project/Memind/MindSpace//public/.html" ls -l /Users/john/Project/Memind/MindSpace//public/.html ' @@ -204,7 +204,7 @@ ssh john@180.159.29.143 ' 修复: ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' cd /Users/john/Project/goosed-prod /opt/homebrew/bin/docker compose -f docker-compose.prod.yml up -d --force-recreate ' @@ -213,7 +213,7 @@ ssh john@180.159.29.143 ' 健康检查: ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' /opt/homebrew/bin/docker ps --format "{{.Names}} {{.Status}}" | grep goosed-prod | sort -V for p in $(seq 18006 18014); do curl -kfsS "https://127.0.0.1:$p/status" >/dev/null || exit 1; done curl -fsS http://127.0.0.1:8081/api/status diff --git a/docs/103-reconciliation-2026-06-26.md b/docs/103-reconciliation-2026-06-26.md index f32a40f..4e501c8 100644 --- a/docs/103-reconciliation-2026-06-26.md +++ b/docs/103-reconciliation-2026-06-26.md @@ -13,7 +13,7 @@ ### 主机与入口 -- 生产主机:`john@180.159.29.143` +- 生产主机:`john@114.85.107.50` - 当前 SSH 端口:`22` - 旧的 `2222` 已关闭,不应再写入文档或脚本 diff --git a/docs/103-runtime-topology.md b/docs/103-runtime-topology.md index 9545271..a6201be 100644 --- a/docs/103-runtime-topology.md +++ b/docs/103-runtime-topology.md @@ -25,7 +25,7 @@ Local Colima may exist for other workloads, but local Memind/goosed is not suppo | Item | Value | |------|-------| -| Host | `180.159.29.143` | +| Host | `114.85.107.50` | | Live directory | `/Users/john/Project/Memind` | | Service | `cn.tkmind.memind-portal` | | Start script | `/Users/john/Project/Memind/scripts/run-memind-portal-prod.sh` | @@ -39,7 +39,7 @@ Portal must be released as a runtime artifact. Do not edit source directly on 10 | Item | Value | |------|-------| -| Stable edge upstream | `105 nginx -> 180.159.29.143:8081` | +| Stable edge upstream | `105 nginx -> 114.85.107.50:8081` | | Identity router | `127.0.0.1:18082` | | Canary edge tunnel | `105 127.0.0.1:19082 -> 103 127.0.0.1:18082` | | Candidate Portal | `127.0.0.1:18081` | @@ -94,8 +94,8 @@ or whose `gitSha` does not match the runtime artifact manifest. **Critical:** Native goosed uses host PostgreSQL on `127.0.0.1:5432`. If PostgreSQL stops, H5 `/agent/start` hangs ~60s. Recovery: ```bash -ssh john@180.159.29.143 'bash /Users/john/Project/Memind/scripts/ensure-goose-session-postgres.sh' -ssh john@180.159.29.143 '/opt/homebrew/opt/postgresql@17/bin/pg_isready -h 127.0.0.1 -p 5432' +ssh john@114.85.107.50 'bash /Users/john/Project/Memind/scripts/ensure-goose-session-postgres.sh' +ssh john@114.85.107.50 '/opt/homebrew/opt/postgresql@17/bin/pg_isready -h 127.0.0.1 -p 5432' ``` Port layout (native listens directly on host port): @@ -153,18 +153,18 @@ is legacy compatibility/storage context only. If Portal or goosed config still p In particular, check these before debugging missing folders/pages: ```bash -ssh john@180.159.29.143 'grep -E "^(MINDSPACE|MINDSPACE_ROOT|MINDSPACE_SERVICE|MEMIND_SHARED_ROOT)=" /Users/john/Project/Memind/.env /Users/john/Project/goosed-prod/.env 2>/dev/null' -ssh john@180.159.29.143 'launchctl print gui/$(id -u)/cn.tkmind.mindspace-service | grep -E "program =|working directory|MINDSPACE|MEMIND_SHARED"' -ssh john@180.159.29.143 '/opt/homebrew/bin/docker inspect goosed-prod-1 --format "{{json .Mounts}}"' +ssh john@114.85.107.50 'grep -E "^(MINDSPACE|MINDSPACE_ROOT|MINDSPACE_SERVICE|MEMIND_SHARED_ROOT)=" /Users/john/Project/Memind/.env /Users/john/Project/goosed-prod/.env 2>/dev/null' +ssh john@114.85.107.50 'launchctl print gui/$(id -u)/cn.tkmind.mindspace-service | grep -E "program =|working directory|MINDSPACE|MEMIND_SHARED"' +ssh john@114.85.107.50 '/opt/homebrew/bin/docker inspect goosed-prod-1 --format "{{json .Mounts}}"' ``` ## Current verification commands ```bash -ssh john@180.159.29.143 'curl -fsS http://127.0.0.1:8081/api/status' -ssh john@180.159.29.143 'curl -fsS http://127.0.0.1:8082/health' -ssh john@180.159.29.143 'for p in $(seq 18006 18014); do curl -kfsS https://127.0.0.1:$p/status; echo; done' -ssh john@180.159.29.143 'grep ^TKMIND_API_TARGETS= /Users/john/Project/Memind/.env' +ssh john@114.85.107.50 'curl -fsS http://127.0.0.1:8081/api/status' +ssh john@114.85.107.50 'curl -fsS http://127.0.0.1:8082/health' +ssh john@114.85.107.50 'for p in $(seq 18006 18014); do curl -kfsS https://127.0.0.1:$p/status; echo; done' +ssh john@114.85.107.50 'grep ^TKMIND_API_TARGETS= /Users/john/Project/Memind/.env' ``` ## imgproxy @@ -196,8 +196,8 @@ Install on 103 reads Portal `.env` for signing keys and storage root; launchd pl Verify: ```bash -ssh john@180.159.29.143 'curl -fsS http://127.0.0.1:20082/health' -ssh john@180.159.29.143 'curl -fsS http://10.10.0.2:20081/health' +ssh john@114.85.107.50 'curl -fsS http://127.0.0.1:20082/health' +ssh john@114.85.107.50 'curl -fsS http://10.10.0.2:20081/health' curl -fsS https://img.tkmind.cn/health ``` diff --git a/docs/105-server-operations.md b/docs/105-server-operations.md index 39ed629..9f87160 100644 --- a/docs/105-server-operations.md +++ b/docs/105-server-operations.md @@ -146,7 +146,7 @@ ssh root@120.26.184.105 ' 1. 先备份并校验 105 活动的 `m.tkmind.cn.conf` 与 `wechat.m.tkmind.cn.conf`。 2. 在 103 启动独立路由器 `18082`,并通过反向隧道只暴露为 105 本机 `19082`。 3. 候选、身份路由和隧道全部通过后,脚本才把两份 nginx 上游从 - `180.159.29.143:8081` 切到 `127.0.0.1:19082`。 + `114.85.107.50:8081` 切到 `127.0.0.1:19082`。 4. 必须先 `nginx -t`,再 reload,并在切换后主动证明候选故障会回落稳定 8081; 任一步失败恢复备份并回到稳定入口。 5. 回滚只能使用 `scripts/rollback-portal-canary-prod.sh`,禁止在 105 手工 `sed -i`。 diff --git a/docs/g2-load-balancing.md b/docs/g2-load-balancing.md index 01cb906..bb6830a 100644 --- a/docs/g2-load-balancing.md +++ b/docs/g2-load-balancing.md @@ -11,38 +11,38 @@ ├─ 转发到 103 / Studio 服务器 → Studio portal 127.0.0.1:8081 └─ [SSH 正向隧道 127.0.0.1:18080] → 105 portal :8080 │ - 105 / Studio 两个 portal ── 都连 ──→ Studio goosed 180.159.29.143:18006(主) - └────→ Studio goosed 180.159.29.143:18007(备用/第二实例) + 105 / Studio 两个 portal ── 都连 ──→ Studio goosed 114.85.107.50:18006(主) + └────→ Studio goosed 114.85.107.50:18007(备用/第二实例) MindSpace 服务 ──→ Studio canonical /Users/john/MindSpace (:8082) 旧发布页目录 ──兼容/存量──→ /Users/john/Project/Memind/MindSpace ``` - **为什么不用旧的 Cloudflare 直连**:当前入口已经迁到阿里云解析,外网流量先到 105,再由 105 转发到 103 / Studio。 -- **为什么直接固定公网 IP**:当前服务器互联和部署链路统一使用固定公网地址 `120.26.184.105` / `180.159.29.143`,不再依赖内网地址、域名别名或临时回退链路。 +- **为什么直接固定公网 IP**:当前服务器互联和部署链路统一使用固定公网地址 `120.26.184.105` / `114.85.107.50`,不再依赖内网地址、域名别名或临时回退链路。 ## 105 / 103 联通约束(硬性要求) **要求:域名只做用户入口;服务器互联、健康检查、部署同步统一走固定公网 IP。** - 105 运维地址:`120.26.184.105`。 -- 103 / Studio 运维地址:`180.159.29.143`。 -- 如果 SSH 别名未更新,直接写 `root@120.26.184.105` / `john@180.159.29.143`。 -- Studio / goosed 目标直接写 `180.159.29.143`,不要写 `g2.tkmind.cn` 或 105 域名。 +- 103 / Studio 运维地址:`114.85.107.50`。 +- 如果 SSH 别名未更新,直接写 `root@120.26.184.105` / `john@114.85.107.50`。 +- Studio / goosed 目标直接写 `114.85.107.50`,不要写 `g2.tkmind.cn` 或 105 域名。 - Studio 对 105 的联通入口是 `127.0.0.1:18080`,不是 `105.tkmind.cn`。 快速自检(每次操作 105 前): ```bash ping -c 1 120.26.184.105 -ping -c 1 180.159.29.143 +ping -c 1 114.85.107.50 ssh root@120.26.184.105 'echo ssh-ok-105' -ssh john@180.159.29.143 'echo ssh-ok-103' +ssh john@114.85.107.50 'echo ssh-ok-103' curl -s http://127.0.0.1:18080/api/status # 应返回 ok ``` - 禁止:用 `105.tkmind.cn` 做 API 健康检查或同步链路入口。 - 禁止:把 105 公网 IP 当成业务上游写进 Caddy / goosed 目标;公网 IP 只保留给外部入口或应急 SSH。 -- 应急:如果 SSH 别名或本地缓存配置仍残留旧地址,显式设置 `H5_DEPLOY_HOST=root@120.26.184.105`,Studio 目标改为 `john@180.159.29.143`。 +- 应急:如果 SSH 别名或本地缓存配置仍残留旧地址,显式设置 `H5_DEPLOY_HOST=root@120.26.184.105`,Studio 目标改为 `john@114.85.107.50`。 ## 调灰度比例(最常用) @@ -58,7 +58,7 @@ curl -s http://127.0.0.1:18080/api/status # 应返回 ok 改完**零停机生效**: ```bash -ssh john@180.159.29.143 +ssh john@114.85.107.50 cd ~/Project/Memind/scripts caddy validate --config g2-lb.Caddyfile # 可选,先校验 caddy reload --config g2-lb.Caddyfile # 零停机热重载 @@ -101,7 +101,7 @@ curl -s http://127.0.0.1:2019/reverse_proxy/upstreams # 在 103 / Studio 上 | 入口反代 | 103 / Studio `scripts/g2-lb.Caddyfile`(LaunchAgent `cn.tkmind.g2-lb`,:8090) | 入口转发 + 健康检查 | | 正向隧道 | 103 / Studio `scripts/memind-fwd-tunnel.sh`(LaunchAgent `cn.tkmind.memind-fwd-tunnel`) | Studio `127.0.0.1:18080` → 105 `:8080` | | 反向隧道 | 103 / Studio `scripts/memind-mac-tunnel.sh`(LaunchAgent `cn.tkmind.memind-tunnel`) | 105 经此挂载 Studio MindSpace 文件 | -| 105 portal | 105 systemd `goose-h5`(:8080),`/root/tkmind_go/ui/h5/.env` | 无状态前端,主 Goose 指向 `https://180.159.29.143:18006`,第二 Goose 指向 `https://180.159.29.143:18007` | +| 105 portal | 105 systemd `goose-h5`(:8080),`/root/tkmind_go/ui/h5/.env` | 无状态前端,主 Goose 指向 `https://114.85.107.50:18006`,第二 Goose 指向 `https://114.85.107.50:18007` | | 105 文件挂载 | 105 systemd `.mount` → `/mnt/memind-shared`(rclone over 反向隧道) | 发布页/工作区共享只读 | ## 关键约束(改动前必读) diff --git a/docs/goose-scale-architecture-2026-06-26.md b/docs/goose-scale-architecture-2026-06-26.md index 7808165..aa2dcf4 100644 --- a/docs/goose-scale-architecture-2026-06-26.md +++ b/docs/goose-scale-architecture-2026-06-26.md @@ -15,7 +15,7 @@ | 数据库 | PostgreSQL + pgvector | **MySQL**(`db.mjs:2` `mysql2/promise`) | 没有向量检索能力,Experience 检索需另建 | | DB 连接池 | —— | **`connectionLimit: 10`**(`db.mjs:32`,写死) | 100 并发 × 多查询 → 连接耗尽、请求排队 | | Goose 实例 | "双 Goose 负载均衡" | **同一台 Mac(Studio/103)上的两个进程** `:18006` / `:18007` | 不是负载均衡,是单点的两进程;共享 CPU/内存/libuv | -| Goose 运行环境 | —— | 个人开发 Mac `john@180.159.29.143` | 生产 Agent 集群跑在个人 Mac 上 = 最大架构债 | +| Goose 运行环境 | —— | 个人开发 Mac `john@114.85.107.50` | 生产 Agent 集群跑在个人 Mac 上 = 最大架构债 | | Session 路由 | —— | DB `goosed_node` 整数下标(0/1),`getSessionNode` @ `user-auth.mjs:651` | 扩到第 3 台直接失效;且该列在 `schema.sql` 里不存在,靠 `columnExists` 运行时动态补 | | 长任务 | —— | 纯 HTTP 流式透传(`tkmind-proxy.mjs`),无队列 | 连接被占满整个执行周期;微信 5s 超时直接死 | | Experience / 上下文 | 共享经验库 | **在各 goosed 进程内存中** | 两实例经验孤岛;重启/部署即丢上下文 | diff --git a/docs/goose-v149-103-cutover-runbook.md b/docs/goose-v149-103-cutover-runbook.md index fb48454..d43469f 100644 --- a/docs/goose-v149-103-cutover-runbook.md +++ b/docs/goose-v149-103-cutover-runbook.md @@ -2,7 +2,7 @@ > **状态:** 草案(本地 v1.49 证据已齐;**未授权**在 103/105 执行任何操作) > -> **适用范围:** 103(`180.159.29.143` / Mac Studio arm64)将 goosed 运行时从 **1.41 native** 升级到 **v1.49 TKMind 补丁树** +> **适用范围:** 103(`114.85.107.50` / Mac Studio arm64)将 goosed 运行时从 **1.41 native** 升级到 **v1.49 TKMind 补丁树** > > **不包含:** Portal runtime 整包发版(见 [portal-release skill](../.claude/skills/portal-release/SKILL.md))、105 nginx 灰度(见 [release-canary-103.md](./release-canary-103.md))、Memory owner 切换(见 [TKMIND_V1_49_MIGRATION.md](../TKMIND_V1_49_MIGRATION.md)) @@ -54,7 +54,7 @@ 在 **103 上只读**执行,保存到本机 `test/_103_baselines/pre-v149-YYYYMMDD/`: ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' date -u +%Y-%m-%dT%H:%M:%SZ cat /Users/john/Project/Memind/.release-manifest.txt grep -E "^(TKMIND_API_TARGETS|GOOSED_RUNTIME|GOOSED_MCP_|GOOSE_SESSION|MEMIND_DEEPSEEK)" /Users/john/Project/Memind/.env | sed "s/=.*/=***/" @@ -153,7 +153,7 @@ Hermit 根目录默认:`/Users/john/Project/tkmind_go-v141-prod-prep/.hermit/r ```bash # 本机 tar -czf /tmp/goose-v149-hermit-vendor.tgz -C /Users/john/Project/tkmind_go-v141-prod-prep .hermit -scp /tmp/goose-v149-hermit-vendor.tgz john@180.159.29.143:/tmp/ +scp /tmp/goose-v149-hermit-vendor.tgz john@114.85.107.50:/tmp/ # 103 mkdir -p /Users/john/Project/tkmind_go-v141-prod-prep tar -xzf /tmp/goose-v149-hermit-vendor.tgz -C /Users/john/Project/tkmind_go-v141-prod-prep @@ -345,7 +345,7 @@ Gate:维护窗 commit 须绑定 **Core + Impact Gate report**([production-re ### Phase 5 — 恢复流量 -- [ ] 105 nginx → `180.159.29.143:8081`(或灰度 `19082` 路径) +- [ ] 105 nginx → `114.85.107.50:8081`(或灰度 `19082` 路径) - [ ] 外网 `https://m.tkmind.cn/api/status` ### Phase 6 — 观察 24–72h diff --git a/docs/goosed-local-build-delivery.md b/docs/goosed-local-build-delivery.md index d59a531..453614a 100644 --- a/docs/goosed-local-build-delivery.md +++ b/docs/goosed-local-build-delivery.md @@ -188,10 +188,10 @@ ls -lh goosed.tar # 3. 传输到 103 # 方式 1: 通过 scp -scp goosed.tar john@180.159.29.143:~/incoming/ +scp goosed.tar john@114.85.107.50:~/incoming/ # 方式 2: 通过 rsync -rsync -av goosed.tar john@180.159.29.143:~/incoming/ +rsync -av goosed.tar john@114.85.107.50:~/incoming/ # 4. 在 103 上导入(后续操作) # docker load -i goosed.tar @@ -287,7 +287,7 @@ docker logs docker save tkmind/goosed:local | gzip > goosed.tar.gz # 传输 -scp goosed.tar.gz john@180.159.29.143:~/ +scp goosed.tar.gz john@114.85.107.50:~/ # 在 103 上解压导入 gunzip < goosed.tar.gz | docker load diff --git a/docs/goosed-native-103-migration-plan.md b/docs/goosed-native-103-migration-plan.md index c7901e7..0e5e3f8 100644 --- a/docs/goosed-native-103-migration-plan.md +++ b/docs/goosed-native-103-migration-plan.md @@ -1,7 +1,7 @@ # 103 生产 goosed 迁移计划:Docker/Colima → Native 多实例 > **状态:** 已执行(2026-07-30 维护窗) -> **适用范围:** 103(`180.159.29.143` / Mac Studio)生产环境 +> **适用范围:** 103(`114.85.107.50` / Mac Studio)生产环境 > **目标运行时:** 去掉 goosed 对 Docker/Colima 的依赖,改为 native launchd 多实例(`18006`–`18014`) > **前提:** 允许维护窗口停机;**不要求**进行中 SSE/工具任务不断线 > **关联拓扑:** [103-runtime-topology.md](./103-runtime-topology.md) @@ -129,11 +129,11 @@ ```bash # 只读,禁止改 103 -ssh john@180.159.29.143 'cat /Users/john/Project/Memind/.release-manifest.txt' -ssh john@180.159.29.143 'grep ^TKMIND_API_TARGETS= /Users/john/Project/Memind/.env' -ssh john@180.159.29.143 'grep ^GOOSED_TAG= /Users/john/Project/goosed-prod/.env' -ssh john@180.159.29.143 'for p in $(seq 18006 18014); do curl -kfsS --connect-timeout 2 https://127.0.0.1:$p/status; echo; done' -ssh john@180.159.29.143 'curl -fsS http://127.0.0.1:8082/mindspace/v1/contract | head -c 400' +ssh john@114.85.107.50 'cat /Users/john/Project/Memind/.release-manifest.txt' +ssh john@114.85.107.50 'grep ^TKMIND_API_TARGETS= /Users/john/Project/Memind/.env' +ssh john@114.85.107.50 'grep ^GOOSED_TAG= /Users/john/Project/goosed-prod/.env' +ssh john@114.85.107.50 'for p in $(seq 18006 18014); do curl -kfsS --connect-timeout 2 https://127.0.0.1:$p/status; echo; done' +ssh john@114.85.107.50 'curl -fsS http://127.0.0.1:8082/mindspace/v1/contract | head -c 400' ``` 保存到本机 `test/_103_baselines/pre-native-migration-YYYYMMDD/`。 @@ -241,7 +241,7 @@ done ### Phase 5 — 恢复流量 -- [ ] 105 nginx 恢复 `180.159.29.143:8081`(或既定 upstream) +- [ ] 105 nginx 恢复 `114.85.107.50:8081`(或既定 upstream) - [ ] 外网抽样:`https://m.tkmind.cn/api/status` - [ ] 维护结束公告 diff --git a/docs/no-source-portal-migration.md b/docs/no-source-portal-migration.md index 9e95972..e693d4a 100644 --- a/docs/no-source-portal-migration.md +++ b/docs/no-source-portal-migration.md @@ -27,7 +27,7 @@ 4. 生产用户公开入口是 `https://g2.tkmind.cn`,不是裸 IP,也不是本地 localhost。 5. 运维、发包、健康检查统一走固定公网地址,不再依赖 `10.10.*` 局域网: - `105`:`120.26.184.105` - - `103 / Studio`:`180.159.29.143` + - `103 / Studio`:`114.85.107.50` ## 迁移原则 @@ -36,7 +36,7 @@ 3. `103` 只接收运行产物、继承持久目录、启动服务。 4. 生产差异通过 `.env` 和启动环境注入,不通过“线上源码和本地源码不同”来兜底。 5. 迁移前必须先打整包备份,且单独备份持久目录。 -6. 后续所有发布脚本默认都应优先直连 `180.159.29.143`,只有用户明确要求时才允许覆盖 `STUDIO_HOST`。 +6. 后续所有发布脚本默认都应优先直连 `114.85.107.50`,只有用户明确要求时才允许覆盖 `STUDIO_HOST`。 ## Portal 运行产物 diff --git a/docs/production-release-guardian.md b/docs/production-release-guardian.md index b0c1861..0d75374 100644 --- a/docs/production-release-guardian.md +++ b/docs/production-release-guardian.md @@ -152,7 +152,7 @@ G8 不能替代 G0-G7;发布后健康检查也不能为发布前缺失的场 全场景执行器必须在代码层拒绝以下目标: -- `180.159.29.143` +- `114.85.107.50` - `m.tkmind.cn` - 生产 MySQL、PostgreSQL、Redis、SearXNG、Deep Search 和图片服务地址 - 生产用户工作区、发布目录和对象存储 @@ -607,7 +607,7 @@ failed = skipped = blocked = unknown = cleanup_failed = 0 用户级灰度入口由 `scripts/release-portal-canary-prod.sh` 安装:稳定 Portal 保持 8081, 候选 Portal 使用 18081,候选 goosed 使用 18015,身份路由器使用 18082;105 使用独立 19082 反向隧道访问路由器。活动 nginx 上游在脚本备份、`nginx -t` 和健康检查后,才允许 -从稳定 `180.159.29.143:8081` 切到 `127.0.0.1:19082`。灰度身份必须 +从稳定 `114.85.107.50:8081` 切到 `127.0.0.1:19082`。灰度身份必须 使用不可变用户 ID、唯一用户名或微信绑定账号标识;禁止按显示昵称(包括“唐”)匹配。未命中、 身份解析失败或候选不可用必须自动回落稳定版本。 diff --git a/docs/regression-guards/103-release-0629002-rollback.md b/docs/regression-guards/103-release-0629002-rollback.md index 937c182..40ab740 100644 --- a/docs/regression-guards/103-release-0629002-rollback.md +++ b/docs/regression-guards/103-release-0629002-rollback.md @@ -24,7 +24,7 @@ ## 健康验证 ```bash -ssh 180.159.29.143 'curl -sf http://127.0.0.1:8081/api/status && echo' +ssh 114.85.107.50 'curl -sf http://127.0.0.1:8081/api/status && echo' ``` 发版脚本已在 103 上完成 health check(200)。 diff --git a/docs/regression-guards/103-release-0630001-rollback.md b/docs/regression-guards/103-release-0630001-rollback.md index aa6465b..801bc2e 100644 --- a/docs/regression-guards/103-release-0630001-rollback.md +++ b/docs/regression-guards/103-release-0630001-rollback.md @@ -26,7 +26,7 @@ ## 健康验证 ```bash -ssh 180.159.29.143 'curl -sf http://127.0.0.1:8081/api/status && echo' +ssh 114.85.107.50 'curl -sf http://127.0.0.1:8081/api/status && echo' ``` 发版脚本已在 103 上完成 health check(200)。 diff --git a/docs/regression-guards/103-release-0630002-rollback.md b/docs/regression-guards/103-release-0630002-rollback.md index 9ed2d8a..26ab69e 100644 --- a/docs/regression-guards/103-release-0630002-rollback.md +++ b/docs/regression-guards/103-release-0630002-rollback.md @@ -25,7 +25,7 @@ ## 健康验证 ```bash -ssh 180.159.29.143 'curl -sf http://127.0.0.1:8081/api/status && echo' +ssh 114.85.107.50 'curl -sf http://127.0.0.1:8081/api/status && echo' ``` **2026-06-30 发版后验证:** `ok`;`.env` 中 `H5_SCHEDULE_ENABLED=1`、`H5_REMINDER_WORKER_ENABLED=1`。 diff --git a/docs/regression-guards/103-release-0630003-rollback.md b/docs/regression-guards/103-release-0630003-rollback.md index 0baa504..ed6d81d 100644 --- a/docs/regression-guards/103-release-0630003-rollback.md +++ b/docs/regression-guards/103-release-0630003-rollback.md @@ -24,7 +24,7 @@ ## 健康验证 ```bash -ssh 180.159.29.143 'curl -sf http://127.0.0.1:8081/api/status && echo' +ssh 114.85.107.50 'curl -sf http://127.0.0.1:8081/api/status && echo' ``` **2026-06-30 发版后验证:** `ok`;live 目录为无源码 runtime(`server.mjs` + `dist/` + `scripts/run-memind-portal-prod.sh`)。 diff --git a/docs/regression-guards/103-release-0630004-rollback.md b/docs/regression-guards/103-release-0630004-rollback.md index af5f460..cf177d6 100644 --- a/docs/regression-guards/103-release-0630004-rollback.md +++ b/docs/regression-guards/103-release-0630004-rollback.md @@ -26,8 +26,8 @@ ## 健康验证 ```bash -ssh 180.159.29.143 'curl -sf http://127.0.0.1:8081/api/status && echo' -ssh 180.159.29.143 'curl -s -o /dev/null -w "brand=%{http_code}\n" http://127.0.0.1:8081/brand/tkmind-icon.png' +ssh 114.85.107.50 'curl -sf http://127.0.0.1:8081/api/status && echo' +ssh 114.85.107.50 'curl -s -o /dev/null -w "brand=%{http_code}\n" http://127.0.0.1:8081/brand/tkmind-icon.png' ``` **2026-06-30 发版后验证:** `ok`;`brand_icon=200`;live 目录为无源码 runtime(`server.mjs` + `dist/` + `scripts/run-memind-portal-prod.sh`)。 diff --git a/docs/release-canary-103.md b/docs/release-canary-103.md index a4061f4..c27bd6f 100644 --- a/docs/release-canary-103.md +++ b/docs/release-canary-103.md @@ -6,7 +6,7 @@ Portal 的首个生产动作必须是用户级灰度,不能直接整包替换 | 组件 | 地址 | 说明 | |---|---|---| -| 稳定 Portal | `103:8081` | 105 当前直接回源 `180.159.29.143:8081`;灰度发布不替换该进程 | +| 稳定 Portal | `103:8081` | 105 当前直接回源 `114.85.107.50:8081`;灰度发布不替换该进程 | | 灰度路由器 | `103 127.0.0.1:18082` | 避开已占用的 18080;只通过专用灰度隧道暴露给 105 | | 灰度边缘隧道 | `105 127.0.0.1:19082` | 反向 SSH 到 103 的 18082;不复用已退役的 19081 链路 | | 候选 Portal | `127.0.0.1:18081` | 独立、无源码 runtime;使用被动运行时模式 | @@ -69,10 +69,10 @@ bash scripts/release-portal-canary-prod.sh --yes 7. 验证不可变身份配置、稳定/候选/依赖健康和路由器诊断。 8. 启动独立的 `105:19082 -> 103:18082` 灰度隧道并从 105 验证。 9. 短暂阻止新 Agent Run,排空活动任务。 -10. 逐文件原子替换、验证并 reload 105 nginx,把活动上游从 `180.159.29.143:8081` 切到 `127.0.0.1:19082`。 +10. 逐文件原子替换、验证并 reload 105 nginx,把活动上游从 `114.85.107.50:8081` 切到 `127.0.0.1:19082`。 11. 主动停止候选,证明目标身份会自动回落稳定版,再恢复候选。 -任一步失败都会把 105 nginx 恢复到稳定 `180.159.29.143:8081`,停止灰度隧道和候选服务, +任一步失败都会把 105 nginx 恢复到稳定 `114.85.107.50:8081`,停止灰度隧道和候选服务, 并保留候选目录与备份证据。活动 nginx 配置变更只能由已提交的发布脚本执行,禁止在线手改。 ## 回滚 @@ -83,7 +83,7 @@ bash scripts/rollback-portal-canary-prod.sh --yes 回滚只执行以下动作: -- 把 105 两份活动 nginx 上游恢复到稳定 Portal `180.159.29.143:8081` 并验证 reload。 +- 把 105 两份活动 nginx 上游恢复到稳定 Portal `114.85.107.50:8081` 并验证 reload。 - 停止灰度隧道、灰度路由器、候选 Portal、候选 goosed 和 DeepSeek 兼容代理。 - 清除发布排水标记。 - 验证稳定 Portal 和 105 HTTPS 入口健康。 diff --git a/docs/studio-goose-permission-runbook.md b/docs/studio-goose-permission-runbook.md index 7b9ab43..46753f9 100644 --- a/docs/studio-goose-permission-runbook.md +++ b/docs/studio-goose-permission-runbook.md @@ -6,7 +6,7 @@ - Studio 上 Goose 是双实例:`18006` 主、`18007` 备用/第二实例。 - 105 不跑 Goose;105 只是无状态 H5 前端,代理回 Studio。 -- Studio 可直接 SSH:`ssh john@180.159.29.143`。不要为了查 Studio 再绕 105。 +- Studio 可直接 SSH:`ssh john@114.85.107.50`。不要为了查 Studio 再绕 105。 - H5 会话权限不是只看数据库,还要看会话启动时实际下发给 Goose 的 `extension_overrides`。 ## 这次案例结论 @@ -242,7 +242,7 @@ Session 路由: 优先查 Studio: ```bash -ssh -o BatchMode=yes -o ConnectTimeout=8 john@180.159.29.143 \ +ssh -o BatchMode=yes -o ConnectTimeout=8 john@114.85.107.50 \ "cd /Users/john/Project/Memind && ps eww -p \$(pgrep -f 'node .*server.mjs' | head -1) | tr ' ' '\n' | grep '^TKMIND_API_TARGET'" ``` @@ -256,7 +256,7 @@ ssh -i ~/.ssh/id_ed25519 root@120.26.184.105 \ ### 查生产用户权限 ```bash -ssh john@180.159.29.143 +ssh john@114.85.107.50 cd /Users/john/Project/Memind node -e 'process.loadEnvFile(".env"); const mysql=require("mysql2/promise"); (async()=>{ const pool=mysql.createPool(process.env.DATABASE_URL); const userId="a70ff537-8908-486e-9b6c-042e07cc25db"; const [userCaps]=await pool.query("SELECT capability_key, allowed FROM h5_capability_grants WHERE subject_type=\"user\" AND subject_id=? ORDER BY capability_key",[userId]); const [roleCaps]=await pool.query("SELECT capability_key, allowed FROM h5_capability_grants WHERE subject_type=\"role\" AND subject_id=\"user\" ORDER BY capability_key"); const [userPolicies]=await pool.query("SELECT policy_key, policy_value FROM h5_user_policies WHERE subject_type=\"user\" AND subject_id=? ORDER BY policy_key",[userId]); const [rolePolicies]=await pool.query("SELECT policy_key, policy_value FROM h5_user_policies WHERE subject_type=\"role\" AND subject_id=\"user\" ORDER BY policy_key"); console.log(JSON.stringify({userCaps,roleCaps,userPolicies,rolePolicies},null,2)); await pool.end(); })();' @@ -265,7 +265,7 @@ node -e 'process.loadEnvFile(".env"); const mysql=require("mysql2/promise"); (as ### 让线上代码直接算最终 session policy ```bash -ssh john@180.159.29.143 +ssh john@114.85.107.50 cd /Users/john/Project/Memind node --input-type=module -e 'import process from "node:process"; process.loadEnvFile(".env"); const { createDbPool } = await import("./db.mjs"); const { createUserAuth } = await import("./user-auth.mjs"); const pool = createDbPool(); const userAuth = createUserAuth(pool, { h5Root: process.cwd() }); const policy = await userAuth.getAgentSessionPolicy("a70ff537-8908-486e-9b6c-042e07cc25db"); console.log(JSON.stringify(policy, null, 2)); await pool.end();' @@ -274,7 +274,7 @@ node --input-type=module -e 'import process from "node:process"; process.loadEnv ### 查用户最近 session 及节点分布 ```bash -ssh john@180.159.29.143 +ssh john@114.85.107.50 cd /Users/john/Project/Memind node -e 'process.loadEnvFile(".env"); const mysql=require("mysql2/promise"); (async()=>{ const pool=mysql.createPool(process.env.DATABASE_URL); const [rows]=await pool.query("SELECT agent_session_id, user_id, goosed_node, created_at FROM h5_user_sessions WHERE user_id = ? ORDER BY created_at DESC LIMIT 20", ["a70ff537-8908-486e-9b6c-042e07cc25db"]); console.log(JSON.stringify(rows,null,2)); await pool.end(); })();' @@ -290,7 +290,7 @@ node -e 'process.loadEnvFile(".env"); const mysql=require("mysql2/promise"); (as 然后查扩展: ```bash -ssh john@180.159.29.143 \ +ssh john@114.85.107.50 \ 'curl -sk -H "X-Secret-Key: local-dev-secret" https://127.0.0.1:18006/sessions/20260620_45/extensions | python3 -m json.tool' ``` diff --git a/docs/发包必看.md b/docs/发包必看.md index cab10d9..df5c11a 100644 --- a/docs/发包必看.md +++ b/docs/发包必看.md @@ -7,7 +7,7 @@ ## 0. 先确认边界 -- 生产 Portal 主机是 `103 / Studio`:`john@180.159.29.143`,默认 SSH 命令不要再写旧端口 `2222`。 +- 生产 Portal 主机是 `103 / Studio`:`john@114.85.107.50`,默认 SSH 命令不要再写旧端口 `2222`。 - `105` 是云侧入口/历史链路,不是 Portal 源码真相;不要 SSH 到 105 直接改业务代码。 - Portal 生产目录:`/Users/john/Project/Memind`。 - goosed 生产目录:`/Users/john/Project/goosed-prod`。 @@ -84,7 +84,7 @@ bash scripts/release-portal-fast-prod.sh --yes - 备份并校验 105 的 `m.tkmind.cn.conf` 与 `wechat.m.tkmind.cn.conf`。 - 保持稳定 Portal `103:8081` 不变,启动候选 Portal `18081`、候选 goosed `18015` 和身份路由器 `18082`。 - 启动独立 `105:19082 -> 103:18082` 灰度隧道;禁止复用历史 19081 或占用 18080。 -- `nginx -t` 通过后才把 105 活动上游从 `180.159.29.143:8081` 切到 `127.0.0.1:19082`。 +- `nginx -t` 通过后才把 105 活动上游从 `114.85.107.50:8081` 切到 `127.0.0.1:19082`。 - 健康检查稳定、候选、回落和 105 HTTPS 入口均通过。 - 校验 `MindSpace/*/public/*.html` 下载/附件相对链接均已落盘(`check-mindspace-public-links.mjs --downloads-only`)。 @@ -113,7 +113,7 @@ curl -k -i https://m.tkmind.cn/auth/login \ 在 103 执行: ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' printf "portal="; curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/api/status for p in $(seq 18006 18014); do printf "goosed_${p}=" @@ -138,7 +138,7 @@ ssh john@180.159.29.143 ' 日志检查: ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' tail -200 ~/Library/Logs/memind-portal.log | egrep "User auth bootstrap failed|ER_PARSE_ERROR|Cannot find package|Failed to add extension|No such file|Unknown extension|Provider not set|not configured" || true ' @@ -175,7 +175,7 @@ ER_PARSE_ERROR release worktree 如果有 `node_modules -> /Users/john/.../node_modules` symlink,构建脚本必须 realpath 后复制真实依赖。发布后必须确认线上: ```bash -ssh john@180.159.29.143 'cd /Users/john/Project/Memind && test -d node_modules/http-proxy-middleware && echo ok' +ssh john@114.85.107.50 'cd /Users/john/Project/Memind && test -d node_modules/http-proxy-middleware && echo ok' ``` 否则可能出现: @@ -282,7 +282,7 @@ tkmind/goosed:prod-20260627-2125-mcp 重建镜像后必须验: ```bash -ssh john@180.159.29.143 ' +ssh john@114.85.107.50 ' cd /Users/john/Project/goosed-prod set -a source .env diff --git a/release-gate/safety.mjs b/release-gate/safety.mjs index 5a192a6..a10d455 100644 --- a/release-gate/safety.mjs +++ b/release-gate/safety.mjs @@ -1,5 +1,5 @@ const FORBIDDEN_HOSTS = new Set([ - '180.159.29.143', + '114.85.107.50', 'm.tkmind.cn', 'plaza.tkmind.cn', ]); @@ -33,7 +33,7 @@ export function isProductionTarget(value) { const hostname = extractHostname(text); return FORBIDDEN_HOSTS.has(hostname) || hostname.endsWith('.tkmind.cn') - || text.includes('180.159.29.143') + || text.includes('114.85.107.50') || text.includes('/users/john/project/memind'); } diff --git a/release-gate/safety.test.mjs b/release-gate/safety.test.mjs index 900c567..dbe977a 100644 --- a/release-gate/safety.test.mjs +++ b/release-gate/safety.test.mjs @@ -10,8 +10,8 @@ import { test('production IP, public domains, and production paths are refused', () => { for (const target of [ - '180.159.29.143', - 'ssh://180.159.29.143', + '114.85.107.50', + 'ssh://114.85.107.50', 'https://m.tkmind.cn', 'https://plaza.tkmind.cn/page', '/Users/john/Project/Memind', @@ -32,8 +32,8 @@ test('unsafe environment keys are reported without exposing values', () => { assert.throws( () => assertSafeGateEnvironment({ env: { - DATABASE_URL: 'postgres://secret@180.159.29.143/prod', - STUDIO_HOST: '180.159.29.143', + DATABASE_URL: 'postgres://secret@114.85.107.50/prod', + STUDIO_HOST: '114.85.107.50', }, }), (error) => { diff --git a/scripts/apply-tang-cursor-config-103.mjs b/scripts/apply-tang-cursor-config-103.mjs index 25055d2..4f5b37d 100644 --- a/scripts/apply-tang-cursor-config-103.mjs +++ b/scripts/apply-tang-cursor-config-103.mjs @@ -41,7 +41,7 @@ async function main() { const apply = process.argv.includes('--apply'); const enableChatBridge = process.argv.includes('--enable-chat-bridge'); const databaseUrl = execSync( - "ssh -o BatchMode=yes -o ConnectTimeout=8 john@180.159.29.143 \"grep '^DATABASE_URL=' /Users/john/Project/Memind/.env | cut -d= -f2-\"", + "ssh -o BatchMode=yes -o ConnectTimeout=8 john@114.85.107.50 \"grep '^DATABASE_URL=' /Users/john/Project/Memind/.env | cut -d= -f2-\"", { encoding: 'utf8' }, ).trim(); const pool = mysql.createPool({ uri: databaseUrl, connectionLimit: 2 }); diff --git a/scripts/audit-103-state.sh b/scripts/audit-103-state.sh index f16fc75..bb2f987 100755 --- a/scripts/audit-103-state.sh +++ b/scripts/audit-103-state.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_ROOT="${STUDIO_REMOTE_ROOT:-/Users/john/Project}" say() { diff --git a/scripts/backfill-mindspace-geo-prod.sh b/scripts/backfill-mindspace-geo-prod.sh index 0cfb91e..517445a 100755 --- a/scripts/backfill-mindspace-geo-prod.sh +++ b/scripts/backfill-mindspace-geo-prod.sh @@ -8,7 +8,7 @@ set -euo pipefail # bash scripts/backfill-mindspace-geo-prod.sh # bash scripts/backfill-mindspace-geo-prod.sh --dry-run -HOST="${MEMIND_PROD_HOST:-john@180.159.29.143}" +HOST="${MEMIND_PROD_HOST:-john@114.85.107.50}" LOCAL_REPO="$(cd "$(dirname "$0")/.." && pwd)" REMOTE_REPO="${MEMIND_PROD_REPO:-/Users/john/Project/Memind}" REMOTE_MINDSPACE_ROOT="${MEMIND_PROD_MINDSPACE_ROOT:-${REMOTE_REPO}/MindSpace}" diff --git a/scripts/capture-goose-v149-baseline.mjs b/scripts/capture-goose-v149-baseline.mjs index 39796b5..a567ac6 100644 --- a/scripts/capture-goose-v149-baseline.mjs +++ b/scripts/capture-goose-v149-baseline.mjs @@ -13,7 +13,7 @@ const port = process.env.GOOSE_V149_PORT || '18049'; const host = process.env.GOOSE_V149_HOST || '127.0.0.1'; const secret = process.env.GOOSE_SERVER__SECRET_KEY || 'local-v149-dev-secret'; const base = `https://${host}:${port}`; -const blockedHosts = ['180.159.29.143', '120.26.184.105']; +const blockedHosts = ['114.85.107.50', '120.26.184.105']; function usage() { return [ diff --git a/scripts/check-goosed-v149-agent-start.mjs b/scripts/check-goosed-v149-agent-start.mjs index 6b25e4a..1972d77 100755 --- a/scripts/check-goosed-v149-agent-start.mjs +++ b/scripts/check-goosed-v149-agent-start.mjs @@ -9,7 +9,7 @@ const host = process.env.GOOSE_V149_HOST || '127.0.0.1'; const secret = process.env.GOOSE_SERVER__SECRET_KEY || 'local-v149-dev-secret'; const workingDir = process.env.GOOSE_V149_WORKING_DIR || process.cwd(); -const blockedHosts = ['180.159.29.143', '120.26.184.105']; +const blockedHosts = ['114.85.107.50', '120.26.184.105']; if (blockedHosts.includes(host)) { console.error(`GOOSE_V149_AGENT_START_FAIL: refusing production host ${host}`); process.exit(1); diff --git a/scripts/check-goosed-v149-executors.mjs b/scripts/check-goosed-v149-executors.mjs index 32bfba5..b7e7ed7 100644 --- a/scripts/check-goosed-v149-executors.mjs +++ b/scripts/check-goosed-v149-executors.mjs @@ -11,7 +11,7 @@ const workingDir = process.env.GOOSE_V149_WORKING_DIR || process.cwd(); const pollMs = Number(process.env.GOOSE_V149_EXECUTOR_POLL_MS || 500); const timeoutMs = Number(process.env.GOOSE_V149_EXECUTOR_TIMEOUT_MS || 30_000); -const blockedHosts = ['180.159.29.143', '120.26.184.105']; +const blockedHosts = ['114.85.107.50', '120.26.184.105']; if (blockedHosts.includes(host)) { console.error(`GOOSE_V149_EXECUTOR_FAIL: refusing production host ${host}`); process.exit(1); diff --git a/scripts/check-goosed-v149-harness.mjs b/scripts/check-goosed-v149-harness.mjs index 17c896a..36ef7fe 100644 --- a/scripts/check-goosed-v149-harness.mjs +++ b/scripts/check-goosed-v149-harness.mjs @@ -13,7 +13,7 @@ const host = process.env.GOOSE_V149_HOST || '127.0.0.1'; const secret = process.env.GOOSE_SERVER__SECRET_KEY || 'local-v149-dev-secret'; const workingDir = process.env.GOOSE_V149_WORKING_DIR || process.cwd(); const base = `https://${host}:${port}`; -const blockedHosts = ['180.159.29.143', '120.26.184.105']; +const blockedHosts = ['114.85.107.50', '120.26.184.105']; if (blockedHosts.includes(host)) { console.error(`GOOSE_V149_HARNESS_FAIL: refusing production host ${host}`); diff --git a/scripts/check-goosed-v149-local.mjs b/scripts/check-goosed-v149-local.mjs index 54ca839..6485631 100644 --- a/scripts/check-goosed-v149-local.mjs +++ b/scripts/check-goosed-v149-local.mjs @@ -9,7 +9,7 @@ const host = process.env.GOOSE_V149_HOST || '127.0.0.1'; const url = `https://${host}:${port}/status`; const maxBuffer = Number(process.env.GOOSE_V149_CHECK_MAX_BUFFER || 64 * 1024 * 1024); -const blockedHosts = ['180.159.29.143', '120.26.184.105']; +const blockedHosts = ['114.85.107.50', '120.26.184.105']; if (blockedHosts.includes(host)) { console.error(`GOOSE_V149_CHECK_FAIL: refusing production host ${host}`); process.exit(1); diff --git a/scripts/check-goosed-v149-memory-loop.mjs b/scripts/check-goosed-v149-memory-loop.mjs index 598e7d4..3179068 100644 --- a/scripts/check-goosed-v149-memory-loop.mjs +++ b/scripts/check-goosed-v149-memory-loop.mjs @@ -12,7 +12,7 @@ import { enforceRealLlmGate } from './goose-v149-real-llm-gate.mjs'; enforceRealLlmGate('check-goosed-v149-memory-loop.mjs'); -const BLOCKED_DB_HOSTS = ['180.159.29.143', '120.26.184.105', 'rds.aliyuncs.com']; +const BLOCKED_DB_HOSTS = ['114.85.107.50', '120.26.184.105', 'rds.aliyuncs.com']; const MARKER = `goose-v149-memory-loop-${Date.now()}`; function assertLocalDatabase(env = process.env) { diff --git a/scripts/check-goosed-v149-provider.mjs b/scripts/check-goosed-v149-provider.mjs index 1efd900..efa8013 100644 --- a/scripts/check-goosed-v149-provider.mjs +++ b/scripts/check-goosed-v149-provider.mjs @@ -53,7 +53,7 @@ const apiUrl = || 'https://api.deepseek.com/v1'; const replyTimeoutMs = Number(process.env.GOOSE_V149_PROVIDER_REPLY_TIMEOUT_MS || 90_000); -const blockedHosts = ['180.159.29.143', '120.26.184.105']; +const blockedHosts = ['114.85.107.50', '120.26.184.105']; if (blockedHosts.includes(host)) { console.error(`GOOSE_V149_PROVIDER_FAIL: refusing production host ${host}`); process.exit(1); diff --git a/scripts/check-goosed-v149-reply-smoke.mjs b/scripts/check-goosed-v149-reply-smoke.mjs index 3058449..e5dc129 100644 --- a/scripts/check-goosed-v149-reply-smoke.mjs +++ b/scripts/check-goosed-v149-reply-smoke.mjs @@ -17,7 +17,7 @@ const secret = process.env.GOOSE_SERVER__SECRET_KEY || 'local-v149-dev-secret'; const workingDir = process.env.GOOSE_V149_WORKING_DIR || process.cwd(); const timeoutMs = Number(process.env.GOOSE_V149_REPLY_TIMEOUT_MS || 30_000); -const blockedHosts = ['180.159.29.143', '120.26.184.105']; +const blockedHosts = ['114.85.107.50', '120.26.184.105']; if (blockedHosts.includes(host)) { console.error(`GOOSE_V149_REPLY_SMOKE_FAIL: refusing production host ${host}`); process.exit(1); diff --git a/scripts/check-goosed-v149-sandbox-fs.mjs b/scripts/check-goosed-v149-sandbox-fs.mjs index 2c0219d..d4b36a5 100644 --- a/scripts/check-goosed-v149-sandbox-fs.mjs +++ b/scripts/check-goosed-v149-sandbox-fs.mjs @@ -19,7 +19,7 @@ const serverPath = const pollMs = Number(process.env.GOOSE_V149_SANDBOX_POLL_MS || 500); const timeoutMs = Number(process.env.GOOSE_V149_SANDBOX_TIMEOUT_MS || 30_000); -const blockedHosts = ['180.159.29.143', '120.26.184.105']; +const blockedHosts = ['114.85.107.50', '120.26.184.105']; if (blockedHosts.includes(host)) { console.error(`GOOSE_V149_SANDBOX_FS_FAIL: refusing production host ${host}`); process.exit(1); diff --git a/scripts/deploy-tang-meinput-pages-103.mjs b/scripts/deploy-tang-meinput-pages-103.mjs index 5e1d9d3..ce09be7 100644 --- a/scripts/deploy-tang-meinput-pages-103.mjs +++ b/scripts/deploy-tang-meinput-pages-103.mjs @@ -10,7 +10,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); -const HOST = 'john@180.159.29.143'; +const HOST = 'john@114.85.107.50'; const REMOTE_ROOT = '/Users/john/Project/Memind'; const TANG = 'a70ff537-8908-486e-9b6c-042e07cc25db'; const JOHN_LOCAL = '1c99b83b-0454-474f-a5d2-129d34506a32'; diff --git a/scripts/deploy-wechat-mp-prod.sh b/scripts/deploy-wechat-mp-prod.sh index 6d01f16..ba3a7d5 100755 --- a/scripts/deploy-wechat-mp-prod.sh +++ b/scripts/deploy-wechat-mp-prod.sh @@ -4,7 +4,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" -HOST="${MEMIND_PROD_HOST:-john@180.159.29.143}" +HOST="${MEMIND_PROD_HOST:-john@114.85.107.50}" REMOTE_ROOT="${MEMIND_PROD_ROOT:-/Users/john/Project/Memind}" BUNDLE=".runtime/portal/wechat-mp.bundle.mjs" diff --git a/scripts/ensure-goose-v149-local-db.sh b/scripts/ensure-goose-v149-local-db.sh index 1ed36f1..2f37e0c 100755 --- a/scripts/ensure-goose-v149-local-db.sh +++ b/scripts/ensure-goose-v149-local-db.sh @@ -15,7 +15,7 @@ fail() { case "${PG_HOST}" in 127.0.0.1|localhost|::1) ;; - 180.159.29.143|120.26.184.105|*rds.aliyuncs.com*|*tkmind.cn*) + 114.85.107.50|120.26.184.105|*rds.aliyuncs.com*|*tkmind.cn*) fail "refusing production or remote host: ${PG_HOST}" ;; *) diff --git a/scripts/export-goose-v149-memory-manifest.mjs b/scripts/export-goose-v149-memory-manifest.mjs index 6e66063..bcdb949 100644 --- a/scripts/export-goose-v149-memory-manifest.mjs +++ b/scripts/export-goose-v149-memory-manifest.mjs @@ -10,7 +10,7 @@ import mysql from 'mysql2/promise'; import { loadMemindEnvFiles } from './memind-runtime-profile.mjs'; -const BLOCKED_DB_HOSTS = new Set(['180.159.29.143', '120.26.184.105', 'rds.aliyuncs.com']); +const BLOCKED_DB_HOSTS = new Set(['114.85.107.50', '120.26.184.105', 'rds.aliyuncs.com']); function usage() { return [ diff --git a/scripts/g2-aliyun-cert.env.example b/scripts/g2-aliyun-cert.env.example index f815f77..6225671 100644 --- a/scripts/g2-aliyun-cert.env.example +++ b/scripts/g2-aliyun-cert.env.example @@ -5,4 +5,4 @@ Ali_Secret=YOUR_ALIYUN_ACCESS_KEY_SECRET # 可选:证书与 DNS 域名 G2_DOMAIN=g2.tkmind.cn -G2_PUBLIC_IP=180.159.29.143 +G2_PUBLIC_IP=114.85.107.50 diff --git a/scripts/goose-v149-canary.mjs b/scripts/goose-v149-canary.mjs index 3cfdb5d..02ac3ae 100644 --- a/scripts/goose-v149-canary.mjs +++ b/scripts/goose-v149-canary.mjs @@ -90,7 +90,7 @@ export function prepareGooseV149CheckEnv(env = process.env, rootDir = memindRoot export const GOOSE_CANARY_MODES = new Set(['off', 'all', 'users']); const BLOCKED_HOSTS = new Set([ - '180.159.29.143', + '114.85.107.50', '120.26.184.105', '103.tkmind.cn', '105.tkmind.cn', diff --git a/scripts/goose-v149-canary.test.mjs b/scripts/goose-v149-canary.test.mjs index 1566bdb..ca24823 100644 --- a/scripts/goose-v149-canary.test.mjs +++ b/scripts/goose-v149-canary.test.mjs @@ -52,7 +52,7 @@ test('resolveGooseTargetForIdentity routes canary users to v149', () => { test('assertLoopbackGooseTarget refuses production hosts', () => { assert.throws( - () => assertLoopbackGooseTarget('https://180.159.29.143:18006'), + () => assertLoopbackGooseTarget('https://114.85.107.50:18006'), /refuses production host/, ); }); diff --git a/scripts/goose-v149-sse.mjs b/scripts/goose-v149-sse.mjs index f72968c..7450f97 100644 --- a/scripts/goose-v149-sse.mjs +++ b/scripts/goose-v149-sse.mjs @@ -5,7 +5,7 @@ import { randomUUID } from 'node:crypto'; import { Readable } from 'node:stream'; import { Agent, fetch } from 'undici'; -const blockedHosts = new Set(['180.159.29.143', '120.26.184.105']); +const blockedHosts = new Set(['114.85.107.50', '120.26.184.105']); export function createV149Client(options = {}) { const host = options.host ?? process.env.GOOSE_V149_HOST ?? '127.0.0.1'; diff --git a/scripts/install-g2-aliyun-cert.sh b/scripts/install-g2-aliyun-cert.sh index 3ee2688..3c33f3f 100755 --- a/scripts/install-g2-aliyun-cert.sh +++ b/scripts/install-g2-aliyun-cert.sh @@ -3,7 +3,7 @@ # # 前置(阿里云控制台): # 1. 云解析 DNS 添加域名 tkmind.cn,NS 改到阿里云(见脚本末尾说明) -# 2. 添加 A 记录:g2 -> 180.159.29.143 +# 2. 添加 A 记录:g2 -> 114.85.107.50 # 3. RAM 创建 AccessKey,权限 AliyunDNSFullAccess # 4. cp scripts/g2-aliyun-cert.env.example scripts/g2-aliyun-cert.env 并填入密钥 # @@ -92,6 +92,6 @@ echo "" echo "==> 阿里云 DNS 迁移检查清单" echo " 1. 云解析 DNS 已添加 tkmind.cn" echo " 2. 域名注册商 NS 已改为阿里云(例如 vip1.alidns.com / vip2.alidns.com)" -echo " 3. A 记录 g2 -> ${G2_PUBLIC_IP:-180.159.29.143}" +echo " 3. A 记录 g2 -> ${G2_PUBLIC_IP:-114.85.107.50}" echo " 4. 删除 Cloudflare 上 g2 的 CNAME/代理记录,避免冲突" -echo " 5. dig @223.5.5.5 +short ${DOMAIN} A 应返回 ${G2_PUBLIC_IP:-180.159.29.143}" +echo " 5. dig @223.5.5.5 +short ${DOMAIN} A 应返回 ${G2_PUBLIC_IP:-114.85.107.50}" diff --git a/scripts/push-wechat-news-morning-draft-now.mjs b/scripts/push-wechat-news-morning-draft-now.mjs new file mode 100644 index 0000000..ed89487 --- /dev/null +++ b/scripts/push-wechat-news-morning-draft-now.mjs @@ -0,0 +1,110 @@ +#!/usr/bin/env node +/** + * 在 Portal 主机(103/143)上直接推送一条新闻早报到微信公众号草稿箱。 + * 不依赖 worker 轮询,适合手动试推。 + * + * 用法(在 143 上): + * cd /Users/john/Project/Memind + * node scripts/push-wechat-news-morning-draft-now.mjs + * node scripts/push-wechat-news-morning-draft-now.mjs --allow-yesterday + * node scripts/push-wechat-news-morning-draft-now.mjs --dry-run + */ +import process from 'node:process'; +import mysql from 'mysql2/promise'; +import { loadH5Environment } from './load-env.mjs'; +import { loadWechatMpConfig } from '../wechat-mp-config.mjs'; +import { createWechatNewsMorningDraftService } from '../wechat-news-morning-draft.mjs'; + +loadH5Environment(import.meta.dirname); + +const DEFAULT_TANG_USER_ID = 'a70ff537-8908-486e-9b6c-042e07cc25db'; + +async function ensureDraftConfig(service) { + const current = await service.getConfig(); + if (current.sourceUserId && current.enabled) return current; + const userId = String(process.env.H5_WECHAT_NEWS_MORNING_DRAFT_USER_ID ?? DEFAULT_TANG_USER_ID).trim(); + return service.updateConfig({ + enabled: true, + sourceUserId: userId, + autoPushEnabled: current.autoPushEnabled ?? false, + autoGenerateEnabled: current.autoGenerateEnabled ?? false, + }, { updatedBy: 'push-now-script' }); +} + +async function main() { + const dryRun = process.argv.includes('--dry-run'); + const allowYesterday = process.argv.includes('--allow-yesterday'); + if (!process.env.DATABASE_URL) { + console.error('DATABASE_URL missing'); + process.exit(1); + } + + const mpConfig = loadWechatMpConfig(process.env); + if (!mpConfig.enabled) { + console.error('微信服务号未启用:请确认 H5_WECHAT_MP_ENABLED=1 且 appId/secret/token/publicBaseUrl 齐全'); + process.exit(1); + } + + const pool = mysql.createPool({ uri: process.env.DATABASE_URL, connectionLimit: 2 }); + const h5Root = process.env.H5_ROOT?.trim() || process.cwd(); + const service = createWechatNewsMorningDraftService(pool, { + mpConfig, + h5Root, + memindLibRoot: h5Root, + env: process.env, + logger: console, + }); + + const config = await ensureDraftConfig(service); + console.log(JSON.stringify({ + dryRun, + allowYesterday, + sourceUserId: config.sourceUserId, + templateId: config.templateId ?? null, + templateVersion: config.templateVersion ?? null, + h5Root, + }, null, 2)); + + const preview = await service.pushDraft({ + dryRun: true, + requireToday: !allowYesterday, + triggeredBy: 'manual-push-now', + }); + console.log('\n[preview]'); + console.log(JSON.stringify({ + pageSlug: preview.preview?.page?.slug ?? null, + pageUrl: preview.preview?.page?.slug ? preview.preview.page.publicUrl : null, + isTodayPage: preview.preview?.page?.isTodayPage ?? null, + title: preview.preview?.article?.title ?? null, + contentLength: preview.preview?.article?.content?.length ?? 0, + }, null, 2)); + + if (dryRun) { + console.log('\ndry-run:未调用微信 draft/add'); + await pool.end(); + return; + } + + const result = await service.pushDraft({ + requireToday: !allowYesterday, + triggeredBy: 'manual-push-now', + }); + console.log('\n[success]'); + console.log(JSON.stringify({ + draftMediaId: result.draftMediaId, + pageSlug: result.preview?.page?.slug ?? null, + pageUrl: result.preview?.page?.publicUrl ?? null, + coverSource: result.cover?.source ?? null, + runId: result.run?.id ?? null, + }, null, 2)); + + await pool.end(); +} + +main().catch((error) => { + console.error('\n[failed]', error instanceof Error ? error.message : error); + if (error?.run) { + console.error(JSON.stringify(error.run, null, 2)); + } + process.exit(1); +}); diff --git a/scripts/regenerate-page-goose-test.mjs b/scripts/regenerate-page-goose-test.mjs index 64ecfd7..1775d1c 100644 --- a/scripts/regenerate-page-goose-test.mjs +++ b/scripts/regenerate-page-goose-test.mjs @@ -254,7 +254,7 @@ ${contentPreview}`; console.log(' 摘要:', pageAfter.summary?.slice(0, 120)); console.log(' 内容已变更:', changed ? '是' : '否'); - const publicBase = (process.env.H5_PUBLIC_BASE_URL ?? 'https://180.159.29.143').replace(/\/$/, ''); + const publicBase = (process.env.H5_PUBLIC_BASE_URL ?? 'https://114.85.107.50').replace(/\/$/, ''); const [pubRows] = await pool.query( `SELECT url_slug, status FROM h5_publish_records WHERE id = (SELECT current_publish_id FROM h5_page_records WHERE id = ?)`, [PAGE_ID], diff --git a/scripts/release-deep-search-runtime-prod.sh b/scripts/release-deep-search-runtime-prod.sh index 8959c77..c15377d 100644 --- a/scripts/release-deep-search-runtime-prod.sh +++ b/scripts/release-deep-search-runtime-prod.sh @@ -4,7 +4,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_ROOT="${STUDIO_REMOTE_ROOT:-/Users/john/Project}" RUNTIME_BASE="${DEEP_SEARCH_RUNTIME_BASE:-${REMOTE_ROOT}/deep-search-runtime}" INCOMING="${REMOTE_ROOT}/incoming/deep-search-runtime" diff --git a/scripts/release-imgproxy-native-prod.sh b/scripts/release-imgproxy-native-prod.sh index e82dbd4..067c685 100755 --- a/scripts/release-imgproxy-native-prod.sh +++ b/scripts/release-imgproxy-native-prod.sh @@ -3,7 +3,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_ROOT="${STUDIO_REMOTE_ROOT:-/Users/john/Project}" RUNTIME_BASE="${REMOTE_ROOT}/imgproxy-runtime" INCOMING="${REMOTE_ROOT}/incoming/imgproxy-runtime" diff --git a/scripts/release-imgproxy-runtime-prod.sh b/scripts/release-imgproxy-runtime-prod.sh index 569e667..2d20568 100644 --- a/scripts/release-imgproxy-runtime-prod.sh +++ b/scripts/release-imgproxy-runtime-prod.sh @@ -4,7 +4,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_ROOT="${STUDIO_REMOTE_ROOT:-/Users/john/Project}" DOCKER_BIN="${DOCKER_BIN:-/opt/homebrew/bin/docker}" RUNTIME_BASE="$REMOTE_ROOT/imgproxy-runtime" diff --git a/scripts/release-mindspace-service-prod.sh b/scripts/release-mindspace-service-prod.sh index 3da0bd0..8c1d435 100644 --- a/scripts/release-mindspace-service-prod.sh +++ b/scripts/release-mindspace-service-prod.sh @@ -2,7 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_USER_ROOT="${STUDIO_USER_ROOT:-/Users/john}" SHARED_MEMIND_ROOT="${STUDIO_SHARED_MEMIND_ROOT:-/Users/john/Project/Memind}" APP_DIR="${REMOTE_USER_ROOT}/MindSpace" diff --git a/scripts/release-portal-canary-prod.sh b/scripts/release-portal-canary-prod.sh index 32c86df..e64bc41 100755 --- a/scripts/release-portal-canary-prod.sh +++ b/scripts/release-portal-canary-prod.sh @@ -2,7 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_ROOT="${STUDIO_REMOTE_ROOT:-/Users/john/Project}" STABLE_DIR="${REMOTE_ROOT}/Memind" CANDIDATE_BASE="${REMOTE_ROOT}/Memind-candidates" diff --git a/scripts/release-portal-runtime-prod.sh b/scripts/release-portal-runtime-prod.sh index 96ab592..b268200 100755 --- a/scripts/release-portal-runtime-prod.sh +++ b/scripts/release-portal-runtime-prod.sh @@ -2,7 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_ROOT="${STUDIO_REMOTE_ROOT:-/Users/john/Project}" APP_DIR="${REMOTE_ROOT}/Memind" INCOMING_DIR="${REMOTE_ROOT}/incoming/memind-portal-runtime" diff --git a/scripts/release-prod.sh b/scripts/release-prod.sh index 7968f85..a4f4e20 100755 --- a/scripts/release-prod.sh +++ b/scripts/release-prod.sh @@ -18,7 +18,7 @@ EOF exit 1 ROOT="$(cd "$(dirname "$0")/.." && pwd)" -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_ROOT="${STUDIO_REMOTE_ROOT:-/Users/john/Project}" APP_NAME="${STUDIO_APP_NAME:-Memind}" APP_DIR="${REMOTE_ROOT}/${APP_NAME}" diff --git a/scripts/reset-tang-subscribe-morning-103.mjs b/scripts/reset-tang-subscribe-morning-103.mjs index b382e80..5028cf7 100644 --- a/scripts/reset-tang-subscribe-morning-103.mjs +++ b/scripts/reset-tang-subscribe-morning-103.mjs @@ -5,7 +5,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); -const HOST = 'john@180.159.29.143'; +const HOST = 'john@114.85.107.50'; const REMOTE_ROOT = '/Users/john/Project/Memind'; const NODE103 = '/opt/homebrew/opt/node@24/bin/node'; const TANG = 'a70ff537-8908-486e-9b6c-042e07cc25db'; diff --git a/scripts/resume-agent-run-prod.sh b/scripts/resume-agent-run-prod.sh index 4b3d674..a9e32b9 100755 --- a/scripts/resume-agent-run-prod.sh +++ b/scripts/resume-agent-run-prod.sh @@ -4,7 +4,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" cd "$ROOT" -HOST="${MEMIND_PROD_HOST:-john@180.159.29.143}" +HOST="${MEMIND_PROD_HOST:-john@114.85.107.50}" REMOTE_ROOT="${MEMIND_PROD_ROOT:-/Users/john/Project/Memind}" echo "[resume-agent-run] stop guard on ${HOST}" diff --git a/scripts/retry-tang-morning-setup-103.mjs b/scripts/retry-tang-morning-setup-103.mjs index ede1042..1e6e087 100644 --- a/scripts/retry-tang-morning-setup-103.mjs +++ b/scripts/retry-tang-morning-setup-103.mjs @@ -5,7 +5,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); -const HOST = 'john@180.159.29.143'; +const HOST = 'john@114.85.107.50'; const REMOTE_ROOT = '/Users/john/Project/Memind'; const NODE103 = '/opt/homebrew/opt/node@24/bin/node'; const TANG = 'a70ff537-8908-486e-9b6c-042e07cc25db'; diff --git a/scripts/rollback-portal-canary-prod.sh b/scripts/rollback-portal-canary-prod.sh index 9e8b884..a64edd1 100755 --- a/scripts/rollback-portal-canary-prod.sh +++ b/scripts/rollback-portal-canary-prod.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -euo pipefail -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" STABLE_DIR="${STUDIO_REMOTE_ROOT:-/Users/john/Project}/Memind" PORTAL_CANDIDATE_LABEL="cn.tkmind.memind-portal-candidate" CANARY_PROXY_LABEL="cn.tkmind.memind-canary-proxy" diff --git a/scripts/rollback-portal-runtime-prod.sh b/scripts/rollback-portal-runtime-prod.sh index 815f10e..32a0f89 100755 --- a/scripts/rollback-portal-runtime-prod.sh +++ b/scripts/rollback-portal-runtime-prod.sh @@ -2,7 +2,7 @@ set -euo pipefail ROOT="$(cd "$(dirname "$0")/.." && pwd)" -HOST="${STUDIO_HOST:-john@180.159.29.143}" +HOST="${STUDIO_HOST:-john@114.85.107.50}" REMOTE_ROOT="${STUDIO_REMOTE_ROOT:-/Users/john/Project}" APP_DIR="${REMOTE_ROOT}/Memind" BACKUP_DIR="${REMOTE_ROOT}/backups/memind" diff --git a/scripts/run-tang-subscribe-morning-e2e-103.mjs b/scripts/run-tang-subscribe-morning-e2e-103.mjs index 82243f8..9183ec8 100644 --- a/scripts/run-tang-subscribe-morning-e2e-103.mjs +++ b/scripts/run-tang-subscribe-morning-e2e-103.mjs @@ -12,7 +12,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); -const HOST = 'john@180.159.29.143'; +const HOST = 'john@114.85.107.50'; const REMOTE_ROOT = '/Users/john/Project/Memind'; const NODE103 = '/opt/homebrew/opt/node@24/bin/node'; const TANG_USER_ID = 'a70ff537-8908-486e-9b6c-042e07cc25db'; diff --git a/scripts/send-morning-greeting-preview-103.mjs b/scripts/send-morning-greeting-preview-103.mjs index aab52a0..8297c1d 100644 --- a/scripts/send-morning-greeting-preview-103.mjs +++ b/scripts/send-morning-greeting-preview-103.mjs @@ -12,7 +12,7 @@ import path from 'node:path'; import { fileURLToPath } from 'node:url'; const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); -const HOST = 'john@180.159.29.143'; +const HOST = 'john@114.85.107.50'; const REMOTE_ROOT = '/Users/john/Project/Memind'; const NODE103 = '/opt/homebrew/opt/node@24/bin/node'; const DEFAULT_TANG_USER_ID = 'a70ff537-8908-486e-9b6c-042e07cc25db'; diff --git a/scripts/sync-deepseek-cp-prod.mjs b/scripts/sync-deepseek-cp-prod.mjs index 47a4255..0c6dab5 100644 --- a/scripts/sync-deepseek-cp-prod.mjs +++ b/scripts/sync-deepseek-cp-prod.mjs @@ -3,7 +3,7 @@ * Copy local deepseek-cp provider config to production and rebind Goose executors. * * Usage (from dev machine): - * eval "$(ssh john@180.159.29.143 'grep -E "^(DATABASE_URL|TKMIND_API_TARGET|TKMIND_API_TARGETS|TKMIND_SERVER__SECRET_KEY)=" /Users/john/Project/Memind/.env | sed "s/^/TARGET_/"')" + * eval "$(ssh john@114.85.107.50 'grep -E "^(DATABASE_URL|TKMIND_API_TARGET|TKMIND_API_TARGETS|TKMIND_SERVER__SECRET_KEY)=" /Users/john/Project/Memind/.env | sed "s/^/TARGET_/"')" * node scripts/sync-deepseek-cp-prod.mjs */ import fs from 'node:fs'; diff --git a/scripts/sync-token-optimization-env-103.sh b/scripts/sync-token-optimization-env-103.sh index 24573bd..8c7a02f 100755 --- a/scripts/sync-token-optimization-env-103.sh +++ b/scripts/sync-token-optimization-env-103.sh @@ -7,7 +7,7 @@ # bash scripts/sync-token-optimization-env-103.sh --apply # write + restart portal set -euo pipefail -HOST="${MEMIND_103_HOST:-john@180.159.29.143}" +HOST="${MEMIND_103_HOST:-john@114.85.107.50}" REMOTE_ENV="/Users/john/Project/Memind/.env" APPLY=0 if [[ "${1:-}" == "--apply" ]]; then diff --git a/scripts/verify-canary-promotion-evidence.mjs b/scripts/verify-canary-promotion-evidence.mjs index 7eea47d..673dde4 100644 --- a/scripts/verify-canary-promotion-evidence.mjs +++ b/scripts/verify-canary-promotion-evidence.mjs @@ -46,7 +46,7 @@ const REMOTE_SCRIPT = [ function parseArgs(argv) { const options = { - host: process.env.STUDIO_HOST ?? 'john@180.159.29.143', + host: process.env.STUDIO_HOST ?? 'john@114.85.107.50', commit: null, artifact: path.join(ROOT, '.runtime', 'portal'), }; diff --git a/scripts/verify-session-repair-local.mjs b/scripts/verify-session-repair-local.mjs index 6d6c7de..9335ac0 100644 --- a/scripts/verify-session-repair-local.mjs +++ b/scripts/verify-session-repair-local.mjs @@ -27,7 +27,7 @@ function previewMessage(message, index) { async function load103Env() { const { execSync } = await import('node:child_process'); - const envText = execSync('ssh -o BatchMode=yes john@180.159.29.143 cat /Users/john/Project/Memind/.env', { + const envText = execSync('ssh -o BatchMode=yes john@114.85.107.50 cat /Users/john/Project/Memind/.env', { encoding: 'utf8', }); const dbLine = envText.match(/^DATABASE_URL=(.+)$/m)?.[1]?.trim().replace(/^["']|["']$/g, ''); @@ -49,7 +49,7 @@ async function load103Env() { async function fetchGooseSession(secret, sid) { const { execSync } = await import('node:child_process'); const json = execSync( - `ssh -o BatchMode=yes john@180.159.29.143 'SECRET=$(grep ^TKMIND_SERVER__SECRET_KEY= /Users/john/Project/Memind/.env | cut -d= -f2- | tr -d "\\""); curl -k -sf "https://127.0.0.1:18006/sessions/${sid}" -H "X-Secret-Key: $SECRET"'`, + `ssh -o BatchMode=yes john@114.85.107.50 'SECRET=$(grep ^TKMIND_SERVER__SECRET_KEY= /Users/john/Project/Memind/.env | cut -d= -f2- | tr -d "\\""); curl -k -sf "https://127.0.0.1:18006/sessions/${sid}" -H "X-Secret-Key: $SECRET"'`, { encoding: 'utf8', maxBuffer: 10 * 1024 * 1024 }, ); return JSON.parse(json); diff --git a/scripts/verify-tang-cursor-channel-103.mjs b/scripts/verify-tang-cursor-channel-103.mjs index 5cf7a5a..9538b83 100644 --- a/scripts/verify-tang-cursor-channel-103.mjs +++ b/scripts/verify-tang-cursor-channel-103.mjs @@ -44,7 +44,7 @@ function fail(label, detail = '') { async function loadProdDatabaseUrl() { return execSync( - "ssh -o BatchMode=yes -o ConnectTimeout=8 john@180.159.29.143 \"grep '^DATABASE_URL=' /Users/john/Project/Memind/.env | cut -d= -f2-\"", + "ssh -o BatchMode=yes -o ConnectTimeout=8 john@114.85.107.50 \"grep '^DATABASE_URL=' /Users/john/Project/Memind/.env | cut -d= -f2-\"", { encoding: 'utf8' }, ).trim(); } @@ -52,7 +52,7 @@ async function loadProdDatabaseUrl() { async function read103Env(pattern) { try { const out = execSync( - `ssh -o BatchMode=yes -o ConnectTimeout=8 john@180.159.29.143 'grep -E "${pattern}" /Users/john/Project/Memind/.env || true'`, + `ssh -o BatchMode=yes -o ConnectTimeout=8 john@114.85.107.50 'grep -E "${pattern}" /Users/john/Project/Memind/.env || true'`, { encoding: 'utf8' }, ).trim(); return out.split('\n').filter(Boolean);