refactor(effect): keep read path handling in app filesystem
Move the repaired Windows path normalization and not-found handling back behind AppFileSystem helpers so the read tool stays on the service abstraction end-to-end. Keep external-directory checks on the same path helper family for consistency.pull/21016/head
parent
b15f1593c0
commit
baff53b759
|
|
@ -188,13 +188,23 @@ export namespace AppFileSystem {
|
|||
|
||||
export function normalizePath(p: string): string {
|
||||
if (process.platform !== "win32") return p
|
||||
const resolved = pathResolve(windowsPath(p))
|
||||
try {
|
||||
return realpathSync.native(p)
|
||||
return realpathSync.native(resolved)
|
||||
} catch {
|
||||
return p
|
||||
return resolved
|
||||
}
|
||||
}
|
||||
|
||||
export function normalizePathPattern(p: string): string {
|
||||
if (process.platform !== "win32") return p
|
||||
if (p === "*") return p
|
||||
const match = p.match(/^(.*)[\\/]\*$/)
|
||||
if (!match) return normalizePath(p)
|
||||
const dir = /^[A-Za-z]:$/.test(match[1]) ? match[1] + "\\" : match[1]
|
||||
return join(normalizePath(dir), "*")
|
||||
}
|
||||
|
||||
export function resolve(p: string): string {
|
||||
const resolved = pathResolve(windowsPath(p))
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import path from "path"
|
||||
import { Effect } from "effect"
|
||||
import type { Tool } from "./tool"
|
||||
import { Instance } from "../project/instance"
|
||||
import { Filesystem } from "@/util/filesystem"
|
||||
import { AppFileSystem } from "../filesystem"
|
||||
|
||||
type Kind = "file" | "directory"
|
||||
|
||||
|
|
@ -15,14 +16,14 @@ export async function assertExternalDirectory(ctx: Tool.Context, target?: string
|
|||
|
||||
if (options?.bypass) return
|
||||
|
||||
const full = process.platform === "win32" ? Filesystem.normalizePath(target) : target
|
||||
const full = process.platform === "win32" ? AppFileSystem.normalizePath(target) : target
|
||||
if (Instance.containsPath(full)) return
|
||||
|
||||
const kind = options?.kind ?? "file"
|
||||
const dir = kind === "directory" ? full : path.dirname(full)
|
||||
const glob =
|
||||
process.platform === "win32"
|
||||
? Filesystem.normalizePathPattern(path.join(dir, "*"))
|
||||
? AppFileSystem.normalizePathPattern(path.join(dir, "*"))
|
||||
: path.join(dir, "*").replaceAll("\\", "/")
|
||||
|
||||
await ctx.ask({
|
||||
|
|
@ -35,3 +36,11 @@ export async function assertExternalDirectory(ctx: Tool.Context, target?: string
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const assertExternalDirectoryEffect = Effect.fn("Tool.assertExternalDirectory")(function* (
|
||||
ctx: Tool.Context,
|
||||
target?: string,
|
||||
options?: Options,
|
||||
) {
|
||||
yield* Effect.promise(() => assertExternalDirectory(ctx, target, options))
|
||||
})
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import { LSP } from "../lsp"
|
|||
import { FileTime } from "../file/time"
|
||||
import DESCRIPTION from "./read.txt"
|
||||
import { Instance } from "../project/instance"
|
||||
import { assertExternalDirectory } from "./external-directory"
|
||||
import { assertExternalDirectoryEffect } from "./external-directory"
|
||||
import { Instruction } from "../session/instruction"
|
||||
|
||||
const DEFAULT_READ_LIMIT = 2000
|
||||
|
|
@ -96,14 +96,17 @@ export const ReadTool = Tool.defineEffect(
|
|||
}
|
||||
const title = path.relative(Instance.worktree, filepath)
|
||||
|
||||
const stat = yield* fs.stat(filepath).pipe(Effect.catch(() => Effect.succeed(undefined)))
|
||||
const stat = yield* fs.stat(filepath).pipe(
|
||||
Effect.catchIf(
|
||||
(err) => "reason" in err && err.reason._tag === "NotFound",
|
||||
() => Effect.succeed(undefined),
|
||||
),
|
||||
)
|
||||
|
||||
yield* Effect.promise(() =>
|
||||
assertExternalDirectory(ctx, filepath, {
|
||||
yield* assertExternalDirectoryEffect(ctx, filepath, {
|
||||
bypass: Boolean(ctx.extra?.["bypassCwdCheck"]),
|
||||
kind: stat?.type === "Directory" ? "directory" : "file",
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
yield* Effect.promise(() =>
|
||||
ctx.ask({
|
||||
|
|
@ -218,15 +221,7 @@ export const ReadTool = Tool.defineEffect(
|
|||
description: DESCRIPTION,
|
||||
parameters,
|
||||
async execute(params: z.infer<typeof parameters>, ctx) {
|
||||
return Effect.runPromise(
|
||||
run(params, ctx).pipe(
|
||||
Effect.catch((err) =>
|
||||
Effect.sync(() => {
|
||||
throw err
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
return Effect.runPromise(run(params, ctx).pipe(Effect.orDie))
|
||||
},
|
||||
}
|
||||
}),
|
||||
|
|
|
|||
Loading…
Reference in New Issue