diff --git a/release-gate/release-script.test.mjs b/release-gate/release-script.test.mjs index f95d3d2..604b202 100644 --- a/release-gate/release-script.test.mjs +++ b/release-gate/release-script.test.mjs @@ -200,6 +200,9 @@ test('production canary keeps stable 8081 live and switches only after verified ); assert.match(source, /MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED/); assert.match(source, /MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS/); + assert.match(source, /CANARY_AIDER_BIN="\/opt\/homebrew\/bin\/aider"/); + assert.match(source, /test -x '\$\{CANARY_AIDER_BIN\}'/); + assert.match(source, /MEMIND_CANARY_AIDER_BIN/); assert.match(source, /route-probe\?\$\{probe_query\}/); assert.match(source, /candidate_healthy/); assert.match(source, /MEMIND_CANARY_RELEASE_ID/); @@ -219,6 +222,7 @@ test('candidate runner overrides stable host MCP paths with container-visible pa const stableRoot = path.join(tempRoot, 'stable'); const fakeNode = path.join(tempRoot, 'node'); + const fakeAider = path.join(tempRoot, 'aider'); await fs.mkdir(stableRoot); await fs.writeFile( path.join(stableRoot, '.env'), @@ -232,6 +236,7 @@ test('candidate runner overrides stable host MCP paths with container-visible pa 'MEMIND_GOOSED_HOST_GATEWAY=wrong.invalid', 'H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_ENABLED=0', 'H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_USERS=wrong-user', + 'AIDER_BIN=/definitely/missing/aider', '', ].join('\n'), ); @@ -249,11 +254,13 @@ test('candidate runner overrides stable host MCP paths with container-visible pa 'printf "deepseek_host=%s\\n" "${MEMIND_DEEPSEEK_NO_THINK_HOST-unset}"', 'printf "page_data_review=%s\\n" "$H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_ENABLED"', 'printf "page_data_review_users=%s\\n" "$H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_USERS"', + 'printf "aider_bin=%s\\n" "$AIDER_BIN"', 'printf "entrypoint=%s\\n" "$1"', '', ].join('\n'), { mode: 0o755 }, ); + await fs.writeFile(fakeAider, '#!/usr/bin/env bash\nexit 0\n', { mode: 0o755 }); const result = spawnSync( 'bash', @@ -269,6 +276,7 @@ test('candidate runner overrides stable host MCP paths with container-visible pa MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED: '1', MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS: 'a70ff537-8908-486e-9b6c-042e07cc25db', + MEMIND_CANARY_AIDER_BIN: fakeAider, NODE_BIN: fakeNode, }, }, @@ -291,6 +299,7 @@ test('candidate runner overrides stable host MCP paths with container-visible pa result.stdout, /^page_data_review_users=a70ff537-8908-486e-9b6c-042e07cc25db$/m, ); + assert.match(result.stdout, new RegExp(`^aider_bin=${fakeAider}$`, 'm')); assert.match(result.stdout, new RegExp(`^entrypoint=${ROOT}/server\\.mjs$`, 'm')); }); diff --git a/scripts/release-portal-canary-prod.sh b/scripts/release-portal-canary-prod.sh index 708a586..72dc92f 100755 --- a/scripts/release-portal-canary-prod.sh +++ b/scripts/release-portal-canary-prod.sh @@ -24,6 +24,7 @@ CANARY_USERNAMES="john" CANARY_WECHAT_USER_IDS="wx_ul610et8" CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED="1" CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS="a70ff537-8908-486e-9b6c-042e07cc25db" +CANARY_AIDER_BIN="/opt/homebrew/bin/aider" RELEASE_TS="$(date +%Y%m%d-%H%M%S)" FULL_SHA="$(git -C "${ROOT}" rev-parse HEAD)" SHORT_SHA="${FULL_SHA:0:7}" @@ -183,6 +184,7 @@ printf '%s %s\n' "${bundle_sha}" "$(basename "${BUNDLE_PATH}")" > "${SHA_PATH}" echo "canary_wechat_user_ids=${CANARY_WECHAT_USER_IDS}" echo "canary_wechat_page_data_aider_review_enabled=${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED}" echo "canary_wechat_page_data_aider_review_user_ids=${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS}" + echo "canary_aider_bin=${CANARY_AIDER_BIN}" echo "manual_environment_changes=none" } > "${MANIFEST_PATH}" @@ -197,6 +199,7 @@ ssh -o BatchMode=yes -o ConnectTimeout=15 "${HOST}" \ "test -d '${STABLE_DIR}' \ && test -f '${STABLE_DIR}/.env' \ && test -f '${GOOSED_DIR}/docker-compose.prod.yml' \ + && test -x '${CANARY_AIDER_BIN}' \ && curl -fsS http://127.0.0.1:8081/api/status >/dev/null \ && ! lsof -nP -iTCP:${CANARY_PROXY_PORT} -sTCP:LISTEN >/dev/null 2>&1 \ && ! lsof -nP -iTCP:${DEEPSEEK_COMPAT_PORT} -sTCP:LISTEN >/dev/null 2>&1 \ @@ -314,6 +317,7 @@ ssh -o BatchMode=yes "${HOST}" \ CANARY_WECHAT_USER_IDS='${CANARY_WECHAT_USER_IDS}' \ CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED='${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED}' \ CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS='${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS}' \ + CANARY_AIDER_BIN='${CANARY_AIDER_BIN}' \ /bin/bash" <<'REMOTE_SCRIPT' set -euo pipefail @@ -578,6 +582,7 @@ cat > "${CANDIDATE_PLIST}" <MEMIND_CANARY_DEEPSEEK_PROXY_PORT${DEEPSEEK_COMPAT_PORT} MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED} MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS${CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS} + MEMIND_CANARY_AIDER_BIN${CANARY_AIDER_BIN} RunAtLoad KeepAlive diff --git a/scripts/run-memind-portal-candidate.sh b/scripts/run-memind-portal-candidate.sh index c3f75a2..dc9fa08 100755 --- a/scripts/run-memind-portal-candidate.sh +++ b/scripts/run-memind-portal-candidate.sh @@ -40,6 +40,7 @@ export MEMIND_DEEPSEEK_NO_THINK_PORT="${MEMIND_CANARY_DEEPSEEK_PROXY_PORT:-18036 export MEMIND_GOOSED_HOST_GATEWAY=host.docker.internal export H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_ENABLED="${MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_ENABLED:-0}" export H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_USERS="${MEMIND_CANARY_WECHAT_PAGE_DATA_AIDER_REVIEW_USER_IDS:-}" +export AIDER_BIN="${MEMIND_CANARY_AIDER_BIN:-/opt/homebrew/bin/aider}" unset MEMIND_DEEPSEEK_NO_THINK_BASE_URL unset MEMIND_DEEPSEEK_NO_THINK_HOST unset TKMIND_API_TARGET_1 @@ -48,6 +49,10 @@ NODE_BIN="${NODE_BIN:-/opt/homebrew/opt/node@24/bin/node}" if [[ ! -x "${NODE_BIN}" ]]; then NODE_BIN="$(command -v node)" fi +if [[ "${H5_WECHAT_MP_PAGE_DATA_AIDER_REVIEW_ENABLED}" == "1" && ! -x "${AIDER_BIN}" ]]; then + echo "[portal-candidate] configured Aider executable is unavailable: ${AIDER_BIN}" >&2 + exit 1 +fi port="${H5_PORT}" if lsof -tiTCP:"${port}" -sTCP:LISTEN >/dev/null 2>&1; then