Compare commits

...

6 Commits

Author SHA1 Message Date
john 486e25f86b fix(release): validate composed goosed containers 2026-07-16 22:37:50 +08:00
john f4bc716789 merge: bundle MindSearch MCP runtime
Memind CI / Test, build, and release guards (push) Successful in 2m23s
2026-07-16 22:29:01 +08:00
john 3cafadba5a fix(runtime): bundle MindSearch MCP for production 2026-07-16 22:26:47 +08:00
john 122e478894 merge: pnpm release dependency lock
Memind CI / Test, build, and release guards (push) Successful in 2m54s
2026-07-16 21:44:53 +08:00
john 7b0f269180 fix: lock patched dependencies for pnpm release builds 2026-07-16 21:44:49 +08:00
john c7e4a063bf merge: production dependency security patches
Memind CI / Test, build, and release guards (push) Successful in 2m34s
2026-07-16 21:41:55 +08:00
4 changed files with 52 additions and 25 deletions
+1
View File
@@ -8,6 +8,7 @@
1. 构建只发生在本机 Mac`node scripts/build-portal-runtime.mjs`
2. 103 只接收 `.runtime/portal/` 打出来的 artifact,不直接覆盖源码树。
- 所有由 goosed 以 stdio 启动的 Portal MCP 入口都必须打进 artifact,并同时加入发布脚本的必需文件和容器可见性检查;当前包括 `mindspace-sandbox-mcp.mjs``tkmind-search-mcp.mjs`
3. 103 在切换前必须做 `Memind` 全量备份,并单独备份持久目录。
4. 103 **禁止** `npm install``npm run build`、在线改源码后继续运行。
5. 切换后必须通过 Portal 健康检查;失败立即回滚。
+10 -10
View File
@@ -24,8 +24,8 @@ importers:
specifier: ^12.42.0
version: 12.42.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
http-proxy-middleware:
specifier: ^3.0.3
version: 3.0.6
specifier: ^3.0.7
version: 3.0.7
jsonrepair:
specifier: ^3.14.0
version: 3.14.0
@@ -60,8 +60,8 @@ importers:
specifier: ^0.35.2
version: 0.35.2
undici:
specifier: ^6.26.0
version: 6.26.0
specifier: ^6.27.0
version: 6.27.0
devDependencies:
'@types/react':
specifier: ^19.0.10
@@ -1201,8 +1201,8 @@ packages:
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
engines: {node: '>= 0.8'}
http-proxy-middleware@3.0.6:
resolution: {integrity: sha512-jhO3QfahaHWfQjEnyGW0vpYIYaXcnA6FEfehrBthOokGppvmI6zcV+1yb6TWn3vyeh8yQUoEqH51DNHOCjivxg==}
http-proxy-middleware@3.0.7:
resolution: {integrity: sha512-iwbQltVlx8bCrqePUM8C+hllHvdawVhQJaLrj1X7qllkvFQdXFsr16pW/mo9+JDVjN+QO2XUx9jd8SmoFkE5qw==}
engines: {node: ^14.18.0 || ^16.10.0 || >=18.0.0}
http-proxy@1.18.1:
@@ -1635,8 +1635,8 @@ packages:
undici-types@7.24.6:
resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==}
undici@6.26.0:
resolution: {integrity: sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==}
undici@6.27.0:
resolution: {integrity: sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==}
engines: {node: '>=18.17'}
unpipe@1.0.0:
@@ -2678,7 +2678,7 @@ snapshots:
statuses: 2.0.2
toidentifier: 1.0.1
http-proxy-middleware@3.0.6:
http-proxy-middleware@3.0.7:
dependencies:
'@types/http-proxy': 1.17.17
debug: 4.4.3
@@ -3125,7 +3125,7 @@ snapshots:
undici-types@7.24.6: {}
undici@6.26.0: {}
undici@6.27.0: {}
unpipe@1.0.0: {}
+22
View File
@@ -143,6 +143,26 @@ async function bundleSandboxMcp() {
await run(esbuildBin, args);
}
async function bundleMindSearchMcp() {
if (!(await exists(esbuildBin))) {
throw new Error(`未找到 esbuild: ${esbuildBin}`);
}
console.log('==> 打包 MindSearch MCP 为单文件 runtime');
const args = [
'tkmind-search-mcp.mjs',
'--bundle',
'--platform=node',
'--format=esm',
`--target=${runtimeNodeTarget}`,
'--outfile=.runtime/portal/tkmind-search-mcp.mjs',
'--banner:js=import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);',
];
for (const pkg of externalPackages) {
args.push(`--external:${pkg}`);
}
await run(esbuildBin, args);
}
async function bundleAgentRunWorker() {
if (!(await exists(esbuildBin))) {
throw new Error(`未找到 esbuild: ${esbuildBin}`);
@@ -414,6 +434,7 @@ async function writeMetadata() {
'',
'Bundled alongside server.mjs (required for sandbox-fs MCP):',
' mindspace-sandbox-mcp.mjs (esbuild bundle; includes schedule-service deps)',
' tkmind-search-mcp.mjs (esbuild bundle; required when MindSearch is enabled)',
' wechat-mp.bundle.mjs (esbuild bundle; hot-swappable WeChat MP module)',
'',
'Post-deploy validation (scripts/check-mindspace-public-links.mjs):',
@@ -486,6 +507,7 @@ async function main() {
await bundleServer();
await bundleWechatMp();
await bundleSandboxMcp();
await bundleMindSearchMcp();
await bundleAgentRunWorker();
if (runtimeInstallMode === 'bundle-node-modules' && !skipNodeModules) {
await copyNodeModules();
+19 -15
View File
@@ -152,7 +152,7 @@ fi
verify_runtime_artifact() {
local missing=0
for required in server.mjs wechat-mp.bundle.mjs mindspace-sandbox-mcp.mjs mindspace-public-links.mjs dist package.json scripts/run-memind-portal-prod.sh scripts/check-mindspace-public-links.mjs scripts/load-env.mjs scripts/wechat-mp-menu.mjs scripts/memind-portal-tunnel.sh; do
for required in server.mjs wechat-mp.bundle.mjs mindspace-sandbox-mcp.mjs tkmind-search-mcp.mjs mindspace-public-links.mjs dist package.json scripts/run-memind-portal-prod.sh scripts/check-mindspace-public-links.mjs scripts/load-env.mjs scripts/wechat-mp-menu.mjs scripts/memind-portal-tunnel.sh; do
if [[ ! -e "${RUNTIME_ROOT}/${required}" ]]; then
echo "runtime 产物缺失: ${RUNTIME_ROOT}/${required}" >&2
missing=1
@@ -214,21 +214,25 @@ else
fi
docker_bin="/opt/homebrew/bin/docker"
if [[ -x "${docker_bin}" ]] && "${docker_bin}" ps --format '{{.Names}}' 2>/dev/null | grep -q '^goosed-prod-1$'; then
goosed_indexes=()
while IFS= read -r name; do
if [[ "${name}" =~ ^goosed-prod-([0-9]+)$ ]]; then
goosed_containers=()
goosed_indexes=()
if [[ -x "${docker_bin}" ]]; then
while IFS='|' read -r name service; do
if [[ "${service}" =~ ^goosed-([0-9]+)$ ]]; then
goosed_containers+=("${name}")
goosed_indexes+=("${BASH_REMATCH[1]}")
fi
done < <("${docker_bin}" ps --format '{{.Names}}' | sort -V)
if ((${#goosed_indexes[@]} == 0)); then
echo "goosed dependency check failed: no goosed-prod-* containers running" >&2
missing=1
fi
for index in "${goosed_indexes[@]}"; do
container="goosed-prod-${index}"
done < <("${docker_bin}" ps \
--filter 'label=com.docker.compose.project=goosed-prod' \
--format '{{.Names}}|{{.Label "com.docker.compose.service"}}')
fi
if ((${#goosed_containers[@]} > 0)); then
for position in "${!goosed_containers[@]}"; do
container="${goosed_containers[$position]}"
index="${goosed_indexes[$position]}"
host_port=$((18005 + index))
if ! "${docker_bin}" ps --format '{{.Names}} {{.Ports}} {{.Status}}' | grep -q "^${container} .*0.0.0.0:${host_port}->18006/tcp.*healthy"; then
health="$("${docker_bin}" inspect "${container}" --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}' 2>/dev/null || true)"
if [[ "${health}" != "healthy" ]] || ! "${docker_bin}" port "${container}" 18006/tcp 2>/dev/null | grep -q "0.0.0.0:${host_port}$"; then
echo "goosed dependency check failed: ${container} is not healthy on host port ${host_port}" >&2
missing=1
fi
@@ -244,8 +248,7 @@ if [[ -x "${docker_bin}" ]] && "${docker_bin}" ps --format '{{.Names}}' 2>/dev/n
echo "goosed dependency check failed: Portal .env must set GOOSED_MCP_NODE_PATH and GOOSED_MCP_SERVER_PATH for Docker goosed" >&2
missing=1
else
for index in "${goosed_indexes[@]}"; do
container="goosed-prod-${index}"
for container in "${goosed_containers[@]}"; do
if ! "${docker_bin}" exec "${container}" sh -lc "test -x '${portal_mcp_node}' && test -f '${portal_mcp_server}'" >/dev/null 2>&1; then
echo "goosed dependency check failed: ${container} cannot resolve Portal .env MCP paths '${portal_mcp_node}' and '${portal_mcp_server}'" >&2
missing=1
@@ -627,6 +630,7 @@ say "检查 live 目录中不再保留源码树"
allowed_live_mjs=(
"${APP_DIR}/server.mjs"
"${APP_DIR}/mindspace-sandbox-mcp.mjs"
"${APP_DIR}/tkmind-search-mcp.mjs"
"${APP_DIR}/mindspace-public-links.mjs"
)
extra_files=""