import { createSidebarWorkspaceRuntime } from './sidebar-workspace-runtime.js';
import { createSidebarPageTreeRuntime } from './sidebar-page-tree-runtime.js';
import { createSidebarTreeLiveApplyRuntime } from './sidebar-tree-live-apply-runtime.js';
import { createSidebarFileTreeOpenRuntime } from './sidebar-filetree-open-runtime.js';
import { createSidebarAttachmentOpenRuntime } from './sidebar-attachment-open-runtime.js';
import { createSidebarFileTreeCommandRuntime } from './sidebar-filetree-command-runtime.js';
import { createSidebarFileTreeUploadRuntime } from './sidebar-filetree-upload-runtime.js';
import { createSidebarPageAiRuntime } from './sidebar-page-ai-runtime.js';
import { createSidebarPageSettingsRuntime } from './sidebar-page-settings-runtime.js';

(function(){
  if (window.__mnoteSidebarTreeRuntimeStarted) return;
  window.__mnoteSidebarTreeRuntimeStarted = true;

  var FILETREE_DRAG_MIME = 'application/x-mnote-filetree-row-ids';
  var MNOTE_SIDEBAR_TREE_MODE_KEY = 'mnote.sidebar.tree.mode';
  var MNOTE_RECENT_LOCAL_ROOTS_KEY_PREFIX = 'mnote.localFolder.recentRoots:';
  var MNOTE_LAST_CLOUD_WORKSPACE_KEY = 'mnote.workspace.lastCloudWorkspaceId';
  var MNOTE_GLOBAL_SHOW_HEADING_NUMBERS_KEY = 'mnote.global.showHeadingNumbers';
  var mnoteNavigationInFlight = '';
  var draggingFileTreeRowIds = [];
  var activeFileTreeDropRow = null;
  var sidebarFileTreeClipboard = null;
  var sidebarFileTreeSelection = {
    selectedRowIds: new Set(),
    anchorRowId: null,
    focusedRowId: null
  };
  var activeTreeContextMenu = null;
  var pageUiState = {
    pageOptions: null,
    pageWidthPreferences: null,
    historySnapshots: [],
    pageSettingsOpen: false,
    localIndexSummary: {
      scopeKey: '',
      loading: false,
      error: '',
      backlinks: null,
      tags: null
    }
  };

  function closestAction(target, selector) {
    var node = target && target.nodeType === Node.TEXT_NODE ? target.parentElement : target;
    return node && typeof node.closest === 'function' ? node.closest(selector) : null;
  }

  function sidebarShellRuntimeFunction(name) {
    var runtime = window.__mnoteSidebarShellRuntime;
    return runtime && typeof runtime[name] === 'function' ? runtime[name] : null;
  }

  function toggleWorkspaceSidebar(trigger) {
    var runtimeFn = sidebarShellRuntimeFunction('toggleWorkspaceSidebar');
    if (runtimeFn) return runtimeFn(trigger);
  }

  function installWorkspaceSidebarResizer() {
    var runtimeFn = sidebarShellRuntimeFunction('installWorkspaceSidebarResizer');
    if (runtimeFn) return runtimeFn();
  }

  function escapeHtml(value) {
    return String(value == null ? '' : value)
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  }

  function cssEscape(value) {
    if (window.CSS && typeof window.CSS.escape === 'function') return window.CSS.escape(value);
    return String(value).replace(/["\\]/g, '\\$&');
  }

  function parseJsonScript(id) {
    var node = document.getElementById(id);
    if (!node) return null;
    try {
      return JSON.parse(node.textContent || 'null');
    } catch (_) {
      return null;
    }
  }

  function currentDocumentId() {
    var match = window.location.pathname.match(/^\/documents\/([^\/]+)/);
    if (!match) match = window.location.pathname.match(/^\/mindmap\/([^\/]+)\/([^\/]+)/);
    if (match) return decodeURIComponent(match[1]);
    var params = new URLSearchParams(window.location.search);
    var fromQuery = (params.get('documentId') || params.get('pageId') || '').trim();
    if (fromQuery) return fromQuery;
    var activePane = document.querySelector('.document-pane[data-pane-role="primary"][data-pane-document-id], .document-pane[data-pane-visible="true"][data-pane-document-id]');
    if (activePane instanceof HTMLElement) {
      var paneDocumentId = (activePane.getAttribute('data-pane-document-id') || '').trim();
      if (paneDocumentId) return paneDocumentId;
    }
    var shell = document.querySelector('.document-shell[data-document-id]');
    if (shell instanceof HTMLElement) return (shell.getAttribute('data-document-id') || '').trim();
    return '';
  }

  function localFolderSelfChangeSuppressions() {
    window.__mnoteLocalFolderSelfChangeSuppressions = window.__mnoteLocalFolderSelfChangeSuppressions || new Map();
    return window.__mnoteLocalFolderSelfChangeSuppressions;
  }

  function persistLocalFolderSelfChangeSuppression(documentId, expiresAt) {
    var doc = String(documentId || '').trim();
    if (!doc) return;
    localFolderSelfChangeSuppressions().set(doc, expiresAt);
    try {
      var key = 'mnote.localFolder.selfChangeSuppressions.v1';
      var existing = JSON.parse(window.sessionStorage.getItem(key) || '{}');
      existing[doc] = expiresAt;
      window.sessionStorage.setItem(key, JSON.stringify(existing));
    } catch (_) {}
  }

  var EDITOR_UPLOAD_ROOT_SELECTOR = '[data-editor-host-kind="leptos_tiptap_island"], [data-editor-host-kind="leptos_tiptap_resource"]';

  function editorUploadRootFromElement(target) {
    if (!(target instanceof Element)) return null;
    var root = target.closest(EDITOR_UPLOAD_ROOT_SELECTOR);
    return root instanceof HTMLElement ? root : null;
  }

  function rememberEditorUploadRootFromTarget(target) {
    var root = editorUploadRootFromElement(target);
    if (root instanceof HTMLElement) {
      window.__mnoteLastEditorUploadRoot = root;
      return root;
    }
    return null;
  }

  document.addEventListener('pointerdown', function(event) {
    rememberEditorUploadRootFromTarget(event.target);
  }, true);

  document.addEventListener('focusin', function(event) {
    rememberEditorUploadRootFromTarget(event.target);
  }, true);

  function currentFileTreeActiveRowId() {
    var explicitRowId = new URL(window.location.href).searchParams.get('restoreFocusRowId') || '';
    if (explicitRowId) return explicitRowId;
    var mindmapMatch = window.location.pathname.match(/^\/mindmap\/([^\/]+)\/([^\/]+)/);
    if (mindmapMatch) return 'asset:' + decodeURIComponent(mindmapMatch[2]);
    var documentId = currentDocumentId();
    return documentId ? 'doc:' + documentId : '';
  }

  function currentPageAggregate() {
    return parseJsonScript('__MNOTE_PAGE_AGGREGATE__') || {};
  }

  const sidebarWorkspace = createSidebarWorkspaceRuntime({
    cssEscape,
    currentDocumentId,
    escapeHtml,
    parseJsonScript,
    setCommandPending: (...args) => setCommandPending(...args),
    sidebarShellRuntimeFunction,
  });
  const normalizeSidebarTreeMode = (...args) => sidebarWorkspace.normalizeSidebarTreeMode(...args);
  const readStoredSidebarTreeMode = (...args) => sidebarWorkspace.readStoredSidebarTreeMode(...args);
  const persistSidebarTreeMode = (...args) => sidebarWorkspace.persistSidebarTreeMode(...args);
  const activeSidebarTreeMode = (...args) => sidebarWorkspace.activeSidebarTreeMode(...args);
  const resolveWorkspaceId = (...args) => sidebarWorkspace.resolveWorkspaceId(...args);
  const currentWorkspaceId = (...args) => sidebarWorkspace.currentWorkspaceId(...args);
  const currentSourceKind = (...args) => sidebarWorkspace.currentSourceKind(...args);
  const currentRootUri = (...args) => sidebarWorkspace.currentRootUri(...args);
  const copyWorkspaceSourceParams = (...args) => sidebarWorkspace.copyWorkspaceSourceParams(...args);
  const currentWorkspaceSourcePayload = (...args) => sidebarWorkspace.currentWorkspaceSourcePayload(...args);
  const openTrashModal = (...args) => sidebarWorkspace.openTrashModal(...args);
  const closeTrashModal = (...args) => sidebarWorkspace.closeTrashModal(...args);
  const closeLocalFolderDialog = (...args) => sidebarWorkspace.closeLocalFolderDialog(...args);
  const requestOpenLocalFolder = (...args) => sidebarWorkspace.requestOpenLocalFolder(...args);
  const createDefaultLocalWorkspace = (...args) => sidebarWorkspace.createDefaultLocalWorkspace(...args);
  const closeWorkspaceSourceMenu = (...args) => sidebarWorkspace.closeWorkspaceSourceMenu(...args);
  const openWorkspaceSourceMenu = (...args) => sidebarWorkspace.openWorkspaceSourceMenu(...args);
  const closeAccountMenu = (...args) => sidebarWorkspace.closeAccountMenu(...args);
  const openAccountMenu = (...args) => sidebarWorkspace.openAccountMenu(...args);
  sidebarWorkspace.autoOpenRecentLocalRootOnHome();

  const sidebarPageSettings = createSidebarPageSettingsRuntime({
    currentDocumentId,
    currentPageAggregate,
    currentRootUri,
    currentSourceKind,
    currentWorkspaceSourcePayload,
    escapeHtml,
    globalShowHeadingNumbersKey: MNOTE_GLOBAL_SHOW_HEADING_NUMBERS_KEY,
    pageUiState,
    resolveWorkspaceId,
    searchText,
  });
  const applyPageOptionsToShell = (...args) => sidebarPageSettings.applyPageOptionsToShell(...args);
  const closePageHistoryDrawer = (...args) => sidebarPageSettings.closePageHistoryDrawer(...args);
  const closeAllSettingsPopovers = (...args) => sidebarPageSettings.closeAllSettingsPopovers(...args);
  const closePageSettingsPopover = (...args) => sidebarPageSettings.closePageSettingsPopover(...args);
  const closePageShareDialog = (...args) => sidebarPageSettings.closePageShareDialog(...args);
  const currentPageOptions = (...args) => sidebarPageSettings.currentPageOptions(...args);
  const ensureHistorySnapshotsSeeded = (...args) => sidebarPageSettings.ensureHistorySnapshotsSeeded(...args);
  const isAnySettingsOpen = (...args) => sidebarPageSettings.isAnySettingsOpen(...args);
  const isPageSettingsOpen = (...args) => sidebarPageSettings.isPageSettingsOpen(...args);
  const openPageHistoryDrawer = (...args) => sidebarPageSettings.openPageHistoryDrawer(...args);
  const openPageIndexSettingsPopover = (...args) => sidebarPageSettings.openPageIndexSettingsPopover(...args);
  const openKnowledgeRagSettingsPopover = (...args) => sidebarPageSettings.openKnowledgeRagSettingsPopover(...args);
  const openPageShareDialog = (...args) => sidebarPageSettings.openPageShareDialog(...args);
  const pageOptionIsSupported = (...args) => sidebarPageSettings.pageOptionIsSupported(...args);
  const addLocalIndexRange = (...args) => sidebarPageSettings.addLocalIndexRange(...args);
  const addKnowledgeRagSourceInput = (...args) => sidebarPageSettings.addKnowledgeRagSourceInput(...args);
  const deleteKnowledgeRagSource = (...args) => sidebarPageSettings.deleteKnowledgeRagSource(...args);
  const ingestKnowledgeRagSources = (...args) => sidebarPageSettings.ingestKnowledgeRagSources(...args);
  const ingestSingleKnowledgeRagSource = (...args) => sidebarPageSettings.ingestSingleKnowledgeRagSource(...args);
  const loadKnowledgeRagStatus = (...args) => sidebarPageSettings.loadKnowledgeRagStatus(...args);
  const openKnowledgeRagDashboard = (...args) => sidebarPageSettings.openKnowledgeRagDashboard(...args);
  const pruneKnowledgeRagRegistry = (...args) => sidebarPageSettings.pruneKnowledgeRagRegistry(...args);
  const setKnowledgeRagSourceFilter = (...args) => sidebarPageSettings.setKnowledgeRagSourceFilter(...args);
  const useKnowledgeRagFileTreeSelection = (...args) => sidebarPageSettings.useKnowledgeRagFileTreeSelection(...args);
  const persistLocalIndexSettings = (...args) => sidebarPageSettings.persistLocalIndexSettings(...args);
  const persistPageOptionsPatch = (...args) => sidebarPageSettings.persistPageOptionsPatch(...args);
  const persistPageWidthPreference = (...args) => sidebarPageSettings.persistPageWidthPreference(...args);
  const refreshLocalIndex = (...args) => sidebarPageSettings.refreshLocalIndex(...args);
  const removeKnowledgeRagSourceInput = (...args) => sidebarPageSettings.removeKnowledgeRagSourceInput(...args);
  const removeLocalIndexRange = (...args) => sidebarPageSettings.removeLocalIndexRange(...args);
  const recordPageHistorySnapshot = (...args) => sidebarPageSettings.recordPageHistorySnapshot(...args);
  const renderPageSettingsPopover = (...args) => sidebarPageSettings.renderPageSettingsPopover(...args);
  const setActivePageSettingsTab = (...args) => sidebarPageSettings.setActivePageSettingsTab(...args);
  const togglePageSettingsPopover = (...args) => sidebarPageSettings.togglePageSettingsPopover(...args);
  const updatePageSettingsTriggerState = (...args) => sidebarPageSettings.updatePageSettingsTriggerState(...args);
  const writeGlobalShowHeadingNumbers = (...args) => sidebarPageSettings.writeGlobalShowHeadingNumbers(...args);
  const loadPageWidthPreferences = (...args) => sidebarPageSettings.loadPageWidthPreferences(...args);

  function setCommandPending(trigger, pending) {
    if (!(trigger instanceof HTMLElement)) return;
    trigger.setAttribute('data-pending', pending ? 'true' : 'false');
    if ('disabled' in trigger) {
      if (pending) trigger.setAttribute('disabled', 'disabled');
      else trigger.removeAttribute('disabled');
    }
  }

  async function dispatchTreeCommand(trigger, body) {
    setCommandPending(trigger, true);
    var commandBody = Object.assign({}, currentWorkspaceSourcePayload(), body || {});
    try {
      var response = await fetch('/api/tree/commands', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(commandBody)
      });
      var payload = await response.json().catch(function(){ return null; });
      if (!response.ok || !payload || !payload.result) {
        throw new Error((payload && payload.message) || 'tree_command_failed_' + response.status);
      }
      window.dispatchEvent(new CustomEvent('tree:local-command', { detail: { body: commandBody, result: payload.result } }));
      setCommandPending(trigger, false);
      return payload.result;
    } catch (error) {
      setCommandPending(trigger, false);
      if (trigger instanceof HTMLElement) {
        trigger.setAttribute('data-error', error instanceof Error ? error.message : String(error));
      }
      throw error;
    }
  }

  var sidebarPageTree = null;
  const navigateToDocument = (...args) => sidebarPageTree.navigateToDocument(...args);
  const createPage = (...args) => sidebarPageTree.createPage(...args);
  const startPageDrag = (...args) => sidebarPageTree.startPageDrag(...args);
  const readPageDragNodeId = (...args) => sidebarPageTree.readPageDragNodeId(...args);
  const clearPageDropFeedback = (...args) => sidebarPageTree.clearPageDropFeedback(...args);
  const setActivePageDropRow = (...args) => sidebarPageTree.setActivePageDropRow(...args);
  const clearPageDragState = (...args) => sidebarPageTree.clearPageDragState(...args);
  const canDropPage = (...args) => sidebarPageTree.canDropPage(...args);
  const pageDropPosition = (...args) => sidebarPageTree.pageDropPosition(...args);
  const resolvePageMoveTarget = (...args) => sidebarPageTree.resolvePageMoveTarget(...args);

  async function createFileTreeFolder(trigger, parentId) {
    if (currentSourceKind() !== 'local_folder') return false;
    var workspaceId = resolveWorkspaceId(trigger || document.body);
    var effectiveParentId = String(parentId || '').trim();
    var result = await dispatchTreeCommand(trigger || document.body, {
      action: 'create_folder',
      workspaceId: workspaceId,
      parentId: effectiveParentId || null,
      title: '新建文件夹'
    });
    document.documentElement.setAttribute('data-mnote-filetree-folder-created', 'true');
    document.documentElement.setAttribute('data-mnote-filetree-folder-created-id', commandDocumentId(result, result.id || ''));
    void refreshLocalFolderSidebarSnapshot();
    return true;
  }

  function applySidebarTreeTab(mode, shell) {
    var runtimeFn = sidebarShellRuntimeFunction('applySidebarTreeTab');
    if (runtimeFn) return runtimeFn(mode, shell);
  }

  function switchSidebarTreeTab(trigger) {
    var runtimeFn = sidebarShellRuntimeFunction('switchSidebarTreeTab');
    if (runtimeFn) return runtimeFn(trigger);
  }

  function restoreSidebarTreeTab() {
    var runtimeFn = sidebarShellRuntimeFunction('restoreSidebarTreeTab');
    if (runtimeFn) return runtimeFn();
  }

  const sidebarTreeLiveApply = createSidebarTreeLiveApplyRuntime({
    activeSidebarTreeMode,
    cssEscape,
    currentDocumentId: (...args) => currentDocumentId(...args),
    currentFileTreeActiveRowId: (...args) => currentFileTreeActiveRowId(...args),
    currentRootUri,
    currentSourceKind,
    currentWorkspaceId,
    escapeHtml,
    fileTreeRuntimeFunction: (...args) => fileTreeRuntimeFunction(...args),
    localFilePathFromAssetId: (...args) => localFilePathFromAssetId(...args),
    navigateToDocument,
    refreshEditorLocalAttachmentExistence: (...args) => refreshEditorLocalAttachmentExistence(...args),
    restoreSidebarTreeTab,
    rowTitle: (...args) => rowTitle(...args),
    schedulePendingLocalFolderRestoreFocus: (...args) => schedulePendingLocalFolderRestoreFocus(...args),
    shortMindmapFileName: (...args) => shortMindmapFileName(...args),
    syncSidebarFileTreeSelection: (...args) => syncSidebarFileTreeSelection(...args),
  });
  const updateTitleEverywhere = (...args) => sidebarTreeLiveApply.updateTitleEverywhere(...args);
  const commandDocumentId = (...args) => sidebarTreeLiveApply.commandDocumentId(...args);
  sidebarPageTree = createSidebarPageTreeRuntime({
    activeSidebarTreeMode,
    commandDocumentId,
    copyWorkspaceSourceParams,
    cssEscape,
    currentDocumentId,
    currentRootUri,
    currentSourceKind,
    dispatchTreeCommand,
    normalizeSidebarTreeMode,
    persistLocalFolderSelfChangeSuppression,
    persistSidebarTreeMode,
    refreshLocalFolderSidebarSnapshot: (...args) => refreshLocalFolderSidebarSnapshot(...args),
    refreshLocalFolderAfterCommand: (...args) => refreshLocalFolderAfterCommand(...args),
    resolveWorkspaceId,
    rowCenter: (...args) => rowCenter(...args),
    selectSidebarFileTreeDocument: (...args) => selectSidebarFileTreeDocument(...args),
    toggleChildren: (...args) => toggleChildren(...args),
    dispatchSidebarEvent: (...args) => dispatchSidebarEvent(...args),
    openPageTreeContextMenu: (...args) => openPageTreeContextMenu(...args),
    updateTitleEverywhere: (...args) => updateTitleEverywhere(...args),
  });
  const fileTreePageTitle = (...args) => sidebarTreeLiveApply.fileTreePageTitle(...args);
  const isFileTreePageRow = (...args) => sidebarTreeLiveApply.isFileTreePageRow(...args);
  const normalizeFileTreePageRenameTitle = (...args) => sidebarTreeLiveApply.normalizeFileTreePageRenameTitle(...args);
  const validateFileTreeRename = (...args) => sidebarTreeLiveApply.validateFileTreeRename(...args);
  const removeDocumentRowForMode = (...args) => sidebarTreeLiveApply.removeDocumentRowForMode(...args);
  const applyCreatedDocumentLocally = (...args) => sidebarTreeLiveApply.applyCreatedDocumentLocally(...args);
  const localCommandNeedsProjectionRefresh = (...args) => sidebarTreeLiveApply.localCommandNeedsProjectionRefresh(...args);
  const refreshLocalFolderAfterCommand = (...args) => sidebarTreeLiveApply.refreshLocalFolderAfterCommand(...args);
  const applyMoveDocumentDelta = (...args) => sidebarTreeLiveApply.applyMoveDocumentDelta(...args);
  const applyRemoveDocumentDelta = (...args) => sidebarTreeLiveApply.applyRemoveDocumentDelta(...args);
  const setTreeLiveApplyError = (...args) => sidebarTreeLiveApply.setTreeLiveApplyError(...args);
  const objectIdentityAttr = (...args) => sidebarTreeLiveApply.objectIdentityAttr(...args);
  const renderPageProjection = (...args) => sidebarTreeLiveApply.renderPageProjection(...args);
  const renderSidebarSnapshot = (...args) => sidebarTreeLiveApply.renderSidebarSnapshot(...args);
  const refreshLocalFolderSidebarSnapshot = (...args) => sidebarTreeLiveApply.refreshLocalFolderSidebarSnapshot(...args);
  const startLocalFolderSidebarWatch = (...args) => sidebarTreeLiveApply.startLocalFolderSidebarWatch(...args);
  const deltaNeedsProjectionRefresh = (...args) => sidebarTreeLiveApply.deltaNeedsProjectionRefresh(...args);
  const toggleChildren = (...args) => sidebarTreeLiveApply.toggleChildren(...args);
  const revealFileTreeResource = (...args) => sidebarTreeLiveApply.revealFileTreeResource(...args);

  function dispatchSidebarEvent(name, detail) {
    document.documentElement.setAttribute('data-mnote-last-tree-action', name);
    window.dispatchEvent(new CustomEvent(name, { detail: detail }));
  }

  function sidebarShortcutWorkspaceId() {
    return currentWorkspaceId()
      || (document.getElementById('sidebar-file-tree-root') && document.getElementById('sidebar-file-tree-root').getAttribute('data-workspace-id') || '')
      || (document.getElementById('sidebar-tree-root') && document.getElementById('sidebar-tree-root').getAttribute('data-workspace-id') || '');
  }

  function sidebarShortcutSourceKind() {
    return currentSourceKind() || 'workspace';
  }

  function currentFileTreeScope() {
    var params = new URLSearchParams(window.location.search);
    var fromUrl = String(params.get('fileTreeScope') || '').trim();
    if (fromUrl) return fromUrl;
    var root = document.getElementById('sidebar-file-tree-root');
    return root instanceof HTMLElement ? String(root.getAttribute('data-mnote-filetree-scope') || '').trim() : '';
  }

  function recordNavigationRecent(payload) {
    var body = Object.assign({
      sourceKind: currentSourceKind() || 'local_folder',
      rootUri: currentRootUri() || '',
    }, payload || {});
    if (!body.kind || !body.rootUri || !body.title) return Promise.resolve(false);
    return fetch('/api/navigation/recent', {
      method: 'POST',
      credentials: 'include',
      headers: {
        accept: 'application/json',
        'content-type': 'application/json'
      },
      body: JSON.stringify(body)
    }).then(function(response) {
      return response.ok;
    }).catch(function(error) {
      console.warn('[mnote navigation] record recent failed', error);
      return false;
    });
  }

  function openNavigationPageForFolder(rootUri, relativePath, workspaceId, title, options) {
    rootUri = String(rootUri || '').trim();
    relativePath = String(relativePath || '').trim().replace(/^\/+|\/+$/g, '');
    workspaceId = String(workspaceId || '').trim();
    title = String(title || relativePath || '本地文件夹').trim();
    if (!rootUri) return false;
    void recordNavigationRecent({
      kind: 'folder',
      sourceKind: 'local_folder',
      rootUri: rootUri,
      relativePath: relativePath,
      title: title,
      workspaceId: workspaceId
    });
    var targetUrl = new URL('/', window.location.origin);
    if (workspaceId) targetUrl.searchParams.set('workspaceId', workspaceId);
    targetUrl.searchParams.set('sourceKind', 'local_folder');
    targetUrl.searchParams.set('rootUri', rootUri);
    targetUrl.searchParams.set('treeView', 'filetree');
    if (relativePath) targetUrl.searchParams.set('fileTreeScope', relativePath);
    var url = targetUrl.pathname + targetUrl.search;
    if (options && options.newTab) {
      window.open(url, '_blank', 'noopener');
    } else {
      window.location.assign(url);
    }
    return true;
  }

  function openCurrentNavigationPage(trigger) {
    if (currentSourceKind() === 'local_folder') {
      var rootUri = currentRootUri();
      var scope = currentFileTreeScope();
      var workspaceId = currentWorkspaceId() || sidebarShortcutWorkspaceId() || resolveWorkspaceId(trigger || document.body);
      var title = scope ? scope.split('/').filter(Boolean).pop() : '本地文件夹';
      return openNavigationPageForFolder(rootUri, scope, workspaceId, title || scope || '本地文件夹');
    }
    var targetUrl = new URL('/', window.location.origin);
    var workspaceId = currentWorkspaceId() || resolveWorkspaceId(trigger || document.body);
    if (workspaceId) targetUrl.searchParams.set('workspaceId', workspaceId);
    window.location.assign(targetUrl.pathname + targetUrl.search);
    return true;
  }

  function currentTopbarTitle() {
    var title = document.querySelector('[data-page-title-current="true"]');
    return title && title.textContent ? title.textContent.trim() : '无标题';
  }

  function fileTreeRowTitleForShortcut(row, fallback) {
    var title = row && row.querySelector ? row.querySelector(':scope > .tree-link > .tree-link-title') : null;
    return title && title.textContent ? title.textContent.trim() : (fallback || '文件夹');
  }

  function isRetiredOcrSidecarMarkdownPath(relativePath) {
    var normalized = String(relativePath || '').trim().replace(/\\/g, '/').replace(/^\/+/, '');
    return /(^|\/)[^/]+\.ocr\/[^/]+\.ocr\.md$/i.test(normalized);
  }

  function sidebarShortcutRows() {
    return Array.from(document.querySelectorAll('.wolai-starred-section [data-mnote-shortcut-kind]'));
  }

  function shortcutMatches(row, kind, targetId, relativePath, documentId) {
    if (!(row instanceof HTMLElement)) return false;
    if ((row.getAttribute('data-mnote-shortcut-kind') || '') !== kind) return false;
    if (documentId && (row.getAttribute('data-mnote-shortcut-document-id') || row.getAttribute('data-document-id') || '') === documentId) return true;
    if (relativePath && (row.getAttribute('data-mnote-shortcut-relative-path') || '') === relativePath) return true;
    return Boolean(targetId && (row.getAttribute('data-mnote-shortcut-target-id') || row.getAttribute('data-node-id') || '') === targetId);
  }

  async function listSidebarShortcuts(workspaceId) {
    var url = new URL('/api/sidebar/shortcuts', window.location.origin);
    url.searchParams.set('workspaceId', workspaceId);
    var response = await fetch(url.toString(), {
      method: 'GET',
      credentials: 'include',
      headers: { accept: 'application/json' },
      cache: 'no-store'
    });
    var payload = await response.json().catch(function() { return null; });
    if (!response.ok) throw new Error(payload && (payload.error || payload.message) || 'sidebar_shortcuts_list_failed_' + response.status);
    return payload && Array.isArray(payload.shortcuts) ? payload.shortcuts : [];
  }

  function shortcutRecordMatches(shortcut, kind, targetId, relativePath, documentId) {
    if (!shortcut || shortcut.kind !== kind) return false;
    var shortcutMetadata = shortcut && shortcut.metadata && typeof shortcut.metadata === 'object' ? shortcut.metadata : {};
    var shortcutRootUri = String(shortcut.rootUri || shortcut.root_uri || shortcutMetadata.rootUri || shortcutMetadata.root_uri || '').trim();
    var currentShortcutRootUri = currentRootUri();
    if (shortcutRootUri && currentShortcutRootUri && shortcutRootUri !== currentShortcutRootUri) return false;
    if (documentId && String(shortcut.documentId || shortcut.document_id || '') === documentId) return true;
    if (relativePath && String(shortcut.relativePath || shortcut.relative_path || '') === relativePath) return true;
    return Boolean(targetId && String(shortcut.targetId || shortcut.target_id || '') === targetId);
  }

  async function findSidebarShortcut(payload) {
    var workspaceId = payload.workspaceId || sidebarShortcutWorkspaceId();
    if (!workspaceId) return null;
    var shortcuts = await listSidebarShortcuts(workspaceId);
    return shortcuts.find(function(shortcut) {
      return shortcutRecordMatches(shortcut, payload.kind, payload.targetId, payload.relativePath, payload.documentId);
    }) || null;
  }

  async function upsertSidebarShortcut(payload) {
    var response = await fetch('/api/sidebar/shortcuts', {
      method: 'POST',
      credentials: 'include',
      headers: { accept: 'application/json', 'content-type': 'application/json' },
      body: JSON.stringify(payload)
    });
    var result = await response.json().catch(function() { return null; });
    if (!response.ok) throw new Error(result && (result.error || result.message) || 'sidebar_shortcut_upsert_failed_' + response.status);
    return result && result.shortcut ? result.shortcut : null;
  }

  async function deleteSidebarShortcut(shortcutId) {
    if (!shortcutId) return false;
    var response = await fetch('/api/sidebar/shortcuts/' + encodeURIComponent(shortcutId), {
      method: 'DELETE',
      credentials: 'include',
      headers: { accept: 'application/json' }
    });
    var result = await response.json().catch(function() { return null; });
    if (!response.ok) throw new Error(result && (result.error || result.message) || 'sidebar_shortcut_delete_failed_' + response.status);
    return true;
  }

  function closeSidebarShortcutMenu() {
    var existing = document.querySelector('[data-testid="mnote-sidebar-shortcut-menu"]');
    if (existing && existing.parentElement) existing.parentElement.removeChild(existing);
    document.querySelectorAll('[data-mnote-shortcut-action="menu"][aria-expanded="true"]').forEach(function(button) {
      button.setAttribute('aria-expanded', 'false');
    });
  }

  async function removeSidebarShortcutByRow(row) {
    if (!(row instanceof HTMLElement)) return false;
    var shortcutId = String(row.getAttribute('data-mnote-shortcut-id') || '').trim();
    if (!shortcutId) return false;
    row.setAttribute('data-mnote-shortcut-pending', 'true');
    try {
      await deleteSidebarShortcut(shortcutId);
      row.remove();
      closeSidebarShortcutMenu();
      document.documentElement.setAttribute('data-mnote-sidebar-shortcut-last-action', 'remove');
      return true;
    } finally {
      if (row.isConnected) row.removeAttribute('data-mnote-shortcut-pending');
    }
  }

  function openSidebarShortcutMenu(row, trigger) {
    if (!(row instanceof HTMLElement)) return;
    closeSidebarShortcutMenu();
    if (trigger instanceof HTMLElement) trigger.setAttribute('aria-expanded', 'true');
    var rect = trigger && trigger.getBoundingClientRect ? trigger.getBoundingClientRect() : row.getBoundingClientRect();
    var menu = document.createElement('div');
    menu.className = 'mnote-tree-context-menu';
    menu.setAttribute('role', 'menu');
    menu.setAttribute('data-testid', 'mnote-sidebar-shortcut-menu');
    menu.innerHTML = '<button type="button" class="mnote-tree-context-menu__item" role="menuitem" data-mnote-sidebar-shortcut-menu-action="open"><span class="material-symbols-outlined mnote-tree-context-menu__icon" data-icon="login" aria-hidden="true"></span><span class="mnote-tree-context-menu__label">在右侧边栏打开</span></button><div class="mnote-tree-context-menu__separator" role="separator"></div><button type="button" class="mnote-tree-context-menu__item" role="menuitem" data-mnote-sidebar-shortcut-menu-action="copy-link"><span class="material-symbols-outlined mnote-tree-context-menu__icon" data-icon="link" aria-hidden="true"></span><span class="mnote-tree-context-menu__label">复制访问链接</span></button><button type="button" class="mnote-tree-context-menu__item mnote-tree-context-menu__item--danger" role="menuitem" data-mnote-sidebar-shortcut-menu-action="remove"><span class="material-symbols-outlined mnote-tree-context-menu__icon" data-icon="star_off" aria-hidden="true"></span><span class="mnote-tree-context-menu__label">取消星标</span></button>';
    menu.__mnoteShortcutRow = row;
    document.body.appendChild(menu);
    var width = menu.offsetWidth || 220;
    var left = Math.min(Math.max(8, rect.right - width), Math.max(8, window.innerWidth - width - 8));
    var top = Math.min(Math.max(8, rect.bottom + 4), Math.max(8, window.innerHeight - (menu.offsetHeight || 120) - 8));
    menu.style.left = left + 'px';
    menu.style.top = top + 'px';
  }

  function removeSidebarShortcutRow(shortcut) {
    sidebarShortcutRows().forEach(function(row) {
      if (shortcutMatches(
        row,
        shortcut.kind,
        String(shortcut.targetId || shortcut.target_id || ''),
        String(shortcut.relativePath || shortcut.relative_path || ''),
        String(shortcut.documentId || shortcut.document_id || '')
      )) {
        row.remove();
      }
    });
  }

  function renderSidebarShortcutRow(shortcut) {
    if (!shortcut) return;
    var section = document.querySelector('.wolai-starred-section');
    if (!(section instanceof HTMLElement)) return;
    removeSidebarShortcutRow(shortcut);
    var kind = String(shortcut.kind || '').trim();
    var shortcutId = String(shortcut.id || shortcut.targetId || shortcut.target_id || '').trim();
    var targetId = String(shortcut.targetId || shortcut.target_id || '').trim();
    var relativePath = String(shortcut.relativePath || shortcut.relative_path || '').trim();
    var documentId = String(shortcut.documentId || shortcut.document_id || '').trim();
    var sourceKind = String(shortcut.sourceKind || shortcut.source_kind || '').trim();
    var metadata = shortcut.metadata && typeof shortcut.metadata === 'object' ? shortcut.metadata : {};
    var rootUri = String(shortcut.rootUri || shortcut.root_uri || metadata.rootUri || metadata.root_uri || '').trim();
    var workspaceId = String(shortcut.workspaceId || shortcut.workspace_id || sidebarShortcutWorkspaceId() || '').trim();
    var title = String(shortcut.title || (kind === 'folder' ? '文件夹' : '无标题')).trim();
    var href = '';
    if (documentId) {
      var targetUrl = new URL('/documents/' + encodeURIComponent(documentId), window.location.origin);
      if (workspaceId) targetUrl.searchParams.set('workspaceId', workspaceId);
      if (sourceKind) targetUrl.searchParams.set('sourceKind', sourceKind);
      if (rootUri) targetUrl.searchParams.set('rootUri', rootUri);
      href = targetUrl.pathname + targetUrl.search;
    }
    var row = document.createElement(href ? 'a' : 'div');
    row.className = 'wolai-page-row';
    if (href) row.setAttribute('href', href);
    else {
      row.setAttribute('role', 'button');
      row.setAttribute('tabindex', '0');
    }
    row.setAttribute('data-testid', 'wolai-sidebar-row');
    row.setAttribute('data-node-id', shortcutId || targetId);
    row.setAttribute('data-document-id', documentId || shortcutId || targetId);
    if (shortcutId) row.setAttribute('data-mnote-shortcut-id', shortcutId);
    if (workspaceId) row.setAttribute('data-workspace-id', workspaceId);
    row.setAttribute('data-mnote-shortcut-kind', kind);
    if (sourceKind) row.setAttribute('data-mnote-shortcut-source-kind', sourceKind);
    row.setAttribute('data-mnote-shortcut-target-id', targetId);
    if (relativePath) row.setAttribute('data-mnote-shortcut-relative-path', relativePath);
    if (rootUri) row.setAttribute('data-mnote-shortcut-root-uri', rootUri);
    if (documentId) row.setAttribute('data-mnote-shortcut-document-id', documentId);
    row.setAttribute('data-depth', '0');
    row.setAttribute('data-active', String(documentId && documentId === currentDocumentId()));
    row.innerHTML = '<span class="wolai-row-caret" aria-hidden="true">›</span><span class="wolai-row-icon"><span class="material-symbols-outlined wolai-row-symbol" data-icon="' + (kind === 'folder' ? 'folder_open' : 'home') + '" aria-hidden="true"></span></span><span class="wolai-row-title">' + escapeHtml(title) + '</span><button type="button" class="wolai-row-more" data-mnote-shortcut-action="menu" aria-label="更多操作" title="更多操作"><span class="material-symbols-outlined" data-icon="more_horiz" aria-hidden="true"></span></button>';
    section.appendChild(row);
  }

  async function toggleSidebarShortcut(payload) {
    var workspaceId = payload.workspaceId || sidebarShortcutWorkspaceId();
    if (!workspaceId) return false;
    var normalized = Object.assign({}, payload, { workspaceId: workspaceId });
    var existing = await findSidebarShortcut(normalized);
    if (existing && existing.id) {
      await deleteSidebarShortcut(existing.id);
      removeSidebarShortcutRow(existing);
      document.documentElement.setAttribute('data-mnote-sidebar-shortcut-last-action', 'remove');
      return true;
    }
    var shortcut = await upsertSidebarShortcut(normalized);
    renderSidebarShortcutRow(shortcut);
    document.documentElement.setAttribute('data-mnote-sidebar-shortcut-last-action', 'upsert');
    return true;
  }

  function currentPageShortcutPayload() {
    var documentId = currentDocumentId();
    var workspaceId = sidebarShortcutWorkspaceId();
    if (!documentId || !workspaceId) return null;
    return {
      workspaceId: workspaceId,
      kind: 'page',
      sourceKind: sidebarShortcutSourceKind(),
      targetId: documentId,
      documentId: documentId,
      title: currentTopbarTitle(),
      icon: 'star',
      rootUri: currentRootUri(),
      metadataJson: JSON.stringify({ rootUri: currentRootUri() })
    };
  }

  function folderShortcutPayload(detail, trigger) {
    detail = detail || {};
    var row = trigger && trigger.closest ? trigger.closest('.tree-row[data-shell-mode="filetree"]') : trigger;
    var rowKind = String(detail.rowKind || (row && row.getAttribute('data-row-kind')) || '').trim();
    if (rowKind !== 'folder' && rowKind !== 'directory') return null;
    var relativePath = String(detail.localRelativePath || (row && row.getAttribute('data-local-relative-path')) || '').trim();
    if (!relativePath) return null;
    var workspaceId = String(detail.workspaceId || sidebarShortcutWorkspaceId() || '').trim();
    if (!workspaceId) return null;
    var rowId = String(detail.rowId || (row && row.getAttribute('data-row-id')) || '').trim();
    return {
      workspaceId: workspaceId,
      kind: 'folder',
      sourceKind: 'local_folder',
      targetId: rowId || ('folder:' + relativePath),
      relativePath: relativePath,
      title: detail.title || fileTreeRowTitleForShortcut(row, relativePath),
      icon: 'folder_open',
      rootUri: currentRootUri(),
      metadataJson: JSON.stringify({ rootUri: currentRootUri() })
    };
  }

  async function toggleCurrentPageSidebarShortcut(trigger) {
    var payload = currentPageShortcutPayload();
    if (!payload) return;
    if (trigger instanceof HTMLElement) trigger.setAttribute('data-mnote-shortcut-pending', 'true');
    try {
      await toggleSidebarShortcut(payload);
    } finally {
      if (trigger instanceof HTMLElement) trigger.removeAttribute('data-mnote-shortcut-pending');
    }
  }

  async function toggleFolderSidebarShortcut(detail, trigger) {
    var payload = folderShortcutPayload(detail, trigger);
    if (!payload) return false;
    await toggleSidebarShortcut(payload);
    return true;
  }

  function ensureStarredFolderFileTreeHost(workspaceId) {
    var root = document.getElementById('sidebar-file-tree-root');
    if (root instanceof HTMLElement) return root;
    var panel = document.getElementById('wolai-sidebar-file-tree-panel');
    if (!(panel instanceof HTMLElement)) return null;
    var section = document.createElement('div');
    section.className = 'sidebar-tree-section sidebar-file-tree-section';
    root = document.createElement('div');
    root.id = 'sidebar-file-tree-root';
    root.className = 'sidebar-tree';
    root.setAttribute('data-tree-shell-mode', 'filetree');
    if (workspaceId) root.setAttribute('data-workspace-id', workspaceId);
    section.appendChild(root);
    panel.appendChild(section);
    return root;
  }

  function ensureStarredFolderPageTreeHost(workspaceId) {
    var root = document.getElementById('sidebar-tree-root');
    if (root instanceof HTMLElement) return root;
    var panel = document.getElementById('wolai-sidebar-page-tree-panel') || document.querySelector('[data-mnote-sidebar-tree-panel="page"]');
    if (!(panel instanceof HTMLElement)) return null;
    var section = document.createElement('div');
    section.className = 'sidebar-tree-section';
    root = document.createElement('div');
    root.id = 'sidebar-tree-root';
    root.className = 'sidebar-tree';
    root.setAttribute('data-tree-shell-mode', 'page');
    if (workspaceId) root.setAttribute('data-workspace-id', workspaceId);
    section.appendChild(root);
    panel.appendChild(section);
    return root;
  }

  function persistStarredFolderScope(workspaceId, rootUri, relativePath) {
    var targetUrl = new URL(window.location.href);
    if (workspaceId) targetUrl.searchParams.set('workspaceId', workspaceId);
    targetUrl.searchParams.set('sourceKind', 'local_folder');
    targetUrl.searchParams.set('rootUri', rootUri);
    targetUrl.searchParams.set('treeView', 'filetree');
    targetUrl.searchParams.set('fileTreeScope', relativePath);
    window.history.replaceState(window.history.state, '', targetUrl.pathname + targetUrl.search + targetUrl.hash);
    if (document.body instanceof HTMLElement) {
      document.body.setAttribute('data-mnote-source-kind', 'local_folder');
      document.body.setAttribute('data-mnote-root-uri', rootUri);
    }
  }

  function readShortcutRootUri(row) {
    if (!(row instanceof HTMLElement)) return '';
    return String(row.getAttribute('data-mnote-shortcut-root-uri') || '').trim();
  }

  async function openStarredFolderShortcut(row) {
    if (!(row instanceof HTMLElement)) return false;
    var relativePath = String(row.getAttribute('data-mnote-shortcut-relative-path') || '').trim();
    var workspaceId = String(row.getAttribute('data-workspace-id') || '').trim() || sidebarShortcutWorkspaceId();
    var rootUri = readShortcutRootUri(row);
    if (!relativePath || !rootUri || !workspaceId) {
      document.documentElement.setAttribute('data-mnote-sidebar-shortcut-open-error', !rootUri ? 'missing_root_uri' : 'missing_target');
      return false;
    }
    document.documentElement.removeAttribute('data-mnote-sidebar-shortcut-open-error');
    var tab = document.querySelector('[data-mnote-sidebar-tree-tab="filetree"]');
    if (tab instanceof HTMLElement) switchSidebarTreeTab(tab);
    var root = ensureStarredFolderFileTreeHost(workspaceId);
    var pageRoot = ensureStarredFolderPageTreeHost(workspaceId);
    if (root instanceof HTMLElement) {
      root.setAttribute('data-workspace-id', workspaceId);
      root.setAttribute('data-mnote-filetree-scope', relativePath);
      root.setAttribute('data-mnote-filetree-scope-title', row.textContent ? row.textContent.trim() : relativePath);
    }
    if (pageRoot instanceof HTMLElement) {
      pageRoot.setAttribute('data-workspace-id', workspaceId);
      pageRoot.setAttribute('data-mnote-page-tree-scope', relativePath);
    }
    persistStarredFolderScope(workspaceId, rootUri, relativePath);
    void recordNavigationRecent({
      kind: 'folder',
      sourceKind: 'local_folder',
      rootUri: rootUri,
      relativePath: relativePath,
      title: row.textContent ? row.textContent.trim() : relativePath,
      workspaceId: workspaceId
    });
    document.documentElement.setAttribute('data-mnote-filetree-scope', relativePath);
    var sidebarUrl = new URL('/api/tree/projections/sidebar', window.location.origin);
    sidebarUrl.searchParams.set('workspaceId', workspaceId);
    sidebarUrl.searchParams.set('sourceKind', 'local_folder');
    sidebarUrl.searchParams.set('rootUri', rootUri);
    sidebarUrl.searchParams.set('parentRelativePath', relativePath);
    var url = new URL('/api/tree/projections/file', window.location.origin);
    url.searchParams.set('workspaceId', workspaceId);
    url.searchParams.set('sourceKind', 'local_folder');
    url.searchParams.set('rootUri', rootUri);
    url.searchParams.set('parentRelativePath', relativePath);
    var sidebarRequest = fetch(sidebarUrl.toString(), {
      method: 'GET',
      credentials: 'include',
      headers: { accept: 'application/json' },
      cache: 'no-store'
    });
    var fileRequest = fetch(url.toString(), {
      method: 'GET',
      credentials: 'include',
      headers: { accept: 'application/json' },
      cache: 'no-store'
    });
    var response = await fileRequest;
    var payload = await response.json().catch(function() { return null; });
    if (!response.ok) throw new Error(payload && (payload.error || payload.message) || 'scoped_filetree_failed_' + response.status);
    var fileProjection = payload && (payload.result || payload);
    var renderedFile = renderSidebarSnapshot({
      dataset: { kernel_file_tree_projection: fileProjection }
    });
    root = document.getElementById('sidebar-file-tree-root');
    if (root instanceof HTMLElement) {
      root.setAttribute('data-workspace-id', workspaceId);
      root.setAttribute('data-mnote-filetree-scope', relativePath);
      root.setAttribute('data-mnote-filetree-scope-title', row.textContent ? row.textContent.trim() : relativePath);
    }
    var sidebarResponse = await sidebarRequest;
    var sidebarPayload = await sidebarResponse.json().catch(function() { return null; });
    if (!sidebarResponse.ok) throw new Error(sidebarPayload && (sidebarPayload.error || sidebarPayload.message) || 'local_page_tree_failed_' + sidebarResponse.status);
    var sidebarProjection = sidebarPayload && (sidebarPayload.result || sidebarPayload) || {};
    var renderedPage = sidebarProjection ? await renderPageProjection(sidebarProjection) : false;
    root = document.getElementById('sidebar-file-tree-root');
    if (root instanceof HTMLElement) {
      root.setAttribute('data-workspace-id', workspaceId);
      root.setAttribute('data-mnote-filetree-scope', relativePath);
      root.setAttribute('data-mnote-filetree-scope-title', row.textContent ? row.textContent.trim() : relativePath);
    }
    return renderedFile || renderedPage;
  }

  const sidebarFileTreeOpen = createSidebarFileTreeOpenRuntime({
    copyWorkspaceSourceParams,
    currentDocumentId,
    currentRootUri,
    currentSourceKind,
    fileTreeIconKindForFileName: (...args) => fileTreeIconKindForFileName(...args),
    getNavigationInFlight: () => mnoteNavigationInFlight,
    isCodeAttachmentFileName: (...args) => isCodeAttachmentFileName(...args),
    isNonOfficeAttachmentName: (...args) => isNonOfficeAttachmentName(...args),
    isPdfAttachmentFileName: (...args) => isPdfAttachmentFileName(...args),
    openCodeEditorAttachment: (...args) => openCodeEditorAttachment(...args),
    resolveWorkspaceId,
    setNavigationInFlight: (value) => { mnoteNavigationInFlight = String(value || ''); },
    shouldOpenLocalResourceInNewWindow: (...args) => shouldOpenLocalResourceInNewWindow(...args),
    uploadedFileSize: (...args) => uploadedFileSize(...args),
  });
  const inferOnlyOfficeFileType = (...args) => sidebarFileTreeOpen.inferOnlyOfficeFileType(...args);
  const buildOnlyOfficeOpenUrl = (...args) => sidebarFileTreeOpen.buildOnlyOfficeOpenUrl(...args);
  const buildOnlyOfficeOpenPath = (...args) => sidebarFileTreeOpen.buildOnlyOfficeOpenPath(...args);
  const buildOfficePreviewOpenUrl = (...args) => sidebarFileTreeOpen.buildOfficePreviewOpenUrl(...args);
  const buildPdfPreviewOpenUrl = (...args) => sidebarFileTreeOpen.buildPdfPreviewOpenUrl(...args);
  const buildLocalOnlyOfficeOpenUrl = (...args) => sidebarFileTreeOpen.buildLocalOnlyOfficeOpenUrl(...args);
  const openLocalOfficeFileInActiveTab = (...args) => sidebarFileTreeOpen.openLocalOfficeFileInActiveTab(...args);
  const buildMindmapOpenPath = (...args) => sidebarFileTreeOpen.buildMindmapOpenPath(...args);
  const navigateToMindmapObject = (...args) => sidebarFileTreeOpen.navigateToMindmapObject(...args);
  const isMindmapAssetDetail = (...args) => sidebarFileTreeOpen.isMindmapAssetDetail(...args);
  const localFilePathFromAssetId = (...args) => sidebarFileTreeOpen.localFilePathFromAssetId(...args);
  const buildLocalFileOpenUrl = (...args) => sidebarFileTreeOpen.buildLocalFileOpenUrl(...args);
  const openLocalResourceInActiveTab = (...args) => sidebarFileTreeOpen.openLocalResourceInActiveTab(...args);
  const readFileTreeObjectIdentity = (...args) => sidebarFileTreeOpen.readFileTreeObjectIdentity(...args);
  const fetchCurrentOnlyOfficeUserId = (...args) => sidebarFileTreeOpen.fetchCurrentOnlyOfficeUserId(...args);
  const openConvexAssetFromFileTree = (...args) => sidebarFileTreeOpen.openConvexAssetFromFileTree(...args);

  var sidebarFileTreeUpload = null;
  const fileTreeRowsForUploadPreflight = (...args) => sidebarFileTreeUpload.fileTreeRowsForUploadPreflight(...args);
  const fileTreeRowCapabilities = (...args) => sidebarFileTreeUpload.fileTreeRowCapabilities(...args);
  const fileTreeRowIsReadonly = (...args) => sidebarFileTreeUpload.fileTreeRowIsReadonly(...args);
  const blockReadonlyFileTreeAction = (...args) => sidebarFileTreeUpload.blockReadonlyFileTreeAction(...args);
  const fileTreeDocumentParentsForPreflight = (...args) => sidebarFileTreeUpload.fileTreeDocumentParentsForPreflight(...args);
  const fileTreeTargetChildrenForPreflight = (...args) => sidebarFileTreeUpload.fileTreeTargetChildrenForPreflight(...args);
  const fileTreeDropPreflightRows = (...args) => sidebarFileTreeUpload.fileTreeDropPreflightRows(...args);
  const ensureFileTreeWritableTarget = (...args) => sidebarFileTreeUpload.ensureFileTreeWritableTarget(...args);
  const fileTreeDocumentWorkspacesForUploadPreflight = (...args) => sidebarFileTreeUpload.fileTreeDocumentWorkspacesForUploadPreflight(...args);
  const preflightFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.preflightFileTreeUploadTarget(...args);
  const fallbackFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.fallbackFileTreeUploadTarget(...args);
  const resolveFileTreeUploadTarget = (...args) => sidebarFileTreeUpload.resolveFileTreeUploadTarget(...args);

  function localUploadRuntimeFunction(name) {
    var runtime = window.__mnoteLocalUploadRuntime;
    var fn = runtime && runtime[name];
    return typeof fn === 'function' ? fn : null;
  }

  function fileTreeRuntimeFunction(name) {
    var runtime = window.__mnoteFileTreeRuntime;
    var fn = runtime && runtime[name];
    return typeof fn === 'function' ? fn : null;
  }

  function fileTreeRuntimeDeps() {
    return {
      currentSourceKind: currentSourceKind,
      currentRootUri: currentRootUri,
      currentDocumentId: currentDocumentId,
      localFilePathFromAssetId: localFilePathFromAssetId,
      rowTitle: rowTitle,
      resolveWorkspaceId: resolveWorkspaceId,
      cssEscape: cssEscape,
      escapeHtml: escapeHtml,
      objectIdentityAttr: objectIdentityAttr,
      uploadedAssetTitle: uploadedAssetTitle,
      uploadedAssetType: uploadedAssetType,
      fileTreeIconKindForFileName: fileTreeIconKindForFileName
    };
  }

  function fileTreeSelectionRuntimeFunction(name) {
    var runtime = window.__mnoteFileTreeSelectionRuntime;
    var fn = runtime && runtime[name];
    return typeof fn === 'function' ? fn : null;
  }

  function fileTreeSelectionRuntimeDeps() {
    return {
      cssEscape: cssEscape
    };
  }

  function uploadedAssetTitle(asset) {
    var runtimeFn = localUploadRuntimeFunction('uploadedAssetTitle');
    if (runtimeFn) return runtimeFn(asset);
    return String(asset && (asset.file_name || asset.title || asset.name) || '未命名附件').trim() || '未命名附件';
  }

  function uploadedAssetUrl(asset) {
    var runtimeFn = localUploadRuntimeFunction('uploadedAssetUrl');
    if (runtimeFn) return runtimeFn(asset);
    return String(asset && (asset.sourcePath || asset.file_url || asset.signedUrl || asset.signed_url || asset.thumbnail_url) || '').trim();
  }

  function uploadedAssetMarkdownHref(asset) {
    var runtimeFn = localUploadRuntimeFunction('uploadedAssetMarkdownHref');
    if (runtimeFn) return runtimeFn(asset);
    var href = String(asset && (asset.markdownHref || asset.markdown_href) || '').trim();
    if (href) {
      var normalizedHref = href.replace(/\\/g, '/');
      if (normalizedHref.indexOf('../') === 0 || normalizedHref.indexOf('/../') >= 0) return '';
      return href;
    }
    var relativePath = String(asset && (asset.markdownRelativePath || asset.markdown_relative_path) || '').trim().replace(/\\/g, '/');
    if (!relativePath) return '';
    if (relativePath.indexOf('../') === 0 || relativePath.indexOf('/../') >= 0) return '';
    if (relativePath.indexOf('./') === 0) return relativePath;
    return './' + relativePath;
  }

  function localAssetOpenUrl(asset, download) {
    var runtimeFn = localUploadRuntimeFunction('localAssetOpenUrl');
    if (runtimeFn) return runtimeFn(asset, download, { rootUri: currentRootUri() });
    if (!isLocalUploadedAsset(asset)) return '';
    var rootUri = String(asset && (asset.rootUri || asset.root_uri) || '').trim() || currentRootUri();
    var rootRelativePath = String(asset && (asset.rootRelativePath || asset.root_relative_path) || '').trim();
    if (!rootUri || !rootRelativePath) return '';
    var url = new URL('/api/local-folder/files/open', window.location.origin);
    url.searchParams.set('rootUri', rootUri);
    url.searchParams.set('path', rootRelativePath);
    if (download) url.searchParams.set('download', 'true');
    return url.toString();
  }

  function uploadedAssetType(asset) {
    var runtimeFn = localUploadRuntimeFunction('uploadedAssetType');
    if (runtimeFn) return runtimeFn(asset);
    return String(asset && (asset.asset_type || asset.assetType || asset.mime_type || '') || '').trim();
  }

  function fileTreeIconKindForFileName(fileName) {
    var runtimeFn = localUploadRuntimeFunction('fileTreeIconKindForFileName');
    if (runtimeFn) return runtimeFn(fileName);
    var name = String(fileName || '').trim().toLowerCase();
    var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : '';
    if (['doc', 'docx', 'odt', 'rtf', 'ppt', 'pptx', 'odp', 'xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return 'office';
    if (ext === 'md' || ext === 'markdown') return 'markdown';
    if (ext === 'pdf') return 'pdf';
    if (['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'bmp'].indexOf(ext) >= 0) return 'image';
    if (['html', 'htm', 'css', 'scss', 'less', 'js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'vue', 'svelte', 'astro'].indexOf(ext) >= 0) return 'web';
    if (['json', 'jsonc', 'json5', 'toml', 'yaml', 'yml', 'ini', 'env', 'xml', 'lock', 'hcl', 'tf', 'tfvars', 'nix', 'properties', 'conf', 'cfg', 'config', 'service', 'desktop', 'gitignore', 'gitattributes', 'editorconfig', 'npmrc', 'prettierrc', 'eslintrc'].indexOf(ext) >= 0 || ['.dockerignore', '.editorconfig', '.env', '.eslintrc', '.gitattributes', '.gitignore', '.npmrc', '.prettierrc', 'dockerfile', 'containerfile', 'makefile', 'cmakelists.txt', 'gemfile', 'rakefile', 'procfile'].indexOf(name) >= 0) return 'config';
    if (['rs', 'py', 'go', 'java', 'c', 'cpp', 'h', 'hpp', 'cs', 'php', 'rb', 'sh', 'bash', 'zsh', 'sql', 'lua', 'dart', 'kt', 'kts', 'swift', 'scala', 'gradle', 'groovy', 'clj', 'ex', 'exs', 'erl', 'hrl', 'fs', 'fsx', 'r', 'jl', 'm', 'mm', 'pl', 'pm', 'ps1', 'bat', 'cmd', 'psm1', 'psd1', 'proto', 'graphql', 'gql', 'prisma', 'cmake', 'bazel', 'bzl'].indexOf(ext) >= 0) return 'code';
    return '';
  }

  function shouldOpenLocalResourceInNewWindow(fileName) {
    return false;
  }

  function isLocalUploadedAsset(asset) {
    var runtimeFn = localUploadRuntimeFunction('isLocalUploadedAsset');
    if (runtimeFn) return runtimeFn(asset);
    var id = String(asset && asset.id || '').trim();
    return String(asset && asset.sourceKind || '').trim() === 'local_folder' || id.indexOf('local:asset:') === 0;
  }

  function uploadedAssetExtension(asset) {
    var runtimeFn = localUploadRuntimeFunction('uploadedAssetExtension');
    if (runtimeFn) return runtimeFn(asset);
    var match = uploadedAssetTitle(asset).toLowerCase().match(/\.([a-z0-9]+)$/);
    return match ? match[1] : '';
  }

  function isNonOfficeAttachmentName(name, ext) {
    var runtimeFn = localUploadRuntimeFunction('isNonOfficeAttachmentName');
    if (runtimeFn) return runtimeFn(name, ext);
    var codeFileNames = [
      '.dockerignore', '.editorconfig', '.env', '.eslintrc', '.gitattributes', '.gitignore', '.npmrc', '.prettierrc',
      'dockerfile', 'makefile', 'cmakelists.txt', 'gemfile', 'rakefile', 'procfile'
    ];
    return [
      'pdf', 'toml', 'json', 'yaml', 'yml', 'md', 'markdown', 'txt', 'ini', 'env', 'xml', 'html', 'htm', 'css', 'scss',
      'less', 'js', 'jsx', 'ts', 'tsx', 'mjs', 'cjs', 'py', 'rs', 'go', 'java', 'c', 'cpp', 'h', 'hpp', 'cs',
      'php', 'rb', 'sh', 'bash', 'zsh', 'sql', 'lock', 'log', 'vue', 'svelte', 'astro', 'jsonc', 'json5',
      'mts', 'cts', 'lua', 'dart', 'kt', 'kts', 'swift', 'scala', 'gradle', 'groovy', 'clj',
      'ex', 'exs', 'erl', 'hrl', 'fs', 'fsx', 'r', 'jl', 'm', 'mm', 'pl', 'pm', 'ps1', 'bat', 'cmd',
      'psm1', 'psd1', 'dockerfile', 'containerfile', 'proto', 'graphql', 'gql', 'prisma', 'tf', 'tfvars',
      'hcl', 'nix', 'cmake', 'bazel', 'bzl', 'properties', 'conf', 'cfg', 'config', 'service', 'desktop',
      'gitignore', 'gitattributes', 'editorconfig', 'npmrc', 'prettierrc', 'eslintrc'
    ].indexOf(ext) >= 0 || codeFileNames.indexOf(name) >= 0;
  }

  function attachmentExtensionFromFileName(fileName) {
    var runtimeFn = localUploadRuntimeFunction('attachmentExtensionFromFileName');
    if (runtimeFn) return runtimeFn(fileName);
    var name = String(fileName || '').trim().toLowerCase();
    return name.indexOf('.') >= 0 ? name.split('.').pop() : '';
  }

  function isPdfAttachmentFileName(fileName) {
    var runtimeFn = localUploadRuntimeFunction('isPdfAttachmentFileName');
    if (runtimeFn) return runtimeFn(fileName);
    return attachmentExtensionFromFileName(fileName) === 'pdf';
  }

  function isCodeAttachmentFileName(fileName) {
    var runtimeFn = localUploadRuntimeFunction('isCodeAttachmentFileName');
    if (runtimeFn) return runtimeFn(fileName);
    var name = String(fileName || '').trim().toLowerCase();
    var ext = attachmentExtensionFromFileName(name);
    return ext !== 'pdf' && isNonOfficeAttachmentName(name, ext);
  }

  function inferCodeAttachmentLanguage(fileName) {
    var runtimeFn = localUploadRuntimeFunction('inferCodeAttachmentLanguage');
    if (runtimeFn) return runtimeFn(fileName);
    var name = String(fileName || '').trim().toLowerCase();
    var ext = attachmentExtensionFromFileName(name);
    var byName = {
      'dockerfile': 'dockerfile',
      'makefile': 'makefile',
      'cmakelists.txt': 'cmake',
      '.gitignore': 'gitignore',
      '.gitattributes': 'gitattributes',
      '.editorconfig': 'ini',
      '.env': 'dotenv'
    };
    if (byName[name]) return byName[name];
    var byExt = {
      bash: 'bash', bat: 'batch', c: 'c', cjs: 'javascript', cmd: 'batch', conf: 'text', cpp: 'cpp',
      cs: 'csharp', css: 'css', cts: 'typescript', dart: 'dart', dockerfile: 'dockerfile', env: 'dotenv',
      go: 'go', gql: 'graphql', gradle: 'groovy', graphql: 'graphql', h: 'c', hcl: 'hcl', hpp: 'cpp',
      htm: 'html', html: 'html', ini: 'ini', java: 'java', js: 'javascript', json: 'json', json5: 'json',
      jsonc: 'jsonc', jsx: 'javascript', kt: 'kotlin', kts: 'kotlin', less: 'less', log: 'text',
      lua: 'lua', m: 'objective-c', markdown: 'markdown', md: 'markdown', mjs: 'javascript',
      mts: 'typescript', nix: 'nix', php: 'php', pl: 'perl', pm: 'perl', prisma: 'prisma',
      proto: 'protobuf', ps1: 'powershell', py: 'python', r: 'r', rb: 'ruby', rs: 'rust',
      scss: 'scss', sh: 'bash', sql: 'sql', svelte: 'svelte', swift: 'swift', tf: 'terraform',
      tfvars: 'terraform', toml: 'toml', ts: 'typescript', tsx: 'typescript', txt: 'text',
      vue: 'vue', xml: 'xml', yaml: 'yaml', yml: 'yaml', zsh: 'bash'
    };
    return byExt[ext] || 'text';
  }

  function attachmentClassForFileName(fileName) {
    var runtimeFn = localUploadRuntimeFunction('attachmentClassForFileName');
    if (runtimeFn) return runtimeFn(fileName);
    var name = String(fileName || '').trim().toLowerCase();
    var ext = name.indexOf('.') >= 0 ? name.split('.').pop() : '';
    if (['doc', 'docx', 'odt', 'rtf'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-word';
    if (['ppt', 'pptx', 'odp'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-ppt';
    if (['xls', 'xlsx', 'ods', 'csv'].indexOf(ext) >= 0) return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-sheet';
    if (ext === 'pdf') return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-pdf';
    if (isNonOfficeAttachmentName(name, ext)) {
      return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-code';
    }
    return 'mnote-uploaded-attachment-row mnote-uploaded-attachment-file';
  }

  function uploadedAttachmentClass(asset) {
    var runtimeFn = localUploadRuntimeFunction('uploadedAttachmentClass');
    if (runtimeFn) return runtimeFn(asset);
    return attachmentClassForFileName(uploadedAssetTitle(asset));
  }

  function buildOnlyOfficeAssetOpenUrl(asset, userId) {
    var title = uploadedAssetTitle(asset);
    var fileType = inferOnlyOfficeFileType(title, asset && asset.mime_type);
    if (!fileType) return '';
    var assetId = String(asset && asset.id || '').trim();
    if (isLocalUploadedAsset(asset)) {
      var localUrl = localAssetOpenUrl(asset, false);
      if (!localUrl) return '';
      return buildOnlyOfficeOpenUrl({
        fileUrl: localUrl,
        fileName: title,
        fileType: fileType,
        assetId: assetId,
        documentId: String(asset && (asset.document_id || asset.documentId) || currentDocumentId() || '').trim(),
        userId: userId || '',
        mode: 'view'
      });
    }
    return buildOnlyOfficeOpenUrl({
      fileUrl: assetId ? '' : uploadedAssetUrl(asset),
      fileName: title,
      fileType: fileType,
      assetId: assetId,
      documentId: String(asset && (asset.document_id || asset.documentId) || currentDocumentId() || '').trim(),
      userId: userId || '',
      mode: 'view'
    });
  }

  function uploadedFileSize(asset) {
    var runtimeFn = localUploadRuntimeFunction('uploadedFileSize');
    if (runtimeFn) return runtimeFn(asset);
    var size = Number(asset && (asset.file_size || asset.fileSize) || 0);
    if (!Number.isFinite(size) || size <= 0) return '';
    if (size >= 1024 * 1024) return (size / 1024 / 1024).toFixed(size >= 10 * 1024 * 1024 ? 1 : 2) + ' MB';
    if (size >= 1024) return (size / 1024).toFixed(size >= 100 * 1024 ? 0 : 2) + ' KB';
    return String(Math.round(size)) + ' B';
  }

  var attachmentMetaCache = Object.create(null);
  var attachmentMetaPending = Object.create(null);
  var legacyOfficeAttachmentIndex = null;
  var legacyOfficeAttachmentIndexPending = null;

  function parseCurrentWorkspaceId() {
    return (new URLSearchParams(window.location.search).get('workspaceId') || '').trim();
  }

  async function fetchLegacyOfficeAttachmentIndex() {
    if (legacyOfficeAttachmentIndex) return legacyOfficeAttachmentIndex;
    if (legacyOfficeAttachmentIndexPending) return legacyOfficeAttachmentIndexPending;
    var documentId = currentDocumentId();
    var workspaceId = parseCurrentWorkspaceId();
    if (!documentId || !workspaceId) {
      legacyOfficeAttachmentIndex = Object.create(null);
      return legacyOfficeAttachmentIndex;
    }
    var projectionUrl = new URL('/api/tree/projections/file', window.location.origin);
    projectionUrl.searchParams.set('documentId', documentId);
    projectionUrl.searchParams.set('workspaceId', workspaceId);
    var sourcePayload = currentWorkspaceSourcePayload();
    if (sourcePayload.sourceKind) projectionUrl.searchParams.set('sourceKind', sourcePayload.sourceKind);
    if (sourcePayload.rootUri) projectionUrl.searchParams.set('rootUri', sourcePayload.rootUri);
    legacyOfficeAttachmentIndexPending = fetch(projectionUrl.toString(), {
      method: 'GET',
      credentials: 'include',
      cache: 'no-store'
    }).then(function(response) {
      return response.json().catch(function() { return null; }).then(function(payload) {
        var items = payload && payload.ok && payload.result && Array.isArray(payload.result.items)
          ? payload.result.items
          : [];
        var index = Object.create(null);
        items.forEach(function(item) {
          if (!item || item.rowKind !== 'asset') return;
          var title = String(item.title || '').trim();
          if (!title || index[title]) return;
          var fileType = inferOnlyOfficeFileType(title, '');
          if (!fileType) return;
          var rowId = String(item.rowId || '').trim();
          var assetId = String(item.assetId || '').trim();
          if (!assetId && rowId.indexOf('asset:') === 0) assetId = rowId.slice('asset:'.length);
          if (!assetId) return;
          index[title] = {
            assetId: assetId,
            fileName: title,
            fileType: fileType,
            documentId: documentId
          };
        });
        legacyOfficeAttachmentIndex = index;
        return index;
      });
    }).catch(function() {
      var empty = Object.create(null);
      legacyOfficeAttachmentIndex = empty;
      return empty;
    }).finally(function() {
      legacyOfficeAttachmentIndexPending = null;
    });
    return legacyOfficeAttachmentIndexPending;
  }

  async function healLegacyOfficeAttachmentParagraphs() {
    var editor = document.querySelector('.editor-surface .ProseMirror');
    if (!(editor instanceof HTMLElement)) return;
    var paragraphs = Array.from(editor.querySelectorAll('p'));
    var candidates = paragraphs.filter(function(paragraph) {
      if (!(paragraph instanceof HTMLParagraphElement)) return;
      if (paragraph.querySelector('a, img, video, audio, table, iframe, canvas')) return;
      if (paragraph.childNodes.length !== 1 || paragraph.firstChild?.nodeType !== Node.TEXT_NODE) return;
      var fileName = String(paragraph.textContent || '').trim();
      if (!fileName) return;
      return Boolean(inferOnlyOfficeFileType(fileName, ''));
    });
    if (!candidates.length) return;
    var index = await fetchLegacyOfficeAttachmentIndex();
    candidates.forEach(function(paragraph) {
      var fileName = String(paragraph.textContent || '').trim();
      var detail = index[fileName];
      if (!detail) return;
      var link = document.createElement('a');
      link.textContent = fileName;
      link.setAttribute('href', buildOnlyOfficeOpenPath({
        fileUrl: '',
        fileName: detail.fileName,
        fileType: detail.fileType,
        assetId: detail.assetId,
        documentId: detail.documentId || currentDocumentId() || '',
        userId: '',
        mode: 'view'
      }));
      link.setAttribute('data-asset-id', detail.assetId);
      attachmentClassForFileName(fileName).split(/\s+/).forEach(function(name) {
        if (name) link.classList.add(name);
      });
      paragraph.replaceChildren(link);
      enhanceEditorAttachmentLink(link);
    });
  }

  function applyEditorAttachmentMeta(link, meta) {
    if (!(link instanceof HTMLAnchorElement) || !meta) return;
    if (meta.assetId) link.setAttribute('data-asset-id', meta.assetId);
    if (meta.fileSize) link.setAttribute('data-file-size', meta.fileSize);
  }

  async function hydrateEditorAttachmentMeta(link) {
    if (!(link instanceof HTMLAnchorElement)) return;
    var detail = detailFromEditorAttachmentLink(link);
    var assetId = String(detail && detail.assetId || '').trim();
    if (!assetId) return;
    var localFilePath = localFilePathFromAssetId(assetId);
    if (localFilePath) {
      var localMeta = {
        assetId: assetId,
        fileSize: String(detail && detail.fileSize || '').trim()
      };
      attachmentMetaCache[assetId] = localMeta;
      applyEditorAttachmentMeta(link, localMeta);
      return;
    }
    if (attachmentMetaCache[assetId]) {
      applyEditorAttachmentMeta(link, attachmentMetaCache[assetId]);
      return;
    }
    if (attachmentMetaPending[assetId]) {
      try { await attachmentMetaPending[assetId]; } catch (_) {}
      applyEditorAttachmentMeta(link, attachmentMetaCache[assetId]);
      return;
    }
    document.documentElement.setAttribute('data-mnote-media-sign-retired', 'true');
    attachmentMetaPending[assetId] = Promise.resolve(null).finally(function() {
      delete attachmentMetaPending[assetId];
    });
    try {
      var meta = await attachmentMetaPending[assetId];
      applyEditorAttachmentMeta(link, meta);
    } catch (_) {}
  }

  function revealFileTreeRow(row) {
    var runtimeFn = fileTreeRuntimeFunction('revealFileTreeRow');
    if (runtimeFn) return runtimeFn(row, fileTreeRuntimeDeps());
    if (!(row instanceof HTMLElement)) return;
    var node = row.closest('.tree-node');
    while (node && node.parentElement) {
      if (node.parentElement.classList && node.parentElement.classList.contains('tree-children')) {
        node.parentElement.classList.remove('tree-children--collapsed');
        var parentNode = node.parentElement.closest('.tree-node');
        var parentRow = parentNode ? parentNode.querySelector(':scope > .tree-row') : null;
        if (parentRow instanceof HTMLElement) {
          parentRow.setAttribute('aria-expanded', 'true');
          var toggle = parentRow.querySelector('[data-rust-action="toggle"]');
          if (toggle) toggle.setAttribute('aria-expanded', 'true');
        }
      }
      node = node.parentElement.closest('.tree-node');
    }
    try { row.scrollIntoView({ block: 'nearest' }); } catch (_) {}
  }

  function revealFileTreeAssetRow(assetId) {
    var runtimeFn = fileTreeRuntimeFunction('revealFileTreeAssetRow');
    if (runtimeFn) return runtimeFn(assetId, fileTreeRuntimeDeps());
    if (!assetId) return false;
    var row = document.querySelector('.tree-row[data-shell-mode="filetree"][data-asset-id="' + cssEscape(assetId) + '"]');
    if (!(row instanceof HTMLElement)) return false;
    revealFileTreeRow(row);
    return true;
  }

  function appendUploadedAssetRow(asset, documentId) {
    var runtimeFn = fileTreeRuntimeFunction('appendUploadedAssetRow');
    if (runtimeFn) return runtimeFn(asset, documentId, fileTreeRuntimeDeps());
    var assetId = String(asset && asset.id || '').trim();
    if (!assetId) return false;
    if (revealFileTreeAssetRow(assetId)) return true;
    var objectKind = String(asset && (asset.objectKind || asset.resourceKind || '') || '').trim();
    if (!objectKind && (String(asset && (asset.asset_type || asset.assetType) || '').trim() === 'mindmap' || /\.mindmap\.json$/i.test(assetId))) {
      objectKind = 'mindmap';
    }
    var targetDocumentId = String(documentId || asset.document_id || asset.documentId || currentDocumentId() || '').trim();
    var parentRow = targetDocumentId
      ? document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + targetDocumentId) + '"]')
      : null;
    if (!parentRow && currentSourceKind() === 'local_folder' && objectKind === 'mindmap') return false;
    if (!parentRow) parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-kind="document"]');
    var root = document.querySelector('#sidebar-file-tree-root .tree-root');
    if (!root && !parentRow) return false;
    var parentLi = parentRow ? parentRow.closest('.tree-node') : null;
    var children = parentLi ? parentLi.querySelector(':scope > .tree-children') : null;
    if (parentLi && !children) {
      children = document.createElement('ul');
      children.className = 'tree-children';
      parentLi.appendChild(children);
    }
    if (children) {
      children.classList.remove('tree-children--collapsed');
      if (parentRow) {
        parentRow.setAttribute('aria-expanded', 'true');
        var toggle = parentRow.querySelector('[data-rust-action="toggle"]');
        if (toggle) toggle.setAttribute('aria-expanded', 'true');
      }
    }
    var container = children || root;
    var li = document.createElement('li');
    li.className = 'tree-node';
    var objectIdentity = {
      objectKind: objectKind || 'attachment',
      documentId: targetDocumentId || null,
      blockId: null,
      assetId: assetId
    };
    li.setAttribute('data-node-id', 'asset:' + assetId);
    var title = uploadedAssetTitle(asset);
    var iconKind = fileTreeIconKindForFileName(title) || uploadedAssetType(asset) || 'file';
    if (objectKind === 'mindmap') iconKind = 'mindmap';
    li.innerHTML =
      '<div class="tree-row" role="treeitem" aria-level="' + (parentRow ? '2' : '1') + '" aria-expanded="false" data-rust-rendered-row="filetree" data-testid="filetree-asset-row" data-row-id="' + escapeHtml('asset:' + assetId) + '" data-row-kind="asset" data-node-id="' + escapeHtml('asset:' + assetId) + '" data-document-id="' + escapeHtml(targetDocumentId) + '" data-doc-id="' + escapeHtml(targetDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '" data-object-identity="' + escapeHtml(objectIdentityAttr(objectIdentity)) + '" data-object-kind="' + escapeHtml(objectKind || 'attachment') + '" data-shell-mode="filetree" data-selected="false" data-active="false" draggable="true">' +
      '<span class="tree-spacer" aria-hidden="true"></span><span class="tree-kind-badge" data-kind="' + escapeHtml(iconKind) + '" aria-hidden="true"></span>' +
      '<button type="button" class="tree-link" data-rust-action="open" data-row-id="' + escapeHtml('asset:' + assetId) + '" data-document-id="' + escapeHtml(targetDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '"><span class="tree-link-title">' + escapeHtml(title) + '</span></button>' +
      '<div class="tree-actions"><button type="button" class="tree-action" data-testid="filetree-action-menu" data-rust-action="menu" data-row-id="' + escapeHtml('asset:' + assetId) + '" aria-label="更多操作">…</button></div></div>';
    container.appendChild(li);
    revealFileTreeRow(li.querySelector('.tree-row'));
    document.documentElement.setAttribute('data-mnote-last-upload-asset-id', assetId);
    return true;
  }

  function removeFileTreeAssetRow(assetId) {
    var normalized = String(assetId || '').trim();
    if (!normalized) return false;
    var row = document.querySelector('.tree-row[data-shell-mode="filetree"][data-asset-id="' + cssEscape(normalized) + '"]');
    var node = row ? row.closest('.tree-node') : null;
    if (!node || !node.parentElement) return false;
    node.parentElement.removeChild(node);
    return true;
  }

  function applyAssetsChangedToFileTree(detail) {
    detail = detail || {};
    var docId = String(detail.docId || detail.documentId || currentDocumentId() || '').trim();
    var changed = false;
    var explicitAsset = detail.asset && typeof detail.asset === 'object' ? detail.asset : null;
    if (explicitAsset) {
      appendUploadedAssetRow(explicitAsset, docId);
      changed = true;
    }
    var mindmapAssetIds = Array.isArray(detail.mindmapAssetIds) ? detail.mindmapAssetIds : [];
    if (detail.mindmapDeleted === true) {
      mindmapAssetIds.forEach(function(assetId) {
        if (removeFileTreeAssetRow(assetId)) changed = true;
      });
    }
    if (changed) {
      document.documentElement.setAttribute('data-mnote-assets-local-applied', 'true');
    }
  }

  function mindmapAssetFromTarget(documentId, mindmapId, writeResult) {
    var docId = String(documentId || currentDocumentId() || '').trim();
    var assetId = String(mindmapId || '').trim();
    if (!docId || !assetId) return null;
    var result = writeResult && typeof writeResult === 'object' ? writeResult : {};
    var resultAssetId = String(result.assetId || result.id || '').trim();
    var relativePath = String(result.relativePath || result.rootRelativePath || '').trim();
    var fileName = String(result.fileName || '').trim() || shortMindmapFileName(assetId);
    return {
      id: resultAssetId || (relativePath ? 'local-file:' + relativePath : assetId),
      document_id: docId,
      asset_type: 'mindmap',
      file_name: fileName,
      file_url: relativePath || ('/documents/' + encodeURIComponent(docId) + '/' + encodeURIComponent(fileName)),
      sourcePath: relativePath,
      rootRelativePath: relativePath,
      sourceKind: currentSourceKind(),
      rootUri: currentRootUri(),
      objectKind: 'mindmap'
    };
  }

  function shortMindmapFileName(mindmapId) {
    var runtimeFn = fileTreeRuntimeFunction('shortMindmapFileName');
    if (runtimeFn) return runtimeFn(mindmapId);
    var raw = String(mindmapId || '').trim();
    var pathName = raw.indexOf('/') >= 0 ? raw.split('/').pop() : raw;
    if (/\.json$/i.test(pathName)) return pathName;
    var digits = raw.match(/(\d{4,})$/);
    var suffix = digits ? digits[1].slice(-6) : '';
    return suffix ? '思维导图' + suffix + '.json' : '思维导图.json';
  }

  function parseMindmapApiTarget(input) {
    var runtimeFn = fileTreeRuntimeFunction('parseMindmapApiTarget');
    if (runtimeFn) return runtimeFn(input);
    try {
      var rawUrl = typeof input === 'string'
        ? input
        : input && typeof input.url === 'string'
          ? input.url
          : '';
      if (!rawUrl) return null;
      var url = new URL(rawUrl, window.location.origin);
      var match = /^\/api\/mindmap\/([^/]+)\/([^/]+)$/.exec(url.pathname);
      if (!match) return null;
      return {
        documentId: decodeURIComponent(match[1]),
        mindmapId: decodeURIComponent(match[2])
      };
    } catch (_) {
      return null;
    }
  }

  function withLocalMindmapSourceParams(input) {
    var target = parseMindmapApiTarget(input);
    if (!target || currentSourceKind() !== 'local_folder') return input;
    var rootUri = currentRootUri();
    if (!rootUri) return input;
    var rawUrl = typeof input === 'string'
      ? input
      : input && typeof input.url === 'string'
        ? input.url
        : '';
    if (!rawUrl) return input;
    var url = new URL(rawUrl, window.location.origin);
    url.searchParams.set('sourceKind', 'local_folder');
    url.searchParams.set('rootUri', rootUri);
    if (typeof input === 'string') return url.pathname + url.search;
    if (typeof Request !== 'undefined' && input instanceof Request) {
      return new Request(url.toString(), input);
    }
    return url.toString();
  }

  function requestMethod(input, init) {
    var runtimeFn = fileTreeRuntimeFunction('requestMethod');
    if (runtimeFn) return runtimeFn(input, init);
    return String(
      init && init.method
        ? init.method
        : input && typeof input.method === 'string'
          ? input.method
          : 'GET'
    ).toUpperCase();
  }

  function requestBodyHasMindmapCreateOnly(init) {
    var runtimeFn = fileTreeRuntimeFunction('requestBodyHasMindmapCreateOnly');
    if (runtimeFn) return runtimeFn(init);
    var body = init && typeof init.body === 'string' ? init.body : '';
    if (!body) return false;
    try {
      var payload = JSON.parse(body);
      return payload && payload.createOnly === true;
    } catch (_) {
      return false;
    }
  }

  function applyMindmapApiMutationToFileTree(target, payload) {
    if (!target || !target.documentId || !target.mindmapId) return;
    var asset = mindmapAssetFromTarget(target.documentId, target.mindmapId, payload && payload.writeResult);
    if (!asset) return;
    var appended = appendUploadedAssetRow(asset, target.documentId);
    if (!appended && currentSourceKind() === 'local_folder') void refreshLocalFolderSidebarSnapshot();
    document.documentElement.setAttribute('data-mnote-assets-local-applied', 'true');
    document.documentElement.setAttribute('data-mnote-last-mindmap-asset-id', asset.id || target.mindmapId);
  }

  function installMindmapAssetFetchObserver() {
    if (window.__mnoteMindmapAssetFetchObserverInstalled === true) return;
    if (typeof window.fetch !== 'function') return;
    window.__mnoteMindmapAssetFetchObserverInstalled = true;
    var originalFetch = window.fetch.bind(window);
    window.fetch = function(input, init) {
      var nextInput = withLocalMindmapSourceParams(input);
      var target = parseMindmapApiTarget(nextInput);
      var method = requestMethod(input, init);
      var createOnly = requestBodyHasMindmapCreateOnly(init || {});
      return originalFetch(nextInput, init).then(function(response) {
        if (target && method === 'POST' && response && response.ok) {
          var cloned = response.clone();
          void cloned.json().then(function(payload) {
            if (createOnly || target.documentId === currentDocumentId()) {
              applyMindmapApiMutationToFileTree(target, payload);
            }
          }).catch(function() {
            if (createOnly || target.documentId === currentDocumentId()) {
              applyMindmapApiMutationToFileTree(target, null);
            }
          });
        }
        return response;
      });
    };
  }

  async function archiveLocalFileTreeAsset(row, assetId) {
    if (!assetId) return false;
    await dispatchTreeCommand(row || document.body, {
      action: 'archive',
      workspaceId: resolveWorkspaceId(row || document.body),
      documentId: assetId
    });
    removeFileTreeAssetRow(assetId);
    return true;
  }

  async function deleteSingleFileTreeAsset(detail, trigger) {
    var assetId = String(detail && detail.assetId || '').trim();
    if (!assetId) return false;
    var row = trigger && trigger.closest ? trigger.closest('.tree-row[data-shell-mode="filetree"]') : null;
    if (!row) row = document.querySelector('.tree-row[data-shell-mode="filetree"][data-asset-id="' + cssEscape(assetId) + '"]');
    if (currentSourceKind() === 'local_folder') {
      return archiveLocalFileTreeAsset(row, assetId);
    }
    var documentId = String(detail && detail.documentId || '').trim();
    var kind = classifySidebarFileTreeAsset(row);
    if (kind === 'mindmap') {
      var response = await fetch('/api/mindmap/' + encodeURIComponent(documentId) + '/' + encodeURIComponent(assetId), { method: 'DELETE' });
      if (!response.ok) throw new Error('mindmap_delete_failed_' + response.status);
      removeFileTreeAssetRow(assetId);
      return true;
    }
    if (kind === 'table') {
      var tableResponse = await fetch('/api/tables/' + encodeURIComponent(assetId), { method: 'DELETE' });
      if (!tableResponse.ok) throw new Error('table_delete_failed_' + tableResponse.status);
      removeFileTreeAssetRow(assetId);
      return true;
    }
    await postSidebarFileTreeJson('/api/media/batch', { action: 'delete', assetIds: [assetId] });
    removeFileTreeAssetRow(assetId);
    return true;
  }

  function resolveEditorUploadContext(detail) {
    var runtimeFn = localUploadRuntimeFunction('resolveEditorUploadContext');
    if (runtimeFn) {
      return runtimeFn(detail || {}, {
        rootSelector: EDITOR_UPLOAD_ROOT_SELECTOR,
        editorUploadRootFromElement: editorUploadRootFromElement,
        currentDocumentId: currentDocumentId,
        resolveWorkspaceId: resolveWorkspaceId
      });
    }
    var root = null;
    var selector = detail && detail.editorRootSelector ? String(detail.editorRootSelector) : '';
    if (selector) {
      try {
        var selected = document.querySelector(selector);
        if (selected instanceof HTMLElement) root = selected;
      } catch (_) {}
    }
    if (!root && window.__mnoteIntendedSlashRoot instanceof HTMLElement && window.__mnoteIntendedSlashRoot.isConnected) {
      root = window.__mnoteIntendedSlashRoot;
    }
    if (!root && window.__mnoteLastEditorUploadRoot instanceof HTMLElement && window.__mnoteLastEditorUploadRoot.isConnected) {
      root = window.__mnoteLastEditorUploadRoot;
    }
    if (!root && document.activeElement instanceof Element) {
      root = editorUploadRootFromElement(document.activeElement);
    }
    if (!root) {
      var focused = document.querySelector(EDITOR_UPLOAD_ROOT_SELECTOR + ' .ProseMirror:focus-within');
      root = editorUploadRootFromElement(focused);
    }
    if (!root) {
      root = document.querySelector('[data-editor-host-kind="leptos_tiptap_island"][data-pane-role="primary"]');
    }
    var pane = root instanceof Element ? root.closest('.document-pane[data-pane-role]') : null;
    var shell = root instanceof Element ? root.closest('.document-shell[data-document-id]') : null;
    return {
      root: root instanceof HTMLElement ? root : null,
      documentId: String(
        detail && detail.documentId
        || (root instanceof HTMLElement && root.getAttribute('data-document-id'))
        || (pane instanceof HTMLElement && pane.getAttribute('data-pane-document-id'))
        || (shell instanceof HTMLElement && shell.getAttribute('data-document-id'))
        || currentDocumentId()
        || ''
      ).trim(),
      workspaceId: String(
        detail && detail.workspaceId
        || (root instanceof HTMLElement && root.getAttribute('data-workspace-id'))
        || (pane instanceof HTMLElement && pane.getAttribute('data-pane-workspace-id'))
        || (shell instanceof HTMLElement && shell.getAttribute('data-workspace-id'))
        || resolveWorkspaceId(document.body)
        || ''
      ).trim()
    };
  }

  function editorRootFromUploadOptions(options) {
    var runtimeFn = localUploadRuntimeFunction('editorRootFromUploadOptions');
    if (runtimeFn) {
      return runtimeFn(options || {}, {
        rootSelector: EDITOR_UPLOAD_ROOT_SELECTOR,
        editorUploadRootFromElement: editorUploadRootFromElement
      });
    }
    if (options && options.editorRoot instanceof HTMLElement) return options.editorRoot;
    if (window.__mnoteIntendedSlashRoot instanceof HTMLElement && window.__mnoteIntendedSlashRoot.isConnected) {
      return window.__mnoteIntendedSlashRoot;
    }
    if (window.__mnoteLastEditorUploadRoot instanceof HTMLElement && window.__mnoteLastEditorUploadRoot.isConnected) {
      return window.__mnoteLastEditorUploadRoot;
    }
    var focused = document.querySelector(EDITOR_UPLOAD_ROOT_SELECTOR + ' .ProseMirror:focus-within');
    return editorUploadRootFromElement(focused);
  }

  async function fetchWithTimeout(input, init, timeoutMs, label) {
    var runtimeFn = localUploadRuntimeFunction('fetchWithTimeout');
    if (runtimeFn) {
      return await runtimeFn(input, init || {}, timeoutMs, label);
    }
    var controller = typeof AbortController === 'function' ? new AbortController() : null;
    var timer = 0;
    try {
      if (controller) {
        timer = window.setTimeout(function() {
          controller.abort();
        }, Math.max(1000, Number(timeoutMs) || 15000));
      }
      var nextInit = Object.assign({}, init || {});
      if (controller) nextInit.signal = controller.signal;
      return await fetch(input, nextInit);
    } catch (error) {
      if (error && error.name === 'AbortError') {
        throw new Error((label || '请求') + '超时');
      }
      throw error;
    } finally {
      if (timer) window.clearTimeout(timer);
    }
  }

  async function insertUploadedAssetIntoEditor(asset, targetRoot) {
    var runtimeFn = localUploadRuntimeFunction('insertUploadedAssetIntoEditor');
    if (runtimeFn) {
      return await runtimeFn(asset, targetRoot, {
        uploadedAssetTitle: uploadedAssetTitle,
        localAssetOpenUrl: localAssetOpenUrl,
        uploadedAssetUrl: uploadedAssetUrl,
        uploadedAssetType: uploadedAssetType,
        isLocalUploadedAsset: isLocalUploadedAsset,
        buildOnlyOfficeAssetOpenUrl: buildOnlyOfficeAssetOpenUrl,
        fetchCurrentOnlyOfficeUserId: fetchCurrentOnlyOfficeUserId,
        buildOnlyOfficeOpenPath: buildOnlyOfficeOpenPath,
        inferOnlyOfficeFileType: inferOnlyOfficeFileType,
        currentDocumentId: currentDocumentId,
        currentRootUri: currentRootUri,
        uploadedAttachmentClass: uploadedAttachmentClass,
        uploadedFileSize: uploadedFileSize,
        cssEscape: cssEscape,
        enhanceEditorAttachmentLinks: enhanceEditorAttachmentLinks
      });
    }
    var editorRoot = targetRoot instanceof HTMLElement
      ? targetRoot.querySelector('.editor-surface .ProseMirror')
      : document.querySelector('.editor-surface .ProseMirror');
    if (targetRoot instanceof HTMLElement) window.__mnoteLastEditorUploadRoot = targetRoot;
    var editor = editorRoot && editorRoot.editor;
    if (!editor || !editor.chain) {
      document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'false');
      document.documentElement.setAttribute('data-mnote-last-upload-insert-error', 'editor_unavailable');
      return false;
    }
    var title = uploadedAssetTitle(asset);
    var markdownHref = uploadedAssetMarkdownHref(asset);
    var localOpenUrl = localAssetOpenUrl(asset, false);
    var fallbackUrl = uploadedAssetUrl(asset);
    var imageUrl = localOpenUrl || fallbackUrl || markdownHref;
    var url = markdownHref || localOpenUrl || fallbackUrl;
    var type = uploadedAssetType(asset);
    var assetId = String(asset && asset.id || '').trim();
    var sizeLabel = uploadedFileSize(asset);
    try {
      if (type === 'image' && imageUrl) {
        return editor.chain().focus().setImage({ src: imageUrl, alt: title, title: title }).run() === true;
      }
      var href = markdownHref || url;
      if (href) {
        var inserted = editor.chain().focus().insertContent([
          {
            type: 'paragraph',
            content: [{
              type: 'text',
              text: title,
              marks: [{
                type: 'link',
                attrs: {
                  href: href,
                  target: '_blank',
                  rel: 'noopener noreferrer nofollow',
                  class: uploadedAttachmentClass(asset)
                }
              }]
            }]
          },
          { type: 'paragraph' }
        ]).focus('end').run() === true;
        if (inserted) {
          document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'true');
          document.documentElement.setAttribute('data-mnote-last-upload-asset-id', assetId || '');
          document.documentElement.removeAttribute('data-mnote-last-upload-insert-error');
        } else {
          document.documentElement.setAttribute('data-mnote-last-upload-inserted', 'false');
          document.documentElement.setAttribute('data-mnote-last-upload-insert-error', 'insert_content_failed');
        }
        window.setTimeout(function annotateUploadedLink(attempt) {
          if (targetRoot instanceof HTMLElement) window.__mnoteLastEditorUploadRoot = targetRoot;
          enhanceEditorAttachmentLinks();
          var selector = assetId
            ? '.editor-surface .ProseMirror a[href*="' + cssEscape(assetId) + '"]'
            : '.editor-surface .ProseMirror a';
          var link = targetRoot instanceof HTMLElement
            ? targetRoot.querySelector(selector)
            : document.querySelector(selector);
          if (!(link instanceof HTMLElement) && assetId) {
            var scope = targetRoot instanceof HTMLElement ? targetRoot : document;
            link = Array.from(scope.querySelectorAll('.editor-surface .ProseMirror a')).find(function(candidate) {
              var href = String(candidate.getAttribute('href') || '');
              try { href = decodeURIComponent(href); } catch (_) {}
              return href.indexOf(assetId) >= 0;
            }) || null;
          }
          if (link instanceof HTMLElement) {
            if (assetId) link.setAttribute('data-asset-id', assetId);
            if (sizeLabel) link.setAttribute('data-file-size', sizeLabel);
          } else if (Number(attempt) < 20) {
            window.setTimeout(function() { annotateUploadedLink(Number(attempt) + 1); }, 50);
          }
        }, 0, 0);
        return inserted;
      }
    } catch (error) {
      console.warn('[mnote upload] insert uploaded asset failed', error);
    }
    return false;
  }

  async function uploadFileToMediaAsset(file, plan, options) {
    var runtimeFn = localUploadRuntimeFunction('uploadFileToMediaAsset');
    if (runtimeFn) {
      return await runtimeFn(file, plan, options || {}, {
        currentSourceKind: currentSourceKind,
        currentRootUri: currentRootUri,
        currentDocumentId: currentDocumentId,
        editorRootFromUploadOptions: editorRootFromUploadOptions,
        appendUploadedAssetRow: appendUploadedAssetRow,
        refreshLocalFolderSidebarSnapshot: refreshLocalFolderSidebarSnapshot,
        dispatchEvent: function(event) { return window.dispatchEvent(event); },
        CustomEvent: CustomEvent,
        buildOnlyOfficeAssetOpenUrl: buildOnlyOfficeAssetOpenUrl,
        fetchCurrentOnlyOfficeUserId: fetchCurrentOnlyOfficeUserId,
        buildOnlyOfficeOpenPath: buildOnlyOfficeOpenPath,
        inferOnlyOfficeFileType: inferOnlyOfficeFileType,
        enhanceEditorAttachmentLinks: enhanceEditorAttachmentLinks,
        cssEscape: cssEscape
      });
    }
    if (currentSourceKind() === 'local_folder') {
      var rootUri = currentRootUri();
      var documentId = String(plan && plan.targetDocumentId || currentDocumentId() || '').trim();
      var hasFolderTarget = plan && Object.prototype.hasOwnProperty.call(plan, 'targetRelativePath');
      var uploadIntent = String(plan && plan.uploadIntent || (hasFolderTarget ? 'filetree.folder.drop' : 'editor.markdown.attach')).trim();
      if (!rootUri || !uploadIntent) {
        throw new Error('本地 Markdown 上传缺少 rootUri 或 documentId');
      }
      var localUploadRuntime = localUploadRuntimeFunction('uploadLocalFolderAsset');
      var localPayload = null;
      if (localUploadRuntime) {
        var localResult = await localUploadRuntime(file, plan, {
          rootUri: rootUri,
          documentId: documentId,
          timeoutMs: 15000
        });
        localPayload = localResult && localResult.asset ? { asset: localResult.asset } : null;
      } else {
        var localForm = new FormData();
        localForm.append('file', file);
        localForm.append('rootUri', rootUri);
        localForm.append('uploadIntent', uploadIntent);
        if (documentId) localForm.append('documentId', documentId);
        if (hasFolderTarget) localForm.append('targetRelativePath', String(plan.targetRelativePath || ''));
        localForm.append('kind', file && String(file.type || '').indexOf('image/') === 0 ? 'image' : 'attachment');
        var localResponse = await fetchWithTimeout('/api/local-folder/assets/upload', {
          method: 'POST',
          credentials: 'include',
          body: localForm
        }, 15000, '本地上传');
        localPayload = await localResponse.json().catch(function() { return null; });
        if (!localResponse.ok || !localPayload || !localPayload.asset) {
          throw new Error(localPayload && localPayload.error ? localPayload.error : '上传失败');
        }
      }
      if (options && options.insertIntoEditor) {
        await insertUploadedAssetIntoEditor(localPayload.asset, editorRootFromUploadOptions(options));
      }
      if (!(options && options.insertIntoEditor)) void refreshLocalFolderSidebarSnapshot();
      window.dispatchEvent(new CustomEvent('wolai:local-assets-changed', {
        detail: { docId: documentId, asset: localPayload.asset, assetIds: [localPayload.asset.id] }
      }));
      return localPayload.asset;
    }
    var mediaUploadRuntime = localUploadRuntimeFunction('uploadMediaAsset');
    var payload = null;
    if (mediaUploadRuntime) {
      var mediaResult = await mediaUploadRuntime(file, plan, { timeoutMs: 15000 });
      payload = mediaResult && mediaResult.asset ? { asset: mediaResult.asset } : null;
      if (!payload || !payload.asset) {
        throw new Error('上传失败');
      }
    } else {
      document.documentElement.setAttribute('data-mnote-media-upload-retired', 'true');
      throw new Error('旧 Convex Files 上传链已退役；local-first 附件请使用本地文件夹上传目标。');
    }
    appendUploadedAssetRow(payload.asset, plan.targetDocumentId);
    if (options && options.insertIntoEditor) {
      await insertUploadedAssetIntoEditor(payload.asset, editorRootFromUploadOptions(options));
    }
    window.dispatchEvent(new CustomEvent('wolai:assets-changed', {
      detail: { docId: plan.targetDocumentId, asset: payload.asset, assetIds: [payload.asset.id] }
    }));
    return payload.asset;
  }

  window.addEventListener('wolai:assets-changed', function(event) {
    applyAssetsChangedToFileTree(event.detail || {});
  });
  window.addEventListener('wolai:local-assets-changed', function(event) {
    applyAssetsChangedToFileTree(event.detail || {});
  });
  window.addEventListener('mnote:knowledge-rag-source-updated', function() {
    if (currentSourceKind() === 'local_folder') void refreshLocalFolderSidebarSnapshot();
  });
  installMindmapAssetFetchObserver();

  async function uploadFilesWithResolvedTarget(files, detail, options) {
    var runtimeFn = localUploadRuntimeFunction('uploadFilesWithResolvedTarget');
    if (runtimeFn) {
      return await runtimeFn(files, detail || {}, options || {}, {
        resolveFileTreeUploadTarget: resolveFileTreeUploadTarget,
        uploadFileToMediaAsset: uploadFileToMediaAsset,
        alert: function(message) { window.alert(message); }
      });
    }
    var list = Array.from(files || []).filter(Boolean);
    if (!list.length) return [];
    var plan = await resolveFileTreeUploadTarget(detail || {});
    var uploaded = [];
    var errors = [];
    for (var i = 0; i < list.length; i += 1) {
      try {
        uploaded.push(await uploadFileToMediaAsset(list[i], plan, options || {}));
      } catch (error) {
        errors.push(list[i].name + ': ' + (error && error.message ? error.message : '上传失败'));
      }
    }
    if (errors.length) {
      window.alert('部分文件上传失败：\n' + errors.slice(0, 6).join('\n') + (errors.length > 6 ? '\n...' : ''));
    }
    return uploaded;
  }

  function openEditorUploadFilePicker(detail) {
    var runtimeFn = localUploadRuntimeFunction('openEditorUploadFilePicker');
    if (runtimeFn) {
      return runtimeFn(detail || {}, {
        rootSelector: EDITOR_UPLOAD_ROOT_SELECTOR,
        editorUploadRootFromElement: editorUploadRootFromElement,
        currentDocumentId: currentDocumentId,
        resolveWorkspaceId: resolveWorkspaceId,
        uploadFilesWithResolvedTarget: uploadFilesWithResolvedTarget
      });
    }
    var uploadContext = resolveEditorUploadContext(detail || {});
    var input = document.createElement('input');
    input.type = 'file';
    input.multiple = detail && detail.multiple !== false;
    if (detail && detail.accept) input.accept = String(detail.accept);
    input.style.position = 'fixed';
    input.style.left = '-9999px';
    input.style.top = '-9999px';
    document.body.appendChild(input);
    input.addEventListener('change', function() {
      var files = Array.from(input.files || []);
      input.remove();
      void uploadFilesWithResolvedTarget(files, {
        workspaceId: uploadContext.workspaceId || resolveWorkspaceId(document.body),
        documentId: uploadContext.documentId || currentDocumentId(),
        targetRowId: null,
        uploadIntent: 'editor.markdown.attach'
      }, {
        insertIntoEditor: detail && detail.insertIntoEditor !== false,
        editorRoot: uploadContext.root
      });
    }, { once: true });
    input.click();
  }

  window.addEventListener('mnote:editor-upload-request', function(event) {
    openEditorUploadFilePicker(event.detail || {});
  });

  window.addEventListener('tree.filetree.external-drop', function(event) {
    var detail = event.detail || {};
    void uploadFilesWithResolvedTarget(detail.files || [], detail, {
      insertIntoEditor: String(detail.documentId || '') === currentDocumentId()
    });
  });

  document.addEventListener('dragover', function(event) {
    var editorTarget = closestAction(event.target, '[data-testid="mnote-leptos-tiptap-editor-stage"], .editor-surface .ProseMirror');
    var hasFiles = event.dataTransfer && Array.prototype.indexOf.call(event.dataTransfer.types || [], 'Files') >= 0;
    if (!editorTarget || !hasFiles) return;
    event.preventDefault();
    event.stopPropagation();
    if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy';
  }, true);

  document.addEventListener('drop', function(event) {
    var editorTarget = closestAction(event.target, '[data-testid="mnote-leptos-tiptap-editor-stage"], .editor-surface .ProseMirror');
    var files = event.dataTransfer ? Array.from(event.dataTransfer.files || []) : [];
    if (!editorTarget || !files.length) return;
    event.preventDefault();
    event.stopPropagation();
    void uploadFilesWithResolvedTarget(files, {
      workspaceId: resolveWorkspaceId(document.body),
      documentId: currentDocumentId(),
      targetRowId: null,
      uploadIntent: 'editor.markdown.attach'
    }, {
      insertIntoEditor: true,
      editorRoot: editorUploadRootFromElement(editorTarget)
    });
  }, true);

  const sidebarFileTreeCommandState = {
    get activeTreeContextMenu() { return activeTreeContextMenu; },
    set activeTreeContextMenu(value) { activeTreeContextMenu = value; },
    get sidebarFileTreeClipboard() { return sidebarFileTreeClipboard; },
    set sidebarFileTreeClipboard(value) { sidebarFileTreeClipboard = value; },
  };
  const sidebarFileTreeCommand = createSidebarFileTreeCommandRuntime({
    applyRemoveDocumentDelta,
    createFileTreeFolder,
    createPage,
    cssEscape,
    currentDocumentId,
    currentRootUri,
    currentSourceKind,
    deleteSingleFileTreeAsset,
    dispatchSidebarEvent,
    dispatchTreeCommand,
    ensureFileTreeWritableTarget,
    fileTreeRuntimeDeps,
    fileTreeRuntimeFunction,
    fileTreeSelectionRuntimeDeps,
    fileTreeSelectionRuntimeFunction,
    isFileTreePageRow,
    localFilePathFromAssetId,
    normalizeFileTreePageRenameTitle,
    openConvexAssetFromFileTree,
    openEditorAttachmentDetail: (...args) => openEditorAttachmentDetail(...args),
    openEditorAttachmentDownload: (...args) => openEditorAttachmentDownload(...args),
    openEditorAttachmentEditTab: (...args) => openEditorAttachmentEditTab(...args),
    openEditorAttachmentNewWindow: (...args) => openEditorAttachmentNewWindow(...args),
    openLocalResourceInActiveTab: (...args) => openLocalResourceInActiveTab(...args),
    refreshLocalFolderSidebarSnapshot,
    removeFileTreeAssetRow,
    revealFileTreeResource,
    resolveWorkspaceId,
    runtimeState: sidebarFileTreeCommandState,
    selectedSidebarFileTreeSelection: sidebarFileTreeSelection,
    updateTitleEverywhere,
    validateFileTreeRename,
  });
  const rowTitle = (...args) => sidebarFileTreeCommand.rowTitle(...args);
  const rowCenter = (...args) => sidebarFileTreeCommand.rowCenter(...args);
  const renameFileTreeAsset = (...args) => sidebarFileTreeCommand.renameFileTreeAsset(...args);
  const beginFileTreeInlineRename = (...args) => sidebarFileTreeCommand.beginFileTreeInlineRename(...args);
  const closeTreeContextMenu = (...args) => sidebarFileTreeCommand.closeTreeContextMenu(...args);
  const copyTreeContextValue = (...args) => sidebarFileTreeCommand.copyTreeContextValue(...args);
  const triggerBrowserDownload = (...args) => sidebarFileTreeCommand.triggerBrowserDownload(...args);
  const recordFileTreeAction = (...args) => sidebarFileTreeCommand.recordFileTreeAction(...args);
  const recordFileTreeActionStatus = (...args) => sidebarFileTreeCommand.recordFileTreeActionStatus(...args);
  const documentHref = (...args) => sidebarFileTreeCommand.documentHref(...args);
  const convertToPreviousSiblingChild = (...args) => sidebarFileTreeCommand.convertToPreviousSiblingChild(...args);
  const fileTreeCopyPath = (...args) => sidebarFileTreeCommand.fileTreeCopyPath(...args);
  const fileTreeMenuTargetParentId = (...args) => sidebarFileTreeCommand.fileTreeMenuTargetParentId(...args);
  const withOfficeEditModeGuard = (...args) => sidebarFileTreeCommand.withOfficeEditModeGuard(...args);
  const handleTreeContextMenuAction = (...args) => sidebarFileTreeCommand.handleTreeContextMenuAction(...args);
  const appendTreeContextMenuButton = (...args) => sidebarFileTreeCommand.appendTreeContextMenuButton(...args);
  const buildSidebarFileTreeContext = (...args) => sidebarFileTreeCommand.buildSidebarFileTreeContext(...args);
  const evaluateSidebarFileTreeWhen = (...args) => sidebarFileTreeCommand.evaluateSidebarFileTreeWhen(...args);
  const openTreeContextMenu = (...args) => sidebarFileTreeCommand.openTreeContextMenu(...args);
  const openPageTreeContextMenu = (...args) => sidebarFileTreeCommand.openPageTreeContextMenu(...args);
  const openFileTreeContextMenu = (...args) => sidebarFileTreeCommand.openFileTreeContextMenu(...args);
  const visibleFileTreeRows = (...args) => sidebarFileTreeCommand.visibleFileTreeRows(...args);
  const syncSidebarFileTreeSelection = (...args) => sidebarFileTreeCommand.syncSidebarFileTreeSelection(...args);
  const selectSidebarFileTreeRow = (...args) => sidebarFileTreeCommand.selectSidebarFileTreeRow(...args);
  const selectSidebarFileTreeDocument = (...args) => sidebarFileTreeCommand.selectSidebarFileTreeDocument(...args);
  const selectSidebarFileTreeRowById = (...args) => sidebarFileTreeCommand.selectSidebarFileTreeRowById(...args);
  const pendingLocalFolderRestoreRowId = (...args) => sidebarFileTreeCommand.pendingLocalFolderRestoreRowId(...args);
  const clearPendingLocalFolderRestoreRowId = (...args) => sidebarFileTreeCommand.clearPendingLocalFolderRestoreRowId(...args);
  const applyPendingLocalFolderRestoreFocusOnce = (...args) => sidebarFileTreeCommand.applyPendingLocalFolderRestoreFocusOnce(...args);
  const schedulePendingLocalFolderRestoreFocus = (...args) => sidebarFileTreeCommand.schedulePendingLocalFolderRestoreFocus(...args);
  const selectedSidebarFileTreeRowIdsForDrag = (...args) => sidebarFileTreeCommand.selectedSidebarFileTreeRowIdsForDrag(...args);
  const selectedSidebarFileTreeRows = (...args) => sidebarFileTreeCommand.selectedSidebarFileTreeRows(...args);
  const fileTreeRowDocumentId = (...args) => sidebarFileTreeCommand.fileTreeRowDocumentId(...args);
  const fileTreeRowAssetId = (...args) => sidebarFileTreeCommand.fileTreeRowAssetId(...args);
  const decodeLocalEncodedPath = (...args) => sidebarFileTreeCommand.decodeLocalEncodedPath(...args);
  const fileTreeRowLocalRelativePath = (...args) => sidebarFileTreeCommand.fileTreeRowLocalRelativePath(...args);
  const fileTreeRowLocalUploadTargetRelativePath = (...args) => sidebarFileTreeCommand.fileTreeRowLocalUploadTargetRelativePath(...args);
  const readWorkspacePathFromRow = (...args) => sidebarFileTreeCommand.readWorkspacePathFromRow(...args);
  const fileTreeRowKind = (...args) => sidebarFileTreeCommand.fileTreeRowKind(...args);
  const isFileTreeDownloadableAssetRow = (...args) => sidebarFileTreeCommand.isFileTreeDownloadableAssetRow(...args);
  const isFileTreeDownloadableRow = (...args) => sidebarFileTreeCommand.isFileTreeDownloadableRow(...args);
  const fileTreeAssetDownloadDetail = (...args) => sidebarFileTreeCommand.fileTreeAssetDownloadDetail(...args);
  const selectedSidebarFileTreeRowsForDownload = (...args) => sidebarFileTreeCommand.selectedSidebarFileTreeRowsForDownload(...args);
  const selectedSidebarFileTreeAssetRowsForDownload = (...args) => sidebarFileTreeCommand.selectedSidebarFileTreeAssetRowsForDownload(...args);
  const downloadSelectedFileTreeAssetRows = (...args) => sidebarFileTreeCommand.downloadSelectedFileTreeAssetRows(...args);
  const hasSelectedDocumentAncestor = (...args) => sidebarFileTreeCommand.hasSelectedDocumentAncestor(...args);
  const classifySidebarFileTreeAsset = (...args) => sidebarFileTreeCommand.classifySidebarFileTreeAsset(...args);
  const buildSidebarFileTreeDeletePlan = (...args) => sidebarFileTreeCommand.buildSidebarFileTreeDeletePlan(...args);
  const sidebarFileTreeDeleteConfirmText = (...args) => sidebarFileTreeCommand.sidebarFileTreeDeleteConfirmText(...args);
  const postSidebarFileTreeJson = (...args) => sidebarFileTreeCommand.postSidebarFileTreeJson(...args);
  const fileTreeRowsByRowIds = (...args) => sidebarFileTreeCommand.fileTreeRowsByRowIds(...args);
  const fileTreeChildCount = (...args) => sidebarFileTreeCommand.fileTreeChildCount(...args);
  const moveSidebarFileTreeRows = (...args) => sidebarFileTreeCommand.moveSidebarFileTreeRows(...args);
  const pasteSidebarFileTreeClipboard = (...args) => sidebarFileTreeCommand.pasteSidebarFileTreeClipboard(...args);
  const deleteSelectedSidebarFileTreeRows = (...args) => sidebarFileTreeCommand.deleteSelectedSidebarFileTreeRows(...args);

  sidebarFileTreeUpload = createSidebarFileTreeUploadRuntime({
    cssEscape,
    currentDocumentId,
    fileTreeRuntimeDeps,
    fileTreeRuntimeFunction,
    recordFileTreeAction,
    recordFileTreeActionStatus,
    resolveWorkspaceId,
    rowTitle,
    selectedSidebarFileTreeSelection: sidebarFileTreeSelection,
  });

  function ensureSearchModal() {
    var existing = document.querySelector('[data-testid="wolai-search-modal"]');
    if (existing instanceof HTMLElement) return existing;

    var overlay = document.createElement('div');
    overlay.className = 'wolai-search-overlay';
    overlay.setAttribute('data-testid', 'wolai-search-modal');
    overlay.setAttribute('role', 'dialog');
    overlay.setAttribute('aria-modal', 'true');
    overlay.hidden = true;

    overlay.innerHTML = '' +
      '<div class="wolai-search-dialog">' +
        '<div class="wolai-search-input-row">' +
          '<span class="material-symbols-outlined wolai-search-input-icon" data-icon="search" aria-hidden="true"></span>' +
          '<input data-testid="wolai-search-input" class="wolai-search-input" type="search" autocomplete="off" placeholder="在当前工作区中搜索" />' +
          '<button type="button" class="wolai-search-close" data-testid="wolai-search-close" aria-label="关闭搜索">×</button>' +
        '</div>' +
        '<div class="wolai-search-options" data-testid="wolai-search-options" aria-label="搜索选项" hidden>' +
          '<div class="wolai-search-options-left">' +
            '<span class="wolai-search-switch-control"><span>仅匹配标题</span><button type="button" class="wolai-search-switch" data-search-switch="title" role="switch" aria-checked="false" aria-label="仅匹配标题"></button></span>' +
            '<span class="wolai-search-switch-control"><span>精确匹配</span><button type="button" class="wolai-search-switch" data-search-switch="exact" role="switch" aria-checked="false" aria-label="精确匹配"></button></span>' +
            '<span class="wolai-search-sort-control"><span>资料库模式</span><select class="wolai-search-sort-value" data-search-knowledge-mode aria-label="资料库检索模式"><option value="exact" selected>关键词</option><option value="mix">综合</option><option value="hybrid">图谱混合</option><option value="naive">向量</option><option value="local">实体</option><option value="global">关系</option></select></span>' +
            '<span class="wolai-search-sort-control"><span>按编辑时间</span><button type="button" class="wolai-search-sort-value" data-search-sort="updated" aria-label="按编辑时间范围">所有</button></span>' +
            '<span class="wolai-search-sort-control"><span>按创建时间</span><button type="button" class="wolai-search-sort-value" data-search-sort="created" aria-label="按创建时间范围">所有</button></span>' +
          '</div>' +
          '<div class="wolai-search-options-right">' +
            '<span class="wolai-search-switch-control"><span>全盘资料库</span><button type="button" class="wolai-search-switch is-on" data-search-switch="knowledge" role="switch" aria-checked="true" aria-label="全盘资料库检索"></button></span>' +
            '<span class="wolai-search-switch-control"><span>页面内搜索</span><button type="button" class="wolai-search-switch" data-search-switch="page" role="switch" aria-checked="false" aria-label="页面内搜索"></button></span>' +
            '<span class="wolai-search-switch-control"><span>折叠同来源</span><button type="button" class="wolai-search-switch is-on" data-search-switch="collapseSource" role="switch" aria-checked="true" aria-label="默认折叠相同来源结果"></button></span>' +
          '</div>' +
        '</div>' +
        '<div class="wolai-search-result-meta" data-testid="wolai-search-result-meta"></div>' +
        '<div class="wolai-search-results" data-testid="wolai-search-results" data-search-results-owner="rust-kernel"></div>' +
      '</div>';

    document.body.appendChild(overlay);
    var input = overlay.querySelector('[data-testid="wolai-search-input"]');
    var closeButton = overlay.querySelector('[data-testid="wolai-search-close"]');
    applySearchSwitchState(overlay, { knowledge: true, collapseSource: readSearchCollapseSourcesDefault() });
    var initialKnowledgeModeSelect = overlay.querySelector('[data-search-knowledge-mode]');
    if (initialKnowledgeModeSelect && 'value' in initialKnowledgeModeSelect) initialKnowledgeModeSelect.value = 'exact';
    if (input) input.addEventListener('input', function() {
      searchUiState.hasRendered = false;
      scheduleSearchResultsRender();
    });
    overlay.querySelectorAll('[data-search-switch]').forEach(function(button) {
      button.addEventListener('click', function() {
        var switchName = searchText(button.getAttribute('data-search-switch'));
        var isOn = button.getAttribute('aria-checked') !== 'true';
        button.setAttribute('aria-checked', isOn ? 'true' : 'false');
        button.classList.toggle('is-on', isOn);
        if (switchName === 'collapseSource') {
          writeSearchCollapseSourcesDefault(isOn);
          searchUiState.sourceCollapsed = {};
        }
        searchUiState.hasRendered = false;
        scheduleSearchResultsRender();
      });
    });
    var knowledgeModeSelect = overlay.querySelector('[data-search-knowledge-mode]');
    if (knowledgeModeSelect) {
      knowledgeModeSelect.addEventListener('change', function() {
        searchUiState.hasRendered = false;
        scheduleSearchResultsRender();
      });
    }
    if (closeButton) closeButton.addEventListener('click', closeSearchModal);
    overlay.addEventListener('click', function(event) {
      if (event.target === overlay) closeSearchModal();
    });
    return overlay;
  }

  var activeSearchRequestId = 0;
  var searchRenderTimer = 0;
  var SEARCH_COLLAPSE_SOURCES_KEY = 'mnote.search.collapseSourcesDefault.v1';
  var searchUiState = {
    query: '',
    switches: {},
    metaHtml: '',
    resultsHtml: '',
    items: [],
    knowledgeMode: 'exact',
    sourceCollapsed: {},
    scrollTop: 0,
    signature: '',
    hasRendered: false
  };

  function searchText(value) {
    return String(value == null ? '' : value).replace(/\s+/g, ' ').trim();
  }

  function searchNonWhitespaceCharCount(value) {
    return String(value == null ? '' : value).replace(/\s+/g, '').length;
  }

  function currentWorkspaceName() {
    var name = document.querySelector('.sidebar-workspace-name');
    return searchText(name && name.textContent) || '当前工作区';
  }

  function currentDocumentId() {
    var shell = document.querySelector('.document-shell[data-document-id]');
    var bodyId = document.body && document.body.getAttribute('data-document-id');
    return searchText(shell && shell.getAttribute('data-document-id')) || searchText(bodyId);
  }

  function localResourceDocumentIdFromPath(path) {
    var normalized = searchText(path).replace(/\\/g, '/');
    return normalized ? 'local-resource:' + normalized.replace(/\//g, '~2F') : '';
  }

  function currentSearchDocumentId() {
    var activePanel = document.querySelector('[data-mnote-resource-tab-panel][data-pane-role="primary"]:not([hidden])');
    if (activePanel instanceof HTMLElement) {
      var resourceKind = searchText(activePanel.getAttribute('data-resource-kind')).toLowerCase();
      var resourcePath = searchText(activePanel.getAttribute('data-resource-path'));
      if (resourceKind && resourceKind !== 'markdown' && resourcePath) return localResourceDocumentIdFromPath(resourcePath);
      try {
        var locator = JSON.parse(activePanel.getAttribute('data-mnote-evidence-locator') || 'null');
        var locatorDoc = searchText(locator && (locator.ownerDocumentId || locator.owner_document_id));
        if (locatorDoc) return locatorDoc;
      } catch (_) {}
    }
    return currentDocumentId();
  }

  function searchSwitchValue(overlay, name) {
    var button = overlay.querySelector('[data-search-switch="' + name + '"]');
    return button instanceof HTMLElement && button.getAttribute('aria-checked') === 'true';
  }

  function searchKnowledgeModeValue(overlay) {
    var select = overlay.querySelector('[data-search-knowledge-mode]');
    var value = select && 'value' in select ? searchText(select.value).toLowerCase() : '';
    if (['mix', 'hybrid', 'naive', 'local', 'global', 'exact'].indexOf(value) >= 0) return value;
    return 'mix';
  }

  function knowledgeSearchRequestMode(overlay) {
    if (searchSwitchValue(overlay, 'exact')) return 'exact';
    return searchKnowledgeModeValue(overlay);
  }

  function knowledgeSearchModeLabel(mode) {
    if (mode === 'exact') return '关键词';
    if (mode === 'naive') return '向量';
    if (mode === 'local') return '实体';
    if (mode === 'global') return '关系';
    if (mode === 'hybrid') return '图谱混合';
    return '综合';
  }

  function readSearchCollapseSourcesDefault() {
    try {
      var stored = window.localStorage && window.localStorage.getItem(SEARCH_COLLAPSE_SOURCES_KEY);
      if (stored === '0') return false;
      if (stored === '1') return true;
    } catch (_) {}
    return true;
  }

  function writeSearchCollapseSourcesDefault(value) {
    try {
      if (window.localStorage) window.localStorage.setItem(SEARCH_COLLAPSE_SOURCES_KEY, value ? '1' : '0');
    } catch (_) {}
  }

  function collectSearchSwitchState(overlay) {
    var state = {};
    if (!(overlay instanceof HTMLElement)) return state;
    overlay.querySelectorAll('[data-search-switch]').forEach(function(button) {
      if (!(button instanceof HTMLElement)) return;
      var name = searchText(button.getAttribute('data-search-switch'));
      if (!name) return;
      state[name] = button.getAttribute('aria-checked') === 'true';
    });
    return state;
  }

  function applySearchSwitchState(overlay, switches) {
    if (!(overlay instanceof HTMLElement) || !switches || typeof switches !== 'object') return;
    overlay.querySelectorAll('[data-search-switch]').forEach(function(button) {
      if (!(button instanceof HTMLElement)) return;
      var name = searchText(button.getAttribute('data-search-switch'));
      if (!name || !Object.prototype.hasOwnProperty.call(switches, name)) return;
      var isOn = Boolean(switches[name]);
      button.setAttribute('aria-checked', isOn ? 'true' : 'false');
      button.classList.toggle('is-on', isOn);
    });
  }

  function searchRequestSignature(overlay, query) {
    var switches = collectSearchSwitchState(overlay);
    return JSON.stringify({
      query: searchText(query),
      knowledge: Boolean(switches.knowledge),
      page: Boolean(switches.page),
      title: Boolean(switches.title),
      exact: Boolean(switches.exact),
      collapseSource: Boolean(switches.collapseSource),
      knowledgeMode: searchKnowledgeModeValue(overlay),
      workspaceId: resolveWorkspaceId(document.body) || '',
      rootUri: currentRootUri() || ''
    });
  }

  function saveSearchUiState(overlay) {
    if (!(overlay instanceof HTMLElement)) return;
    var input = overlay.querySelector('[data-testid="wolai-search-input"]');
    var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]');
    var results = overlay.querySelector('[data-testid="wolai-search-results"]');
    var query = input && 'value' in input ? searchText(input.value) : searchUiState.query;
    searchUiState.query = query;
    searchUiState.switches = collectSearchSwitchState(overlay);
    searchUiState.knowledgeMode = searchKnowledgeModeValue(overlay);
    searchUiState.metaHtml = meta ? meta.innerHTML : searchUiState.metaHtml;
    searchUiState.resultsHtml = results ? results.innerHTML : searchUiState.resultsHtml;
    searchUiState.items = Array.isArray(window.__mnoteSearchResults) ? window.__mnoteSearchResults.slice() : searchUiState.items;
    searchUiState.scrollTop = results instanceof HTMLElement ? results.scrollTop : searchUiState.scrollTop;
    searchUiState.signature = query ? searchRequestSignature(overlay, query) : '';
  }

  function restoreSearchUiState(overlay) {
    if (!(overlay instanceof HTMLElement) || !searchUiState.hasRendered) return false;
    var input = overlay.querySelector('[data-testid="wolai-search-input"]');
    var options = overlay.querySelector('[data-testid="wolai-search-options"]');
    var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]');
    var results = overlay.querySelector('[data-testid="wolai-search-results"]');
    if (input && 'value' in input) input.value = searchUiState.query || '';
    applySearchSwitchState(overlay, searchUiState.switches);
    var knowledgeModeSelect = overlay.querySelector('[data-search-knowledge-mode]');
    if (knowledgeModeSelect && 'value' in knowledgeModeSelect) knowledgeModeSelect.value = searchUiState.knowledgeMode || 'exact';
    if (options instanceof HTMLElement) options.hidden = !searchText(searchUiState.query);
    if (meta && searchUiState.metaHtml) meta.innerHTML = searchUiState.metaHtml;
    if (results && searchUiState.resultsHtml) {
      results.innerHTML = searchUiState.resultsHtml;
      results.scrollTop = Number(searchUiState.scrollTop || 0);
    }
    window.__mnoteSearchResults = Array.isArray(searchUiState.items) ? searchUiState.items.slice() : [];
    return true;
  }

  function searchHighlightTerms(item, query) {
    var info = item && item.matchInfo || item && item.evidence && item.evidence.matchInfo || null;
    var terms = info && Array.isArray(info.matchedTerms) ? info.matchedTerms : [];
    terms = terms.map(searchText).filter(Boolean);
    if (!terms.length) {
      terms = searchText(query).split(/[\s,;:，；：。、()[\]{}]+/).map(searchText).filter(Boolean);
    }
    terms.sort(function(left, right) { return right.length - left.length; });
    return terms.filter(function(term, index) { return terms.indexOf(term) === index; });
  }

  function highlightSearchText(value, query, exact, terms) {
    var text = searchText(value);
    var cleanQuery = searchText(query);
    if (!text || !cleanQuery) return escapeHtml(text);
    var lower = text.toLowerCase();
    var lowerQuery = cleanQuery.toLowerCase();
    var exactIndex = lower.indexOf(lowerQuery);
    if (exact || exactIndex >= 0) {
      if (exactIndex < 0) return escapeHtml(text);
      return escapeHtml(text.slice(0, exactIndex)) +
        '<mark>' + escapeHtml(text.slice(exactIndex, exactIndex + cleanQuery.length)) + '</mark>' +
        escapeHtml(text.slice(exactIndex + cleanQuery.length));
    }
    terms = Array.isArray(terms) ? terms.map(searchText).filter(Boolean) : [];
    if (!terms.length) return escapeHtml(text);
    var ranges = [];
    terms.forEach(function(term) {
      var lowerTerm = term.toLowerCase();
      var start = lower.indexOf(lowerTerm);
      while (start >= 0) {
        var end = start + lowerTerm.length;
        var overlaps = ranges.some(function(range) { return start < range.end && end > range.start; });
        if (!overlaps) ranges.push({ start: start, end: end });
        start = lower.indexOf(lowerTerm, end);
      }
    });
    if (!ranges.length) return escapeHtml(text);
    ranges.sort(function(left, right) { return left.start - right.start; });
    var html = '';
    var cursor = 0;
    ranges.forEach(function(range) {
      if (range.start > cursor) html += escapeHtml(text.slice(cursor, range.start));
      html += '<mark>' + escapeHtml(text.slice(range.start, range.end)) + '</mark>';
      cursor = range.end;
    });
    if (cursor < text.length) html += escapeHtml(text.slice(cursor));
    return html;
  }

  function cleanSearchDisplayText(value) {
    var text = String(value == null ? '' : value);
    text = text.replace(/<drawing\b[^>]*\/?>/gi, ' ');
    text = text.replace(/<equation\b[^>]*>([\s\S]*?)<\/equation>/gi, '$1');
    text = text.replace(/<drawing\b[^<>]*$/gi, ' ');
    text = text.replace(/<\/?equat[^<>]*$/gi, ' ');
    text = text.replace(/<\/?e(?:q(?:uation)?)?[^<>]*$/gi, ' ');
    text = text.replace(/<[^>]+>/g, ' ');
    text = text
      .replace(/\b(?:equation|latex|drawing)\b(?:\s+[a-z_-]+=(?:"[^"]*"|'[^']*'|[^\s<>]+))*/gi, ' ')
      .replace(/\\left|\\right|\\mathrm|\\text|\\operatorname/g, '')
      .replace(/\\gt/g, '>')
      .replace(/\\lt/g, '<')
      .replace(/\\sim/g, '∼')
      .replace(/\\[a-zA-Z]+/g, ' ')
      .replace(/\{([^{}]*)\}/g, '$1')
      .replace(/\{([^{}]*)\}/g, '$1')
      .replace(/[_^]/g, '')
      .replace(/[<>]\/?(?:equation|eq)\b[^<>]*>?/gi, ' ')
      .replace(/<\/?e(?:q(?:uation)?)?[^<>\s]*>?/gi, ' ')
      .replace(/\s+(?:equation|latex|drawing)\s+/gi, ' ');
    return searchText(text);
  }

  function searchResultEvidenceLocator(item) {
    if (item && item.locator && typeof item.locator === 'object') return item.locator;
    if (item && item.evidence && item.evidence.source && typeof item.evidence.source === 'object') return item.evidence.source;
    if (item && item.source && item.source.locator && typeof item.source.locator === 'object') return item.source.locator;
    if (item && Array.isArray(item.evidence) && item.evidence[0] && item.evidence[0].source && typeof item.evidence[0].source === 'object') return item.evidence[0].source;
    return null;
  }

  function searchResultSourceKey(item) {
    var locator = searchResultEvidenceLocator(item);
    var locatorPath = locator ? searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path) : '';
    return locatorPath || searchText(item && (item.path || item.documentId || item.nodeId || item.id)) || 'unknown-source';
  }

  function searchResultSourceTitle(item) {
    var key = searchResultSourceKey(item);
    var locator = searchResultEvidenceLocator(item);
    var path = locator ? searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path) : '';
    var sourcePath = path || searchText(item && item.path) || key;
    var title = searchText(item && (item.title || item.name || item.documentTitle));
    return title || sourcePath.split('/').filter(Boolean).pop() || sourcePath || '未知来源';
  }

  function renderSearchResultButton(item, index, query, exact, grouped) {
    var title = searchText(item.title || item.name || item.documentTitle || '无标题');
    var snippet = searchText(item.displayQuote || item.snippet || item.evidence && item.evidence.displayQuote || item.evidence && item.evidence.quote || (Array.isArray(item.evidence) && item.evidence[0] && (item.evidence[0].displayQuote || item.evidence[0].quote || item.evidence[0].snippet)) || '');
    if (!item.displayQuote) snippet = cleanSearchDisplayText(snippet);
    var path = searchText(item.path || item.parentTitle || item.workspaceName || currentWorkspaceName());
    var resourceType = searchText(item.resourceType || item.resourceKind || 'page');
    var locator = searchResultEvidenceLocator(item);
    var locatorAttr = locator ? escapeHtml(JSON.stringify(locator)) : '';
    var highlightTerms = searchHighlightTerms(item, query);
    var titleHtml = grouped && snippet ? '' : '<span class="wolai-search-result-title">' + highlightSearchText(title, query, exact, highlightTerms) + '</span>';
    var page = locator && locator.page != null && locator.page !== '' ? String(locator.page) : '';
    var metaParts = grouped ? [] : [escapeHtml(path)];
    if (page) metaParts.push('第 ' + escapeHtml(page) + ' 页');
    if (!grouped) metaParts.push('<span class="wolai-search-result-type">' + escapeHtml(resourceType) + '</span>');
    var metaHtml = metaParts.length ? '<span class="wolai-search-result-path"><span>' + metaParts.join('</span><span>') + '</span></span>' : '';
    return '<button type="button" class="wolai-search-result-row" data-testid="wolai-search-result-row" data-search-result-owner="' + escapeHtml(item.provider || 'rust-kernel') + '" data-search-result-index="' + String(index) + '" data-document-id="' + escapeHtml(item.documentId || item.nodeId || item.id || '') + '" data-resource-type="' + escapeHtml(resourceType) + '"' + (locatorAttr ? ' data-evidence-locator="' + locatorAttr + '"' : '') + '>' +
      '<span class="material-symbols-outlined wolai-search-result-icon" data-icon="article" aria-hidden="true"></span>' +
      '<span class="wolai-search-result-main">' + titleHtml +
      '<span class="wolai-search-result-snippet">' + (snippet ? highlightSearchText(snippet, query, exact, highlightTerms) : escapeHtml(path)) + '</span>' +
      metaHtml + '</span>' +
    '</button>';
  }

  function renderSearchResultsHtml(items, overlay, query) {
    var exact = searchSwitchValue(overlay, 'exact');
    if (!searchSwitchValue(overlay, 'collapseSource')) {
      return items.map(function(item, index) {
        return renderSearchResultButton(item, index, query, exact, false);
      }).join('');
    }
    var groups = [];
    var groupByKey = {};
    items.forEach(function(item, index) {
      var key = searchResultSourceKey(item);
      var group = groupByKey[key];
      if (!group) {
        group = { key: key, title: searchResultSourceTitle(item), path: searchText(item.path || key), resourceType: searchText(item.resourceType || item.resourceKind || 'page'), rows: [] };
        groupByKey[key] = group;
        groups.push(group);
      }
      group.rows.push({ item: item, index: index });
    });
    return groups.map(function(group) {
      var collapsed = Object.prototype.hasOwnProperty.call(searchUiState.sourceCollapsed, group.key)
        ? searchUiState.sourceCollapsed[group.key]
        : true;
      var children = group.rows.map(function(row) {
        return renderSearchResultButton(row.item, row.index, query, exact, true);
      }).join('');
      return '<section class="wolai-search-source-group" data-search-source-key="' + escapeHtml(group.key) + '">' +
        '<button type="button" class="wolai-search-source-header" data-search-source-toggle="true" aria-expanded="' + (collapsed ? 'false' : 'true') + '">' +
          '<span class="material-symbols-outlined wolai-search-result-icon" data-icon="article" aria-hidden="true"></span>' +
          '<span class="wolai-search-source-main"><span class="wolai-search-result-title">' + escapeHtml(group.title) + '</span>' +
          '<span class="wolai-search-result-path"><span class="wolai-search-result-type">' + escapeHtml(group.resourceType) + '</span><span>' + String(group.rows.length) + ' 处</span></span></span>' +
          '<span class="wolai-search-source-chevron" aria-hidden="true">' + (collapsed ? '展开' : '收起') + '</span>' +
        '</button>' +
        '<div class="wolai-search-source-results" data-search-source-results="true"' + (collapsed ? ' hidden' : '') + '>' + children + '</div>' +
      '</section>';
    }).join('');
  }

  function evidenceLocatorResourceKind(locator, fallback) {
    return searchText(locator && (locator.resourceKind || locator.resource_kind) || fallback || '').toLowerCase();
  }

  function evidenceLocatorBbox(locator) {
    var bbox = locator && locator.bbox;
    if (Array.isArray(bbox)) return bbox.slice(0, 4).join(',');
    if (bbox && typeof bbox === 'object') return [bbox.x0, bbox.y0, bbox.x1, bbox.y1].join(',');
    return '';
  }

  function evidenceLocatorOpenUrl(locator) {
    var action = locator && locator.openAction && typeof locator.openAction === 'object' ? locator.openAction : null;
    return searchText(action && action.url);
  }

  function evidenceLocatorLineRange(locator) {
    return locator && (locator.lineRange || locator.line_range) || null;
  }

  function evidenceLocatorCharRange(locator) {
    return locator && (locator.charRange || locator.char_range) || null;
  }

  function evidenceLocatorBlockId(locator) {
    return searchText(locator && (locator.blockId || locator.block_id));
  }

  function resourceHrefForEvidenceLocator(resourceKind, resourcePath, fileName, ownerDocumentId, locator) {
    var localFileUrl = buildLocalFileOpenUrl(resourcePath, false);
    if (!localFileUrl) return '';
    if (resourceKind === 'pdf') return buildPdfPreviewOpenUrl(localFileUrl, fileName);
    if (resourceKind === 'office') {
      var fileType = inferOnlyOfficeFileType(fileName, '') || (fileName.indexOf('.') >= 0 ? fileName.split('.').pop() : 'docx');
      return buildOfficePreviewOpenUrl({
        fileUrl: localFileUrl,
        fileName: fileName,
        fileType: fileType,
        assetId: 'local-file:' + resourcePath,
        documentId: ownerDocumentId || currentDocumentId() || '',
        workspaceId: resolveWorkspaceId(document.body) || '',
        sourceKind: currentSourceKind() || 'local_folder',
        rootUri: searchText(locator && (locator.rootUri || locator.root_uri) || currentRootUri())
      });
    }
    return localFileUrl;
  }

  async function openEvidenceSearchResult(item, event) {
    var locator = searchResultEvidenceLocator(item);
    if (!locator) {
      var citationUrl = searchText(item && (item.citationUrl || item.publicPath));
      if (citationUrl) {
        closeSearchModal();
        window.location.assign(citationUrl);
        return;
      }
      var fallbackId = searchText(item && (item.documentId || item.nodeId || item.id));
      if (fallbackId) window.location.assign('/documents/' + encodeURIComponent(fallbackId));
      return;
    }
    var resourcePath = searchText(locator.resourcePath || locator.resource_path || locator.ownerDocumentPath || locator.owner_document_path);
    var ownerDocumentId = searchText(locator.ownerDocumentId || locator.owner_document_id || item.documentId || '');
    var resourceKind = evidenceLocatorResourceKind(locator, item && item.resourceType);
    var overlay = document.querySelector('[data-testid="wolai-search-modal"]');
    var searchInput = overlay instanceof HTMLElement ? overlay.querySelector('[data-testid="wolai-search-input"]') : null;
    var searchQueryText = searchText(item && (item.searchQuery || item.query) || locator && locator.openAction && locator.openAction.params && locator.openAction.params.searchQuery)
      || searchText(searchInput && 'value' in searchInput ? searchInput.value : '')
      || searchText(searchUiState.query);
    var locatorEvidenceText = searchText(item && item.locatorEvidenceText || locator.evidenceText || locator.query || locator.openAction && locator.openAction.params && (locator.openAction.params.evidenceText || locator.openAction.params.query) || '');
    var locatorParams = locator && locator.openAction && locator.openAction.params && typeof locator.openAction.params === 'object' ? locator.openAction.params : {};
    var openTarget = event && event.altKey ? 'side' : 'active-tab';
    if (resourcePath && resourceKind) {
      var fileName = resourcePath.split('/').filter(Boolean).pop() || resourcePath;
      var normalizedKind = resourceKind === 'raw_file' || resourceKind === 'resource' ? fileTreeIconKindForFileName(fileName) || 'file' : resourceKind;
      var hostDocumentId = currentDocumentId() || ownerDocumentId || '';
      var href = resourceHrefForEvidenceLocator(normalizedKind, resourcePath, fileName, hostDocumentId, locator);
      var openedInResourceTab = await openLocalResourceInActiveTab({
        path: resourcePath,
        title: fileName,
        kind: normalizedKind,
        href: href,
        officeUrl: normalizedKind === 'office' ? href : '',
        assetId: 'local-file:' + resourcePath,
        documentId: hostDocumentId,
        ownerDocumentId: ownerDocumentId || hostDocumentId,
        workspaceId: resolveWorkspaceId(document.body) || '',
        sourceKind: currentSourceKind() || 'local_folder',
        rootUri: searchText(locator.rootUri || locator.root_uri || currentRootUri()),
        paneRole: openTarget === 'side' ? 'secondary' : 'primary',
        evidenceLocator: locator,
        page: locator.page,
        bbox: locator.bbox,
        sourceMapPath: searchText(locator.sourceMapPath || locator.source_map_path),
        blockId: evidenceLocatorBlockId(locator),
        paragraphOrdinal: searchText(locator.paragraphOrdinal || locatorParams.paragraphOrdinal),
        paraIdStart: searchText(locator.paraIdStart || locatorParams.paraIdStart),
        paraIdEnd: searchText(locator.paraIdEnd || locatorParams.paraIdEnd),
        textFingerprint: searchText(locator.textFingerprint || locatorParams.textFingerprint),
        evidenceText: locatorEvidenceText,
        query: searchQueryText,
        searchQuery: searchQueryText,
        lineRange: evidenceLocatorLineRange(locator),
        charRange: evidenceLocatorCharRange(locator)
      });
      if (!openedInResourceTab) console.warn('mnote evidence 搜索结果无法在当前页面资源标签打开', locator);
      closeSearchModal();
      return;
    }
    var url = evidenceLocatorOpenUrl(locator) || ('/documents/' + encodeURIComponent(ownerDocumentId || currentDocumentId() || ''));
    try {
      var target = new URL(url, window.location.origin);
      var blockId = searchText(locator.blockId || locator.block_id);
      var sourceMapPath = searchText(locator.sourceMapPath || locator.source_map_path);
      if (blockId) target.searchParams.set('blockId', blockId);
      if (locator.page) target.searchParams.set('page', String(locator.page));
      var bbox = evidenceLocatorBbox(locator);
      if (bbox) target.searchParams.set('bbox', bbox);
      if (sourceMapPath) target.searchParams.set('sourceMapPath', sourceMapPath);
      if (locatorParams.paragraphOrdinal != null) target.searchParams.set('paragraphOrdinal', searchText(locatorParams.paragraphOrdinal));
      if (locatorParams.paraIdStart) target.searchParams.set('paraIdStart', searchText(locatorParams.paraIdStart));
      if (locatorParams.paraIdEnd) target.searchParams.set('paraIdEnd', searchText(locatorParams.paraIdEnd));
      if (locatorParams.textFingerprint) target.searchParams.set('textFingerprint', searchText(locatorParams.textFingerprint));
      window.location.assign(target.pathname + target.search + target.hash);
    } catch (_) {
      window.location.assign(url);
    }
  }

  function renderSearchRecentState(overlay) {
    var options = overlay.querySelector('[data-testid="wolai-search-options"]');
    var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]');
    var results = overlay.querySelector('[data-testid="wolai-search-results"]');
    if (options instanceof HTMLElement) options.hidden = true;
    if (meta) meta.innerHTML = '<span>最近浏览</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
    if (results) {
      results.innerHTML = '<div class="wolai-search-recent" data-testid="wolai-search-recent">暂无最近浏览</div>';
    }
    saveSearchUiState(overlay);
    searchUiState.hasRendered = true;
  }

  function scheduleSearchResultsRender() {
    window.clearTimeout(searchRenderTimer);
    searchRenderTimer = window.setTimeout(function() { void renderSearchResults(); }, 120);
  }

  async function renderSearchResults() {
    var overlay = document.querySelector('[data-testid="wolai-search-modal"]');
    if (!(overlay instanceof HTMLElement)) return;
    var input = overlay.querySelector('[data-testid="wolai-search-input"]');
    var options = overlay.querySelector('[data-testid="wolai-search-options"]');
    var meta = overlay.querySelector('[data-testid="wolai-search-result-meta"]');
    var results = overlay.querySelector('[data-testid="wolai-search-results"]');
    if (!input || !meta || !results) return;
    var query = searchText(input.value);
    if (!query) {
      activeSearchRequestId += 1;
      renderSearchRecentState(overlay);
      return;
    }
    if (options instanceof HTMLElement) options.hidden = false;
    var knowledgeMode = searchSwitchValue(overlay, 'knowledge');
    if (knowledgeMode && searchNonWhitespaceCharCount(query) < 2) {
      activeSearchRequestId += 1;
      meta.innerHTML = '<span>资料库检索</span><span>请输入至少 2 个字再搜索</span>';
      results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">请输入至少 2 个字再搜索</div>';
      window.__mnoteSearchResults = [];
      saveSearchUiState(overlay);
      searchUiState.hasRendered = true;
      return;
    }
    var requestId = ++activeSearchRequestId;
    var knowledgeRequestMode = knowledgeMode ? knowledgeSearchRequestMode(overlay) : '';
    meta.innerHTML = '<span>搜索中…</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
    results.innerHTML = '<div class="wolai-search-empty" data-search-loading="true">搜索中…</div>';
    try {
      var response = await fetch(knowledgeMode ? '/api/knowledge-rag/search' : '/api/search/documents', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(knowledgeMode ? {
          workspaceId: resolveWorkspaceId(document.body),
          rootUri: currentRootUri() || null,
          query: query,
          mode: knowledgeRequestMode,
          topK: 12,
          chunkTopK: 24,
          includeChunkContent: true
        } : {
          workspaceId: resolveWorkspaceId(document.body),
          sourceKind: currentSourceKind() || null,
          rootUri: currentRootUri() || null,
          documentId: searchSwitchValue(overlay, 'page') ? (currentSearchDocumentId() || null) : (currentDocumentId() || null),
          query: query,
          limit: 30,
          filters: {
            titleOnly: searchSwitchValue(overlay, 'title'),
            exact: searchSwitchValue(overlay, 'exact'),
            includeOcr: false,
            onlyCurrentPage: searchSwitchValue(overlay, 'page'),
            timeRange: 'any',
            timeField: 'updated'
          }
        })
      });
      var payload = await response.json();
      if (requestId !== activeSearchRequestId) return;
      var items = Array.isArray(payload.results) ? payload.results : [];
      var ownerLabel = knowledgeMode ? ('资料库检索 · ' + knowledgeSearchModeLabel(payload.retrievalMode || knowledgeRequestMode)) : '工作区搜索';
      meta.innerHTML = '<span>' + ownerLabel + ' · 共 ' + items.length + ' 条匹配结果</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
      if (!items.length) {
        results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">没有搜索结果</div>';
        window.__mnoteSearchResults = [];
        saveSearchUiState(overlay);
        searchUiState.hasRendered = true;
        return;
      }
      window.__mnoteSearchResults = items;
      results.innerHTML = renderSearchResultsHtml(items, overlay, query);
      saveSearchUiState(overlay);
      searchUiState.hasRendered = true;
    } catch (error) {
      if (requestId !== activeSearchRequestId) return;
      meta.innerHTML = '<span>共 0 条匹配结果</span><span>Ctrl + Enter 新窗口打开 / Alt + Enter 右侧边栏打开</span>';
      results.innerHTML = '<div class="wolai-search-empty" data-search-empty="true">没有搜索结果</div>';
      window.__mnoteSearchResults = [];
      saveSearchUiState(overlay);
      searchUiState.hasRendered = true;
    }
  }

  function isSearchModalOpen() {
    var overlay = document.querySelector('[data-testid="wolai-search-modal"]');
    return overlay instanceof HTMLElement && !overlay.hidden;
  }

  function openSearchModal() {
    var overlay = ensureSearchModal();
    overlay.hidden = false;
    document.documentElement.setAttribute('data-mnote-search-modal-open', 'true');
    var restored = restoreSearchUiState(overlay);
    var input = overlay.querySelector('[data-testid="wolai-search-input"]');
    if (input) input.setAttribute('placeholder', '在 ' + currentWorkspaceName() + ' 中搜索');
    var query = input && 'value' in input ? searchText(input.value) : '';
    var signature = query ? searchRequestSignature(overlay, query) : '';
    if (!restored || signature !== searchUiState.signature) void renderSearchResults();
    if (input) {
      setTimeout(function() { input.focus(); input.select(); }, 0);
    }
  }

  function closeSearchModal() {
    var overlay = document.querySelector('[data-testid="wolai-search-modal"]');
    if (overlay instanceof HTMLElement) {
      saveSearchUiState(overlay);
      overlay.hidden = true;
    }
    document.documentElement.removeAttribute('data-mnote-search-modal-open');
  }

  function toggleSearchModal() {
    if (isSearchModalOpen()) closeSearchModal();
    else openSearchModal();
  }

  function isSearchShortcutEvent(event) {
    return Boolean(event && (event.metaKey || event.ctrlKey) && !event.shiftKey && !event.altKey && event.key && event.key.toLowerCase() === 'p');
  }

  document.addEventListener('keydown', function(event) {
    if (!isSearchShortcutEvent(event)) return;
    event.preventDefault();
    event.stopPropagation();
    openSearchModal();
  }, true);

  const sidebarPageAi = createSidebarPageAiRuntime({
    buildLocalFileOpenUrl,
    currentDocumentId,
    currentPageAggregate,
    currentPageOptions,
    currentRootUri,
    currentSourceKind,
    escapeHtml,
    cssEscape,
    openLocalResourceInActiveTab,
    pageUiState,
    resolveWorkspaceId,
    searchText,
  });
  const openPageAiDrawer = (...args) => sidebarPageAi.openPageAiDrawer(...args);
  const closePageAiDrawer = (...args) => sidebarPageAi.closePageAiDrawer(...args);
  const isPageAiDrawerOpen = (...args) => sidebarPageAi.isPageAiDrawerOpen(...args);
  const ensurePageAiDrawer = (...args) => sidebarPageAi.ensurePageAiDrawer(...args);
  const sendPageAiMessage = (...args) => sidebarPageAi.sendPageAiMessage(...args);
  const pageAiOpenHermesSettings = (...args) => sidebarPageAi.pageAiOpenHermesSettings(...args);
  const pageAiStopRun = (...args) => sidebarPageAi.pageAiStopRun(...args);
  const pageAiLoadGatewayHealth = (...args) => sidebarPageAi.pageAiLoadGatewayHealth(...args);
  const renderPageAiControls = (...args) => sidebarPageAi.renderPageAiControls(...args);
  const renderPageAiConversation = (...args) => sidebarPageAi.renderPageAiConversation(...args);
  const renderPageAiProviderButtons = (...args) => sidebarPageAi.renderPageAiProviderButtons(...args);
  const renderPageAiSuggestions = (...args) => sidebarPageAi.renderPageAiSuggestions(...args);
  const pageAiSaveProfileMemory = (...args) => sidebarPageAi.pageAiSaveProfileMemory(...args);
  const pageAiToggleSkill = (...args) => sidebarPageAi.pageAiToggleSkill(...args);
  const pageAiToggleTool = (...args) => sidebarPageAi.pageAiToggleTool(...args);
  const pageAiResumeBackendSession = (...args) => sidebarPageAi.pageAiResumeBackendSession(...args);
  const pageAiRenameBackendSession = (...args) => sidebarPageAi.pageAiRenameBackendSession(...args);
  const pageAiDeleteBackendSession = (...args) => sidebarPageAi.pageAiDeleteBackendSession(...args);
  const pageAiResolvePermission = (...args) => sidebarPageAi.pageAiResolvePermission(...args);
  const pageAiOpenLocation = (...args) => sidebarPageAi.pageAiOpenLocation(...args);
  const pageAiSetActiveSession = (...args) => sidebarPageAi.pageAiSetActiveSession(...args);
  const pageAiStartNewSession = (...args) => sidebarPageAi.pageAiStartNewSession(...args);
  const pageAiLoadSessions = (...args) => sidebarPageAi.pageAiLoadSessions(...args);
  const pageAiLoadBackendSessions = (...args) => sidebarPageAi.pageAiLoadBackendSessions(...args);
  const pageAiCancelQueuedRun = (...args) => sidebarPageAi.pageAiCancelQueuedRun(...args);
  const pageAiSearchBackendSessions = (...args) => sidebarPageAi.pageAiSearchBackendSessions(...args);
  const pageAiPersistSessions = (...args) => sidebarPageAi.pageAiPersistSessions(...args);
  const pageAiLoadProfiles = (...args) => sidebarPageAi.pageAiLoadProfiles(...args);
  const pageAiLoadProfileMemory = (...args) => sidebarPageAi.pageAiLoadProfileMemory(...args);
  const pageAiLoadSkills = (...args) => sidebarPageAi.pageAiLoadSkills(...args);
  const pageAiSwitchProfile = (...args) => sidebarPageAi.pageAiSwitchProfile(...args);
  const pageAiSetSkillSource = (...args) => sidebarPageAi.pageAiSetSkillSource(...args);
  const pageAiToggleSkillGroup = (...args) => sidebarPageAi.pageAiToggleSkillGroup(...args);
  const pageAiSetReasonixMemoryEnabled = (...args) => sidebarPageAi.pageAiSetReasonixMemoryEnabled(...args);
  const pageAiSetHideHermesBuiltinSkills = (...args) => sidebarPageAi.pageAiSetHideHermesBuiltinSkills(...args);
  const pageAiSetContextScope = (...args) => sidebarPageAi.pageAiSetContextScope(...args);
  const pageAiSetAgentId = (...args) => sidebarPageAi.pageAiSetAgentId(...args);
  const pageAiToggleContextRef = (...args) => sidebarPageAi.pageAiToggleContextRef(...args);
  const pageAiSetAgentPopoverOpen = (...args) => sidebarPageAi.pageAiSetAgentPopoverOpen(...args);
  const pageAiSetTargetPopoverOpen = (...args) => sidebarPageAi.pageAiSetTargetPopoverOpen(...args);
  const pageAiSelectTarget = (...args) => sidebarPageAi.pageAiSelectTarget(...args);
  const updatePageAiTriggerState = (...args) => sidebarPageAi.updatePageAiTriggerState(...args);

  const sidebarAttachmentOpen = createSidebarAttachmentOpenRuntime({
    attachmentClassForFileName: (...args) => attachmentClassForFileName(...args),
    buildLocalFileOpenUrl,
    buildLocalOnlyOfficeOpenUrl,
    buildOnlyOfficeOpenPath,
    buildOnlyOfficeOpenUrl,
    buildPdfPreviewOpenUrl,
    closestAction,
    currentDocumentId,
    currentRootUri,
    currentWorkspaceSourcePayload,
    fileTreeIconKindForFileName,
    healLegacyOfficeAttachmentParagraphs,
    hydrateEditorAttachmentMeta,
    inferCodeAttachmentLanguage: (...args) => inferCodeAttachmentLanguage(...args),
    inferOnlyOfficeFileType,
    isCodeAttachmentFileName: (...args) => isCodeAttachmentFileName(...args),
    isPdfAttachmentFileName: (...args) => isPdfAttachmentFileName(...args),
    localFilePathFromAssetId,
    openLocalOfficeFileInActiveTab,
    openLocalResourceInActiveTab,
    openTreeContextMenu: (...args) => openTreeContextMenu(...args),
    resolveWorkspaceId,
    triggerBrowserDownload: (...args) => triggerBrowserDownload(...args),
    uploadedFileSize,
  });
  const refreshEditorLocalAttachmentExistence = (...args) => sidebarAttachmentOpen.refreshEditorLocalAttachmentExistence(...args);
  const detailFromEditorAttachmentLink = (...args) => sidebarAttachmentOpen.detailFromEditorAttachmentLink(...args);
  const enhanceEditorAttachmentLink = (...args) => sidebarAttachmentOpen.enhanceEditorAttachmentLink(...args);
  const enhanceEditorAttachmentLinks = (...args) => sidebarAttachmentOpen.enhanceEditorAttachmentLinks(...args);
  const openEditorAttachmentDetail = (...args) => sidebarAttachmentOpen.openEditorAttachmentDetail(...args);
  const openEditorAttachmentNewWindow = (...args) => sidebarAttachmentOpen.openEditorAttachmentNewWindow(...args);
  const openEditorAttachmentEditTab = (...args) => sidebarAttachmentOpen.openEditorAttachmentEditTab(...args);
  const openCodeEditorAttachment = (...args) => sidebarAttachmentOpen.openCodeEditorAttachment(...args);
  const openEditorAttachmentDownload = (...args) => sidebarAttachmentOpen.openEditorAttachmentDownload(...args);

  document.addEventListener('click', function(e) {
    if (activeTreeContextMenu && activeTreeContextMenu.contains(e.target)) return;
    if (activeTreeContextMenu) closeTreeContextMenu();

    var sidebarToggle = closestAction(e.target, '[data-mnote-action="toggle-sidebar"]');
    if (sidebarToggle) {
      e.preventDefault();
      toggleWorkspaceSidebar(sidebarToggle);
      return;
    }

    var attachmentAction = closestAction(e.target, '[data-attachment-action]');
    if (attachmentAction) {
      e.preventDefault();
      e.stopPropagation();
      var link = activeEditorAttachmentLink;
      if (!(link instanceof HTMLAnchorElement)) return;
      var attachmentDetail = detailFromEditorAttachmentLink(link);
      var attachmentActionName = attachmentAction.getAttribute('data-attachment-action') || '';
      if (attachmentActionName === 'download') {
        openEditorAttachmentDownload(attachmentDetail);
        return;
      }
      if (attachmentActionName === 'menu') {
        openEditorAttachmentMenu(link, attachmentAction);
        return;
      }
      return;
    }

    var editorAttachmentLink = closestAction(e.target, '.editor-surface .ProseMirror a.mnote-uploaded-attachment-row');
    if (editorAttachmentLink instanceof HTMLAnchorElement) {
      e.preventDefault();
      openEditorAttachmentLink(editorAttachmentLink);
      return;
    }

    var historyClose = closestAction(e.target, '[data-page-history-action="close"]');
    if (historyClose) {
      e.preventDefault();
      closePageHistoryDrawer();
      return;
    }

    var shareClose = closestAction(e.target, '[data-page-share-action="close"]');
    if (shareClose) {
      e.preventDefault();
      closePageShareDialog();
      return;
    }

    var shareCopy = closestAction(e.target, '[data-page-share-action="copy-link"]');
    if (shareCopy) {
      e.preventDefault();
      void copyTreeContextValue(window.location.href, 'page-share-link');
      return;
    }

    var pageHistoryTrigger = closestAction(e.target, '[data-mnote-action="open-page-history"]');
    if (pageHistoryTrigger) {
      e.preventDefault();
      openPageHistoryDrawer();
      return;
    }

    var pageSettingsTrigger = closestAction(e.target, '[data-mnote-action="open-page-settings"]');
    if (pageSettingsTrigger) {
      e.preventDefault();
      togglePageSettingsPopover();
      return;
    }

    var indexSettingsTrigger = closestAction(e.target, '[data-mnote-action="open-index-settings"]');
    if (indexSettingsTrigger) {
      e.preventDefault();
      openKnowledgeRagSettingsPopover();
      return;
    }

    var knowledgeRagSettingsTrigger = closestAction(e.target, '[data-mnote-action="open-knowledge-rag-settings"]');
    if (knowledgeRagSettingsTrigger) {
      e.preventDefault();
      openKnowledgeRagSettingsPopover();
      return;
    }

    var settingsClose = closestAction(e.target, '[data-settings-action="close"]');
    if (settingsClose) {
      e.preventDefault();
      closeAllSettingsPopovers();
      return;
    }

    var pageSettingsPanel = closestAction(e.target, '.wolai-page-settings-panel');
    if (isAnySettingsOpen() && !pageSettingsPanel) {
      closeAllSettingsPopovers();
    }

    var pageSettingsTab = closestAction(e.target, '[data-page-settings-tab]');
    if (pageSettingsTab) {
      e.preventDefault();
      setActivePageSettingsTab(pageSettingsTab.getAttribute('data-page-settings-tab') || 'page');
      return;
    }

    var localIndexAction = closestAction(e.target, '[data-local-index-action]');
    if (localIndexAction) {
      e.preventDefault();
      var localIndexActionName = localIndexAction.getAttribute('data-local-index-action') || '';
      if (localIndexActionName === 'save') {
        void persistLocalIndexSettings();
        return;
      }
      if (localIndexActionName === 'refresh') {
        void refreshLocalIndex();
        return;
      }
      if (localIndexActionName === 'add-path') {
        addLocalIndexRange();
        return;
      }
      if (localIndexActionName === 'remove-path') {
        removeLocalIndexRange(localIndexAction.getAttribute('data-local-index-path-index') || '0');
        return;
      }
    }

    var knowledgeRagAction = closestAction(e.target, '[data-knowledge-rag-action]');
    if (knowledgeRagAction) {
      e.preventDefault();
      var knowledgeRagActionName = knowledgeRagAction.getAttribute('data-knowledge-rag-action') || '';
      if (knowledgeRagActionName === 'refresh') {
        void loadKnowledgeRagStatus(true);
        return;
      }
      if (knowledgeRagActionName === 'add-source') {
        addKnowledgeRagSourceInput();
        return;
      }
      if (knowledgeRagActionName === 'remove-source') {
        removeKnowledgeRagSourceInput(knowledgeRagAction);
        return;
      }
      if (knowledgeRagActionName === 'use-filetree-selection') {
        useKnowledgeRagFileTreeSelection();
        return;
      }
      if (knowledgeRagActionName === 'ingest') {
        void ingestKnowledgeRagSources();
        return;
      }
      if (knowledgeRagActionName === 'reindex-source') {
        void ingestSingleKnowledgeRagSource(knowledgeRagAction.getAttribute('data-knowledge-rag-source-path') || '');
        return;
      }
      if (knowledgeRagActionName === 'delete-source') {
        void deleteKnowledgeRagSource(knowledgeRagAction.getAttribute('data-knowledge-rag-source-path') || '');
        return;
      }
      if (knowledgeRagActionName === 'prune') {
        void pruneKnowledgeRagRegistry();
        return;
      }
      if (knowledgeRagActionName === 'filter-sources') {
        setKnowledgeRagSourceFilter(knowledgeRagAction.getAttribute('data-knowledge-rag-filter') || 'attention');
        return;
      }
      if (knowledgeRagActionName === 'open-dashboard') {
        openKnowledgeRagDashboard();
        return;
      }
    }

    var pageSettingsAction = closestAction(e.target, '[data-page-settings-action]');
    if (pageSettingsAction) {
      e.preventDefault();
      var actionName = pageSettingsAction.getAttribute('data-page-settings-action') || '';
      if (actionName === 'history') {
        openPageHistoryDrawer();
        return;
      }
      if (actionName === 'share') {
        openPageShareDialog();
        return;
      }
      return;
    }

    var pageAiTrigger = closestAction(e.target, '[data-mnote-action="open-page-ai"]');
    if (pageAiTrigger) {
      e.preventDefault();
      openPageAiDrawer();
      return;
    }

    var navigationPageTrigger = closestAction(e.target, '[data-mnote-action="open-navigation-page"]');
    if (navigationPageTrigger) {
      e.preventDefault();
      openCurrentNavigationPage(navigationPageTrigger);
      return;
    }

    var searchTrigger = closestAction(e.target, '[data-mnote-action="open-search-modal"]');
    if (searchTrigger) {
      e.preventDefault();
      toggleSearchModal();
      return;
    }
    var searchDialog = closestAction(e.target, '.wolai-search-dialog');
    if (isSearchModalOpen() && !searchDialog) {
      closeSearchModal();
      return;
    }
    var searchSourceToggle = closestAction(e.target, '[data-search-source-toggle]');
    if (searchSourceToggle) {
      e.preventDefault();
      var sourceGroup = searchSourceToggle.closest('.wolai-search-source-group');
      var sourceResults = sourceGroup && sourceGroup.querySelector('[data-search-source-results="true"]');
      var sourceKey = sourceGroup ? searchText(sourceGroup.getAttribute('data-search-source-key')) : '';
      var nextCollapsed = !(sourceResults instanceof HTMLElement && sourceResults.hidden);
      if (sourceResults instanceof HTMLElement) sourceResults.hidden = nextCollapsed;
      searchSourceToggle.setAttribute('aria-expanded', nextCollapsed ? 'false' : 'true');
      var chevron = searchSourceToggle.querySelector('.wolai-search-source-chevron');
      if (chevron) chevron.textContent = nextCollapsed ? '展开' : '收起';
      if (sourceKey) searchUiState.sourceCollapsed[sourceKey] = nextCollapsed;
      var overlay = document.querySelector('[data-testid="wolai-search-modal"]');
      if (overlay instanceof HTMLElement) saveSearchUiState(overlay);
      return;
    }
    var searchResultRow = closestAction(e.target, '[data-testid="wolai-search-result-row"]');
    if (searchResultRow) {
      e.preventDefault();
      var index = Number(searchResultRow.getAttribute('data-search-result-index') || -1);
      var item = Array.isArray(window.__mnoteSearchResults) && index >= 0 ? window.__mnoteSearchResults[index] : null;
      if (!item) {
        var locatorPayload = searchResultRow.getAttribute('data-evidence-locator') || '';
        try {
          var locator = locatorPayload ? JSON.parse(locatorPayload) : null;
          item = locator ? { evidence: { source: locator }, documentId: searchResultRow.getAttribute('data-document-id') || '' } : null;
        } catch (_) {
          item = null;
        }
      }
      void openEvidenceSearchResult(item || { documentId: searchResultRow.getAttribute('data-document-id') || '' }, e)
        .catch(function(error) { console.warn('mnote evidence 搜索结果打开失败', error); });
      return;
    }

    var sourceMenuTrigger = closestAction(e.target, '[data-mnote-action="open-workspace-source-menu"]');
    if (sourceMenuTrigger) {
      e.preventDefault();
      var existingSourceMenu = document.querySelector('[data-testid="mnote-workspace-source-menu"]');
      if (existingSourceMenu) closeWorkspaceSourceMenu();
      else openWorkspaceSourceMenu(sourceMenuTrigger);
      return;
    }
    var sourceMenu = closestAction(e.target, '[data-testid="mnote-workspace-source-menu"]');
    if (!sourceMenu) closeWorkspaceSourceMenu();

    var accountMenuTrigger = closestAction(e.target, '[data-mnote-action="open-account-menu"]');
    if (accountMenuTrigger) {
      e.preventDefault();
      var existingAccountMenu = document.querySelector('[data-testid="mnote-account-menu"]');
      if (existingAccountMenu) closeAccountMenu();
      else openAccountMenu(accountMenuTrigger);
      return;
    }
    var accountMenu = closestAction(e.target, '[data-testid="mnote-account-menu"]');
    if (!accountMenu) closeAccountMenu();

    var trashTrigger = closestAction(e.target, '[data-mnote-action="open-trash-modal"]');
    if (trashTrigger) {
      e.preventDefault();
      openTrashModal(trashTrigger);
      return;
    }
    var trashClose = closestAction(e.target, '[data-mnote-trash-modal-close]');
    if (trashClose) {
      e.preventDefault();
      closeTrashModal();
      return;
    }

    var tabTrigger = closestAction(e.target, '[data-mnote-sidebar-tree-tab]');
    if (tabTrigger) {
      e.preventDefault();
      switchSidebarTreeTab(tabTrigger);
      return;
    }

    var pageShortcutTrigger = closestAction(e.target, '[data-mnote-action="toggle-sidebar-shortcut"]');
    if (pageShortcutTrigger) {
      e.preventDefault();
      void toggleCurrentPageSidebarShortcut(pageShortcutTrigger);
      return;
    }

    var shortcutMenu = closestAction(e.target, '[data-testid="mnote-sidebar-shortcut-menu"]');
    var shortcutMenuAction = closestAction(e.target, '[data-mnote-sidebar-shortcut-menu-action]');
    if (shortcutMenuAction) {
      e.preventDefault();
      var action = String(shortcutMenuAction.getAttribute('data-mnote-sidebar-shortcut-menu-action') || '').trim();
      var shortcutRowFromMenu = shortcutMenu && shortcutMenu.__mnoteShortcutRow instanceof HTMLElement
        ? shortcutMenu.__mnoteShortcutRow
        : null;
      if (action === 'remove') {
        void removeSidebarShortcutByRow(shortcutRowFromMenu);
        return;
      }
      if (action === 'open') {
        closeSidebarShortcutMenu();
        if (shortcutRowFromMenu && shortcutRowFromMenu.getAttribute('data-mnote-shortcut-kind') === 'folder') {
          void openStarredFolderShortcut(shortcutRowFromMenu);
        } else if (shortcutRowFromMenu && shortcutRowFromMenu.getAttribute('href')) {
          window.location.assign(shortcutRowFromMenu.getAttribute('href'));
        }
        return;
      }
      if (action === 'copy-link') {
        var href = shortcutRowFromMenu && shortcutRowFromMenu.getAttribute('href') || window.location.href;
        if (navigator.clipboard && href) void navigator.clipboard.writeText(new URL(href, window.location.origin).toString());
        closeSidebarShortcutMenu();
        return;
      }
    }
    if (!shortcutMenu) closeSidebarShortcutMenu();

    var shortcutMenuTrigger = closestAction(e.target, '.wolai-starred-section [data-mnote-shortcut-action="menu"]');
    if (shortcutMenuTrigger) {
      e.preventDefault();
      var shortcutRow = shortcutMenuTrigger.closest('[data-mnote-shortcut-id]');
      openSidebarShortcutMenu(shortcutRow, shortcutMenuTrigger);
      return;
    }

    var folderShortcutRow = closestAction(e.target, '.wolai-starred-section [data-mnote-shortcut-kind="folder"]');
    if (folderShortcutRow) {
      e.preventDefault();
      void openStarredFolderShortcut(folderShortcutRow);
      return;
    }

    var localFolderTrigger = closestAction(e.target, '[data-mnote-action="open-local-folder"]');
    if (localFolderTrigger) {
      e.preventDefault();
      requestOpenLocalFolder();
      return;
    }

    var createLocalWorkspaceTrigger = closestAction(e.target, '[data-mnote-action="create-local-workspace"]');
    if (createLocalWorkspaceTrigger) {
      e.preventDefault();
      void createDefaultLocalWorkspace(createLocalWorkspaceTrigger);
      return;
    }

    var createTrigger = closestAction(e.target, '[data-mnote-action="create-page"]');
    if (createTrigger) {
      e.preventDefault();
      void createPage(createTrigger, null);
      return;
    }

    var createFolderTrigger = closestAction(e.target, '[data-mnote-action="create-folder"]');
    if (createFolderTrigger) {
      e.preventDefault();
      if (currentSourceKind() !== 'local_folder') return;
      var scope = currentFileTreeScope();
      var parentId = scope ? 'local:folder:' + scope : null;
      void createFileTreeFolder(createFolderTrigger, parentId);
      return;
    }

    var fileTree = document.getElementById('sidebar-file-tree-root');
    if (fileTree && fileTree.contains(e.target)) {
      var fileBtn = closestAction(e.target, '[data-rust-action]');
      var fileRow = closestAction(e.target, '.tree-row[data-shell-mode="filetree"]');
      if (!fileRow) return;
      var fileAction = fileBtn ? fileBtn.getAttribute('data-rust-action') : 'open';
      var rowId = fileRow.getAttribute('data-row-id') || '';
      var rowKind = fileRow.getAttribute('data-row-kind') || '';
      var documentId = fileRow.getAttribute('data-document-id') || fileRow.getAttribute('data-doc-id') || '';
      var ownerDocumentId = fileRow.getAttribute('data-owner-document-id') || documentId;
      var assetId = fileRow.getAttribute('data-asset-id') || '';
      var assetType = '';
      var kindBadge = fileRow.querySelector('.tree-kind-badge');
      if (kindBadge instanceof HTMLElement) {
        assetType = kindBadge.getAttribute('data-kind') || '';
      }
      if (fileAction === 'toggle') {
        e.preventDefault();
        toggleChildren(fileRow, fileBtn);
        return;
      }
      if (fileAction === 'create') {
        e.preventDefault();
        void createPage(fileBtn || fileRow, documentId || fileRow.getAttribute('data-node-id'));
        return;
      }
      if (fileAction === 'menu') {
        e.preventDefault();
        if (rowId && !sidebarFileTreeSelection.selectedRowIds.has(rowId)) {
          selectSidebarFileTreeRow(fileRow, { ctrlKey: false, metaKey: false, shiftKey: false });
        }
        var point = rowCenter(fileBtn || fileRow);
        dispatchSidebarEvent('tree.filetree.context-menu', { rowId: rowId, rowKind: rowKind, documentId: documentId || null, assetId: assetId || null });
        openFileTreeContextMenu(fileRow, point.x, point.y, fileBtn || fileRow);
        return;
      }
      if (fileAction === 'open' && rowKind === 'folder') {
        e.preventDefault();
        selectSidebarFileTreeRow(fileRow, { ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey });
        toggleChildren(fileRow, fileRow.querySelector('[data-rust-action="toggle"]'));
        return;
      }
      e.preventDefault();
      selectSidebarFileTreeRow(fileRow, { ctrlKey: e.ctrlKey, metaKey: e.metaKey, shiftKey: e.shiftKey });
      var objectIdentity = readFileTreeObjectIdentity(fileRow);
      var workspacePath = readWorkspacePathFromRow(fileRow);
      var localRelativePath = fileTreeRowLocalRelativePath(fileRow) || String(workspacePath && (workspacePath.relativePath || workspacePath.localRelativePath) || '').trim();
      dispatchSidebarEvent('tree.filetree.open', { rowId: rowId, rowKind: rowKind, documentId: ownerDocumentId || null, assetId: assetId || null, assetType: assetType || null, objectIdentity: objectIdentity, workspacePath: workspacePath, workspaceId: resolveWorkspaceId(fileRow) });
      if (e.shiftKey || e.ctrlKey || e.metaKey) {
        return;
      }
      if ((rowKind === 'document' || rowKind === 'index' || rowKind === 'markdown') && isRetiredOcrSidecarMarkdownPath(localRelativePath)) {
        document.documentElement.setAttribute('data-mnote-retired-ocr-sidecar-filetree-open', 'resource-tab');
        var retiredOcrSidecarResourceInput = {
          path: localRelativePath,
          title: fileTreeRowTitleForShortcut(fileRow, localRelativePath),
          kind: 'markdown',
          objectIdentity: 'retired-ocr-sidecar:' + localRelativePath,
          assetId: 'retired-ocr-sidecar:' + localRelativePath,
          documentId: documentId || ownerDocumentId || null,
          workspaceId: resolveWorkspaceId(fileRow),
          sourceKind: 'local_folder',
          rootUri: currentRootUri(),
          resourceKind: 'markdown',
          workspacePath: workspacePath,
          paneRole: 'primary'
        };
        if (typeof window.__mnoteDocumentPaneRuntime?.openResourceInActiveTab === 'function') {
          void window.__mnoteDocumentPaneRuntime.openResourceInActiveTab(retiredOcrSidecarResourceInput);
        } else {
          void openLocalResourceInActiveTab(retiredOcrSidecarResourceInput);
        }
        return;
      }
      if ((rowKind === 'document' || rowKind === 'index' || rowKind === 'markdown') && documentId) {
        void recordNavigationRecent({
          kind: 'page',
          sourceKind: currentSourceKind() || 'local_folder',
          rootUri: currentRootUri(),
          relativePath: String(fileRow.getAttribute('data-local-relative-path') || '').trim(),
          documentId: documentId,
          title: fileTreeRowTitleForShortcut(fileRow, documentId),
          workspaceId: resolveWorkspaceId(fileRow)
        });
        navigateToDocument(documentId, resolveWorkspaceId(fileRow), { treeView: 'filetree', fileTreeScope: currentFileTreeScope() });
      } else if (assetId) {
        dispatchSidebarEvent('tree.asset.open', { rowId: rowId, rowKind: rowKind, documentId: ownerDocumentId || null, assetId: assetId, assetType: assetType || null, objectIdentity: objectIdentity, workspacePath: workspacePath, workspaceId: resolveWorkspaceId(fileRow), openTarget: e.shiftKey || e.ctrlKey || e.metaKey ? 'new-window' : 'active-tab' });
      }
      return;
    }

    if (sidebarPageTree.handlePageTreeClick(e, { closestAction: closestAction })) return;
  });

  window.addEventListener('tree.sidebarShortcut.toggleFolder', function(event) {
    var detail = event.detail || {};
    var row = detail.rowId
      ? document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(detail.rowId) + '"]')
      : null;
    void toggleFolderSidebarShortcut(detail, row);
  });

  window.addEventListener('tree.filetree.internal-drop', function(event) {
    var detail = event.detail || {};
    var rowIds = Array.isArray(detail.rowIds) ? detail.rowIds : [];
    if (!rowIds.length) return;
    var targetRow = detail.targetRowId
      ? document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(detail.targetRowId) + '"]')
      : null;
    recordFileTreeAction('internal-drop', {
      rowId: detail.targetRowId || '',
      sourceRowIds: rowIds,
      copy: Boolean(detail.copy)
    });
    void moveSidebarFileTreeRows(rowIds, targetRow, { copy: Boolean(detail.copy) });
  });

  document.addEventListener('contextmenu', function(event) {
    var editorAttachmentLink = closestAction(event.target, '.editor-surface .ProseMirror a.mnote-uploaded-attachment-row');
    if (editorAttachmentLink instanceof HTMLAnchorElement) {
      event.preventDefault();
      event.stopPropagation();
      enhanceEditorAttachmentLink(editorAttachmentLink);
      openEditorAttachmentMenu(editorAttachmentLink, editorAttachmentLink, { x: event.clientX, y: event.clientY });
      return;
    }
    var fileRow = closestAction(event.target, '.tree-row[data-shell-mode="filetree"]');
    if (fileRow) {
      event.preventDefault();
      var contextRowId = fileRow.getAttribute('data-row-id') || '';
      if (contextRowId && !sidebarFileTreeSelection.selectedRowIds.has(contextRowId)) {
        selectSidebarFileTreeRow(fileRow, { ctrlKey: false, metaKey: false, shiftKey: false });
      }
      openFileTreeContextMenu(fileRow, event.clientX, event.clientY, fileRow);
      return;
    }
    if (sidebarPageTree.handlePageTreeContextMenu(event, { closestAction: closestAction })) return;
  });

  document.addEventListener('keydown', function(event) {
    var keyTarget = event.target;
    var fileTreeRootForKey = document.getElementById('sidebar-file-tree-root');
    var fileTreeRowForKey = closestAction(keyTarget, '.tree-row[data-shell-mode="filetree"]');
    if (!fileTreeRowForKey && fileTreeRootForKey && fileTreeRootForKey.contains(document.activeElement)) {
      fileTreeRowForKey = closestAction(document.activeElement, '.tree-row[data-shell-mode="filetree"]');
    }
    if (fileTreeRowForKey) {
      var _kbRT_ = window.__mnoteFileTreeKeyboardRuntime;
      if (_kbRT_ && typeof _kbRT_.handleFileTreeKeyDown === 'function') {
        var handled = _kbRT_.handleFileTreeKeyDown(event, {
          closestAction: closestAction,
          beginFileTreeInlineRename: beginFileTreeInlineRename,
          selectedSidebarFileTreeRows: selectedSidebarFileTreeRows,
          buildSidebarFileTreeContext: buildSidebarFileTreeContext,
          evaluateSidebarFileTreeWhen: evaluateSidebarFileTreeWhen,
          deleteSelectedSidebarFileTreeRows: deleteSelectedSidebarFileTreeRows,
          pasteSidebarFileTreeClipboard: pasteSidebarFileTreeClipboard,
        });
        if (handled) return;
      } else {
        // inline fallback
        if (event.key === 'F2') {
          event.preventDefault();
          var renameCtx = buildSidebarFileTreeContext('filetree', { targetRow: fileTreeRowForKey });
          if (!evaluateSidebarFileTreeWhen(renameCtx, '!workspace.readonly && !editor.dirty')) {
            return;
          }
          beginFileTreeInlineRename(fileTreeRowForKey);
          return;
        }
        if ((event.ctrlKey || event.metaKey) && !event.altKey && event.key) {
          var shortcutKey = event.key.toLowerCase();
          if (shortcutKey === 'c' || shortcutKey === 'x') {
            var selectedRows = selectedSidebarFileTreeRows();
            var selectedRowIds = selectedRows.map(function(row) { return row.getAttribute('data-row-id') || ''; }).filter(Boolean);
            if (selectedRowIds.length > 0) {
              event.preventDefault();
              sidebarFileTreeClipboard = { action: shortcutKey === 'x' ? 'cut' : 'copy', rowIds: selectedRowIds };
              document.documentElement.setAttribute('data-mnote-filetree-clipboard-action', sidebarFileTreeClipboard.action);
            }
            return;
          }
          if (shortcutKey === 'v') {
            event.preventDefault();
            var pasteCtx = buildSidebarFileTreeContext('filetree', { targetRow: fileTreeRowForKey });
            if (!evaluateSidebarFileTreeWhen(pasteCtx, '!workspace.readonly')) {
              return;
            }
            void pasteSidebarFileTreeClipboard(fileTreeRowForKey);
            return;
          }
        }
        if (event.key === 'Delete' || event.key === 'Backspace') {
          event.preventDefault();
          var delCtx = buildSidebarFileTreeContext('filetree', { targetRow: fileTreeRowForKey });
          if (!evaluateSidebarFileTreeWhen(delCtx, '!workspace.readonly && !editor.dirty')) {
            return;
          }
          void deleteSelectedSidebarFileTreeRows(fileTreeRowForKey);
          return;
        }
      }
    }
    if (event.key === 'Escape' && isAnySettingsOpen()) {
      event.preventDefault();
      closeAllSettingsPopovers();
      return;
    }
    if (isSearchShortcutEvent(event)) {
      event.preventDefault();
      openSearchModal();
      return;
    }
    if (event.key === 'Escape') {
      closeTrashModal();
      closeSearchModal();
      closeTreeContextMenu();
    }
  });

  document.addEventListener('change', function(event) {
    var globalCheckbox = closestAction(event.target, '[data-global-option-checkbox="showHeadingNumbers"]');
    if (globalCheckbox instanceof HTMLInputElement) {
      writeGlobalShowHeadingNumbers(globalCheckbox.checked);
      applyPageOptionsToShell();
      renderPageSettingsPopover();
      return;
    }
    var checkbox = closestAction(event.target, '[data-page-option-checkbox]');
    if (checkbox instanceof HTMLInputElement) {
      var key = checkbox.getAttribute('data-page-option-checkbox') || '';
      if (!pageOptionIsSupported(key)) return;
      var patch = {};
      patch[key] = checkbox.checked;
      void persistPageOptionsPatch(patch);
      return;
    }
    var select = closestAction(event.target, '[data-page-option-select]');
    if (select instanceof HTMLSelectElement) {
      var selectKey = select.getAttribute('data-page-option-select') || '';
      var next = {};
      if (selectKey === 'layoutDensity') next.layoutDensity = select.value;
      if (selectKey === 'pageFont') next.pageFont = select.value;
      if (Object.keys(next).length) {
        void persistPageOptionsPatch(next);
      }
      return;
    }
    var pageWidthSelect = closestAction(event.target, '[data-page-width-select]');
    if (pageWidthSelect instanceof HTMLSelectElement) {
      var pageWidthType = pageWidthSelect.getAttribute('data-page-width-select') || '';
      void persistPageWidthPreference(pageWidthType, pageWidthSelect.value);
    }
  });
  sidebarPageAi.installPageAiDelegates();

  function initializePageUiSurfaces() {
    pageUiState.pageOptions = null;
    pageUiState.pageWidthPreferences = null;
    applyPageOptionsToShell();
    void loadPageWidthPreferences();
    updatePageSettingsTriggerState();
    updatePageAiTriggerState();
    ensureHistorySnapshotsSeeded();
    installWorkspaceSidebarResizer();
  }

  window.__mnoteRecordPageHistorySnapshot = recordPageHistorySnapshot;
  window.__mnoteApplyPageOptionsToShell = applyPageOptionsToShell;
  function scheduleInitializePageUiSurfaces() {
    if (document.readyState === 'loading') {
      document.addEventListener('DOMContentLoaded', function() {
        setTimeout(initializePageUiSurfaces, 0);
      }, { once: true });
      return;
    }
    setTimeout(initializePageUiSurfaces, 0);
  }
  scheduleInitializePageUiSurfaces();

  function mnoteDevHotReloadEnabled() {
    try {
      return new URL(import.meta.url).searchParams.has('devHot');
    } catch (_) {
      return false;
    }
  }

  function installMnoteDevHotReload() {
    var bootId = '';
    var failedOnce = false;
    var timer = 0;
    function tick() {
      fetch('/api/dev/hot-reload', { cache: 'no-store', headers: { accept: 'application/json' } })
        .then(function(response) { return response.ok ? response.json() : null; })
        .then(function(payload) {
          if (!payload || payload.enabled !== true || !payload.bootId) {
            if (!bootId && timer) window.clearInterval(timer);
            return;
          }
          document.documentElement.setAttribute('data-mnote-dev-hot-reload', 'enabled');
          if (!bootId) {
            bootId = String(payload.bootId);
            return;
          }
          if (failedOnce || String(payload.bootId) !== bootId) {
            window.location.assign(window.location.href);
          }
        })
        .catch(function() {
          if (bootId) failedOnce = true;
        });
    }
    tick();
    timer = window.setInterval(tick, 1000);
  }
  if (mnoteDevHotReloadEnabled()) {
    installMnoteDevHotReload();
  }

  document.addEventListener('dragstart', function(event) {
    var pageRow = closestAction(event.target, '.tree-row[data-shell-mode="page"][draggable="true"]');
    if (pageRow) {
      startPageDrag(pageRow, event);
      return;
    }
    var fileRow = closestAction(event.target, '.tree-row[data-shell-mode="filetree"][draggable="true"]');
    if (fileRow) {
      var _dndRT_ = window.__mnoteFileTreeDndRuntime;
      if (_dndRT_ && typeof _dndRT_.startFileTreeDrag === 'function') {
        var dragInfo = _dndRT_.startFileTreeDrag(fileRow, {
          selectedSidebarFileTreeRowIdsForDrag: selectedSidebarFileTreeRowIdsForDrag,
        });
        draggingFileTreeRowIds = _dndRT_.draggingFileTreeRowIds;
        if (event.dataTransfer && dragInfo) {
          event.dataTransfer.effectAllowed = dragInfo.effectAllowed || 'copyMove';
          event.dataTransfer.setData(_dndRT_.FILETREE_DRAG_MIME, dragInfo.payload);
          event.dataTransfer.setData('application/x-mnote-file-tree', dragInfo.payload);
          event.dataTransfer.setData('text/plain', dragInfo.payload);
        }
      } else {
        // inline fallback
        draggingFileTreeRowIds = selectedSidebarFileTreeRowIdsForDrag(fileRow);
        if (event.dataTransfer) {
          var payload = JSON.stringify({ type: 'mnote-file-tree-dnd', version: 1, rowIds: draggingFileTreeRowIds });
          event.dataTransfer.effectAllowed = 'copyMove';
          event.dataTransfer.setData(FILETREE_DRAG_MIME, payload);
          event.dataTransfer.setData('application/x-mnote-file-tree', payload);
          event.dataTransfer.setData('text/plain', payload);
        }
      }
    }
  });

  document.addEventListener('dragover', function(event) {
    var pageRow = closestAction(event.target, '.tree-row[data-shell-mode="page"]');
    var sourceNodeId = readPageDragNodeId(event);
    if (pageRow && canDropPage(sourceNodeId, pageRow)) {
      event.preventDefault();
      clearPageDropFeedback();
      pageRow.setAttribute('data-drop-feedback', 'true');
      pageRow.setAttribute('data-drop-position', pageDropPosition(event, pageRow));
      setActivePageDropRow(pageRow);
      if (event.dataTransfer) event.dataTransfer.dropEffect = 'move';
      return;
    }
    var _dndRT_ = window.__mnoteFileTreeDndRuntime;
    if (_dndRT_ && typeof _dndRT_.handleFileTreeDragOver === 'function') {
      if (_dndRT_.handleFileTreeDragOver(event, { closestAction: closestAction })) {
        return;
      }
    } else {
      // inline fallback
      var fileTree = document.getElementById('sidebar-file-tree-root');
      if (fileTree && fileTree.contains(event.target)) {
        var hasFiles = event.dataTransfer && Array.prototype.indexOf.call(event.dataTransfer.types || [], 'Files') >= 0;
        var hasInternal = event.dataTransfer && Array.prototype.indexOf.call(event.dataTransfer.types || [], FILETREE_DRAG_MIME) >= 0;
        if (!hasFiles && !hasInternal && draggingFileTreeRowIds.length === 0) return;
        event.preventDefault();
        if (activeFileTreeDropRow instanceof HTMLElement) activeFileTreeDropRow.setAttribute('data-drop-target', 'false');
        activeFileTreeDropRow = closestAction(event.target, '.tree-row[data-shell-mode="filetree"]') || fileTree;
        if (activeFileTreeDropRow instanceof HTMLElement) activeFileTreeDropRow.setAttribute('data-drop-target', 'true');
        var copyModifier = event.altKey || event.ctrlKey || event.metaKey;
        if (event.dataTransfer) event.dataTransfer.dropEffect = hasFiles || copyModifier ? 'copy' : 'move';
      }
    }
  });

  document.addEventListener('drop', function(event) {
    var pageRow = closestAction(event.target, '.tree-row[data-shell-mode="page"]');
    var sourceNodeId = readPageDragNodeId(event);
    if (pageRow && canDropPage(sourceNodeId, pageRow)) {
      event.preventDefault();
      var position = pageDropPosition(event, pageRow);
      var target = resolvePageMoveTarget(pageRow, position);
      clearPageDragState();
      void dispatchTreeCommand(pageRow, {
        action: 'move',
        workspaceId: resolveWorkspaceId(pageRow),
        documentId: sourceNodeId,
        parentId: target.parentId,
        sortOrder: target.sortOrder
      });
      return;
    }
    var _dndRT_ = window.__mnoteFileTreeDndRuntime;
    if (_dndRT_ && typeof _dndRT_.handleFileTreeDrop === 'function') {
      _dndRT_.handleFileTreeDrop(event, {
        closestAction: closestAction,
        resolveWorkspaceId: resolveWorkspaceId,
        fileTreeRowLocalUploadTargetRelativePath: fileTreeRowLocalUploadTargetRelativePath,
        ensureFileTreeWritableTarget: ensureFileTreeWritableTarget,
        dispatchSidebarEvent: dispatchSidebarEvent,
      });
    } else {
      // inline fallback
      var fileTree = document.getElementById('sidebar-file-tree-root');
      if (fileTree && fileTree.contains(event.target)) {
        var targetRow = closestAction(event.target, '.tree-row[data-shell-mode="filetree"]');
        var files = event.dataTransfer ? Array.from(event.dataTransfer.files || []) : [];
        var raw = event.dataTransfer ? event.dataTransfer.getData(FILETREE_DRAG_MIME) || event.dataTransfer.getData('application/x-mnote-file-tree') || '' : '';
        var rowIds = draggingFileTreeRowIds.slice();
        if (raw) {
          try {
            var parsed = JSON.parse(raw);
            if (Array.isArray(parsed.rowIds)) rowIds = parsed.rowIds;
          } catch (_) {}
        }
        if (!files.length && !rowIds.length) return;
        event.preventDefault();
        var detail = {
          workspaceId: resolveWorkspaceId(targetRow || fileTree),
          targetRowId: targetRow ? targetRow.getAttribute('data-row-id') : null,
          targetRowKind: targetRow ? targetRow.getAttribute('data-row-kind') : 'root',
          documentId: targetRow ? targetRow.getAttribute('data-document-id') || targetRow.getAttribute('data-doc-id') : null,
          assetId: targetRow ? targetRow.getAttribute('data-asset-id') : null,
          targetRelativePath: targetRow ? fileTreeRowLocalUploadTargetRelativePath(targetRow) : '',
          uploadIntent: 'filetree.folder.drop'
        };
        if (activeFileTreeDropRow instanceof HTMLElement) activeFileTreeDropRow.setAttribute('data-drop-target', 'false');
        activeFileTreeDropRow = null;
        if (files.length) {
          dispatchSidebarEvent('tree.filetree.external-drop', Object.assign({}, detail, { files: files }));
        } else {
          void Promise.resolve(ensureFileTreeWritableTarget('drop', targetRow, rowIds, event.altKey === true || event.ctrlKey === true || event.metaKey === true)).then(function(writable) {
            if (!writable) return;
            dispatchSidebarEvent('tree.filetree.internal-drop', Object.assign({}, detail, { rowIds: rowIds, copy: event.altKey === true || event.ctrlKey === true || event.metaKey === true }));
          });
        }
        draggingFileTreeRowIds = [];
      }
    }
  });

  document.addEventListener('dragend', function() {
    clearPageDragState();
    var _dndRT_ = window.__mnoteFileTreeDndRuntime;
    if (_dndRT_ && typeof _dndRT_.resetFileTreeDragState === 'function') {
      _dndRT_.resetFileTreeDragState();
    } else {
      draggingFileTreeRowIds = [];
      clearPageDropFeedback();
      if (activeFileTreeDropRow instanceof HTMLElement) activeFileTreeDropRow.setAttribute('data-drop-target', 'false');
      activeFileTreeDropRow = null;
    }
  });

  sidebarTreeLiveApply.installTreeLiveApplyEventListeners();

  var tree = document.getElementById('sidebar-tree-root');
  var activeId = currentDocumentId();
  if (tree && activeId) {
    var activeRow = tree.querySelector('.tree-row[data-node-id="' + cssEscape(activeId) + '"]');
    if (activeRow instanceof HTMLElement) activeRow.setAttribute('data-active', 'true');
  }
  var initiallySelectedFileRows = document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-selected="true"]');
  initiallySelectedFileRows.forEach(function(row) {
    if (!(row instanceof HTMLElement)) return;
    var rowId = row.getAttribute('data-row-id') || '';
    if (!rowId) return;
    sidebarFileTreeSelection.selectedRowIds.add(rowId);
    if (!sidebarFileTreeSelection.anchorRowId) sidebarFileTreeSelection.anchorRowId = rowId;
    sidebarFileTreeSelection.focusedRowId = rowId;
  });
  syncSidebarFileTreeSelection();
  schedulePendingLocalFolderRestoreFocus();
  window.addEventListener('mnote:primary-document-activated', function(event) {
    var detail = event && event.detail ? event.detail : {};
    pageUiState.pageOptions = null;
    applyPageOptionsToShell();
    if (isPageSettingsOpen()) renderPageSettingsPopover();
    selectSidebarFileTreeDocument(detail.documentId, { scrollIntoView: false });
  });
  window.addEventListener('mnote:page-aggregate-synced', function(event) {
    var detail = event && event.detail ? event.detail : {};
    if (detail.scriptId && detail.scriptId !== '__MNOTE_PAGE_AGGREGATE__') return;
    var documentId = searchText(detail.documentId || '');
    if (documentId && currentDocumentId() && documentId !== currentDocumentId()) return;
    pageUiState.pageOptions = null;
    applyPageOptionsToShell();
    if (isPageSettingsOpen()) renderPageSettingsPopover();
  });
  restoreSidebarTreeTab();
  startLocalFolderSidebarWatch();
})();
