From 5e238423d6daabbfbb8f1619517366304e7b5239 Mon Sep 17 00:00:00 2001 From: Hao19911125 <99091644+Hao19911125@users.noreply.github.com> Date: Tue, 21 Apr 2026 14:47:03 +0800 Subject: [PATCH 1/3] Fix cloud backup restore runtime refresh --- index.js | 6 ++++- tests/graph-persistence.mjs | 45 +++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 684b59c..cdb6a8e 100644 --- a/index.js +++ b/index.js @@ -5559,7 +5559,11 @@ async function refreshRuntimeGraphAfterSyncApplied(syncPayload = {}) { const action = String(syncPayload?.action || "") .trim() .toLowerCase(); - if (action !== "download" && action !== "merge") { + if ( + action !== "download" && + action !== "merge" && + action !== "restore-backup" + ) { return { refreshed: false, reason: "action-not-supported", diff --git a/tests/graph-persistence.mjs b/tests/graph-persistence.mjs index 892a1d6..cd9d6c6 100644 --- a/tests/graph-persistence.mjs +++ b/tests/graph-persistence.mjs @@ -1936,6 +1936,51 @@ result = { ); } +{ + const harness = await createGraphPersistenceHarness({ + chatId: "chat-sync-refresh-restore", + chatMetadata: { + integrity: "chat-sync-refresh-restore-ready", + }, + }); + harness.api.setCurrentGraph( + normalizeGraphRuntimeState( + createMeaningfulGraph("chat-sync-refresh-restore", "stale-runtime-restore"), + "chat-sync-refresh-restore", + ), + ); + harness.api.setGraphPersistenceState({ + loadState: "loaded", + chatId: "chat-sync-refresh-restore", + reason: "runtime-stale", + revision: 5, + lastPersistedRevision: 5, + dbReady: true, + writesBlocked: false, + }); + harness.api.setIndexedDbSnapshot( + buildSnapshotFromGraph( + createMeaningfulGraph("chat-sync-refresh-restore", "fresh-indexeddb-restore"), + { + chatId: "chat-sync-refresh-restore", + revision: 9, + }, + ), + ); + + const runtimeOptions = harness.api.buildBmeSyncRuntimeOptions(); + await runtimeOptions.onSyncApplied({ + chatId: "chat-sync-refresh-restore", + action: "restore-backup", + }); + + assert.equal( + harness.api.getCurrentGraph().nodes[0]?.fields?.title, + "事件-fresh-indexeddb-restore", + "restore-backup 后应刷新当前运行时图谱", + ); +} + { const harness = await createGraphPersistenceHarness({ chatId: "chat-sync-refresh-active", From 1b82f54216b850c7f253e105a3eb54dca46b1c20 Mon Sep 17 00:00:00 2001 From: Hao19911125 <99091644+Hao19911125@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:35:02 +0800 Subject: [PATCH 2/3] Fix ENA planner toggle autosave race --- ui/panel-ena-sections.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui/panel-ena-sections.js b/ui/panel-ena-sections.js index fb2baae..29e5d17 100644 --- a/ui/panel-ena-sections.js +++ b/ui/panel-ena-sections.js @@ -29,6 +29,7 @@ let undoState = null; let fieldChangeHandler = null; let autosaveInProgress = false; let externalGetSettings = null; +let pendingSavePatch = null; /* ── DOM helpers ────────────────────────────────────────────────────────── */ @@ -610,6 +611,7 @@ function resetPlannerSaveStatusIfReady() { /* ── Save flow ──────────────────────────────────────────────────────────── */ function scheduleSave() { + pendingSavePatch = collectPatch(); if (autoSaveTimer) clearTimeout(autoSaveTimer); autoSaveTimer = setTimeout(doSave, AUTOSAVE_DELAY_MS); } @@ -624,9 +626,10 @@ async function doSave() { autosaveInProgress = true; setStatusChip('bme-planner-save-chip', '保存中…', 'loading'); try { - const patch = collectPatch(); + const patch = pendingSavePatch || collectPatch(); const res = await api.patchConfig(patch); if (res?.ok) { + pendingSavePatch = null; setStatusChip('bme-planner-save-chip', '已保存', 'success'); setTimeout(() => { if ($('bme-planner-save-chip')?.dataset?.tone === 'success') { @@ -1017,6 +1020,7 @@ export function cleanupPlannerSections() { cfgCache = null; logsCache = []; fetchedModels = []; + pendingSavePatch = null; externalGetSettings = null; clearUndo(); } From 2228ec42786702a345b36afb90b06403dd61fcd8 Mon Sep 17 00:00:00 2001 From: Hao19911125 <99091644+Hao19911125@users.noreply.github.com> Date: Fri, 24 Apr 2026 12:41:17 +0800 Subject: [PATCH 3/3] Persist planner toggles immediately --- ui/panel-ena-sections.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ui/panel-ena-sections.js b/ui/panel-ena-sections.js index 29e5d17..323ce69 100644 --- a/ui/panel-ena-sections.js +++ b/ui/panel-ena-sections.js @@ -616,6 +616,15 @@ function scheduleSave() { autoSaveTimer = setTimeout(doSave, AUTOSAVE_DELAY_MS); } +function flushSave() { + if (autoSaveTimer) { + clearTimeout(autoSaveTimer); + autoSaveTimer = null; + } + pendingSavePatch = collectPatch(); + void doSave(); +} + async function doSave() { if (autosaveInProgress) return; const api = getPlannerApi(); @@ -668,6 +677,11 @@ function bindOnce(section) { toBool($('bme-planner-enabled').value, false) ? '已启用' : '未启用', toBool($('bme-planner-enabled').value, false) ? 'active' : 'idle', ); + flushSave(); + }); + + $('bme-planner-skip-plot')?.addEventListener('change', () => { + flushSave(); }); $('bme-planner-run-test')?.addEventListener('click', async () => { @@ -939,6 +953,8 @@ function bindOnce(section) { if (target.closest('.bme-planner-prompt-block')) return; if (target.id === 'bme-planner-test-input') return; if (target.id === 'bme-planner-llm-preset-select') return; + if (target.id === 'bme-planner-enabled') return; + if (target.id === 'bme-planner-skip-plot') return; if (!target.classList?.contains('bme-config-input')) return; syncPlannerLlmPresetSelect(); scheduleSave();