chore: retire openhub and pi ts runtime

This commit is contained in:
Agent Board
2026-07-12 14:18:26 +08:00
parent 62959b0c4d
commit 2f5902e3e7
45 changed files with 367 additions and 925 deletions
+4 -158
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env node
/**
* 热启动 mnote-web 单入口,以及按需启用的 FastAPI。
* 热启动 mnote-web 单入口,以及按需启用的 FastAPI / opencode
* 可使用以下环境变量调整行为:
* - ENABLE_BACKEND:设为 "1" or "true" 时启用默认 FastAPI 后端
* - BACKEND_CMD:覆盖 FastAPI 启动命令;设置后即视为显式启用后端
@@ -9,16 +9,7 @@
* - ENABLE_OPENCODE:设为 "1" or "true" 时启用 opencode serve
* - OPENCODE_CMD:覆盖 opencode 启动命令;设置后即视为显式启用 opencode
* - SKIP_OPENCODE:设为 "1" or "true" 可强制跳过 opencode
* - ENABLE_OPENHUB:设为 "1" or "true" 时启用 OpenHub FastAPI
* - OPENHUB_CMD / OPENHUB_BACKEND_CMD:覆盖 OpenHub FastAPI 启动命令;设置后即视为显式启用 OpenHub
* - OPENHUB_HOST / OPENHUB_BIND_HOSTOpenHub FastAPI 监听地址,默认 0.0.0.0 便于局域网访问
* - OPENHUB_PORT / OPENHUB_BACKEND_PORTOpenHub FastAPI 端口,默认 18080
* - SKIP_OPENHUB:设为 "1" or "true" 可强制跳过 OpenHub
* - OPENHUB_REDIS_URL / OPENHUB_REDIS_DB:记录 OpenHub Redis 位置;OPENHUB_REDIS_HEALTH_URL 可选做 HTTP health 检查
* - OPENHUB_REDIS_HEALTH_URL:可选 Redis health URLdev-hot 只检查,不释放或结束 OpenHub 相关端口
* - OPENHUB_OPENCODE_BASE_URLOpenHub 侧 opencode serve base URL;默认复用 MNOTE_OPENCODE_BASE_URL
* - SKIP_OPENHUB_HEALTH:设为 "1" or "true" 可跳过 OpenHub/Redis/opencode health 预检
* - MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE:默认 "1",禁用 OpenHub Git snapshot/restore/revert 写链
* - MNOTE_OPENCODE_XDG_ROOT / MNOTE_OPENCODE_HOMEopencode 专用运行目录
* - MNOTE_CONTROL_PLANE_BACKEND:控制面后端,默认 libsql-local;可设 turso-remote / turso-local-replica / turso-synced
* - MNOTE_TURSO_LOCAL_PATHlibsql-local 本地库路径,默认 /mnt/Data1T/Mnote_data/control-plane/control-plane-libsql.db
* - MNOTE_PAGE_AI_PI_WARMUP:设为 "1" or "true" 时,在 mnote-web 可用后预启动 Pi Lab runtime / MCP cache
@@ -64,7 +55,6 @@ function resolveBackendExecutable(envName, fallbackName) {
const pythonBin = resolveBackendExecutable("PYTHON_BIN", "python");
const backendPortFromEnv = Number(process.env.BACKEND_PORT || 8000);
const opencodePortFromEnv = Number(process.env.OPENCODE_PORT || 4096);
const openhubPortFromEnv = Number(process.env.OPENHUB_BACKEND_PORT || process.env.OPENHUB_PORT || 18080);
const defaultControlPlaneDir = "/mnt/Data1T/Mnote_data/control-plane";
function hasCommand(command) {
@@ -90,8 +80,8 @@ function buildDefaultBackendCommand(port) {
}
function buildDefaultOpencodeCommand(port) {
const opencodeXdgRoot = process.env.OPENHUB_OPENCODE_XDG_ROOT || "/mnt/Data1T/Mnote_data/openhub/opencode-runtime";
const opencodeHome = process.env.OPENHUB_OPENCODE_HOME || "/mnt/Data1T/Mnote_data/openhub/opencode-home";
const opencodeXdgRoot = process.env.MNOTE_OPENCODE_XDG_ROOT || "/mnt/Data1T/Mnote_data/opencode/runtime";
const opencodeHome = process.env.MNOTE_OPENCODE_HOME || "/mnt/Data1T/Mnote_data/opencode/home";
const modelEnvNames = [
"OPENCODE_API_KEY",
"OPENAI_API_KEY",
@@ -124,19 +114,6 @@ function buildDefaultOpencodeCommand(port) {
].join(" && ");
}
function buildDefaultOpenHubCommand(port) {
const openhubBackendDir = process.env.OPENHUB_BACKEND_DIR || "/mnt/Data1T/Mnote_data/openhub/OpenHub/smart-query-backend";
const openhubHost = process.env.OPENHUB_HOST || process.env.OPENHUB_BIND_HOST || "0.0.0.0";
const uvicornBin = fs.existsSync(path.join(openhubBackendDir, ".venv", "bin", "uvicorn"))
? path.join(openhubBackendDir, ".venv", "bin", "uvicorn")
: "uvicorn";
const opencodeBaseUrl = process.env.OPENHUB_OPENCODE_BASE_URL || process.env.MNOTE_OPENCODE_BASE_URL || `http://127.0.0.1:${opencodePortFromEnv}`;
return [
`cd ${JSON.stringify(openhubBackendDir)}`,
`OPENCODE_BASE_URL=${JSON.stringify(opencodeBaseUrl)} MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE=${JSON.stringify(process.env.MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE || "1")} exec ${JSON.stringify(uvicornBin)} app.main:app --host ${JSON.stringify(openhubHost)} --port ${port}`,
].join(" && ");
}
function isEnabledEnv(value) {
const normalized = String(value || "").toLowerCase();
return normalized === "1" || normalized === "true";
@@ -154,54 +131,6 @@ function shouldStartOpencode(env = process.env) {
return true;
}
function shouldStartOpenHub(env = process.env) {
if (isEnabledEnv(env.SKIP_OPENHUB)) return false;
if (String(env.OPENHUB_BACKEND_CMD || env.OPENHUB_CMD || "").trim()) return true;
return isEnabledEnv(env.ENABLE_OPENHUB);
}
function shouldCheckOpenHubHealth(env = process.env) {
if (isEnabledEnv(env.SKIP_OPENHUB_HEALTH)) return false;
return shouldStartOpenHub(env) || isEnabledEnv(env.CHECK_OPENHUB_HEALTH);
}
function resolveOpenHubHealthPlan(env = process.env) {
const openhubPort = Number(env.OPENHUB_BACKEND_PORT || env.OPENHUB_PORT || openhubPortFromEnv);
const opencodePort = Number(env.OPENCODE_PORT || opencodePortFromEnv);
const baseUrl = String(env.MNOTE_OPENHUB_BASE_URL || env.OPENHUB_BASE_URL || `http://127.0.0.1:${openhubPort}`).replace(/\/+$/, "");
const redisHealthUrl = String(env.OPENHUB_REDIS_HEALTH_URL || "").trim();
const redisUrl = String(env.OPENHUB_REDIS_URL || "").trim();
const redisDb = String(env.OPENHUB_REDIS_DB || "").trim();
const opencodeBaseUrl = String(env.OPENHUB_OPENCODE_BASE_URL || env.MNOTE_OPENCODE_BASE_URL || `http://127.0.0.1:${opencodePort}`).replace(/\/+$/, "");
const requireHealth = isEnabledEnv(env.REQUIRE_OPENHUB_HEALTH);
return {
enabled: shouldCheckOpenHubHealth(env),
openhub: {
label: "OpenHub FastAPI",
url: env.OPENHUB_HEALTH_URL || `${baseUrl}/api/health`,
required: requireHealth,
},
redis: {
label: "OpenHub Redis",
url: redisHealthUrl,
redisUrl,
redisDb,
required: isEnabledEnv(env.REQUIRE_OPENHUB_REDIS_HEALTH),
skipped: !redisHealthUrl,
},
opencode: {
label: "opencode",
url: env.OPENCODE_HEALTH_URL || `${opencodeBaseUrl}/global/health`,
required: requireHealth,
},
gitSnapshotRestore: {
env: "MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE",
value: String(env.MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE || "1"),
defaultDisabled: true,
},
};
}
function resolveRuntimePlan(env = process.env) {
const frontendPort = Number(env.FRONTEND_PORT || 3000);
const skipGateway = false;
@@ -234,8 +163,6 @@ function resolveRuntimePlan(env = process.env) {
MNOTE_WEB_PUBLIC_BIND: env.MNOTE_WEB_PUBLIC_BIND || `127.0.0.1:${publicPort}`,
MNOTE_KNOWLEDGE_PROVIDER: env.MNOTE_KNOWLEDGE_PROVIDER || "lightrag_legacy",
MNOTE_OPENCODE_BASE_URL: env.MNOTE_OPENCODE_BASE_URL || `http://127.0.0.1:${opencodePortFromEnv}`,
MNOTE_OPENHUB_BASE_URL: env.MNOTE_OPENHUB_BASE_URL || `http://127.0.0.1:${openhubPortFromEnv}`,
MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE: env.MNOTE_OPENHUB_DISABLE_GIT_SNAPSHOT_RESTORE || "1",
...controlPlaneEnv,
},
};
@@ -279,18 +206,6 @@ const tasks = [
},
]
: []),
...(shouldStartOpenHub(process.env)
? [
{
name: "openhub",
command:
process.env.OPENHUB_BACKEND_CMD ||
process.env.OPENHUB_CMD ||
buildDefaultOpenHubCommand(openhubPortFromEnv),
cwd: rootDir,
},
]
: []),
];
function findTask(name) {
@@ -613,32 +528,6 @@ async function ensurePortFree(port, nameForLog) {
return false;
}
async function checkHttpHealth(url, label, required) {
if (!url) {
logPrefix("openhub-health", `${label} health 未配置,已跳过。`);
return true;
}
try {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), 1200);
const response = await fetch(url, {
method: "GET",
headers: { accept: "application/json,text/plain,*/*" },
signal: controller.signal,
});
clearTimeout(timer);
if (response.ok) {
logPrefix("openhub-health", `${label} 可达:${url}`);
return true;
}
logPrefix("openhub-health", `${label} 返回 HTTP ${response.status}${url}`);
return !required;
} catch (error) {
logPrefix("openhub-health", `${label} 不可达:${url} (${error.message})`);
return !required;
}
}
async function isHttpHealthy(url) {
if (!url) return false;
try {
@@ -656,24 +545,6 @@ async function isHttpHealthy(url) {
}
}
async function checkOpenHubHealth(plan = resolveOpenHubHealthPlan(process.env)) {
if (!plan.enabled) {
return true;
}
logPrefix(
"openhub-health",
`Git snapshot/restore 默认关闭:${plan.gitSnapshotRestore.env}=${plan.gitSnapshotRestore.value || "1"}`,
);
const checks = [
await checkHttpHealth(plan.openhub.url, plan.openhub.label, plan.openhub.required),
plan.redis.skipped
? (logPrefix("openhub-health", "OpenHub Redis health 未配置,已跳过非破坏性检查。"), true)
: await checkHttpHealth(plan.redis.url, plan.redis.label, plan.redis.required),
await checkHttpHealth(plan.opencode.url, plan.opencode.label, plan.opencode.required),
];
return checks.every(Boolean);
}
function loadEnvFile(filePath) {
if (!fs.existsSync(filePath)) return {};
const content = fs.readFileSync(filePath, "utf8");
@@ -854,27 +725,6 @@ async function main() {
}
if (shouldStartOpenHub(process.env) && !process.env.OPENHUB_BACKEND_CMD && !process.env.OPENHUB_CMD) {
const openhubPortOk = await ensurePortFree(openhubPortFromEnv, "openhub");
if (!openhubPortOk) {
console.error(`OpenHub 端口 ${openhubPortFromEnv} 无法释放,已中止启动。`);
process.exit(1);
}
const openhubTask = findTask("openhub");
if (!openhubTask) {
throw new Error("缺少 OpenHub 任务配置");
}
openhubTask.command = buildDefaultOpenHubCommand(openhubPortFromEnv);
} else if (isEnabledEnv(process.env.SKIP_OPENHUB)) {
logPrefix("openhub", "已跳过 OpenHub FastAPISKIP_OPENHUB=1)。");
}
const healthOk = await checkOpenHubHealth(resolveOpenHubHealthPlan(process.env));
if (!healthOk) {
console.error("OpenHub health 预检失败,已中止启动。");
process.exit(1);
}
if (tasks.length === 0) {
console.error("未配置任何可运行的任务,检查环境变量设置。");
process.exit(1);
@@ -895,8 +745,6 @@ if (require.main === module) {
module.exports = {
buildDefaultOpencodeCommand,
buildDefaultOpenHubCommand,
checkOpenHubHealth,
collectStaleMnoteWebCargoPids,
ensurePortFree,
getListeningPidsByPort,
@@ -905,12 +753,10 @@ module.exports = {
getProcessNameByPid,
isHttpHealthy,
isPortFree,
resolveOpenHubHealthPlan,
resolveRuntimePlan,
resolveBackendExecutable,
schedulePiLabWarmup,
shouldStartBackend,
shouldStartOpenHub,
stopStaleMnoteWebCargoProcesses,
terminatePid,
};