export const createSidebarTreeLiveApplyRuntime = (dependencies = {}) => {
  const {
    activeSidebarTreeMode,
    cssEscape,
    currentDocumentId,
    currentFileTreeActiveRowId,
    currentRootUri,
    currentSourceKind,
    currentWorkspaceId,
    escapeHtml,
    fileTreeRuntimeFunction,
    localFilePathFromAssetId,
    navigateToDocument,
    refreshEditorLocalAttachmentExistence,
    restoreSidebarTreeTab,
    rowTitle,
    schedulePendingLocalFolderRestoreFocus,
    shortMindmapFileName,
    syncSidebarFileTreeSelection,
  } = dependencies;
  var fileTreeViewState = {
    rootUri: '',
    scope: '',
    expandedParents: new Set(),
    selectedRowIds: new Set(),
    focusedRowId: '',
    activeRowId: '',
    scrollTop: 0,
    rowsByParent: new Map(),
    loadedParents: new Set(),
    loadingParents: new Map(),
    dirtyParents: new Set(),
    staleParents: new Set(),
    revisionByParent: new Map(),
    requestGeneration: 0,
    latestGenerationByParent: new Map()
  };
  var fileTreeState = fileTreeViewState;
  var fileTreeExpandedRelativePaths = fileTreeViewState.expandedParents;
  var pageTreeState = {
    pageTreeRequestGeneration: 0
  };
  var fileTreeLazyCacheRootUri = '';
  var fileTreeExpansionStorageRootUri = '';
  var fileTreeExpansionRestoreTimer = 0;
  var fileTreeCommandBatchRefreshParents = new Map();
  var FILETREE_EXPANSION_STORAGE_KEY = 'mnote.localFileTree.expandedRelativePaths.v1';
  var SIDEBAR_TREE_VIEW_STATE_KEY = 'mnote.sidebarTreeViewState.v1:{userId}:{workspaceId}:{sourceKind}:{treeKind}:{rootUriHash}:{scopeHash}';
  var SIDEBAR_TREE_VIEW_STATE_API_KEY = 'sidebarTreeViewState.v1';
  var SIDEBAR_TREE_VIEW_STATE_SAVE_DELAY_MS = 500;
  var sidebarTreeViewStates = new Map();
  var sidebarTreeViewStateRequests = new Map();
  var sidebarTreeViewStateSaveTimers = new Map();

  function updateTitleEverywhere(documentId, title) {
    if (!documentId) return;
    var escaped = cssEscape(documentId);
    var escapedDocRowId = cssEscape('doc:' + documentId);
    var isCurrentDocument = currentDocumentId() === documentId;
    var pageSelectors = [
      '.tree-row[data-shell-mode="page"][data-node-id="' + escaped + '"] > .tree-link > .tree-link-title',
      '.wolai-page-row[data-node-id="' + escaped + '"] > .wolai-row-title',
      'a[href="/documents/' + escaped + '"] > .wolai-row-title',
      'a[href^="/documents/' + escaped + '?"] > .wolai-row-title'
    ];
    pageSelectors.forEach(function(selector) {
      document.querySelectorAll(selector).forEach(function(node) {
        if (node instanceof HTMLElement) node.textContent = title;
      });
    });
    document.querySelectorAll('.tree-row[data-shell-mode="filetree"][data-row-id="' + escapedDocRowId + '"] > .tree-link > .tree-link-title').forEach(function(node) {
      if (node instanceof HTMLElement) node.textContent = fileTreePageTitle(title);
    });
    document.querySelectorAll('[data-page-title-input="true"][data-document-id="' + escaped + '"]').forEach(function(node) {
      if (!(node instanceof HTMLTextAreaElement)) return;
      node.value = title;
      node.setAttribute('data-title-last-saved', title);
      node.setAttribute('data-title-save-status', 'saved');
      node.style.height = 'auto';
      node.style.height = Math.max(48, node.scrollHeight) + 'px';
    });
    document.querySelectorAll('[data-document-pane="true"][data-pane-document-id="' + escaped + '"] [data-page-title-current="true"]').forEach(function(node) {
      if (node instanceof HTMLElement) node.textContent = title;
    });
    if (isCurrentDocument) {
      document.title = title;
      var topbarCurrent = document.querySelector('.wolai-breadcrumb-current [data-page-title-current]');
      if (topbarCurrent instanceof HTMLElement) topbarCurrent.textContent = title;
    }
  }

  function fileTreePageTitle(title) {
    var normalized = String(title || '无标题').trim() || '无标题';
    return normalized.endsWith('.md') ? normalized : normalized + '.md';
  }

  function isFileTreePageRow(row) {
    if (!(row instanceof HTMLElement)) return false;
    if (row.getAttribute('data-asset-id')) return false;
    var documentId = row.getAttribute('data-document-id') || row.getAttribute('data-doc-id') || '';
    if (documentId.indexOf('local-md:') === 0) return true;
    var rowKind = row.getAttribute('data-row-kind') || '';
    return rowKind === 'document' || rowKind === 'doc' || rowKind === 'index' || rowKind === 'markdown';
  }

  function normalizeFileTreePageRenameTitle(value) {
    var normalized = String(value || '').trim();
    if (/\.md$/i.test(normalized)) normalized = normalized.slice(0, -3).trim();
    return normalized;
  }

  function validateFileTreeRename(row, draft) {
    var raw = String(draft || '').trim();
    if (!raw) return '名称不能为空';
    if (/[\\/:*?"<>|]/.test(raw)) return '文件名不能包含 / \\ : * ? " < > |';
    if (!isFileTreePageRow(row)) return '';
    var pageTitle = normalizeFileTreePageRenameTitle(raw);
    if (!pageTitle) return '名称不能为空';
    var expectedFileName = fileTreePageTitle(pageTitle).toLocaleLowerCase();
    var rowId = row.getAttribute('data-row-id') || '';
    var parentId = row.getAttribute('data-parent-id') || '';
    var siblings = Array.from(document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-kind="document"], #sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-kind="doc"], #sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-kind="markdown"]'));
    var duplicate = siblings.some(function(sibling) {
      if (!(sibling instanceof HTMLElement)) return false;
      if ((sibling.getAttribute('data-row-id') || '') === rowId) return false;
      if ((sibling.getAttribute('data-parent-id') || '') !== parentId) return false;
      return fileTreePageTitle(normalizeFileTreePageRenameTitle(rowTitle(sibling))).toLocaleLowerCase() === expectedFileName;
    });
    return duplicate ? '同级已存在同名页面' : '';
  }

  function documentIdFromDelta(data) {
    return String(data && (data.documentId || data.id || (data.document && data.document.id) || (data.node && data.node.id) || (data.args && data.args.documentId)) || '').trim();
  }

  function parentIdFromDelta(data) {
    if (!data || typeof data !== 'object') return null;
    if (Object.prototype.hasOwnProperty.call(data, 'parentId')) return data.parentId ? String(data.parentId).trim() : null;
    if (Object.prototype.hasOwnProperty.call(data, 'parent_id')) return data.parent_id ? String(data.parent_id).trim() : null;
    if (data.args && Object.prototype.hasOwnProperty.call(data.args, 'parentId')) return data.args.parentId ? String(data.args.parentId).trim() : null;
    return null;
  }

  function treeRootForMode(mode) {
    var id = mode === 'filetree' ? 'sidebar-file-tree-root' : 'sidebar-tree-root';
    return document.querySelector('#' + id + ' .tree-root');
  }

  function rowSelectorForDocument(mode, documentId) {
    var escaped = cssEscape(documentId);
    if (mode === 'filetree') {
      return '.tree-row[data-shell-mode="filetree"][data-doc-id="' + escaped + '"], .tree-row[data-shell-mode="filetree"][data-document-id="' + escaped + '"]';
    }
    return '.tree-row[data-shell-mode="page"][data-node-id="' + escaped + '"]';
  }

  function ensureTreeChildren(parentRow) {
    var parentNode = parentRow ? parentRow.closest('.tree-node') : null;
    if (!parentNode) return null;
    var children = parentNode.querySelector(':scope > .tree-children');
    if (!children) {
      children = document.createElement('ul');
      children.className = 'tree-children';
      parentNode.appendChild(children);
    }
    children.classList.remove('tree-children--collapsed');
    parentRow.setAttribute('aria-expanded', 'true');
    var toggle = parentRow.querySelector('[data-rust-action="toggle"]');
    if (toggle) toggle.setAttribute('aria-expanded', 'true');
    return children;
  }

  function removeDocumentRowForMode(mode, documentId) {
    var row = document.querySelector(rowSelectorForDocument(mode, documentId));
    var node = row ? row.closest('.tree-node') : null;
    if (!node || !node.parentElement) return false;
    node.parentElement.removeChild(node);
    return true;
  }

  function commandDocumentId(result, fallback) {
    var value = result && (
      (result.execution && (result.execution.documentId || result.execution.id || result.execution.nodeId)) ||
      result.documentId ||
      result.id ||
      result.nodeId ||
      (result.document && (result.document.id || result.document.documentId)) ||
      (result.node && (result.node.id || result.node.documentId)) ||
      (result.payload && result.payload.documentId)
    );
    return String(value || fallback || '').trim();
  }

  function commandDocumentTitle(result, fallback) {
    var value = result && (
      (result.execution && result.execution.title) ||
      result.title ||
      (result.document && result.document.title) ||
      (result.node && result.node.title) ||
      (result.payload && result.payload.title)
    );
    return String(value || fallback || '新页面').trim() || '新页面';
  }

  function normalizeDocumentRowId(value) {
    return String(value || '').trim().replace(/^doc:/, '').replace(/^index:/, '');
  }

  function appendRenderedTreeNode(container, html) {
    if (!container || !html) return false;
    var empty = container.querySelector(':scope > .tree-empty');
    if (empty && empty.parentElement) empty.parentElement.removeChild(empty);
    var template = document.createElement('template');
    template.innerHTML = html;
    var node = template.content.firstElementChild;
    if (!node) return false;
    container.appendChild(node);
    return true;
  }

  function localPageInsertDepth(parentId) {
    if (!parentId) return 0;
    var parentRow = document.querySelector(rowSelectorForDocument('page', parentId));
    var depth = parentRow ? Number(parentRow.getAttribute('data-depth') || 0) : 0;
    return Number.isFinite(depth) ? depth + 1 : 1;
  }

  function upsertPageDocumentRow(documentId, parentId, title) {
    if (!documentId) return false;
    var existing = document.querySelector(rowSelectorForDocument('page', documentId));
    if (existing instanceof HTMLElement) {
      updateTitleEverywhere(documentId, title);
      moveDocumentRowForMode('page', documentId, parentId || null);
      return true;
    }
    var root = treeRootForMode('page');
    if (!root) return false;
    var targetContainer = root;
    if (parentId) {
      var parentRow = document.querySelector(rowSelectorForDocument('page', parentId));
      targetContainer = ensureTreeChildren(parentRow);
      if (!targetContainer) targetContainer = root;
    }
    var grouped = new Map();
    grouped.set(parentId || '', [{
      id: documentId,
      nodeId: documentId,
      documentId: documentId,
      parentNodeId: parentId || '',
      rowKind: 'document',
      title: title,
      expandable: false,
      childCount: 0
    }]);
    return appendRenderedTreeNode(targetContainer, renderPageRows(parentId || '', grouped, currentDocumentId(), localPageInsertDepth(parentId)));
  }

  function fileTreeParentContainer(parentId) {
    var root = treeRootForMode('filetree');
    if (!root) return null;
    if (!parentId) return root;
    var parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + parentId) + '"]');
    var children = ensureTreeChildren(parentRow);
    return children || root;
  }

  function localFileInsertDepth(parentId) {
    if (!parentId) return 0;
    var parentRow = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + parentId) + '"]');
    var level = parentRow ? Number(parentRow.getAttribute('aria-level') || 1) : 1;
    return Number.isFinite(level) ? level : 1;
  }

  function upsertFileDocumentRows(documentId, parentId, title) {
    if (!documentId) return false;
    var existing = document.querySelector('.tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape('doc:' + documentId) + '"]');
    if (existing instanceof HTMLElement) {
      updateTitleEverywhere(documentId, title);
      moveDocumentRowForMode('filetree', documentId, parentId || null);
      return true;
    }
    var targetContainer = fileTreeParentContainer(parentId);
    if (!targetContainer) return false;
    var parentNodeId = parentId ? 'doc:' + parentId : '';
    var docNodeId = 'doc:' + documentId;
    var depth = localFileInsertDepth(parentId);
    var grouped = new Map();
    grouped.set(parentNodeId, [{
      id: docNodeId,
      nodeId: docNodeId,
      rowId: docNodeId,
      rowKind: 'document',
      title: fileTreePageTitle(title),
      documentId: documentId,
      parentNodeId: parentNodeId,
      depth: depth,
      expandable: false,
      childCount: 0
    }]);
    return appendRenderedTreeNode(targetContainer, renderFileRows(parentNodeId, grouped, currentDocumentId()));
  }

  function applyCreatedDocumentLocally(result, parentId, fallbackTitle) {
    var documentId = commandDocumentId(result, null);
    if (!documentId) return false;
    var normalizedParentId = normalizeDocumentRowId(parentId);
    var title = commandDocumentTitle(result, fallbackTitle);
    var pageChanged = upsertPageDocumentRow(documentId, normalizedParentId, title);
    var fileChanged = upsertFileDocumentRows(documentId, normalizedParentId, title);
    if (pageChanged || fileChanged) {
      document.documentElement.setAttribute('data-mnote-tree-local-command-applied', 'create');
    }
    return pageChanged || fileChanged;
  }

  function localCommandNeedsProjectionRefresh(action, result) {
    if (currentSourceKind() !== 'local_folder') return false;
    if (action === 'create' || action === 'rename' || action === 'move' || action === 'delete' || action === 'archive' || action === 'trash' || action === 'purge') {
      return true;
    }
    if (result && (result.previousDocumentId || result.previousRelativePath || result.relativePath || result.trashPath)) {
      return true;
    }
    return false;
  }

  function parentRelativePathForPath(relativePath) {
    var normalized = String(relativePath || '').trim().replace(/^\/+|\/+$/g, '');
    if (!normalized || normalized === '.') return '';
    var index = normalized.lastIndexOf('/');
    return index > 0 ? normalized.slice(0, index) : '';
  }

  function addCommandRefreshParent(parents, value) {
    var normalized = String(value || '').trim().replace(/^\/+|\/+$/g, '');
    if (normalized === '.') normalized = '';
    parents.add(normalized);
  }

  function addAffectedParentsFromCommandResult(parents, result) {
    var affectedParents = Array.isArray(result && result.affectedParents)
      ? result.affectedParents
      : Array.isArray(result && result.execution && result.execution.affectedParents)
        ? result.execution.affectedParents
        : null;
    if (!affectedParents) return false;
    var before = parents.size;
    affectedParents.forEach(function(parent) {
      addCommandRefreshParent(parents, parent && (parent.relativePath || parent.relative_path));
    });
    return parents.size > before;
  }

  function collectFileTreeRefreshParentsForCommand(result, body) {
    var parents = new Set();
    if (!addAffectedParentsFromCommandResult(parents, result)) {
    document.documentElement.setAttribute('data-mnote-filetree-command-refresh-fallback', 'legacy-path-fields');
    var values = [
      result && (result.parentRelativePath || result.parent_relative_path),
      result && result.execution && (result.execution.parentRelativePath || result.execution.parent_relative_path),
      result && (result.relativePath || result.relative_path),
      result && result.execution && (result.execution.relativePath || result.execution.relative_path),
      result && (result.previousRelativePath || result.previous_relative_path),
      result && result.execution && (result.execution.previousRelativePath || result.execution.previous_relative_path),
      body && (body.parentRelativePath || body.parent_relative_path)
    ];
    values.forEach(function(value) {
      var normalized = String(value || '').trim();
      if (!normalized) return;
      if (normalized.indexOf('/') >= 0 || /\.[^/]+$/.test(normalized)) addCommandRefreshParent(parents, parentRelativePathForPath(normalized));
      else addCommandRefreshParent(parents, normalized);
    });
    }
    if (!parents.size) addCommandRefreshParent(parents, currentFileTreeScope());
    return parents;
  }

  function fileTreeRefreshParentsForCommand(result, body) {
    var parents = collectFileTreeRefreshParentsForCommand(result, body);
    return Promise.all(Array.from(parents).map(function(parentRelativePath) {
      return refreshFileTreeParent(parentRelativePath).catch(function(error) {
        setTreeLiveApplyError(error && error.message ? error.message : '文件树局部刷新失败');
        return false;
      });
    }));
  }

  function queueFileTreeBatchRefresh(batchId, result, body) {
    var normalizedBatchId = String(batchId || '').trim();
    if (!normalizedBatchId) return false;
    var batchParents = fileTreeCommandBatchRefreshParents.get(normalizedBatchId);
    if (!batchParents) {
      batchParents = new Set();
      fileTreeCommandBatchRefreshParents.set(normalizedBatchId, batchParents);
    }
    collectFileTreeRefreshParentsForCommand(result, body).forEach(function(parent) {
      batchParents.add(parent);
    });
    document.documentElement.setAttribute('data-mnote-filetree-batch-refresh-pending', normalizedBatchId);
    return true;
  }

  function flushFileTreeBatchRefresh(batchId) {
    var normalizedBatchId = String(batchId || '').trim();
    if (!normalizedBatchId) return false;
    var parents = fileTreeCommandBatchRefreshParents.get(normalizedBatchId);
    fileTreeCommandBatchRefreshParents.delete(normalizedBatchId);
    if (!parents || !parents.size) return false;
    document.documentElement.setAttribute('data-mnote-filetree-batch-refresh-applied', normalizedBatchId);
    void Promise.all(Array.from(parents).map(function(parentRelativePath) {
      return refreshFileTreeParent(parentRelativePath).catch(function(error) {
        setTreeLiveApplyError(error && error.message ? error.message : '文件树批量刷新失败');
        return false;
      });
    }));
    return true;
  }

  function applyLocalFolderWatchBatch(payload) {
    var batch = payload && (payload.payload || payload);
    var affectedParents = Array.isArray(batch && batch.affectedParents)
      ? batch.affectedParents
      : Array.isArray(batch && batch.affected_parents)
        ? batch.affected_parents
        : [];
    if (!affectedParents.length) {
      setTreeLiveApplyError('local_folder_watch_batch_missing_affected_parents');
      return false;
    }
    var parents = new Set();
    affectedParents.forEach(function(parent) {
      addCommandRefreshParent(parents, parent && (parent.relativePath || parent.relative_path));
    });
    document.documentElement.setAttribute('data-mnote-local-folder-watch-batch-applied', String(batch.revision || 'true'));
    void Promise.all(Array.from(parents).map(function(parentRelativePath) {
      return refreshFileTreeParent(parentRelativePath).catch(function(error) {
        setTreeLiveApplyError(error && error.message ? error.message : '文件树 watch batch 刷新失败');
        return false;
      });
    })).then(function() {
      markLocalFolderWatchApplied('watch_batch');
    });
    return true;
  }

  function refreshLocalFolderAfterCommand(action, result, body) {
    if (!localCommandNeedsProjectionRefresh(action, result)) return Promise.resolve(false);
    if (body && body.batchId) {
      queueFileTreeBatchRefresh(body.batchId, result, body);
      return Promise.resolve(true);
    }
    return fileTreeRefreshParentsForCommand(result, body);
  }

  function sortOrderFromDelta(data) {
    var raw = data && (data.sortOrder ?? data.sort_order);
    var value = Number(raw);
    return Number.isFinite(value) && value >= 0 ? Math.floor(value) : null;
  }

  function insertTreeNodeAtSortOrder(targetContainer, node, sortOrder) {
    if (!targetContainer || !node) return false;
    if (sortOrder === null || sortOrder === undefined) {
      targetContainer.appendChild(node);
      return true;
    }
    var siblings = Array.from(targetContainer.querySelectorAll(':scope > .tree-node')).filter(function(candidate) {
      return candidate !== node;
    });
    var targetIndex = Math.max(0, Math.min(Number(sortOrder), siblings.length));
    var referenceNode = siblings[targetIndex] || null;
    if (referenceNode) targetContainer.insertBefore(node, referenceNode);
    else targetContainer.appendChild(node);
    return true;
  }

  function moveDocumentRowForMode(mode, documentId, parentId, sortOrder) {
    var row = document.querySelector(rowSelectorForDocument(mode, documentId));
    var node = row ? row.closest('.tree-node') : null;
    var root = treeRootForMode(mode);
    if (!row || !node || !root) return false;
    var targetContainer = root;
    if (parentId) {
      var parentRow = document.querySelector(rowSelectorForDocument(mode, parentId));
      targetContainer = ensureTreeChildren(parentRow);
      if (!targetContainer) return false;
      row.setAttribute('data-parent-id', parentId);
    } else {
      row.removeAttribute('data-parent-id');
    }
    return insertTreeNodeAtSortOrder(targetContainer, node, sortOrder);
  }

  function applyMoveDocumentDelta(data) {
    var documentId = documentIdFromDelta(data);
    if (!documentId) return false;
    var parentId = parentIdFromDelta(data);
    var sortOrder = sortOrderFromDelta(data);
    var movedPage = moveDocumentRowForMode('page', documentId, parentId, sortOrder);
    var movedFile = moveDocumentRowForMode('filetree', documentId, parentId, sortOrder);
    return movedPage || movedFile;
  }

  function applyRemoveDocumentDelta(data) {
    var documentId = documentIdFromDelta(data);
    if (!documentId) return false;
    var removedPage = removeDocumentRowForMode('page', documentId);
    var removedFile = removeDocumentRowForMode('filetree', documentId);
    return removedPage || removedFile;
  }

  function readProjection(value) {
    var runtimeFn = fileTreeRuntimeFunction('readProjection');
    if (runtimeFn) return runtimeFn(value);
    if (!value || typeof value !== 'object') return null;
    if (value.result && typeof value.result === 'object') return value.result;
    if (value.snapshot && value.snapshot.tree) return value.snapshot.tree;
    if (value.data && value.data.tree) return value.data.tree;
    if (value.tree && typeof value.tree === 'object') return value.tree;
    return value;
  }

  function readSidebarDataset(value) {
    var runtimeFn = fileTreeRuntimeFunction('readSidebarDataset');
    if (runtimeFn) return runtimeFn(value);
    if (!value || typeof value !== 'object') return null;
    if (value.snapshot && value.snapshot.dataset && typeof value.snapshot.dataset === 'object') return value.snapshot.dataset;
    if (value.data && value.data.dataset && typeof value.data.dataset === 'object') return value.data.dataset;
    if (value.dataset && typeof value.dataset === 'object') return value.dataset;
    if (value.sidebar && typeof value.sidebar === 'object') return value.sidebar;
    return null;
  }

  function readDatasetProjection(value, snakeCaseKey, camelCaseKey) {
    var runtimeFn = fileTreeRuntimeFunction('readDatasetProjection');
    if (runtimeFn) return runtimeFn(value, snakeCaseKey, camelCaseKey);
    var dataset = readSidebarDataset(value);
    if (!dataset || typeof dataset !== 'object') return null;
    if (dataset[snakeCaseKey] && typeof dataset[snakeCaseKey] === 'object') return dataset[snakeCaseKey];
    if (dataset[camelCaseKey] && typeof dataset[camelCaseKey] === 'object') return dataset[camelCaseKey];
    return null;
  }

  function setTreeLiveApplyError(reason) {
    document.documentElement.setAttribute('data-mnote-tree-live-apply-error', String(reason || 'tree_live_apply_failed'));
  }

  function projectionItems(projection) {
    var runtimeFn = fileTreeRuntimeFunction('projectionItems');
    if (runtimeFn) return runtimeFn(projection);
    var resolved = readProjection(projection);
    return resolved && Array.isArray(resolved.items) ? resolved.items : [];
  }

  function hasProjectionItems(projection) {
    var runtimeFn = fileTreeRuntimeFunction('hasProjectionItems');
    if (runtimeFn) return runtimeFn(projection);
    var resolved = readProjection(projection);
    return Boolean(resolved && Array.isArray(resolved.items));
  }

  function nodeIdOf(item) {
    var runtimeFn = fileTreeRuntimeFunction('nodeIdOf');
    if (runtimeFn) return runtimeFn(item);
    return String(item && (item.nodeId || item.id || item.documentId) || '').trim();
  }

  function rowIdOf(item) {
    var runtimeFn = fileTreeRuntimeFunction('rowIdOf');
    if (runtimeFn) return runtimeFn(item);
    return String(item && (item.rowId || item.nodeId || item.id) || '').trim();
  }

  function parentIdOf(item) {
    var runtimeFn = fileTreeRuntimeFunction('parentIdOf');
    if (runtimeFn) return runtimeFn(item);
    return String(item && (item.parentNodeId || item.parentId || '') || '').trim();
  }

  function titleOf(item) {
    var runtimeFn = fileTreeRuntimeFunction('titleOf');
    if (runtimeFn) return runtimeFn(item);
    return String(item && item.title || '无标题').trim() || '无标题';
  }

  function fileWorkspaceRelativePath(item) {
    var runtimeFn = fileTreeRuntimeFunction('fileWorkspaceRelativePath');
    if (runtimeFn) return runtimeFn(item);
    var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {};
    var workspacePath = meta.workspacePath && typeof meta.workspacePath === 'object' ? meta.workspacePath : {};
    var fromWorkspacePath = String(workspacePath.relativePath || '').trim();
    if (fromWorkspacePath) return fromWorkspacePath;
    var extra = meta.extra && typeof meta.extra === 'object' ? meta.extra : {};
    var source = extra.source && typeof extra.source === 'object' ? extra.source : {};
    var fromSource = String(source.relativePath || '').trim();
    if (fromSource) return fromSource;
    return String(item && (item.relativePath || item.rootRelativePath) || '').trim();
  }

  function normalizeFileTreeRelativePath(value) {
    var normalized = String(value || '').trim().replace(/^\/+|\/+$/g, '');
    return normalized === '.' ? '' : normalized;
  }

  function fileTreeRowByRelativePath(relativePath) {
    var normalized = normalizeFileTreeRelativePath(relativePath);
    if (!normalized) return null;
    return document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-local-relative-path="' + cssEscape(normalized) + '"]');
  }

  function groupRowsByParent(rows) {
    var runtimeFn = fileTreeRuntimeFunction('groupRowsByParent');
    if (runtimeFn) return runtimeFn(rows);
    var ids = new Set(rows.map(nodeIdOf).filter(Boolean));
    var grouped = new Map();
    rows.forEach(function(item) {
      var parentId = parentIdOf(item);
      if (!ids.has(parentId)) parentId = '';
      if (!grouped.has(parentId)) grouped.set(parentId, []);
      grouped.get(parentId).push(item);
    });
    return grouped;
  }

  function fileTreeParentKey(rootUri, parentRelativePath) {
    return String(rootUri || '').trim() + '\n' + String(parentRelativePath || '').trim();
  }

  function currentFileTreeParentKey(parentRelativePath) {
    return fileTreeParentKey(currentRootUri(), parentRelativePath);
  }

  function stableTreeViewStateHash(value) {
    var hash = 0xcbf29ce484222325n;
    var prime = 0x100000001b3n;
    var text = String(value || '').trim();
    for (var index = 0; index < text.length; index += 1) {
      hash ^= BigInt(text.charCodeAt(index) & 0xff);
      hash = (hash * prime) & 0xffffffffffffffffn;
    }
    return hash.toString(16).padStart(16, '0');
  }

  function currentActorStorageId() {
    var body = document.body instanceof HTMLElement ? document.body : null;
    var fromBody = body ? String(body.getAttribute('data-mnote-actor-id') || '').trim() : '';
    if (fromBody) return fromBody;
    var match = document.cookie.match(/(?:^|;\s*)mnote_actor_id=([^;]+)/);
    if (match) {
      try {
        return decodeURIComponent(match[1]);
      } catch (_) {
        return match[1] || '';
      }
    }
    return 'anonymous';
  }

  function sidebarTreeViewScope(treeKind) {
    var normalizedTreeKind = String(treeKind || '').trim() === 'pagetree' ? 'pagetree' : 'filetree';
    var rootUri = String(currentRootUri() || '').trim();
    var scope = currentFileTreeScope() || 'root';
    return {
      userId: currentActorStorageId(),
      workspaceId: String(currentWorkspaceId() || '').trim() || (rootUri ? 'local:' + rootUri.replace(/^file:\/\//, '').replace(/[^A-Za-z0-9]+/g, '_') : 'default'),
      sourceKind: String(currentSourceKind() || 'convex_workspace').trim() || 'convex_workspace',
      treeKind: normalizedTreeKind,
      rootUri: rootUri,
      scope: scope
    };
  }

  function sidebarTreeViewStateMapKey(scope) {
    return [
      scope.userId,
      scope.workspaceId,
      scope.sourceKind,
      scope.treeKind,
      scope.rootUri,
      scope.scope
    ].join('\n');
  }

  function sidebarTreeViewLocalStorageKey(scope) {
    return SIDEBAR_TREE_VIEW_STATE_KEY
      .replace('{userId}', encodeURIComponent(scope.userId || 'anonymous'))
      .replace('{workspaceId}', encodeURIComponent(scope.workspaceId || 'default'))
      .replace('{sourceKind}', encodeURIComponent(scope.sourceKind || 'convex_workspace'))
      .replace('{treeKind}', encodeURIComponent(scope.treeKind || 'filetree'))
      .replace('{rootUriHash}', stableTreeViewStateHash(scope.rootUri || ''))
      .replace('{scopeHash}', stableTreeViewStateHash(scope.scope || 'root'));
  }

  function normalizeSidebarTreeViewState(treeKind, value, source) {
    var scope = sidebarTreeViewScope(treeKind);
    var state = value && typeof value === 'object' ? value : {};
    return {
      schemaVersion: 1,
      treeKind: scope.treeKind,
      rootUri: scope.rootUri,
      scope: scope.scope,
      expandedIds: new Set(Array.isArray(state.expandedIds) ? state.expandedIds.map(String).filter(Boolean) : []),
      expandedRelativePaths: new Set(Array.isArray(state.expandedRelativePaths) ? state.expandedRelativePaths.map(normalizeFileTreeRelativePath).filter(Boolean) : []),
      selectedId: String(state.selectedId || '').trim(),
      focusedId: String(state.focusedId || '').trim(),
      activeId: String(state.activeId || '').trim(),
      scrollTop: Math.max(0, Number(state.scrollTop || 0) || 0),
      updatedAtMs: Number(state.updatedAtMs || 0) || 0,
      hasUserState: source === 'sqlite' || source === 'local' || source === 'legacy',
      source: source || 'default'
    };
  }

  function serializeSidebarTreeViewState(state) {
    return {
      schemaVersion: 1,
      treeKind: state.treeKind,
      rootUri: state.rootUri,
      scope: state.scope,
      expandedIds: Array.from(state.expandedIds || []).slice(0, 512),
      expandedRelativePaths: Array.from(state.expandedRelativePaths || []).slice(0, 512),
      selectedId: String(state.selectedId || ''),
      focusedId: String(state.focusedId || ''),
      activeId: String(state.activeId || ''),
      scrollTop: Math.max(0, Number(state.scrollTop || 0) || 0),
      updatedAtMs: Number(state.updatedAtMs || 0) || Date.now()
    };
  }

  function sidebarTreeViewStateFor(treeKind) {
    var scope = sidebarTreeViewScope(treeKind);
    var key = sidebarTreeViewStateMapKey(scope);
    var state = sidebarTreeViewStates.get(key);
    if (!state) {
      var localValue = null;
      try {
        if (window.localStorage) {
          localValue = JSON.parse(window.localStorage.getItem(sidebarTreeViewLocalStorageKey(scope)) || 'null');
        }
      } catch (_) {
        localValue = null;
      }
      state = normalizeSidebarTreeViewState(scope.treeKind, localValue, localValue ? 'local' : 'default');
      sidebarTreeViewStates.set(key, state);
      void loadSidebarTreeViewState(scope.treeKind);
    }
    if (scope.treeKind === 'filetree') {
      fileTreeViewState.expandedParents = state.expandedRelativePaths;
      fileTreeExpandedRelativePaths = state.expandedRelativePaths;
    }
    return state;
  }

  function loadSidebarTreeViewState(treeKind) {
    var scope = sidebarTreeViewScope(treeKind);
    var key = sidebarTreeViewStateMapKey(scope);
    if (sidebarTreeViewStateRequests.has(key)) return sidebarTreeViewStateRequests.get(key);
    var url = new URL('/api/tree/view-state', window.location.origin);
    url.searchParams.set('workspaceId', scope.workspaceId);
    url.searchParams.set('sourceKind', scope.sourceKind);
    url.searchParams.set('treeKind', scope.treeKind);
    if (scope.rootUri) url.searchParams.set('rootUri', scope.rootUri);
    url.searchParams.set('scope', scope.scope);
    var promise = fetch(url.toString(), {
      credentials: 'include',
      cache: 'no-store',
      headers: { accept: 'application/json' }
    }).then(function(response) {
      return response.json().catch(function() { return null; }).then(function(payload) {
        if (!response.ok) return null;
        var result = payload && payload.result ? payload.result : null;
        if (!result || !result.state) return null;
        var latestScope = sidebarTreeViewScope(scope.treeKind);
        if (sidebarTreeViewStateMapKey(latestScope) !== key) return null;
        var loaded = normalizeSidebarTreeViewState(scope.treeKind, result.state, result.source === 'sqlite' ? 'sqlite' : 'default');
        sidebarTreeViewStates.set(key, loaded);
        applySidebarTreeViewState(scope.treeKind, loaded);
        return loaded;
      });
    }).catch(function(error) {
      document.documentElement.setAttribute('data-mnote-sidebar-tree-view-state-load-error', String(error && error.message || error || 'load_failed'));
      return null;
    }).finally(function() {
      sidebarTreeViewStateRequests.delete(key);
    });
    sidebarTreeViewStateRequests.set(key, promise);
    return promise;
  }

  function persistSidebarTreeViewState(treeKind, options) {
    options = options || {};
    var scope = sidebarTreeViewScope(treeKind);
    var key = sidebarTreeViewStateMapKey(scope);
    var state = sidebarTreeViewStateFor(scope.treeKind);
    state.hasUserState = true;
    state.source = state.source === 'legacy' ? 'legacy' : 'local';
    state.updatedAtMs = Date.now();
    var serialized = serializeSidebarTreeViewState(state);
    try {
      if (window.localStorage) {
        window.localStorage.setItem(sidebarTreeViewLocalStorageKey(scope), JSON.stringify(serialized));
      }
    } catch (_) {}
    var flush = function() {
      sidebarTreeViewStateSaveTimers.delete(key);
      var latestScope = sidebarTreeViewScope(scope.treeKind);
      if (sidebarTreeViewStateMapKey(latestScope) !== key) return;
      fetch('/api/tree/view-state', {
        method: 'PUT',
        credentials: 'include',
        cache: 'no-store',
        headers: { accept: 'application/json', 'content-type': 'application/json' },
        body: JSON.stringify({
          workspaceId: scope.workspaceId,
          sourceKind: scope.sourceKind,
          treeKind: scope.treeKind,
          rootUri: scope.rootUri,
          scope: scope.scope,
          state: serialized
        })
      }).then(function(response) {
        return response.json().catch(function() { return null; }).then(function(payload) {
          if (!response.ok) throw new Error(payload && (payload.error || payload.message) || 'tree_view_state_save_failed_' + response.status);
          document.documentElement.setAttribute('data-mnote-sidebar-tree-view-state-saved', scope.treeKind + ':' + scope.scope);
          return payload;
        });
      }).catch(function(error) {
        document.documentElement.setAttribute('data-mnote-sidebar-tree-view-state-save-error', String(error && error.message || error || 'save_failed'));
      });
    };
    if (options.flush) {
      if (sidebarTreeViewStateSaveTimers.has(key)) {
        window.clearTimeout(sidebarTreeViewStateSaveTimers.get(key));
        sidebarTreeViewStateSaveTimers.delete(key);
      }
      flush();
      return;
    }
    if (sidebarTreeViewStateSaveTimers.has(key)) window.clearTimeout(sidebarTreeViewStateSaveTimers.get(key));
    sidebarTreeViewStateSaveTimers.set(key, window.setTimeout(flush, SIDEBAR_TREE_VIEW_STATE_SAVE_DELAY_MS));
  }

  function flushPendingSidebarTreeViewState(treeKind) {
    var scope = sidebarTreeViewScope(treeKind);
    var key = sidebarTreeViewStateMapKey(scope);
    if (!sidebarTreeViewStateSaveTimers.has(key)) return;
    persistSidebarTreeViewState(scope.treeKind, { flush: true });
  }

  function applySidebarTreeViewState(treeKind, state) {
    if (String(treeKind || '').trim() === 'pagetree') {
      applyPageTreeExpansionState(state);
      return;
    }
    fileTreeExpandedRelativePaths = state.expandedRelativePaths;
    fileTreeViewState.expandedParents = state.expandedRelativePaths;
    restorePersistedFileTreeExpansionState();
  }

  function applyPageTreeExpansionState(state) {
    if (!state || !state.hasUserState) return false;
    var changed = false;
    document.querySelectorAll('#sidebar-tree-root .tree-row[data-shell-mode="page"]').forEach(function(row) {
      if (!(row instanceof HTMLElement)) return;
      var nodeId = String(row.getAttribute('data-node-id') || '').trim();
      var button = row.querySelector('[data-rust-action="toggle"]');
      var node = row.closest('.tree-node');
      var children = node ? node.querySelector(':scope > .tree-children') : null;
      if (!nodeId || !button || !(children instanceof HTMLElement)) return;
      var expanded = state.expandedIds.has(nodeId);
      row.setAttribute('aria-expanded', String(expanded));
      button.setAttribute('aria-expanded', String(expanded));
      children.classList.toggle('tree-children--collapsed', !expanded);
      changed = true;
    });
    if (changed) document.documentElement.setAttribute('data-mnote-page-tree-view-state-applied', state.scope || 'root');
    return changed;
  }

  function pageTreeActiveParentIds(grouped, activeId) {
    var parentsById = new Map();
    grouped.forEach(function(items) {
      items.forEach(function(item) {
        parentsById.set(nodeIdOf(item), parentIdOf(item));
      });
    });
    var parents = new Set();
    var cursor = String(activeId || '').trim();
    var guard = 0;
    while (cursor && parentsById.has(cursor) && guard < 512) {
      cursor = String(parentsById.get(cursor) || '').trim();
      if (cursor) parents.add(cursor);
      guard += 1;
    }
    return parents;
  }

  function projectionParentRelativePath(projection) {
    var resolved = readProjection(projection);
    return String(resolved && (resolved.parentRelativePath || resolved.parent_relative_path) || '').trim();
  }

  function isFileTreeRootProjectionParent(parentRelativePath) {
    return normalizeFileTreeRelativePath(parentRelativePath) === normalizeFileTreeRelativePath(currentFileTreeScope());
  }

  function rememberFileTreeProjection(parentRelativePath, rows, projection) {
    var key = currentFileTreeParentKey(parentRelativePath);
    fileTreeState.rowsByParent.set(key, rows);
    fileTreeState.loadedParents.add(key);
    fileTreeState.dirtyParents.delete(key);
    fileTreeState.staleParents.delete(key);
    var resolved = readProjection(projection);
    var watchRevision = resolved && (resolved.watchRevision || resolved.watch_revision);
    if (watchRevision) fileTreeState.revisionByParent.set(key, watchRevision);
  }

  function cachedFileTreeRows(parentRelativePath) {
    return fileTreeState.rowsByParent.get(currentFileTreeParentKey(parentRelativePath)) || [];
  }

  function beginFileTreeRequest(key) {
    fileTreeState.requestGeneration += 1;
    fileTreeState.latestGenerationByParent.set(key, fileTreeState.requestGeneration);
    return fileTreeState.requestGeneration;
  }

  function isLatestFileTreeRequest(key, generation) {
    return fileTreeState.latestGenerationByParent.get(key) === generation;
  }

  function markFileTreeParentStale(key) {
    fileTreeState.staleParents.add(key);
    fileTreeState.dirtyParents.add(key);
  }

  function beginPageTreeRequest() {
    pageTreeState.pageTreeRequestGeneration += 1;
    return pageTreeState.pageTreeRequestGeneration;
  }

  function isLatestPageTreeRequest(generation) {
    return generation === pageTreeState.pageTreeRequestGeneration;
  }

  function yieldForPageTreeRender() {
    return new Promise(function(resolve) {
      if (typeof window !== 'undefined' && typeof window.requestIdleCallback === 'function') {
        window.requestIdleCallback(function() { resolve(); }, { timeout: 120 });
        return;
      }
      if (typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function') {
        window.requestAnimationFrame(function() { resolve(); });
        return;
      }
      setTimeout(resolve, 0);
    });
  }

  function pageTreeChevronSvg() {
    return '<svg class="tree-toggle-icon" viewBox="0 0 20 20" width="20" height="20" aria-hidden="true" focusable="false"><path d="M7.84 14.955c.206 0 .37-.07.505-.21l4.277-4.179a.79.79 0 0 0 .264-.574.78.78 0 0 0-.258-.574L8.35 5.24a.7.7 0 0 0-.51-.21.721.721 0 0 0-.498 1.247l3.814 3.721-3.814 3.709a.721.721 0 0 0 .498 1.248"></path></svg>';
  }

  function renderPageRows(parentId, grouped, activeId, inheritedDepth) {
    var computedDepth = Number(inheritedDepth || 0);
    var pageTreeStateView = sidebarTreeViewStateFor('pagetree');
    var pageTreeExpandedIds = pageTreeStateView.expandedIds;
    var activeParentIds = pageTreeActiveParentIds(grouped, activeId);
    return (grouped.get(parentId) || []).map(function(item) {
      var nodeId = nodeIdOf(item);
      var title = titleOf(item);
      var depth = computedDepth;
      var parent = parentIdOf(item);
      var children = grouped.get(nodeId) || [];
      var expandable = Boolean(item.expandable || item.childCount > 0 || children.length);
      var expanded = expandable && (
        pageTreeExpandedIds.has(nodeId) ||
        (!pageTreeStateView.hasUserState && (activeParentIds.has(nodeId) || item.expandedByDefault !== false))
      );
      var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {};
      var openable = Boolean(meta.documentId || item.documentId || !String(nodeId).startsWith('local-dir:'));
      var toggle = expandable
        ? '<button type="button" class="tree-toggle" data-testid="tree-node-toggle" data-rust-action="toggle" data-node-id="' + escapeHtml(nodeId) + '" aria-label="' + (expanded ? '折叠 ' : '展开 ') + escapeHtml(title) + '" aria-expanded="' + String(expanded) + '">' + pageTreeChevronSvg() + '</button>'
        : '<span class="tree-spacer" aria-hidden="true"></span>';
      var childHtml = expandable
        ? '<ul class="tree-children' + (expanded ? '' : ' tree-children--collapsed') + '">' + renderPageRows(nodeId, grouped, activeId, depth + 1) + '</ul>'
        : '';
      var currentAttr = nodeId === activeId ? ' aria-current="page" aria-selected="true"' : ' aria-selected="false"';
      return '<li class="tree-node" data-node-id="' + escapeHtml(nodeId) + '"><div class="tree-row" role="treeitem" aria-level="' + (depth + 1) + '" aria-expanded="' + String(expandable && expanded) + '" data-rust-rendered-row="page" data-testid="wolai-sidebar-row" data-tree-testid="tree-node-open" data-node-id="' + escapeHtml(nodeId) + '"' + (parent ? ' data-parent-id="' + escapeHtml(parent) + '"' : '') + ' data-depth="' + depth + '" data-shell-mode="page" data-active="' + String(nodeId === activeId) + '"' + currentAttr + ' data-focused="false" data-page-openable="' + String(openable) + '" data-draggable="true" draggable="true" tabindex="-1">' + toggle + '<button type="button" class="tree-link" data-testid="tree-node-open" data-rust-action="open" data-node-id="' + escapeHtml(nodeId) + '" data-page-openable="' + String(openable) + '" title="' + escapeHtml(title) + '"><span class="tree-link-title" title="' + escapeHtml(title) + '">' + escapeHtml(title) + '</span></button><div class="tree-actions"><button type="button" class="tree-action" data-testid="tree-action-menu" data-rust-action="menu" data-node-id="' + escapeHtml(nodeId) + '" aria-label="更多操作">…</button><button type="button" class="tree-action" data-testid="tree-action-create" data-rust-action="create" data-node-id="' + escapeHtml(nodeId) + '" aria-label="新建子页面">+</button></div></div>' + childHtml + '</li>';
    }).join('');
  }

  async function renderPageProjection(projection) {
    var generation = beginPageTreeRequest();
    var tree = document.getElementById('sidebar-tree-root');
    if (!tree) return false;
    var rows = projectionItems(projection).filter(function(item) {
      return String(item.rowKind || 'document') === 'document';
    });
    await yieldForPageTreeRender();
    if (!isLatestPageTreeRequest(generation)) {
      document.documentElement.setAttribute('data-mnote-page-tree-stale-projection-ignored', String(generation));
      return false;
    }
    var activeId = currentDocumentId();
    var template = document.createElement('template');
    template.innerHTML = '<ul class="tree-root" role="tree" data-rust-page-renderer="initial_v1">' + (rows.length ? renderPageRows('', groupRowsByParent(rows), activeId, 0) : '') + '</ul>';
    if (!isLatestPageTreeRequest(generation)) {
      document.documentElement.setAttribute('data-mnote-page-tree-stale-projection-ignored', String(generation));
      return false;
    }
    tree.replaceChildren(template.content.cloneNode(true));
    return true;
  }

  function fileDocumentId(item) {
    var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {};
    if (meta.documentId) return String(meta.documentId).trim();
    if (item && item.documentId) return String(item.documentId).trim();
    if (item && item.rowKind === 'document') return nodeIdOf(item);
    if (item && item.rowKind === 'index') return nodeIdOf(item).replace(/^index:/, '');
    return '';
  }

  function fileAssetId(item) {
    var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {};
    if (meta.assetId) return String(meta.assetId).trim();
    if (item && item.assetId) return String(item.assetId).trim();
    if (item && item.rowKind === 'asset') return nodeIdOf(item).replace(/^asset:/, '');
    return '';
  }

  function fileObjectIdentity(item) {
    var meta = item && item.resourceMeta && typeof item.resourceMeta === 'object' ? item.resourceMeta : {};
    // Phase A1: workspacePath 优先于旧猜测逻辑
    var wp = meta.workspacePath;
    if (wp && typeof wp === 'object' && wp.objectIdentity && typeof wp.objectIdentity === 'object') {
      return wp.objectIdentity;
    }
    if (meta.objectIdentity && typeof meta.objectIdentity === 'object') return meta.objectIdentity;
    var rowKind = String(item && item.rowKind || '');
    var documentId = fileDocumentId(item) || null;
    var assetId = fileAssetId(item) || null;
    var iconKind = iconKindOf(item);
    var objectKind = rowKind === 'document' ? 'page' : rowKind === 'index' ? 'index' : iconKind === 'mindmap' ? 'mindmap' : 'attachment';
    return { objectKind: objectKind, documentId: documentId, blockId: null, assetId: assetId };
  }

  function fileOwnerDocumentId(item, fallbackDocumentId, objectIdentity) {
    var identity = objectIdentity && typeof objectIdentity === 'object' ? objectIdentity : fileObjectIdentity(item);
    var owner = String(identity && identity.documentId || '').trim();
    if (owner) return owner;
    var assetId = fileAssetId(item);
    var localPath = localFilePathFromAssetId(assetId);
    if (localPath && localPath.indexOf('/') > 0) {
      var parts = localPath.split('/');
      var bundleName = parts[0] || '';
      if (bundleName) return 'local-md:' + bundleName + '~2F' + bundleName + '.md';
    }
    return String(fallbackDocumentId || '').trim();
  }

  function objectIdentityAttr(identity) {
    try {
      return JSON.stringify(identity || {});
    } catch (_error) {
      return '';
    }
  }

  function iconKindOf(item) {
    return String(item && (item.iconHint || item.rowKind || 'file') || 'file').trim() || 'file';
  }

  function fileCapabilitiesAttr(item) {
    try {
      return JSON.stringify(Array.isArray(item && item.capabilities) ? item.capabilities : []);
    } catch (_error) {
      return '[]';
    }
  }

  function isFileTreeProjectionPageRow(rowKind, assetId) {
    if (assetId) return false;
    return rowKind === 'document' || rowKind === 'doc' || rowKind === 'markdown';
  }

  function normalizeMindmapFileTreeTitle(rawTitle, assetId, iconKind, objectIdentity) {
    var title = String(rawTitle || '').trim();
    var isMindmap = iconKind === 'mindmap' || String(objectIdentity && objectIdentity.objectKind || '') === 'mindmap';
    if (!isMindmap) return title || '无标题';
    return title || shortMindmapFileName(assetId);
  }

  function renderFileRows(parentId, grouped, activeId, activeRowId) {
    var fileTreeStateView = sidebarTreeViewStateFor('filetree');
    var expandedRelativePaths = fileTreeStateView.expandedRelativePaths;
    return (grouped.get(parentId) || []).map(function(item) {
      var nodeId = nodeIdOf(item);
      var rowId = rowIdOf(item);
      var rowKind = String(item.rowKind || 'document');
      var rawTitle = titleOf(item);
      var depth = Number(item.depth || 0);
      var parent = parentIdOf(item);
      var documentId = fileDocumentId(item);
      var assetId = fileAssetId(item);
      var relativePath = fileWorkspaceRelativePath(item);
      var objectIdentity = fileObjectIdentity(item);
      var ownerDocumentId = fileOwnerDocumentId(item, documentId, objectIdentity);
      var iconKind = iconKindOf(item);
      var cachedChildren = relativePath ? cachedFileTreeRows(relativePath) : [];
      var title = isFileTreeProjectionPageRow(rowKind, assetId)
        ? fileTreePageTitle(rawTitle)
        : normalizeMindmapFileTreeTitle(rawTitle, assetId, iconKind, objectIdentity);
      var children = grouped.get(nodeId) || [];
      var expandable = Boolean(item.expandable || item.childCount > 0 || children.length || cachedChildren.length);
      var expanded = expandable && (expandedRelativePaths.has(relativePath) || (!fileTreeStateView.hasUserState && item.expandedByDefault !== false));
      var selected = activeRowId ? rowId === activeRowId : rowId === 'doc:' + activeId;
      var testId = rowKind === 'document' ? 'filetree-doc-row' : rowKind === 'index' ? 'filetree-index-row' : 'filetree-asset-row';
      var toggle = expandable
        ? '<button type="button" class="tree-toggle" data-testid="filetree-toggle" data-rust-action="toggle" data-row-id="' + escapeHtml(rowId) + '" aria-label="' + (expanded ? '折叠 ' : '展开 ') + escapeHtml(title) + '">' + (expanded ? '▾' : '▸') + '</button>'
        : '<span class="tree-spacer" aria-hidden="true"></span>';
      var createAction = rowKind === 'document'
        ? '<button type="button" class="tree-action" data-testid="filetree-create" data-rust-action="create" data-row-id="' + escapeHtml(rowId) + '" data-node-id="' + escapeHtml(documentId || nodeId) + '" aria-label="新建子页面">+</button>'
        : '';
      var childRowsHtml = children.length
        ? renderFileRows(nodeId, grouped, activeId, activeRowId)
        : cachedChildren.length
          ? renderFileRows('', groupRowsByParent(cachedChildren), activeId, activeRowId)
          : '';
      var childHtml = expandable && expanded && childRowsHtml
        ? '<ul class="tree-children">' + childRowsHtml + '</ul>'
        : '';
      return '<li class="tree-node" data-node-id="' + escapeHtml(nodeId) + '"><div class="tree-row" role="treeitem" aria-level="' + (depth + 1) + '" aria-expanded="' + String(expandable && expanded) + '" data-rust-rendered-row="filetree" data-testid="' + testId + '" data-row-id="' + escapeHtml(rowId) + '" data-row-kind="' + escapeHtml(rowKind) + '" data-node-id="' + escapeHtml(nodeId) + '"' + (parent ? ' data-parent-id="' + escapeHtml(parent) + '"' : '') + ' data-document-id="' + escapeHtml(documentId) + '" data-doc-id="' + escapeHtml(documentId) + '" data-owner-document-id="' + escapeHtml(ownerDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '" data-local-relative-path="' + escapeHtml(relativePath) + '" data-object-identity="' + escapeHtml(objectIdentityAttr(objectIdentity)) + '" data-object-kind="' + escapeHtml(String(objectIdentity.objectKind || '')) + '" data-capabilities="' + escapeHtml(fileCapabilitiesAttr(item)) + '" data-shell-mode="filetree" data-selected="' + String(selected) + '" data-active="false" draggable="true">' + toggle + '<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(rowId) + '" data-document-id="' + escapeHtml(documentId) + '" data-owner-document-id="' + escapeHtml(ownerDocumentId) + '" data-asset-id="' + escapeHtml(assetId) + '" data-local-relative-path="' + escapeHtml(relativePath) + '" title="' + escapeHtml(title) + '"><span class="tree-link-title" title="' + escapeHtml(title) + '">' + escapeHtml(title) + '</span></button><div class="tree-actions">' + createAction + '<button type="button" class="tree-action" data-testid="filetree-action-menu" data-rust-action="menu" data-row-id="' + escapeHtml(rowId) + '" aria-label="更多操作">…</button></div></div>' + childHtml + '</li>';
    }).join('');
  }

  function ensureFileTreeLazyCacheScope() {
    var rootUri = currentRootUri();
    var scope = currentFileTreeScope();
    if (rootUri === fileTreeLazyCacheRootUri && scope === fileTreeState.scope) return;
    fileTreeLazyCacheRootUri = rootUri;
    fileTreeState.rootUri = rootUri;
    fileTreeState.scope = scope;
    fileTreeState.rowsByParent.clear();
    fileTreeState.loadedParents.clear();
    fileTreeState.loadingParents.clear();
    fileTreeState.dirtyParents.clear();
    fileTreeState.staleParents.clear();
    fileTreeState.revisionByParent.clear();
    fileTreeState.latestGenerationByParent.clear();
    fileTreeState.requestGeneration += 1;
    var nextState = sidebarTreeViewStateFor('filetree');
    fileTreeExpandedRelativePaths = nextState.expandedRelativePaths;
    fileTreeViewState.expandedParents = nextState.expandedRelativePaths;
    loadStoredFileTreeExpansionState(rootUri);
  }

  function storedFileTreeExpansionBuckets() {
    try {
      if (!window.sessionStorage) return {};
      var parsed = JSON.parse(window.sessionStorage.getItem(FILETREE_EXPANSION_STORAGE_KEY) || '{}');
      return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {};
    } catch (_) {
      return {};
    }
  }

  function loadStoredFileTreeExpansionState(rootUri) {
    var normalizedRootUri = String(rootUri || '').trim();
    if (!normalizedRootUri || fileTreeExpansionStorageRootUri === normalizedRootUri) return;
    fileTreeExpansionStorageRootUri = normalizedRootUri;
    var state = sidebarTreeViewStateFor('filetree');
    if (state.hasUserState && state.expandedRelativePaths.size) return;
    var buckets = storedFileTreeExpansionBuckets();
    var paths = Array.isArray(buckets[normalizedRootUri]) ? buckets[normalizedRootUri] : [];
    paths.forEach(function(path) {
      var normalized = String(path || '').trim();
      if (normalized) state.expandedRelativePaths.add(normalized);
    });
    if (state.expandedRelativePaths.size) {
      state.hasUserState = true;
      state.source = 'legacy';
      fileTreeExpandedRelativePaths = state.expandedRelativePaths;
      fileTreeViewState.expandedParents = state.expandedRelativePaths;
      persistSidebarTreeViewState('filetree');
    }
  }

  function persistFileTreeExpansionState() {
    var rootUri = String(currentRootUri() || fileTreeLazyCacheRootUri || '').trim();
    if (!rootUri) return;
    var state = sidebarTreeViewStateFor('filetree');
    try {
      if (!window.sessionStorage) return;
      var buckets = storedFileTreeExpansionBuckets();
      buckets[rootUri] = Array.from(state.expandedRelativePaths)
        .map(function(path) { return String(path || '').trim(); })
        .filter(Boolean)
        .slice(0, 256);
      window.sessionStorage.setItem(FILETREE_EXPANSION_STORAGE_KEY, JSON.stringify(buckets));
    } catch (_) {}
  }

  function scheduleRestorePersistedFileTreeExpansionState() {
    if (fileTreeExpansionRestoreTimer) window.clearTimeout(fileTreeExpansionRestoreTimer);
    fileTreeExpansionRestoreTimer = window.setTimeout(function() {
      fileTreeExpansionRestoreTimer = 0;
      restorePersistedFileTreeExpansionState();
    }, 0);
  }

  function rememberFileTreeExpansionState() {
    var changed = false;
    document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]').forEach(function(row) {
      if (!(row instanceof HTMLElement)) return;
      var relativePath = localFileTreeRelativePathFromRow(row);
      if (!relativePath) return;
      if (row.getAttribute('aria-expanded') === 'true') {
        if (!fileTreeExpandedRelativePaths.has(relativePath)) changed = true;
        fileTreeExpandedRelativePaths.add(relativePath);
      } else {
        if (fileTreeExpandedRelativePaths.has(relativePath)) changed = true;
        fileTreeExpandedRelativePaths.delete(relativePath);
      }
    });
    if (changed) persistFileTreeExpansionState();
  }

  function rememberFileTreeSelectionState() {
    fileTreeViewState.selectedRowIds.clear();
    fileTreeViewState.focusedRowId = '';
    fileTreeViewState.activeRowId = '';
    document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]').forEach(function(row) {
      if (!(row instanceof HTMLElement)) return;
      var rowId = String(row.getAttribute('data-row-id') || '').trim();
      if (!rowId) return;
      if (row.getAttribute('data-selected') === 'true') fileTreeViewState.selectedRowIds.add(rowId);
      if (row.getAttribute('data-focused') === 'true') fileTreeViewState.focusedRowId = rowId;
      if (row.getAttribute('data-active') === 'true') fileTreeViewState.activeRowId = rowId;
    });
  }

  function reprojectFileTreeSelectionState() {
    document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]').forEach(function(row) {
      if (!(row instanceof HTMLElement)) return;
      var rowId = String(row.getAttribute('data-row-id') || '').trim();
      row.setAttribute('data-selected', String(fileTreeViewState.selectedRowIds.has(rowId)));
      row.setAttribute('data-focused', String(rowId === fileTreeViewState.focusedRowId));
      if (fileTreeViewState.activeRowId) {
        row.setAttribute('data-active', String(rowId === fileTreeViewState.activeRowId));
      }
    });
  }

  function renderFileProjection(projection) {
    var tree = document.getElementById('sidebar-file-tree-root');
    if (!tree) return false;
    ensureFileTreeLazyCacheScope();
    rememberFileTreeExpansionState();
    rememberFileTreeSelectionState();
    var rows = projectionItems(projection);
    var parentRelativePath = projectionParentRelativePath(projection) || currentFileTreeScope();
    rememberFileTreeProjection(parentRelativePath, rows, projection);
    if (!isFileTreeRootProjectionParent(parentRelativePath)) {
      return patchFileTreeParentChildren(parentRelativePath, rows);
    }
    var activeId = currentDocumentId();
    var activeRowId = currentFileTreeActiveRowId();
    var template = document.createElement('template');
    template.innerHTML = '<ul class="tree-root" role="tree" data-rust-filetree-renderer="initial_v1">' + (rows.length ? renderFileRows('', groupRowsByParent(rows), activeId, activeRowId) : '') + '</ul>';
    tree.replaceChildren(template.content.cloneNode(true));
    reprojectFileTreeSelectionState();
    scheduleRestorePersistedFileTreeExpansionState();
    return true;
  }

  function patchFileTreeParentChildren(parentRelativePath, rows) {
    var row = fileTreeRowByRelativePath(parentRelativePath);
    if (!(row instanceof HTMLElement)) return true;
    var node = row.closest('.tree-node');
    if (!node) return true;
    rememberFileTreeSelectionState();
    var button = row.querySelector('[data-rust-action="toggle"]');
    var wasExpanded = row.getAttribute('aria-expanded') === 'true';
    var children = node.querySelector(':scope > .tree-children');
    if (!children && !wasExpanded && row.getAttribute('data-filetree-children-loaded') !== 'true') {
      return true;
    }
    if (!children) {
      children = document.createElement('ul');
      children.className = 'tree-children';
      node.appendChild(children);
    }
    var template = document.createElement('template');
    template.innerHTML = renderFileRows('', groupRowsByParent(rows), currentDocumentId(), currentFileTreeActiveRowId());
    children.replaceChildren(template.content.cloneNode(true));
    children.classList.toggle('tree-children--collapsed', !wasExpanded);
    row.setAttribute('data-filetree-children-loaded', 'true');
    row.removeAttribute('data-filetree-children-loading');
    setTreeRowExpanded(row, button, wasExpanded);
    syncSidebarFileTreeSelection();
    reprojectFileTreeSelectionState();
    return true;
  }

  function renderSidebarSnapshot(payload) {
    var renderedPage = false;
    if (hasProjectionItems(payload)) {
      renderedPage = true;
      void renderPageProjection(payload);
    }
    var fileProjection = readDatasetProjection(payload, 'kernel_file_tree_projection', 'kernelFileTreeProjection');
    var renderedFile = fileProjection && hasProjectionItems(fileProjection) ? renderFileProjection(fileProjection) : false;
    return renderedPage || renderedFile;
  }

  function renderLiveSidebarSnapshot(payload) {
    var renderedPage = false;
    if (hasProjectionItems(payload)) {
      renderedPage = true;
      void renderPageProjection(payload);
    }
    var fileProjection = readDatasetProjection(payload, 'kernel_file_tree_projection', 'kernelFileTreeProjection');
    var hasFileProjection = fileProjection && hasProjectionItems(fileProjection);
    if (currentFileTreeScope()) {
      if (!hasFileProjection) return renderedPage;
      var projectionParent = projectionParentRelativePath(fileProjection);
      if (isFileTreeRootProjectionParent(projectionParent)) {
        return renderFileProjection(fileProjection) || renderedPage;
      }
      document.documentElement.setAttribute('data-mnote-filetree-scoped-live-snapshot-ignored', projectionParent || 'root');
      return true;
    }
    var renderedFile = hasFileProjection ? renderFileProjection(fileProjection) : false;
    return renderedPage || renderedFile;
  }

  function replaceSidebarTreeFromDocument(nextDocument, rootId) {
    var runtimeFn = fileTreeRuntimeFunction('replaceSidebarTreeFromDocument');
    if (runtimeFn) return runtimeFn(nextDocument, rootId);
    var current = document.getElementById(rootId);
    var next = nextDocument ? nextDocument.getElementById(rootId) : null;
    if (!(current instanceof HTMLElement) || !(next instanceof HTMLElement)) return false;
    current.innerHTML = next.innerHTML;
    Array.from(next.attributes || []).forEach(function(attr) {
      current.setAttribute(attr.name, attr.value);
    });
    return true;
  }

  function applyLocalFolderSidebarSnapshot(nextDocument, options) {
    var runtimeFn = fileTreeRuntimeFunction('applyLocalFolderSidebarSnapshot');
    if (runtimeFn) return runtimeFn(nextDocument, options);
    options = options || {};
    var pageRootId = String(options.pageRootId || 'sidebar-tree-root');
    var fileRootId = String(options.fileRootId || 'sidebar-file-tree-root');
    var appliedPage = replaceSidebarTreeFromDocument(nextDocument, pageRootId);
    var appliedFile = replaceSidebarTreeFromDocument(nextDocument, fileRootId);
    var applied = appliedPage || appliedFile;
    if (applied && typeof options.onApplied === 'function') options.onApplied({
      pageRootApplied: appliedPage,
      fileRootApplied: appliedFile
    });
    return applied;
  }

  function markLocalFolderWatchApplied(value) {
    var runtimeFn = fileTreeRuntimeFunction('markLocalFolderWatchApplied');
    if (runtimeFn) return runtimeFn(value);
    var appliedValue = String(value || 'projection');
    document.documentElement.setAttribute('data-mnote-local-folder-watch-applied', appliedValue);
    return true;
  }

  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() : '';
  }

  async function fetchFileTreeProjection(parentRelativePath, options) {
    options = options || {};
    var rootUri = currentRootUri();
    if (!rootUri) return null;
    var url = new URL(options.childrenOnly ? '/api/tree/projections/file/children' : '/api/tree/projections/file', window.location.origin);
    var workspaceId = currentWorkspaceId();
    if (workspaceId) url.searchParams.set('workspaceId', workspaceId);
    url.searchParams.set('sourceKind', 'local_folder');
    url.searchParams.set('rootUri', rootUri);
    if (parentRelativePath) url.searchParams.set('parentRelativePath', parentRelativePath);
    var currentId = currentDocumentId();
    if (!options.childrenOnly && currentId) url.searchParams.set('rootNodeId', currentId);
    var response = await fetch(url.toString(), { headers: { accept: 'application/json' } });
    var payload = await response.json().catch(function() { return null; });
    if (!response.ok) throw new Error(payload && (payload.error || payload.message) || 'filetree_projection_failed_' + response.status);
    return readProjection(payload && (payload.result || payload));
  }

  async function refreshFileTreeParent(parentRelativePath) {
    ensureFileTreeLazyCacheScope();
    var key = currentFileTreeParentKey(parentRelativePath);
    fileTreeState.dirtyParents.add(key);
    if (!isFileTreeRootProjectionParent(parentRelativePath)) {
      var row = fileTreeRowByRelativePath(parentRelativePath);
      if (row instanceof HTMLElement && row.getAttribute('aria-expanded') !== 'true') {
        markFileTreeParentStale(key);
        return true;
      }
    }
    if (fileTreeState.loadingParents.has(key)) {
      return fileTreeState.loadingParents.get(key).then(function(rows) {
        fileTreeState.dirtyParents.delete(key);
        return isFileTreeRootProjectionParent(parentRelativePath)
          ? renderFileProjection({ parentRelativePath: parentRelativePath, items: rows })
          : patchFileTreeParentChildren(parentRelativePath, rows);
      });
    }
    var projection = await fetchFileTreeProjection(parentRelativePath, { childrenOnly: false });
    if (!projection) return false;
    return renderFileProjection(projection);
  }

  async function refreshLocalFolderSidebarSnapshot() {
    var workspaceId = currentWorkspaceId();
    var rootUri = currentRootUri();
    var currentId = currentDocumentId();
    var fileTreeScope = currentFileTreeScope();
    if (!workspaceId || !rootUri) return false;

    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);
    if (currentId) sidebarUrl.searchParams.set('rootNodeId', currentId);
    if (fileTreeScope) sidebarUrl.searchParams.set('parentRelativePath', fileTreeScope);
    var responses = await Promise.allSettled([
      fetch(sidebarUrl.toString(), { headers: { accept: 'application/json' } }),
      refreshFileTreeParent(fileTreeScope)
    ]);
    var sidebarResponse = responses[0].status === 'fulfilled' ? responses[0].value : null;
    var renderedFile = responses[1].status === 'fulfilled' ? responses[1].value : false;
    if ((!sidebarResponse || !sidebarResponse.ok) && !renderedFile) return false;

    var sidebarPayload = sidebarResponse && sidebarResponse.ok ? await sidebarResponse.json().catch(function() { return null; }) : null;
    var resolvedSidebarPayload = sidebarPayload ? (sidebarPayload.result || sidebarPayload) : null;
    var renderedPage = false;
    if (resolvedSidebarPayload && hasProjectionItems(resolvedSidebarPayload)) {
      renderedPage = true;
      void renderPageProjection(resolvedSidebarPayload);
    }
    if (renderedFile && fileTreeScope) {
      var fileRoot = document.getElementById('sidebar-file-tree-root');
      if (fileRoot instanceof HTMLElement) fileRoot.setAttribute('data-mnote-filetree-scope', fileTreeScope);
      document.documentElement.setAttribute('data-mnote-filetree-scope', fileTreeScope);
    }
    if (!renderedPage && !renderedFile) return false;
    syncSidebarFileTreeSelection();
    schedulePendingLocalFolderRestoreFocus();
    restoreSidebarTreeTab();
    refreshEditorLocalAttachmentExistence();
    markLocalFolderWatchApplied('projection');
    return true;
  }

  function startLocalFolderSidebarWatch() {
    if (currentSourceKind() !== 'local_folder') return;
    var rootUri = currentRootUri();
    if (!rootUri) return;
    ensureFileTreeLazyCacheScope();
    scheduleRestorePersistedFileTreeExpansionState();
    var revision = '';
    var refreshTimer = 0;
    var treeLiveEventsActive = function() {
      var treeTransport = document.documentElement.getAttribute('data-mnote-tree-live-transport') || '';
      return treeTransport === 'local-folder-events';
    };
    var scheduleRefresh = function() {
      if (treeLiveEventsActive()) return;
      if (refreshTimer) return;
      refreshTimer = window.setTimeout(function() {
        refreshTimer = 0;
        if (treeLiveEventsActive()) return;
        var fileTreeScope = currentFileTreeScope();
        if (fileTreeScope) {
          markFileTreeParentStale(currentFileTreeParentKey(fileTreeScope));
          markLocalFolderWatchApplied('scope_stale');
          document.documentElement.setAttribute('data-mnote-filetree-scope-watch-stale', fileTreeScope);
          return;
        }
        void refreshLocalFolderSidebarSnapshot();
      }, 180);
    };
    var poll = async function() {
      if (document.hidden) return;
      // If tree live SSE transport is active for local_folder, skip polling (fallback)
      if (treeLiveEventsActive()) return;
      var url = new URL('/api/tree/local-folder-watch', window.location.origin);
      url.searchParams.set('rootUri', rootUri);
      var response = await fetch(url.toString(), { headers: { accept: 'application/json' } });
      if (!response.ok) return;
      if (treeLiveEventsActive()) return;
      var payload = await response.json();
      var nextRevision = payload && payload.result && typeof payload.result.revision === 'string'
        ? payload.result.revision
        : '';
      if (!nextRevision) return;
      if (!revision) {
        revision = nextRevision;
        return;
      }
      if (nextRevision !== revision) {
        revision = nextRevision;
        scheduleRefresh();
      }
    };
    window.setInterval(function() {
      void poll();
    }, 1200);
    void poll();
  }

  function isTitleOnlyDocumentPatch(candidate) {
    if (!candidate || typeof candidate !== 'object') return false;
    var allowedKeys = {
      id: true,
      documentId: true,
      title: true,
      updatedAt: true,
      updated_at: true
    };
    return Object.keys(candidate).every(function(key) {
      return allowedKeys[key] === true;
    });
  }

  function deltaNeedsProjectionRefresh(payload) {
    var data = payload && (payload.data || payload.delta || payload);
    var op = data && typeof data.op === 'string' ? String(data.op).trim() : '';
    if (!op || op === 'noop') return false;
    if (op === 'upsert_document') {
      return !isTitleOnlyDocumentPatch(data.node || data.document || null);
    }
    if (op === 'upsert_documents') {
      var documents = Array.isArray(data.upsertDocuments) ? data.upsertDocuments : Array.isArray(data.upsert_documents) ? data.upsert_documents : [];
      if (documents.length > 0 && documents.every(isTitleOnlyDocumentPatch)) {
        return false;
      }
    }
    return true;
  }

  function localFileTreeRelativePathFromRow(row) {
    if (!(row instanceof HTMLElement)) return '';
    var direct = String(row.getAttribute('data-local-relative-path') || '').trim();
    if (direct) return direct;
    var runtimeFn = fileTreeRuntimeFunction('fileTreeRowLocalRelativePath');
    if (runtimeFn) {
      try {
        return String(runtimeFn(row, { localFilePathFromAssetId: localFilePathFromAssetId }) || '').trim();
      } catch (_) {}
    }
    var rowId = String(row.getAttribute('data-row-id') || '').trim();
    var nodeId = String(row.getAttribute('data-node-id') || '').trim();
    if (rowId.indexOf('local:folder:') === 0) return rowId.slice('local:folder:'.length);
    if (rowId.indexOf('local:markdown:') === 0) return rowId.slice('local:markdown:'.length);
    if (rowId.indexOf('local:asset:') === 0) return rowId.slice('local:asset:'.length);
    if (nodeId.indexOf('local:node:') === 0) return nodeId.slice('local:node:'.length);
    return '';
  }

  function setTreeRowExpanded(row, button, expanded) {
    row.setAttribute('aria-expanded', expanded ? 'true' : 'false');
    var shellMode = row.getAttribute('data-shell-mode') || '';
    if (button) {
      button.setAttribute('aria-expanded', expanded ? 'true' : 'false');
      if (shellMode === 'filetree') button.textContent = expanded ? '▾' : '▸';
    }
    if (shellMode === 'page') {
      var nodeId = String(row.getAttribute('data-node-id') || '').trim();
      if (!nodeId) return;
      var pageState = sidebarTreeViewStateFor('pagetree');
      if (expanded) pageState.expandedIds.add(nodeId);
      else pageState.expandedIds.delete(nodeId);
      pageState.hasUserState = true;
      persistSidebarTreeViewState('pagetree');
      return;
    }
    var relativePath = localFileTreeRelativePathFromRow(row);
    if (!relativePath) return;
    if (expanded) fileTreeExpandedRelativePaths.add(relativePath);
    else fileTreeExpandedRelativePaths.delete(relativePath);
    persistFileTreeExpansionState();
    persistSidebarTreeViewState('filetree');
  }

  function markExistingFileTreeChildrenLoaded(row, button) {
    if (!(row instanceof HTMLElement)) return false;
    var node = row.closest('.tree-node');
    if (!node) return false;
    var children = node.querySelector(':scope > .tree-children');
    if (!(children instanceof HTMLElement)) return false;
    row.setAttribute('data-filetree-children-loaded', 'true');
    children.classList.remove('tree-children--collapsed');
    setTreeRowExpanded(row, button, true);
    syncSidebarFileTreeSelection();
    return true;
  }

  function renderCachedFileTreeChildren(row, button, relativePath) {
    var key = currentFileTreeParentKey(relativePath);
    if (fileTreeState.staleParents.has(key) || fileTreeState.dirtyParents.has(key)) return false;
    var cachedRows = cachedFileTreeRows(relativePath);
    if (!cachedRows.length) return false;
    var node = row.closest('.tree-node');
    if (!node) return false;
    var children = node.querySelector(':scope > .tree-children');
    if (!children) {
      children = document.createElement('ul');
      children.className = 'tree-children';
      node.appendChild(children);
    }
    var template = document.createElement('template');
    template.innerHTML = renderFileRows('', groupRowsByParent(cachedRows), currentDocumentId(), currentFileTreeActiveRowId());
    children.replaceChildren(template.content.cloneNode(true));
    children.classList.remove('tree-children--collapsed');
    row.setAttribute('data-filetree-children-loaded', 'true');
    setTreeRowExpanded(row, button, true);
    syncSidebarFileTreeSelection();
    return true;
  }

  async function getFileTreeChildren(parentRelativePath) {
    ensureFileTreeLazyCacheScope();
    var key = currentFileTreeParentKey(parentRelativePath);
    if (fileTreeState.loadedParents.has(key) && !fileTreeState.dirtyParents.has(key) && !fileTreeState.staleParents.has(key)) {
      return fileTreeState.rowsByParent.get(key) || [];
    }
    if (fileTreeState.loadingParents.has(key)) {
      return fileTreeState.loadingParents.get(key);
    }
    var generation = beginFileTreeRequest(key);
    var promise = fetchFileTreeProjection(parentRelativePath, { childrenOnly: true }).then(function(projection) {
      if (!isLatestFileTreeRequest(key, generation)) {
        return fileTreeState.rowsByParent.get(key) || [];
      }
      var rows = projectionItems(projection);
      rememberFileTreeProjection(parentRelativePath, rows, projection);
      return rows;
    }).finally(function() {
      fileTreeState.loadingParents.delete(key);
    });
    fileTreeState.loadingParents.set(key, promise);
    return promise;
  }

  async function loadFileTreeChildren(row, button) {
    if (!(row instanceof HTMLElement)) return false;
    if (row.getAttribute('data-shell-mode') !== 'filetree') return false;
    if (currentSourceKind() !== 'local_folder') return false;
    ensureFileTreeLazyCacheScope();
    var relativePath = localFileTreeRelativePathFromRow(row);
    var key = currentFileTreeParentKey(relativePath);
    var stale = fileTreeState.staleParents.has(key) || fileTreeState.dirtyParents.has(key);
    if (!stale && markExistingFileTreeChildrenLoaded(row, button)) return true;
    if (!stale && relativePath && renderCachedFileTreeChildren(row, button, relativePath)) return true;
    if (row.getAttribute('data-filetree-children-loaded') === 'true') return false;
    var rootUri = currentRootUri();
    if (!rootUri || !relativePath) return false;
    setTreeRowExpanded(row, button, true);
    row.setAttribute('data-filetree-children-loading', 'true');
    try {
      var rows = await getFileTreeChildren(relativePath);
      if (!rows.length) {
        row.setAttribute('data-filetree-children-loaded', 'true');
        setTreeRowExpanded(row, button, true);
        return true;
      }
      return renderCachedFileTreeChildren(row, button, relativePath);
    } catch (error) {
      setTreeLiveApplyError(error && error.message ? error.message : '文件树子目录加载失败');
      return false;
    } finally {
      row.removeAttribute('data-filetree-children-loading');
    }
  }

  function fileTreeParentChainForRelativePath(relativePath) {
    var normalized = normalizeFileTreeRelativePath(relativePath);
    if (!normalized) return [];
    var parts = normalized.split('/').filter(Boolean);
    parts.pop();
    var chain = [];
    for (var index = 0; index < parts.length; index += 1) {
      chain.push(parts.slice(0, index + 1).join('/'));
    }
    return chain;
  }

  async function revealFileTreeResource(input) {
    input = input || {};
    var rootUri = String(input.rootUri || currentRootUri() || '').trim();
    if (!rootUri || rootUri !== currentRootUri()) return false;
    ensureFileTreeLazyCacheScope();
    var relativePath = normalizeFileTreeRelativePath(input.relativePath || input.relative_path || '');
    var rowId = String(input.rowId || input.row_id || '').trim();
    var parentChain = fileTreeParentChainForRelativePath(relativePath);
    for (var index = 0; index < parentChain.length; index += 1) {
      var parentRelativePath = parentChain[index];
      var parentRow = fileTreeRowByRelativePath(parentRelativePath);
      if (!(parentRow instanceof HTMLElement)) continue;
      var button = parentRow.querySelector('[data-rust-action="toggle"]');
      await getFileTreeChildren(parentRelativePath);
      renderCachedFileTreeChildren(parentRow, button, parentRelativePath);
      setTreeRowExpanded(parentRow, button, true);
    }
    var targetRow = rowId
      ? document.querySelector('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"][data-row-id="' + cssEscape(rowId) + '"]')
      : null;
    if (!(targetRow instanceof HTMLElement) && relativePath) {
      targetRow = fileTreeRowByRelativePath(relativePath);
    }
    if (!(targetRow instanceof HTMLElement)) return false;
    var targetRowId = String(targetRow.getAttribute('data-row-id') || rowId || '').trim();
    if (targetRowId) {
      fileTreeViewState.selectedRowIds = new Set([targetRowId]);
      fileTreeViewState.focusedRowId = targetRowId;
      fileTreeViewState.activeRowId = targetRowId;
    }
    reprojectFileTreeSelectionState();
    try { targetRow.scrollIntoView({ block: 'nearest' }); } catch (_) {}
    return true;
  }

  function toggleChildren(row, button) {
    var li = row && row.parentElement;
    var children = li ? li.querySelector(':scope > .tree-children') : null;
    if (!children) {
      void loadFileTreeChildren(row, button);
      return;
    }
    children.classList.toggle('tree-children--collapsed');
    var collapsed = children.classList.contains('tree-children--collapsed');
    setTreeRowExpanded(row, button, !collapsed);
  }

  function restorePersistedFileTreeExpansionState() {
    if (currentSourceKind() !== 'local_folder') return false;
    ensureFileTreeLazyCacheScope();
    if (!fileTreeExpandedRelativePaths.size) return false;
    var restored = false;
    document.querySelectorAll('#sidebar-file-tree-root .tree-row[data-shell-mode="filetree"]').forEach(function(row) {
      if (!(row instanceof HTMLElement)) return;
      if (String(row.getAttribute('data-row-kind') || '').trim() !== 'folder') return;
      var relativePath = localFileTreeRelativePathFromRow(row);
      if (!relativePath || !fileTreeExpandedRelativePaths.has(relativePath)) return;
      var button = row.querySelector('[data-rust-action="toggle"]');
      if (markExistingFileTreeChildrenLoaded(row, button)) {
        restored = true;
        return;
      }
      if (row.getAttribute('data-filetree-children-loaded') === 'true') {
        setTreeRowExpanded(row, button, true);
        restored = true;
        return;
      }
      void loadFileTreeChildren(row, button).then(function(loaded) {
        if (loaded) restorePersistedFileTreeExpansionState();
      });
      restored = true;
    });
    if (restored) document.documentElement.setAttribute('data-mnote-filetree-expansion-restored', 'true');
    return restored;
  }


  function installTreeLiveApplyEventListeners() {
    sidebarTreeViewStateFor('pagetree');
    document.addEventListener('visibilitychange', function() {
      if (!document.hidden) return;
      flushPendingSidebarTreeViewState('filetree');
      flushPendingSidebarTreeViewState('pagetree');
    });
    window.addEventListener('pagehide', function() {
      flushPendingSidebarTreeViewState('filetree');
      flushPendingSidebarTreeViewState('pagetree');
    });

    window.addEventListener('tree:title-updated', function(event) {
    var detail = event.detail || {};
    var previousDocumentId = detail.previousDocumentId || (detail.payload && detail.payload.result && detail.payload.result.previousDocumentId) || '';
    if (previousDocumentId && previousDocumentId !== detail.documentId) {
      removeDocumentRowForMode('page', previousDocumentId);
      removeDocumentRowForMode('filetree', previousDocumentId);
      if (currentDocumentId() === previousDocumentId) {
        navigateToDocument(detail.documentId, detail.workspaceId || currentWorkspaceId(), { treeView: activeSidebarTreeMode() });
      }
    }
    updateTitleEverywhere(detail.documentId, detail.title);
    if (currentSourceKind() === 'local_folder') void refreshLocalFolderSidebarSnapshot();
    document.documentElement.setAttribute('data-mnote-title-local-applied', 'true');
    });

    window.addEventListener('tree:local-command', function(event) {
    var detail = event.detail || {};
    var body = detail.body || {};
    var action = String(body.action || '').trim();
    var result = detail.result || {};
    if (action === 'create') {
      applyCreatedDocumentLocally(result, body.parentId || null, body.title || '新页面');
      refreshLocalFolderAfterCommand(action, result, body);
      return;
    }
    if (action === 'rename' && body.documentId && body.title) {
      var newDocumentId = commandDocumentId(result, body.documentId);
      if (newDocumentId && newDocumentId !== body.documentId) {
        removeDocumentRowForMode('page', body.documentId);
        removeDocumentRowForMode('filetree', body.documentId);
        if (currentDocumentId() === body.documentId) {
          navigateToDocument(newDocumentId, body.workspaceId || currentWorkspaceId(), { treeView: activeSidebarTreeMode() });
        }
      } else {
        updateTitleEverywhere(body.documentId, body.title);
      }
      refreshLocalFolderAfterCommand(action, result, body);
      document.documentElement.setAttribute('data-mnote-tree-local-command-applied', 'rename');
      return;
    }
    if (action === 'move' && body.documentId) {
      if (applyMoveDocumentDelta({ documentId: body.documentId, parentId: body.parentId || null, sortOrder: body.sortOrder })) {
        document.documentElement.setAttribute('data-mnote-tree-local-command-applied', 'move');
      }
      refreshLocalFolderAfterCommand(action, result, body);
      return;
    }
    if ((action === 'purge' || action === 'delete' || action === 'archive') && body.documentId) {
      if (applyRemoveDocumentDelta({ documentId: body.documentId })) {
        document.documentElement.setAttribute('data-mnote-tree-local-command-applied', 'remove');
      }
      refreshLocalFolderAfterCommand(action, result, body);
    }
    });

    window.addEventListener('tree:local-command-batch-complete', function(event) {
    var detail = event.detail || {};
    flushFileTreeBatchRefresh(detail.batchId || detail.batch_id || '');
    });

    window.addEventListener('tree:snapshot', function(event) {
    var payload = event.detail && event.detail.payload ? event.detail.payload : event.detail;
    if (renderLiveSidebarSnapshot(payload)) {
      document.documentElement.setAttribute('data-mnote-tree-live-applied', 'snapshot');
      return;
    }
    setTreeLiveApplyError('tree_snapshot_missing_projection_payload');
    });

    window.addEventListener('tree:delta', function(event) {
    var payload = event.detail && event.detail.payload ? event.detail.payload : event.detail;
    var data = payload && (payload.data || payload.delta || payload);
    var documentPatch = data && (data.document || data.node);
    if (data && data.op === 'upsert_document' && documentPatch) {
      updateTitleEverywhere(documentPatch.id || documentPatch.documentId, documentPatch.title || '无标题');
    }
    if (data && data.op === 'move_document' && applyMoveDocumentDelta(data)) {
      document.documentElement.setAttribute('data-mnote-tree-live-applied', 'delta');
      return;
    }
    if (data && data.op === 'remove_document' && applyRemoveDocumentDelta(data)) {
      document.documentElement.setAttribute('data-mnote-tree-live-applied', 'delta');
      return;
    }
    var documents = data && (data.upsertDocuments || data.upsert_documents);
    if (Array.isArray(documents)) {
      documents.forEach(function(doc) {
        updateTitleEverywhere(doc.id || doc.documentId, doc.title || '无标题');
      });
    }
    if (renderLiveSidebarSnapshot(payload)) {
      document.documentElement.setAttribute('data-mnote-tree-live-applied', 'delta');
      return;
    }
    document.documentElement.setAttribute('data-mnote-tree-live-applied', 'delta');
    if (deltaNeedsProjectionRefresh(payload)) {
      setTreeLiveApplyError('tree_delta_missing_projection_payload');
    }
    });

    window.addEventListener('tree:resync', function(event) {
    var payload = event.detail && event.detail.payload ? event.detail.payload : event.detail;
    if (renderLiveSidebarSnapshot(payload)) {
      refreshEditorLocalAttachmentExistence();
      document.documentElement.setAttribute('data-mnote-tree-live-applied', 'resync');
      return;
    }
    document.documentElement.setAttribute('data-mnote-tree-live-applied', 'resync');
    setTreeLiveApplyError('tree_resync_missing_projection_payload');
    });

    window.addEventListener('tree:local-folder-watch-batch', function(event) {
    var payload = event.detail && event.detail.payload ? event.detail.payload : event.detail;
    applyLocalFolderWatchBatch(payload);
    });

    window.addEventListener('tree:error', function(event) {
    var payload = event.detail && event.detail.payload ? event.detail.payload : event.detail;
    var code = payload && (payload.code || payload.error || payload.message);
    document.documentElement.setAttribute('data-mnote-tree-live-error-schema', String(payload && payload.schema || ''));
    setTreeLiveApplyError(code || 'tree_live_error');
    });
  }

  return {
    applyCreatedDocumentLocally,
    applyMoveDocumentDelta,
    applyRemoveDocumentDelta,
    commandDocumentId,
    commandDocumentTitle,
    deltaNeedsProjectionRefresh,
    fileTreePageTitle,
    flushFileTreeBatchRefresh,
    installTreeLiveApplyEventListeners,
    isFileTreePageRow,
    applyLocalFolderWatchBatch,
    localCommandNeedsProjectionRefresh,
    normalizeFileTreePageRenameTitle,
    objectIdentityAttr,
    refreshLocalFolderSidebarSnapshot,
    refreshLocalFolderAfterCommand,
    removeDocumentRowForMode,
    renderSidebarSnapshot,
    revealFileTreeResource,
    restorePersistedFileTreeExpansionState,
    setTreeLiveApplyError,
    startLocalFolderSidebarWatch,
    toggleChildren,
    updateTitleEverywhere,
    validateFileTreeRename,
  };
};
