mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-05-15 22:30:38 +08:00
feat: 新增「数据清理」配置页
- 图谱清理:清空当前图谱、按楼层范围删除节点 - 缓存清理:清空向量缓存、清空提取历史 - 存储清理:清空当前/全部 IDB、清空服务端同步文件 - 高危操作全部需要 confirm 弹窗确认 - 清空全部 IDB 和清空服务端同步文件需要输入 DELETE 确认
This commit is contained in:
79
index.js
79
index.js
@@ -27,6 +27,7 @@ import {
|
||||
import {
|
||||
autoSyncOnChatChange,
|
||||
autoSyncOnVisibility,
|
||||
deleteRemoteSyncFile,
|
||||
scheduleUpload,
|
||||
syncNow,
|
||||
} from "./sync/bme-sync.js";
|
||||
@@ -212,6 +213,13 @@ import {
|
||||
onTestMemoryLLMController,
|
||||
onViewGraphController,
|
||||
onViewLastInjectionController,
|
||||
onClearGraphController,
|
||||
onClearGraphRangeController,
|
||||
onClearVectorCacheController,
|
||||
onClearBatchJournalController,
|
||||
onDeleteCurrentIdbController,
|
||||
onDeleteAllIdbController,
|
||||
onDeleteServerSyncFileController,
|
||||
} from "./ui/ui-actions-controller.js";
|
||||
import {
|
||||
clampInt,
|
||||
@@ -10917,6 +10925,70 @@ async function onReembedDirect() {
|
||||
});
|
||||
}
|
||||
|
||||
// ==================== 数据清理 ====================
|
||||
|
||||
const _cleanupRuntime = () => ({
|
||||
confirm: (msg) => (typeof globalThis.confirm === "function" ? globalThis.confirm(msg) : false),
|
||||
prompt: (msg) => (typeof globalThis.prompt === "function" ? globalThis.prompt(msg) : null),
|
||||
createEmptyGraph,
|
||||
clearInjectionState,
|
||||
ensureGraphMutationReady,
|
||||
getCurrentChatId,
|
||||
getCurrentGraph: () => currentGraph,
|
||||
markVectorStateDirty: (reason) => {
|
||||
if (currentGraph?.vectorIndexState) {
|
||||
currentGraph.vectorIndexState.dirty = true;
|
||||
currentGraph.vectorIndexState.dirtyReason = reason;
|
||||
}
|
||||
},
|
||||
normalizeGraphRuntimeState,
|
||||
refreshPanelLiveState,
|
||||
removeNode: (graph, nodeId) => removeNode(graph, nodeId),
|
||||
saveGraphToChat,
|
||||
setCurrentGraph: (graph) => { currentGraph = graph; },
|
||||
setExtractionCount: (count) => {
|
||||
if (currentGraph?.historyState) {
|
||||
currentGraph.historyState.extractionCount = count;
|
||||
}
|
||||
},
|
||||
setLastExtractedItems: () => { lastExtractedItems = []; },
|
||||
buildBmeDbName,
|
||||
closeBmeDb: null,
|
||||
deleteRemoteSyncFile: (chatId) => deleteRemoteSyncFile(chatId, {
|
||||
fetch: globalThis.fetch?.bind(globalThis),
|
||||
getRequestHeaders: typeof getRequestHeaders === "function" ? getRequestHeaders : undefined,
|
||||
}),
|
||||
toastr,
|
||||
});
|
||||
|
||||
async function onClearGraph() {
|
||||
return await onClearGraphController(_cleanupRuntime());
|
||||
}
|
||||
|
||||
async function onClearGraphRange(startSeq, endSeq) {
|
||||
return await onClearGraphRangeController(_cleanupRuntime(), startSeq, endSeq);
|
||||
}
|
||||
|
||||
async function onClearVectorCache() {
|
||||
return await onClearVectorCacheController(_cleanupRuntime());
|
||||
}
|
||||
|
||||
async function onClearBatchJournal() {
|
||||
return await onClearBatchJournalController(_cleanupRuntime());
|
||||
}
|
||||
|
||||
async function onDeleteCurrentIdb() {
|
||||
return await onDeleteCurrentIdbController(_cleanupRuntime());
|
||||
}
|
||||
|
||||
async function onDeleteAllIdb() {
|
||||
return await onDeleteAllIdbController(_cleanupRuntime());
|
||||
}
|
||||
|
||||
async function onDeleteServerSyncFile() {
|
||||
return await onDeleteServerSyncFileController(_cleanupRuntime());
|
||||
}
|
||||
|
||||
// ==================== 初始化 ====================
|
||||
|
||||
(async function init() {
|
||||
@@ -10953,6 +11025,13 @@ async function onReembedDirect() {
|
||||
rebuildVectorRange: (range) => onRebuildVectorIndex(range),
|
||||
reembedDirect: onReembedDirect,
|
||||
reroll: onReroll,
|
||||
clearGraph: onClearGraph,
|
||||
clearGraphRange: (startSeq, endSeq) => onClearGraphRange(startSeq, endSeq),
|
||||
clearVectorCache: onClearVectorCache,
|
||||
clearBatchJournal: onClearBatchJournal,
|
||||
deleteCurrentIdb: onDeleteCurrentIdb,
|
||||
deleteAllIdb: onDeleteAllIdb,
|
||||
deleteServerSyncFile: onDeleteServerSyncFile,
|
||||
},
|
||||
console,
|
||||
document,
|
||||
|
||||
15
style.css
15
style.css
@@ -1350,6 +1350,21 @@
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.bme-cleanup-warning-text {
|
||||
color: #ffc54f;
|
||||
border-left: 3px solid #ffc54f;
|
||||
padding-left: 10px;
|
||||
margin-top: 12px;
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.bme-cleanup-warning-text i {
|
||||
flex-shrink: 0;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.bme-config-subgroup + .bme-config-subgroup {
|
||||
margin-top: 16px;
|
||||
padding-top: 16px;
|
||||
|
||||
158
ui/panel.html
158
ui/panel.html
@@ -144,6 +144,14 @@
|
||||
<i class="fa-solid fa-palette"></i>
|
||||
<span>面板外观</span>
|
||||
</button>
|
||||
<button
|
||||
class="bme-config-nav-btn"
|
||||
data-config-section="cleanup"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-broom"></i>
|
||||
<span>数据清理</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -542,6 +550,14 @@
|
||||
<i class="fa-solid fa-palette"></i>
|
||||
<span>面板外观</span>
|
||||
</button>
|
||||
<button
|
||||
class="bme-config-nav-btn"
|
||||
data-config-section="cleanup"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-broom"></i>
|
||||
<span>数据清理</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bme-config-sections">
|
||||
@@ -2327,6 +2343,148 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
class="bme-config-section"
|
||||
data-config-section="cleanup"
|
||||
>
|
||||
<div class="bme-config-section-head">
|
||||
<div class="bme-config-section-kicker">数据清理</div>
|
||||
<h3 class="bme-config-section-title">图谱、缓存与存储清理</h3>
|
||||
<p class="bme-config-section-desc">
|
||||
在这里执行高危清理操作。所有操作均需二次确认,部分操作不可撤销。
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 图谱清理 -->
|
||||
<div class="bme-config-card">
|
||||
<div class="bme-config-card-head">
|
||||
<div>
|
||||
<div class="bme-config-card-title">图谱清理</div>
|
||||
<div class="bme-config-card-subtitle">
|
||||
清空整个图谱或删除指定楼层范围内的记忆节点。操作不可撤销。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bme-action-grid">
|
||||
<button
|
||||
class="bme-action-btn danger"
|
||||
id="bme-act-clear-graph"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-trash-can"></i>
|
||||
<span>清空当前图谱</span>
|
||||
</button>
|
||||
<button
|
||||
class="bme-action-btn danger"
|
||||
id="bme-act-clear-graph-range"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-scissors"></i>
|
||||
<span>按楼层范围清理</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="bme-action-group-extra">
|
||||
<div class="bme-config-help">
|
||||
按楼层范围清理:删除指定楼层范围内的所有节点和相关边。留空则不执行。
|
||||
</div>
|
||||
<div class="bme-action-range-row">
|
||||
<div class="bme-config-row">
|
||||
<label for="bme-cleanup-range-start">起始楼层</label>
|
||||
<input
|
||||
id="bme-cleanup-range-start"
|
||||
class="bme-config-input"
|
||||
type="number"
|
||||
min="0"
|
||||
max="999999"
|
||||
/>
|
||||
</div>
|
||||
<div class="bme-config-row">
|
||||
<label for="bme-cleanup-range-end">结束楼层</label>
|
||||
<input
|
||||
id="bme-cleanup-range-end"
|
||||
class="bme-config-input"
|
||||
type="number"
|
||||
min="0"
|
||||
max="999999"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 缓存清理 -->
|
||||
<div class="bme-config-card">
|
||||
<div class="bme-config-card-head">
|
||||
<div>
|
||||
<div class="bme-config-card-title">缓存清理</div>
|
||||
<div class="bme-config-card-subtitle">
|
||||
清空运行时向量缓存或提取历史。不影响已持久化的图谱节点。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bme-action-grid">
|
||||
<button
|
||||
class="bme-action-btn"
|
||||
id="bme-act-clear-vector-cache"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-database"></i>
|
||||
<span>清空向量缓存</span>
|
||||
</button>
|
||||
<button
|
||||
class="bme-action-btn"
|
||||
id="bme-act-clear-batch-journal"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-clock-rotate-left"></i>
|
||||
<span>清空提取历史</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 数据存储清理 -->
|
||||
<div class="bme-config-card">
|
||||
<div class="bme-config-card-head">
|
||||
<div>
|
||||
<div class="bme-config-card-title">数据存储清理</div>
|
||||
<div class="bme-config-card-subtitle">
|
||||
删除本地 IndexedDB 缓存或服务端同步文件。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bme-action-grid">
|
||||
<button
|
||||
class="bme-action-btn danger"
|
||||
id="bme-act-delete-current-idb"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-hard-drive"></i>
|
||||
<span>清空当前聊天 IDB</span>
|
||||
</button>
|
||||
<button
|
||||
class="bme-action-btn danger"
|
||||
id="bme-act-delete-all-idb"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-explosion"></i>
|
||||
<span>清空全部 BME IDB</span>
|
||||
</button>
|
||||
<button
|
||||
class="bme-action-btn danger"
|
||||
id="bme-act-delete-server-sync"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-cloud-arrow-down"></i>
|
||||
<span>清空服务端同步文件</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="bme-config-help bme-cleanup-warning-text">
|
||||
<i class="fa-solid fa-triangle-exclamation"></i>
|
||||
「清空全部 BME IDB」和「清空服务端同步文件」需要输入 DELETE 确认。
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
56
ui/panel.js
56
ui/panel.js
@@ -1990,6 +1990,12 @@ function _bindActions() {
|
||||
"bme-act-undo-maintenance": "undoMaintenance",
|
||||
"bme-act-vector-rebuild": "rebuildVectorIndex",
|
||||
"bme-act-vector-reembed": "reembedDirect",
|
||||
"bme-act-clear-graph": "clearGraph",
|
||||
"bme-act-clear-vector-cache": "clearVectorCache",
|
||||
"bme-act-clear-batch-journal": "clearBatchJournal",
|
||||
"bme-act-delete-current-idb": "deleteCurrentIdb",
|
||||
"bme-act-delete-all-idb": "deleteAllIdb",
|
||||
"bme-act-delete-server-sync": "deleteServerSyncFile",
|
||||
};
|
||||
|
||||
const actionLabels = {
|
||||
@@ -2004,6 +2010,12 @@ function _bindActions() {
|
||||
undoMaintenance: "撤销最近维护",
|
||||
rebuildVectorIndex: "重建向量",
|
||||
reembedDirect: "直连重嵌",
|
||||
clearGraph: "清空图谱",
|
||||
clearVectorCache: "清空向量缓存",
|
||||
clearBatchJournal: "清空提取历史",
|
||||
deleteCurrentIdb: "清空当前 IDB",
|
||||
deleteAllIdb: "清空全部 IDB",
|
||||
deleteServerSyncFile: "清空服务端同步文件",
|
||||
};
|
||||
|
||||
for (const [elementId, actionKey] of Object.entries(bindings)) {
|
||||
@@ -2148,6 +2160,50 @@ function _bindActions() {
|
||||
_refreshGraphAvailabilityState();
|
||||
}
|
||||
});
|
||||
|
||||
// 按楼层范围清理 (cleanup)
|
||||
document
|
||||
.getElementById("bme-act-clear-graph-range")
|
||||
?.addEventListener("click", async () => {
|
||||
const btn = document.getElementById("bme-act-clear-graph-range");
|
||||
if (btn?.disabled) return;
|
||||
|
||||
const startStr = document.getElementById("bme-cleanup-range-start")?.value;
|
||||
const endStr = document.getElementById("bme-cleanup-range-end")?.value;
|
||||
const startSeq = _parseOptionalInt(startStr);
|
||||
const endSeq = _parseOptionalInt(endStr);
|
||||
|
||||
if (btn) {
|
||||
btn.disabled = true;
|
||||
btn.style.opacity = "0.5";
|
||||
}
|
||||
|
||||
_showActionProgressUi("按楼层范围清理");
|
||||
try {
|
||||
await _actionHandlers.clearGraphRange?.(
|
||||
Number.isFinite(startSeq) ? startSeq : null,
|
||||
Number.isFinite(endSeq) ? endSeq : null,
|
||||
);
|
||||
_refreshDashboard();
|
||||
_refreshGraph();
|
||||
if (
|
||||
document
|
||||
.getElementById("bme-pane-memory")
|
||||
?.classList.contains("active")
|
||||
) {
|
||||
_refreshMemoryBrowser();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[ST-BME] Action clearGraphRange failed:", error);
|
||||
toastr.error(`按楼层范围清理失败: ${error?.message || error}`, "ST-BME");
|
||||
} finally {
|
||||
if (btn) {
|
||||
btn.style.opacity = "";
|
||||
}
|
||||
_refreshRuntimeStatus();
|
||||
_refreshGraphAvailabilityState();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function _refreshConfigTab() {
|
||||
|
||||
@@ -860,3 +860,221 @@ export async function onUndoLastMaintenanceController(runtime) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 数据清理 ====================
|
||||
|
||||
export async function onClearGraphController(runtime) {
|
||||
if (!runtime.confirm("确定要清空当前图谱?\n\n所有节点和边将被删除,操作不可撤销。")) {
|
||||
return { cancelled: true };
|
||||
}
|
||||
if (!runtime.ensureGraphMutationReady("清空图谱")) return;
|
||||
|
||||
const nextGraph = runtime.normalizeGraphRuntimeState(
|
||||
runtime.createEmptyGraph(),
|
||||
runtime.getCurrentChatId(),
|
||||
);
|
||||
runtime.setCurrentGraph(nextGraph);
|
||||
runtime.clearInjectionState();
|
||||
runtime.markVectorStateDirty?.("清空图谱后需要重建向量索引");
|
||||
runtime.setExtractionCount(0);
|
||||
runtime.setLastExtractedItems([]);
|
||||
runtime.saveGraphToChat({ reason: "manual-clear-graph" });
|
||||
runtime.refreshPanelLiveState();
|
||||
runtime.toastr.success("当前图谱已清空");
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
export async function onClearGraphRangeController(runtime, startSeq, endSeq) {
|
||||
if (!Number.isFinite(startSeq) || !Number.isFinite(endSeq) || startSeq > endSeq) {
|
||||
runtime.toastr.warning("请填写有效的起始和结束楼层");
|
||||
return { handledToast: true };
|
||||
}
|
||||
if (
|
||||
!runtime.confirm(
|
||||
`确定要删除楼层 ${startSeq} ~ ${endSeq} 范围内的所有节点?\n\n操作不可撤销。`,
|
||||
)
|
||||
) {
|
||||
return { cancelled: true };
|
||||
}
|
||||
if (!runtime.ensureGraphMutationReady("按楼层范围清理")) return;
|
||||
|
||||
const graph = runtime.getCurrentGraph();
|
||||
if (!graph) return;
|
||||
|
||||
const nodesToRemove = graph.nodes.filter((node) => {
|
||||
const range = Array.isArray(node.seqRange) ? node.seqRange : [node.seq, node.seq];
|
||||
const nodeStart = Number(range[0]) || 0;
|
||||
const nodeEnd = Number(range[1]) || 0;
|
||||
return nodeEnd >= startSeq && nodeStart <= endSeq;
|
||||
});
|
||||
|
||||
let removedCount = 0;
|
||||
for (const node of nodesToRemove) {
|
||||
if (runtime.removeNode(graph, node.id)) {
|
||||
removedCount += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (removedCount > 0) {
|
||||
runtime.markVectorStateDirty?.("按楼层范围清理后需要重建向量索引");
|
||||
runtime.saveGraphToChat({ reason: "manual-clear-graph-range" });
|
||||
}
|
||||
runtime.refreshPanelLiveState();
|
||||
runtime.toastr.success(`已删除楼层 ${startSeq}~${endSeq} 范围内 ${removedCount} 个节点`);
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
export async function onClearVectorCacheController(runtime) {
|
||||
if (!runtime.confirm("确定要清空向量缓存?\n\n清空后需要重新构建向量索引。")) {
|
||||
return { cancelled: true };
|
||||
}
|
||||
|
||||
const graph = runtime.getCurrentGraph();
|
||||
if (!graph) {
|
||||
runtime.toastr.warning("当前没有加载的图谱");
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
if (graph.vectorIndexState) {
|
||||
graph.vectorIndexState.hashToNodeId = {};
|
||||
graph.vectorIndexState.nodeToHash = {};
|
||||
graph.vectorIndexState.dirty = true;
|
||||
graph.vectorIndexState.dirtyReason = "manual-clear-vector-cache";
|
||||
graph.vectorIndexState.lastWarning = "向量缓存已手动清空,需要重建索引";
|
||||
}
|
||||
|
||||
runtime.saveGraphToChat({ reason: "manual-clear-vector-cache" });
|
||||
runtime.refreshPanelLiveState();
|
||||
runtime.toastr.success("向量缓存已清空,请重建向量索引");
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
export async function onClearBatchJournalController(runtime) {
|
||||
if (!runtime.confirm("确定要清空提取历史?\n\n提取批次记录和计数将被重置。")) {
|
||||
return { cancelled: true };
|
||||
}
|
||||
|
||||
const graph = runtime.getCurrentGraph();
|
||||
if (!graph) {
|
||||
runtime.toastr.warning("当前没有加载的图谱");
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
graph.batchJournal = [];
|
||||
if (graph.historyState) {
|
||||
graph.historyState.extractionCount = 0;
|
||||
}
|
||||
runtime.setExtractionCount(0);
|
||||
runtime.saveGraphToChat({ reason: "manual-clear-batch-journal" });
|
||||
runtime.refreshPanelLiveState();
|
||||
runtime.toastr.success("提取历史已清空");
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
export async function onDeleteCurrentIdbController(runtime) {
|
||||
const chatId = runtime.getCurrentChatId();
|
||||
if (!chatId) {
|
||||
runtime.toastr.warning("当前没有聊天上下文");
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
const dbName = runtime.buildBmeDbName(chatId);
|
||||
if (
|
||||
!runtime.confirm(
|
||||
`确定要删除当前聊天的本地缓存数据库?\n\n目标: ${dbName}\n操作不可撤销。`,
|
||||
)
|
||||
) {
|
||||
return { cancelled: true };
|
||||
}
|
||||
|
||||
try {
|
||||
await runtime.closeBmeDb?.(chatId);
|
||||
await new Promise((resolve, reject) => {
|
||||
const req = indexedDB.deleteDatabase(dbName);
|
||||
req.onsuccess = () => resolve();
|
||||
req.onerror = () => reject(req.error);
|
||||
req.onblocked = () => resolve();
|
||||
});
|
||||
runtime.toastr.success(`已删除数据库 ${dbName}`);
|
||||
} catch (error) {
|
||||
runtime.toastr.error(`删除失败: ${error?.message || error}`);
|
||||
}
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
export async function onDeleteAllIdbController(runtime) {
|
||||
const userInput = runtime.prompt(
|
||||
"此操作会删除所有聊天的 BME 本地缓存数据库,不可恢复。\n\n请输入 DELETE 确认:",
|
||||
);
|
||||
if (userInput !== "DELETE") {
|
||||
if (userInput != null) {
|
||||
runtime.toastr.warning("输入不匹配,操作已取消");
|
||||
}
|
||||
return { cancelled: true };
|
||||
}
|
||||
|
||||
try {
|
||||
const databases = await indexedDB.databases();
|
||||
const bmeDbs = databases.filter((db) =>
|
||||
String(db.name || "").startsWith("STBME_"),
|
||||
);
|
||||
if (bmeDbs.length === 0) {
|
||||
runtime.toastr.info("没有找到 BME 本地缓存数据库");
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
let deletedCount = 0;
|
||||
for (const db of bmeDbs) {
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
const req = indexedDB.deleteDatabase(db.name);
|
||||
req.onsuccess = () => resolve();
|
||||
req.onerror = () => reject(req.error);
|
||||
req.onblocked = () => resolve();
|
||||
});
|
||||
deletedCount += 1;
|
||||
} catch {
|
||||
// continue deleting others
|
||||
}
|
||||
}
|
||||
|
||||
runtime.toastr.success(`已删除 ${deletedCount}/${bmeDbs.length} 个 BME 数据库`);
|
||||
} catch (error) {
|
||||
runtime.toastr.error(`删除失败: ${error?.message || error}`);
|
||||
}
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
export async function onDeleteServerSyncFileController(runtime) {
|
||||
const chatId = runtime.getCurrentChatId();
|
||||
if (!chatId) {
|
||||
runtime.toastr.warning("当前没有聊天上下文");
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
const userInput = runtime.prompt(
|
||||
"此操作会删除当前聊天在服务端的同步文件,不可恢复。\n\n请输入 DELETE 确认:",
|
||||
);
|
||||
if (userInput !== "DELETE") {
|
||||
if (userInput != null) {
|
||||
runtime.toastr.warning("输入不匹配,操作已取消");
|
||||
}
|
||||
return { cancelled: true };
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await runtime.deleteRemoteSyncFile(chatId);
|
||||
if (result?.deleted) {
|
||||
runtime.toastr.success(`已删除服务端同步文件: ${result.filename}`);
|
||||
} else {
|
||||
runtime.toastr.info(
|
||||
result?.reason === "not-found"
|
||||
? "服务端没有找到同步文件"
|
||||
: `删除未成功: ${result?.reason || "未知原因"}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
runtime.toastr.error(`删除失败: ${error?.message || error}`);
|
||||
}
|
||||
return { handledToast: true };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user