fix: "Show in folder" reveals in the explorer instead of opening a directory in the editor

The open-path interception reroutes EVERY chat-side file open into the
sidebar editor, including the stock "Show in folder" gesture: the
ui-deliverables row passes "." (resolved to "<cwd>/." by the chat view),
so clicking it opened a bogus editor tab for the workspace directory
(host error: '"..." is a directory').

- openpath-intercept: detect the folder-reveal gesture ("." / "./" /
  "<cwd>/.") and route it to a new revealInExplorer dep instead of the editor.
- intercept: revealInExplorer switches to the explorer tab (expanding the
  panel), expands the produced files' parent directories, and highlights /
  scrolls to them; the intercepted produced-files row now also renders its
  own "Show in folder" button when files are hidden.
- produced-files: selectProducedFiles reads the engine Turn data
  (owner.turn.data.get("deliverables")) — the same source ui-deliverables
  uses — with the node replica as fallback. The old code read owner.nodes,
  which the real TurnTailOwnerProps ({turn, seq, openFile}) does not carry,
  so the takeover never claimed the chain.
- state: transient `revealed` set (never persisted) plus a revealPaths
  reducer that expands ancestor directories.
- ExplorerView: highlight + scroll revealed rows; Sidebar/tabs/service
  thread `revealed` through TabComponentProps.
- tests: folder-gesture routing, engine-data selector, wiring seat, zh/en copy.
This commit is contained in:
GammaChineYov
2026-08-15 17:08:04 +08:00
parent 5d2d6e5801
commit 1ca4d4ef4d
11 changed files with 267 additions and 22 deletions
+4 -2
View File
@@ -61,6 +61,7 @@ function TabContent(props: {
sessionId: string
cwd: string | undefined
expanded: string[]
revealed: string[]
onToggleDir: (path: string) => void
onReferenceFile: (path: string) => void
ctx: Context
@@ -72,7 +73,7 @@ function TabContent(props: {
/** Open a diff tab from the git panel (placement handled by the store). */
onOpenDiff: (tab: SidebarTab) => void
}) {
const { tab, sessionId, cwd, expanded, onToggleDir, onReferenceFile, ctx, store, visible, onSubagentJump, onOpenDiff } = props
const { tab, sessionId, cwd, expanded, revealed, onToggleDir, onReferenceFile, ctx, store, visible, onSubagentJump, onOpenDiff } = props
const scope = { sessionId, cwd }
const descriptor = ctx.betterSidebar?.getTab(tab.type)
if (descriptor === undefined) {
@@ -90,7 +91,7 @@ function TabContent(props: {
RenderBoundary,
{ className: css.tabBoundaryError },
createElement(descriptor.component, {
ctx, store, scope, tab, visible, expanded,
ctx, store, scope, tab, visible, expanded, revealed,
onToggleDir, onReferenceFile, onOpenDiff, onSubagentJump,
}),
)
@@ -714,6 +715,7 @@ export function Sidebar(props: { ctx: Context; store: SidebarStore }) {
sessionId={sessionId}
cwd={cwd}
expanded={state.expanded}
revealed={state.revealed ?? []}
onToggleDir={(path) => { store.reduce(s => toggleExpanded(s, path)) }}
onReferenceFile={referenceInChat}
ctx={ctx}