From bb3f260faceb1a667ec5cd6a1e9d8ce554a1315d Mon Sep 17 00:00:00 2001 From: cmliu Date: Fri, 31 Jul 2026 01:44:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=20expandNode=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E7=9A=84=20silent=20=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E4=BB=A5=E6=94=AF=E6=8C=81=E9=9D=99=E9=BB=98=E9=87=8D=E6=A0=B9?= =?UTF-8?q?=EF=BC=8C=E4=BC=98=E5=8C=96=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/file-tree.ts | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/frontend/src/file-tree.ts b/frontend/src/file-tree.ts index e6e3bed..44ed654 100644 --- a/frontend/src/file-tree.ts +++ b/frontend/src/file-tree.ts @@ -437,7 +437,7 @@ export class FileTree { * - `loadToken` — per-node: a newer expand/collapse superseded this fetch. * - `treeEpoch` — per-tree: the whole tree was torn down while awaiting. */ - private async expandNode(node: TreeNode): Promise { + private async expandNode(node: TreeNode, silent = false): Promise { if (!this.isExpandable(node) || node.state === 'expanded' || node.state === 'loading') return; // Capture the tree generation this call belongs to. @@ -469,6 +469,32 @@ export class FileTree { if (epoch !== this.treeEpoch || !this.ready || !this.root) return; if (token !== node.loadToken) return; + // ── Silent re-rooting for setCwd auto-expansion ───────────────── + // When setCwd triggers expandToPath and an ancestor node fetch fails + // (e.g. Permission denied on root in a restricted shell), silently + // re-root the tree to cwd so users can still browse their accessible + // directory. Manual expand (user click/keyboard) does NOT pass + // silent=true, so those errors still surface via the error path below. + if (silent) { + const cwd = this.selectedPath; + if (cwd && isDescendantPath(node.path, cwd)) { + if (node.path !== cwd) { + // Failed node is a strict ancestor of cwd: switch root to cwd + // then expand the new root so the user sees their directory. + this.setRootPath(cwd); + const newRoot = this.root; + if (newRoot) void this.expandNode(newRoot); + } else { + // Failed node is cwd itself: leave it as a collapsed leaf + // without surfacing an error. + node.state = 'collapsed'; + this.refreshRowContent(node); + } + return; + } + } + // ── End silent re-rooting ──────────────────────────────────────── + node.state = 'error'; node.children = null; this.removeDescendantRows(node); @@ -521,7 +547,7 @@ export class FileTree { // Ensure current is expanded so we can search its children if (current.state !== 'expanded') { - await this.expandNode(current); + await this.expandNode(current, true); if (token !== this.setCwdToken) return; // cancelled }