Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 486e25f86b | |||
| f4bc716789 | |||
| 3cafadba5a | |||
| 122e478894 | |||
| 7b0f269180 | |||
| c7e4a063bf |
@@ -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 健康检查;失败立即回滚。
|
||||
|
||||
Generated
+10
-10
@@ -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: {}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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=""
|
||||
|
||||
Reference in New Issue
Block a user