@@ -3,15 +3,7 @@ import { dirname, join, resolve, sep } from "node:path";
33import { homedir } from "node:os" ;
44import { realpathOrOriginal , type RootsProvider } from "./worktree-roots.js" ;
55import { projectSessionsRoot } from "../session/project-key.js" ;
6- import {
7- cachedLinkReal ,
8- cachedNodeReal ,
9- enterPathResolution ,
10- lstatMemoized ,
11- readlinkMemoized ,
12- rememberLink ,
13- rememberNode ,
14- } from "./realpath-cache.js" ;
6+ import { enterPathResolution , lstatMemoized } from "./realpath-cache.js" ;
157
168// Paths the agent must not touch without explicit operator approval, even
179// though read tools are otherwise allow-tier and write/edit auto-allow in
@@ -41,7 +33,7 @@ const LEGACY_STATE_DIR = ".agent-state";
4133export const UNRESOLVABLE = "\0unresolvable\0" ;
4234
4335// A single normal path segment. `.`, `..`, a trailing slash, or an empty tail
44- // stay on realpathSync so the cached join cannot diverge from the kernel.
36+ // stay on realpathSync so the join cannot diverge from the kernel.
4537function existingTail ( path : string , parent : string ) : string | undefined {
4638 const tailStart = parent . endsWith ( sep ) ? parent . length : parent . length + 1 ;
4739 const tail = path . slice ( tailStart ) ;
@@ -56,14 +48,9 @@ function existingTail(path: string, parent: string): string | undefined {
5648 return tail ;
5749}
5850
59- function rememberRealpath (
60- path : string ,
61- st : NonNullable < ReturnType < typeof lstatMemoized > > ,
62- ) : string {
51+ function realpathOrUnresolvable ( path : string ) : string {
6352 try {
64- const real = realpathSync ( path ) ;
65- rememberNode ( path , st , real ) ;
66- return real ;
53+ return realpathSync ( path ) ;
6754 } catch {
6855 return UNRESOLVABLE ;
6956 }
@@ -72,32 +59,17 @@ function rememberRealpath(
7259function resolveNearest ( path : string ) : string {
7360 const st = lstatMemoized ( path ) ;
7461 if ( st !== undefined && ! st . isSymbolicLink ( ) ) {
75- const hit = cachedNodeReal ( path , st ) ;
76- if ( hit !== undefined ) return hit ;
7762 const parent = dirname ( path ) ;
78- if ( parent === path ) return rememberRealpath ( path , st ) ;
63+ if ( parent === path ) return realpathOrUnresolvable ( path ) ;
7964 const tail = existingTail ( path , parent ) ;
80- if ( tail === undefined ) return rememberRealpath ( path , st ) ;
65+ if ( tail === undefined ) return realpathOrUnresolvable ( path ) ;
8166 const parentReal = resolveNearest ( parent ) ;
8267 if ( parentReal === UNRESOLVABLE ) return UNRESOLVABLE ;
83- const real = join ( parentReal , tail ) ;
84- rememberNode ( path , st , real ) ;
85- return real ;
68+ return join ( parentReal , tail ) ;
8669 }
8770
8871 if ( st !== undefined && st . isSymbolicLink ( ) ) {
89- const linkTarget = readlinkMemoized ( path ) ;
90- if ( linkTarget !== undefined ) {
91- const hit = cachedLinkReal ( path , st , linkTarget ) ;
92- if ( hit !== undefined ) return hit ;
93- }
94- try {
95- const real = realpathSync ( path ) ;
96- if ( linkTarget !== undefined ) rememberLink ( path , st , linkTarget , real ) ;
97- return real ;
98- } catch {
99- return UNRESOLVABLE ;
100- }
72+ return realpathOrUnresolvable ( path ) ;
10173 }
10274
10375 const parent = dirname ( path ) ;
@@ -122,9 +94,8 @@ function resolveNearest(path: string): string {
12294// distinguishes the two: it succeeds for an existing-but-broken symlink and
12395// fails only when the component is genuinely absent.
12496//
125- // Already-resolved ancestors are memoized across calls only while each
126- // ancestor keeps the dev/ino (and symlink text) stored with the entry. The
127- // check stays synchronous.
97+ // lstat results are shared only for the duration of this synchronous check.
98+ // A resolved path is not reused on a later tool call.
12899export function realpathNearestOr ( path : string ) : string {
129100 return enterPathResolution ( ( ) => resolveNearest ( path ) ) ;
130101}
0 commit comments