From d864bcd6fb6a95f6afc5402c966f5d2dd3db1ff2 Mon Sep 17 00:00:00 2001 From: john Date: Fri, 17 Jul 2026 13:54:25 +0800 Subject: [PATCH] fix: package Excel skill controls in admin runtime --- scripts/release-prod.sh | 27 +++++++++++++++++++++ server/bootstrap.mjs | 20 ++++++++++++--- server/bootstrap.test.mjs | 51 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 server/bootstrap.test.mjs diff --git a/scripts/release-prod.sh b/scripts/release-prod.sh index d8b1be5..f6cb7e4 100755 --- a/scripts/release-prod.sh +++ b/scripts/release-prod.sh @@ -120,6 +120,9 @@ fi exit 1 } +MEMIND_GIT_HEAD="$(git -C "${MEMIND_SRC}" rev-parse HEAD 2>/dev/null || echo unknown)" +MEMIND_GIT_BRANCH="$(git -C "${MEMIND_SRC}" branch --show-current 2>/dev/null || echo detached)" + say "打包 Memind 共享模块到 memind-lib" rm -rf "${MEMIND_LIB}" mkdir -p "${MEMIND_LIB}" @@ -133,10 +136,32 @@ rsync -a \ --include '*.js' \ --exclude '*' \ "${MEMIND_SRC}/" "${MEMIND_LIB}/" + +if [[ -d "${MEMIND_SRC}/skills" ]]; then + say "打包 Memind 平台技能目录到 memind-lib" + mkdir -p "${MEMIND_LIB}/skills" + rsync -a \ + --exclude '.DS_Store' \ + --exclude '__pycache__/' \ + "${MEMIND_SRC}/skills/" "${MEMIND_LIB}/skills/" +fi + [[ -f "${MEMIND_LIB}/user-auth.mjs" ]] || { echo "memind-lib 缺少 user-auth.mjs" >&2 exit 1 } +[[ -f "${MEMIND_LIB}/skills/excel-analyst/SKILL.md" ]] || { + echo "memind-lib 缺少 Excel Analyst 技能" >&2 + exit 1 +} +grep -q 'EXCEL_ANALYST_SKILL_NAME' "${MEMIND_LIB}/skills-registry.mjs" || { + echo "memind-lib 缺少 Excel Analyst 技能授权映射" >&2 + exit 1 +} +grep -q 'tkmind-excel' "${MEMIND_LIB}/capabilities.mjs" || { + echo "memind-lib 缺少 Excel Analyst runtime 扩展映射" >&2 + exit 1 +} if [[ "${AUTO_YES}" -ne 1 && "${DRY_RUN}" -ne 1 ]]; then say "发布确认" @@ -158,6 +183,8 @@ say "生成发布清单" echo "root=${ROOT}" echo "git_head=$(git -C "${ROOT}" rev-parse HEAD 2>/dev/null || echo unknown)" echo "git_branch=$(git -C "${ROOT}" branch --show-current 2>/dev/null || echo detached)" + echo "memind_git_head=${MEMIND_GIT_HEAD}" + echo "memind_git_branch=${MEMIND_GIT_BRANCH}" echo "git_status_begin" git -C "${ROOT}" status --short --branch || true echo "git_status_end" diff --git a/server/bootstrap.mjs b/server/bootstrap.mjs index cb603c2..601f67e 100644 --- a/server/bootstrap.mjs +++ b/server/bootstrap.mjs @@ -1,18 +1,32 @@ +import fs from 'node:fs'; import path from 'node:path'; import { createDbPool, isDatabaseConfigured } from './db.mjs'; import { projectRoot } from './load-env.mjs'; import { importMemind, resolveMemindLib } from './lib-path.mjs'; import { createSystemTestAccountService, ensureSystemTestAccountSchema } from './system-test-accounts.mjs'; +export function resolveAdminH5Root({ + memindLib, + env = process.env, + root = projectRoot, +} = {}) { + const explicitSkillsRoot = env.MEMIND_SKILLS_ROOT?.trim(); + if (explicitSkillsRoot) return explicitSkillsRoot; + + if (memindLib && fs.existsSync(path.join(memindLib, 'skills'))) { + return memindLib; + } + + return env.MEMIND_LIB_ROOT?.trim() ?? path.join(root, '../Memind'); +} + export async function bootstrapAdminServices() { if (!isDatabaseConfigured()) { throw new Error('数据库未配置'); } const memindLib = resolveMemindLib(); - const h5Root = - process.env.MEMIND_LIB_ROOT?.trim() ?? - path.join(projectRoot, '../Memind'); + const h5Root = resolveAdminH5Root({ memindLib }); const pool = createDbPool(); const { loadCreateLlmProviderService } = await import('./llm-provider-loader.mjs'); const createLlmProviderService = await loadCreateLlmProviderService(); diff --git a/server/bootstrap.test.mjs b/server/bootstrap.test.mjs new file mode 100644 index 0000000..c2555a5 --- /dev/null +++ b/server/bootstrap.test.mjs @@ -0,0 +1,51 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; + +import { resolveAdminH5Root } from './bootstrap.mjs'; + +test('resolveAdminH5Root prefers an explicit skills root', () => { + assert.equal( + resolveAdminH5Root({ + memindLib: '/runtime/memind-lib', + env: { + MEMIND_SKILLS_ROOT: '/srv/platform-skills', + MEMIND_LIB_ROOT: '/srv/legacy-memind', + }, + root: '/srv/admin', + }), + '/srv/platform-skills', + ); +}); + +test('resolveAdminH5Root uses packaged memind-lib skills before the legacy Memind path', () => { + const root = fs.mkdtempSync(path.join(os.tmpdir(), 'memind-adm-skills-')); + const memindLib = path.join(root, 'memind-lib'); + fs.mkdirSync(path.join(memindLib, 'skills'), { recursive: true }); + + try { + assert.equal( + resolveAdminH5Root({ + memindLib, + env: { MEMIND_LIB_ROOT: '/srv/legacy-memind' }, + root, + }), + memindLib, + ); + } finally { + fs.rmSync(root, { recursive: true, force: true }); + } +}); + +test('resolveAdminH5Root keeps the existing development fallback', () => { + assert.equal( + resolveAdminH5Root({ + memindLib: '/missing/memind-lib', + env: { MEMIND_LIB_ROOT: '/srv/memind' }, + root: '/srv/admin', + }), + '/srv/memind', + ); +});