Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 486e25f86b | |||
| f4bc716789 | |||
| 3cafadba5a | |||
| 122e478894 |
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
1. 构建只发生在本机 Mac:`node scripts/build-portal-runtime.mjs`。
|
1. 构建只发生在本机 Mac:`node scripts/build-portal-runtime.mjs`。
|
||||||
2. 103 只接收 `.runtime/portal/` 打出来的 artifact,不直接覆盖源码树。
|
2. 103 只接收 `.runtime/portal/` 打出来的 artifact,不直接覆盖源码树。
|
||||||
|
- 所有由 goosed 以 stdio 启动的 Portal MCP 入口都必须打进 artifact,并同时加入发布脚本的必需文件和容器可见性检查;当前包括 `mindspace-sandbox-mcp.mjs` 与 `tkmind-search-mcp.mjs`。
|
||||||
3. 103 在切换前必须做 `Memind` 全量备份,并单独备份持久目录。
|
3. 103 在切换前必须做 `Memind` 全量备份,并单独备份持久目录。
|
||||||
4. 103 **禁止** `npm install`、`npm run build`、在线改源码后继续运行。
|
4. 103 **禁止** `npm install`、`npm run build`、在线改源码后继续运行。
|
||||||
5. 切换后必须通过 Portal 健康检查;失败立即回滚。
|
5. 切换后必须通过 Portal 健康检查;失败立即回滚。
|
||||||
|
|||||||
@@ -143,6 +143,26 @@ async function bundleSandboxMcp() {
|
|||||||
await run(esbuildBin, args);
|
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() {
|
async function bundleAgentRunWorker() {
|
||||||
if (!(await exists(esbuildBin))) {
|
if (!(await exists(esbuildBin))) {
|
||||||
throw new Error(`未找到 esbuild: ${esbuildBin}`);
|
throw new Error(`未找到 esbuild: ${esbuildBin}`);
|
||||||
@@ -414,6 +434,7 @@ async function writeMetadata() {
|
|||||||
'',
|
'',
|
||||||
'Bundled alongside server.mjs (required for sandbox-fs MCP):',
|
'Bundled alongside server.mjs (required for sandbox-fs MCP):',
|
||||||
' mindspace-sandbox-mcp.mjs (esbuild bundle; includes schedule-service deps)',
|
' 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)',
|
' wechat-mp.bundle.mjs (esbuild bundle; hot-swappable WeChat MP module)',
|
||||||
'',
|
'',
|
||||||
'Post-deploy validation (scripts/check-mindspace-public-links.mjs):',
|
'Post-deploy validation (scripts/check-mindspace-public-links.mjs):',
|
||||||
@@ -486,6 +507,7 @@ async function main() {
|
|||||||
await bundleServer();
|
await bundleServer();
|
||||||
await bundleWechatMp();
|
await bundleWechatMp();
|
||||||
await bundleSandboxMcp();
|
await bundleSandboxMcp();
|
||||||
|
await bundleMindSearchMcp();
|
||||||
await bundleAgentRunWorker();
|
await bundleAgentRunWorker();
|
||||||
if (runtimeInstallMode === 'bundle-node-modules' && !skipNodeModules) {
|
if (runtimeInstallMode === 'bundle-node-modules' && !skipNodeModules) {
|
||||||
await copyNodeModules();
|
await copyNodeModules();
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ fi
|
|||||||
|
|
||||||
verify_runtime_artifact() {
|
verify_runtime_artifact() {
|
||||||
local missing=0
|
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
|
if [[ ! -e "${RUNTIME_ROOT}/${required}" ]]; then
|
||||||
echo "runtime 产物缺失: ${RUNTIME_ROOT}/${required}" >&2
|
echo "runtime 产物缺失: ${RUNTIME_ROOT}/${required}" >&2
|
||||||
missing=1
|
missing=1
|
||||||
@@ -214,21 +214,25 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
docker_bin="/opt/homebrew/bin/docker"
|
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_containers=()
|
||||||
goosed_indexes=()
|
goosed_indexes=()
|
||||||
while IFS= read -r name; do
|
if [[ -x "${docker_bin}" ]]; then
|
||||||
if [[ "${name}" =~ ^goosed-prod-([0-9]+)$ ]]; then
|
while IFS='|' read -r name service; do
|
||||||
|
if [[ "${service}" =~ ^goosed-([0-9]+)$ ]]; then
|
||||||
|
goosed_containers+=("${name}")
|
||||||
goosed_indexes+=("${BASH_REMATCH[1]}")
|
goosed_indexes+=("${BASH_REMATCH[1]}")
|
||||||
fi
|
fi
|
||||||
done < <("${docker_bin}" ps --format '{{.Names}}' | sort -V)
|
done < <("${docker_bin}" ps \
|
||||||
if ((${#goosed_indexes[@]} == 0)); then
|
--filter 'label=com.docker.compose.project=goosed-prod' \
|
||||||
echo "goosed dependency check failed: no goosed-prod-* containers running" >&2
|
--format '{{.Names}}|{{.Label "com.docker.compose.service"}}')
|
||||||
missing=1
|
fi
|
||||||
fi
|
if ((${#goosed_containers[@]} > 0)); then
|
||||||
for index in "${goosed_indexes[@]}"; do
|
for position in "${!goosed_containers[@]}"; do
|
||||||
container="goosed-prod-${index}"
|
container="${goosed_containers[$position]}"
|
||||||
|
index="${goosed_indexes[$position]}"
|
||||||
host_port=$((18005 + index))
|
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
|
echo "goosed dependency check failed: ${container} is not healthy on host port ${host_port}" >&2
|
||||||
missing=1
|
missing=1
|
||||||
fi
|
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
|
echo "goosed dependency check failed: Portal .env must set GOOSED_MCP_NODE_PATH and GOOSED_MCP_SERVER_PATH for Docker goosed" >&2
|
||||||
missing=1
|
missing=1
|
||||||
else
|
else
|
||||||
for index in "${goosed_indexes[@]}"; do
|
for container in "${goosed_containers[@]}"; do
|
||||||
container="goosed-prod-${index}"
|
|
||||||
if ! "${docker_bin}" exec "${container}" sh -lc "test -x '${portal_mcp_node}' && test -f '${portal_mcp_server}'" >/dev/null 2>&1; then
|
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
|
echo "goosed dependency check failed: ${container} cannot resolve Portal .env MCP paths '${portal_mcp_node}' and '${portal_mcp_server}'" >&2
|
||||||
missing=1
|
missing=1
|
||||||
@@ -627,6 +630,7 @@ say "检查 live 目录中不再保留源码树"
|
|||||||
allowed_live_mjs=(
|
allowed_live_mjs=(
|
||||||
"${APP_DIR}/server.mjs"
|
"${APP_DIR}/server.mjs"
|
||||||
"${APP_DIR}/mindspace-sandbox-mcp.mjs"
|
"${APP_DIR}/mindspace-sandbox-mcp.mjs"
|
||||||
|
"${APP_DIR}/tkmind-search-mcp.mjs"
|
||||||
"${APP_DIR}/mindspace-public-links.mjs"
|
"${APP_DIR}/mindspace-public-links.mjs"
|
||||||
)
|
)
|
||||||
extra_files=""
|
extra_files=""
|
||||||
|
|||||||
Reference in New Issue
Block a user