Harden panel entry initialization

This commit is contained in:
Youzini-afk
2026-04-08 02:00:31 +08:00
parent c0c04ab864
commit 50113035df
3 changed files with 131 additions and 91 deletions

108
index.js
View File

@@ -11228,59 +11228,6 @@ async function onReembedDirect() {
await loadServerSettings();
syncGraphPersistenceDebugState();
ensureBmeChatManager();
scheduleBmeIndexedDbWarmup("init");
initializeHostCapabilityBridge();
installSendIntentHooks();
autoSyncOnVisibility(buildBmeSyncRuntimeOptions());
scheduleMessageHideApply("init", 180);
// 注册事件钩子
registerCoreEventHooksController({
console,
eventSource,
eventTypes: event_types,
getCoreEventBindingState,
handlers: {
onBeforeCombinePrompts,
onCharacterMessageRendered,
onChatChanged,
onChatLoaded,
onGenerationAfterCommands,
onGenerationEnded,
onGenerationStarted,
onMessageDeleted,
onMessageEdited,
onMessageReceived,
onMessageSent,
onMessageSwiped,
onUserMessageRendered,
},
registerBeforeCombinePrompts,
registerGenerationAfterCommands,
setCoreEventBindingState,
});
// 加载当前聊天的图谱
scheduleBmeIndexedDbTask(async () => {
const syncResult = await syncBmeChatManagerWithCurrentChat("initial-load");
if (!syncResult?.chatId) {
syncGraphLoadFromLiveContext({
source: "initial-load:no-chat",
force: true,
});
return;
}
await runBmeAutoSyncForChat("initial-load", syncResult.chatId);
await loadGraphFromIndexedDb(syncResult.chatId, {
source: "initial-load",
allowOverride: true,
applyEmptyState: true,
});
});
// ==================== 操控面板初始化 ====================
await initializePanelBridgeController({
$,
actions: {
@@ -11341,6 +11288,61 @@ async function onReembedDirect() {
updateSettings: updateModuleSettings,
});
try {
ensureBmeChatManager();
scheduleBmeIndexedDbWarmup("init");
initializeHostCapabilityBridge();
installSendIntentHooks();
autoSyncOnVisibility(buildBmeSyncRuntimeOptions());
scheduleMessageHideApply("init", 180);
// 注册事件钩子
registerCoreEventHooksController({
console,
eventSource,
eventTypes: event_types,
getCoreEventBindingState,
handlers: {
onBeforeCombinePrompts,
onCharacterMessageRendered,
onChatChanged,
onChatLoaded,
onGenerationAfterCommands,
onGenerationEnded,
onGenerationStarted,
onMessageDeleted,
onMessageEdited,
onMessageReceived,
onMessageSent,
onMessageSwiped,
onUserMessageRendered,
},
registerBeforeCombinePrompts,
registerGenerationAfterCommands,
setCoreEventBindingState,
});
// 加载当前聊天的图谱
scheduleBmeIndexedDbTask(async () => {
const syncResult = await syncBmeChatManagerWithCurrentChat("initial-load");
if (!syncResult?.chatId) {
syncGraphLoadFromLiveContext({
source: "initial-load:no-chat",
force: true,
});
return;
}
await runBmeAutoSyncForChat("initial-load", syncResult.chatId);
await loadGraphFromIndexedDb(syncResult.chatId, {
source: "initial-load",
allowOverride: true,
applyEmptyState: true,
});
});
} catch (bootError) {
console.error("[ST-BME] 核心初始化阶段失败(面板入口已保留):", bootError);
}
schedulePersistedRecallMessageUiRefresh(120);
try {
const { initEnaPlanner } = await import("./ena-planner/ena-planner.js");

View File

@@ -1,5 +1,8 @@
import { debugLog } from "../runtime/debug-logging.js";
const MENU_ENTRY_RETRY_MS = 400;
const MENU_ENTRY_MAX_ATTEMPTS = 30;
function resolvePanelTheme(settings) {
return settings?.panelTheme || "crimson";
}
@@ -25,7 +28,7 @@ export function openPanelController(runtime) {
function injectOptionsMenuEntry(runtime) {
if (runtime.document.getElementById("option_st_bme_panel")) {
return;
return true;
}
const $menuItem = runtime.$(`
@@ -33,7 +36,8 @@ function injectOptionsMenuEntry(runtime) {
<i class="fa-lg fa-solid fa-brain"></i>
<span>记忆图谱</span>
</a>
`).on("click", () => {
`).on("click", async () => {
await ensurePanelBridgeReady(runtime);
openPanelController(runtime);
runtime.$("#options").hide();
});
@@ -43,48 +47,82 @@ function injectOptionsMenuEntry(runtime) {
if ($anchor.length > 0) {
$anchor.after($menuItem);
return true;
} else if ($optionsContent.length > 0) {
$optionsContent.append($menuItem);
return true;
}
return false;
}
function scheduleOptionsMenuInjection(runtime, attempt = 0) {
if (injectOptionsMenuEntry(runtime)) {
return;
}
if (attempt >= MENU_ENTRY_MAX_ATTEMPTS) {
runtime.console.warn(
"[ST-BME] 操控面板菜单入口注入失败:宿主 options DOM 长时间未就绪",
);
return;
}
globalThis.setTimeout(() => {
scheduleOptionsMenuInjection(runtime, attempt + 1);
}, MENU_ENTRY_RETRY_MS);
}
async function ensurePanelBridgeReady(runtime) {
const hasPanelDom = Boolean(
runtime.document.getElementById("st-bme-panel-overlay") &&
runtime.document.getElementById("st-bme-panel"),
);
if (runtime.getPanelModule()?.openPanel && hasPanelDom) {
return runtime.getPanelModule();
}
const panelModule = await runtime.importPanelModule();
const themesModule = await runtime.importThemesModule();
runtime.setPanelModule(panelModule);
runtime.setThemesModule(themesModule);
const settings = runtime.getSettings();
const theme = resolvePanelTheme(settings);
themesModule.applyTheme(theme);
await panelModule.initPanel({
getGraph: runtime.getGraph,
getSettings: runtime.getSettings,
getLastExtract: runtime.getLastExtract,
getLastRecall: runtime.getLastRecall,
getRuntimeStatus: runtime.getRuntimeStatus,
getLastExtractionStatus: runtime.getLastExtractionStatus,
getLastVectorStatus: runtime.getLastVectorStatus,
getLastRecallStatus: runtime.getLastRecallStatus,
getLastBatchStatus: runtime.getLastBatchStatus,
getLastInjection: runtime.getLastInjection,
getRuntimeDebugSnapshot: runtime.getRuntimeDebugSnapshot,
getGraphPersistenceState: runtime.getGraphPersistenceState,
updateSettings: (patch) => {
const nextSettings = runtime.updateSettings(patch);
if (Object.prototype.hasOwnProperty.call(patch || {}, "panelTheme")) {
const nextTheme = resolvePanelTheme(nextSettings);
runtime.getThemesModule()?.applyTheme?.(nextTheme);
runtime.getPanelModule()?.updatePanelTheme?.(nextTheme);
}
return nextSettings;
},
actions: runtime.actions,
});
return panelModule;
}
export async function initializePanelBridgeController(runtime) {
try {
const panelModule = await runtime.importPanelModule();
const themesModule = await runtime.importThemesModule();
runtime.setPanelModule(panelModule);
runtime.setThemesModule(themesModule);
const settings = runtime.getSettings();
const theme = resolvePanelTheme(settings);
themesModule.applyTheme(theme);
await panelModule.initPanel({
getGraph: runtime.getGraph,
getSettings: runtime.getSettings,
getLastExtract: runtime.getLastExtract,
getLastRecall: runtime.getLastRecall,
getRuntimeStatus: runtime.getRuntimeStatus,
getLastExtractionStatus: runtime.getLastExtractionStatus,
getLastVectorStatus: runtime.getLastVectorStatus,
getLastRecallStatus: runtime.getLastRecallStatus,
getLastBatchStatus: runtime.getLastBatchStatus,
getLastInjection: runtime.getLastInjection,
getRuntimeDebugSnapshot: runtime.getRuntimeDebugSnapshot,
getGraphPersistenceState: runtime.getGraphPersistenceState,
updateSettings: (patch) => {
const nextSettings = runtime.updateSettings(patch);
if (Object.prototype.hasOwnProperty.call(patch || {}, "panelTheme")) {
const nextTheme = resolvePanelTheme(nextSettings);
runtime.getThemesModule()?.applyTheme?.(nextTheme);
runtime.getPanelModule()?.updatePanelTheme?.(nextTheme);
}
return nextSettings;
},
actions: runtime.actions,
});
injectOptionsMenuEntry(runtime);
scheduleOptionsMenuInjection(runtime);
await ensurePanelBridgeReady(runtime);
debugLog("[ST-BME] 操控面板初始化完成");
} catch (panelError) {
runtime.console.error(

View File

@@ -254,7 +254,7 @@ function mountPanelHtml(html) {
}
if (document.body?.insertAdjacentHTML) {
document.body.insertAdjacentHTML("beforebegin", markup);
document.body.insertAdjacentHTML("beforeend", markup);
return;
}