Improve WeChat MP replies and ship MindSpace/H5 production updates.

Add WeChat service account routing with sync acks, connectivity tests, and context isolation; document deploy runbooks; and bundle related MindSpace, voice, Plaza, and server gateway changes for production rollout.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
john
2026-06-19 23:06:43 +08:00
parent b0f5d6a51c
commit 229805a070
241 changed files with 13190 additions and 902 deletions
+237
View File
@@ -0,0 +1,237 @@
#!/usr/bin/env bash
set -euo pipefail
# 一键把源码同步到开发机测试目录:Memind / memind_adm / Plaza
# 适用:更新基于源码的开发机器环境。goose 不在本流程内。
HOST="${DEPLOY_HOST:-192.168.1.9}"
USER="${DEPLOY_USER:-john}"
TARGET="${DEPLOY_USER_HOST:-${USER}@${HOST}}"
ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
EXCLUDE_FILE="${ROOT_DIR}/scripts/.rsync-exclude-test-host"
MEMIND_SRC="${MEMIND_SRC:-${ROOT_DIR}}"
ADM_SRC="${ADM_SRC:-${ROOT_DIR}/../memind_adm}"
PLAZA_SRC="${PLAZA_SRC:-${ROOT_DIR}/../tkmind_go/ui/plaza}"
MEMIND_DST="${MEMIND_DST:-/Users/john/PycharmProjects/test/test-memind}"
ADM_DST="${ADM_DST:-/Users/john/PycharmProjects/test/test-memindadm}"
PLAZA_DST="${PLAZA_DST:-/Users/john/PycharmProjects/test/test-memindplaza}"
RSYNC_OPTS=(
-az
--delete
--exclude-from="${EXCLUDE_FILE}"
)
DRY_RUN=0
CHECK_ONLY=0
ONLY_MEMIND=0
ONLY_ADM=0
ONLY_PLAZA=0
SKIP_MV=0
AUTO_YES=0
usage() {
cat <<USAGE
用法: ./scripts/deploy-to-test-host.sh [选项]
目标目录(支持环境变量覆盖)
DEPLOY_HOST, DEPLOY_USER, DEPLOY_USER_HOST
MEMIND_SRC, ADM_SRC, PLAZA_SRC
MEMIND_DST, ADM_DST, PLAZA_DST
MEMIND_STATUS_URL, ADMIN_STATUS_URL, PLAZA_URL
常用选项
--only-memind 仅同步 test-memind
--only-adm 仅同步 test-memindadm
--only-plaza 仅同步 test-memindplaza
--skip-delete 同步时不做 --delete(避免误删未排除文件)
--dry-run 预览变更,不实际写入
--check-only 只做连通性和目录检查,不做 rsync
--yes 非交互,自动确认
--help 显示帮助
示例
./scripts/deploy-to-test-host.sh --dry-run
./scripts/deploy-to-test-host.sh --only-memind --skip-delete
USAGE
}
while [[ "$#" -gt 0 ]]; do
case "$1" in
--only-memind) ONLY_MEMIND=1 ;;
--only-adm) ONLY_ADM=1 ;;
--only-plaza) ONLY_PLAZA=1 ;;
--skip-delete) SKIP_MV=1 ;;
--dry-run) DRY_RUN=1 ;;
--check-only) CHECK_ONLY=1 ;;
--yes) AUTO_YES=1 ;;
--help|-h)
usage
exit 0
;;
*)
echo "未知参数: $1" >&2
usage
exit 1
;;
esac
shift
done
if [[ "${ONLY_MEMIND}" -eq 1 && ("${ONLY_ADM}" -eq 1 || "${ONLY_PLAZA}" -eq 1) ]] ||
[[ "${ONLY_ADM}" -eq 1 && "${ONLY_PLAZA}" -eq 1 ]]; then
echo "错误: --only-* 只能选一个" >&2
exit 1
fi
if [[ "${SKIP_MV}" -eq 1 ]]; then
RSYNC_OPTS=(
-az
--exclude-from="${EXCLUDE_FILE}"
)
fi
if [[ ! -f "${EXCLUDE_FILE}" ]]; then
echo "错误: 未找到排除规则文件 ${EXCLUDE_FILE}" >&2
exit 1
fi
SSH_OPTS=(-o BatchMode=yes -o ConnectTimeout=12)
log() { printf '%s\n' "$*"; }
err() { printf '%s\n' "$*" >&2; }
fail() { err "$*"; exit 1; }
ok() { printf '%s\n' "$*"; }
ssh_to_host() {
ssh "${SSH_OPTS[@]}" "${TARGET}" "$*"
}
preflight_local() {
local src=$1
[[ -d "$src" ]] || fail "本地源目录不存在: $src"
[[ -f "$src/.gitignore" ]] || true
ok "本地源目录存在: $src"
}
preflight_remote() {
local dst=$1
local label=$2
ssh_to_host "mkdir -p '${dst}'" >/dev/null
if ! ssh_to_host "test -w '${dst}'" >/dev/null 2>&1; then
fail "远端目标不可写: ${label} -> ${TARGET}:${dst}"
fi
ok "远端目录可写: ${label} -> ${dst}"
}
ensure_host() {
log "检查 SSH: ${TARGET}"
ssh_to_host "echo connected" >/dev/null || fail "SSH 连接失败:${TARGET}"
ok "SSH 连接成功: ${TARGET}"
}
need_confirm() {
local target=$1
[[ "${AUTO_YES}" -eq 1 ]] && return 0
read -r -p "确认同步 ${target}[y/N] " input
[[ "$input" == "y" || "$input" == "Y" ]]
}
do_sync() {
local label=$1
local src=$2
local dst=$3
local flags=("${RSYNC_OPTS[@]}")
preflight_local "$src"
preflight_remote "$dst" "$label"
if [[ "${DRY_RUN}" -eq 1 ]]; then
flags+=(--dry-run --itemize-changes)
log "[预览] ${label}: ${src} -> ${TARGET}:${dst}"
rsync "${flags[@]}" "${src}/" "${TARGET}:${dst}/" | head -80
return 0
fi
if ! need_confirm "$label"; then
fail "用户取消:${label}"
fi
log "同步中 ${label}: ${src} -> ${TARGET}:${dst}"
rsync "${flags[@]}" "${src}/" "${TARGET}:${dst}/"
ok "同步完成 ${label}"
}
health_check() {
local label=$1
local url=$2
if [[ -z "${url}" ]]; then
return 0
fi
if ssh_to_host "command -v curl >/dev/null && curl -fsS '${url}' >/dev/null" >/dev/null 2>&1; then
ok "${label} 健康检查通过:${url}"
else
log "${label} 健康检查失败:${url}(仅提示)"
fi
}
export MEMIND_STATUS_URL="${MEMIND_STATUS_URL:-http://127.0.0.1:18081/api/status}"
export ADMIN_STATUS_URL="${ADMIN_STATUS_URL:-http://127.0.0.1:18082/healthz}"
export PLAZA_URL="${PLAZA_URL:-http://127.0.0.1:13001/plaza}"
ensure_host
if [[ "${CHECK_ONLY}" -eq 1 ]]; then
preflight_remote "${MEMIND_DST}" "Memind"
preflight_remote "${ADM_DST}" "memind_adm"
preflight_remote "${PLAZA_DST}" "Plaza"
ok "检查通过:远端目录可用"
health_check "Memind" "${MEMIND_STATUS_URL}"
health_check "memind_adm" "${ADMIN_STATUS_URL}"
health_check "Plaza" "${PLAZA_URL}"
exit 0
fi
TARGETS=()
if [[ "${ONLY_MEMIND}" -eq 1 ]]; then
TARGETS+=("memind")
elif [[ "${ONLY_ADM}" -eq 1 ]]; then
TARGETS+=("adm")
elif [[ "${ONLY_PLAZA}" -eq 1 ]]; then
TARGETS+=("plaza")
else
TARGETS+=("memind" "adm" "plaza")
fi
for t in "${TARGETS[@]}"; do
case "$t" in
memind)
do_sync "Memind" "${MEMIND_SRC}" "${MEMIND_DST}"
;;
adm)
do_sync "memind_adm" "${ADM_SRC}" "${ADM_DST}"
;;
plaza)
do_sync "Plaza" "${PLAZA_SRC}" "${PLAZA_DST}"
;;
esac
done
log "同步完成。建议检查:"
log " Memind: ${MEMIND_STATUS_URL}"
log " memind_adm: ${ADMIN_STATUS_URL}"
log " Plaza: ${PLAZA_URL}"
echo "\n可在远端执行 restart(不包含 goose"
echo " ssh ${TARGET}"
echo " cd ${MEMIND_DST} && pnpm install && pnpm dev:server 或 pm2 reload memind"
echo " cd ${ADM_DST} && pnpm install && pnpm start:??"
echo " cd ${PLAZA_DST} && pnpm install && pnpm dev:plaza"
echo ""
echo "如果需要,我也可以把 restart 命令固定成你们当前启动脚架构(例如 launchctl/systemd/pm2/nodemon)。"