diff --git a/src/agents/pi-tools.sandbox-mounted-paths.workspace-only.test.ts b/src/agents/pi-tools.sandbox-mounted-paths.workspace-only.test.ts index df9817fea65..36571da8e71 100644 --- a/src/agents/pi-tools.sandbox-mounted-paths.workspace-only.test.ts +++ b/src/agents/pi-tools.sandbox-mounted-paths.workspace-only.test.ts @@ -4,8 +4,9 @@ import path from "node:path"; import { describe, expect, it, vi } from "vitest"; import type { OpenClawConfig } from "../config/config.js"; import type { SandboxContext } from "./sandbox.js"; -import type { SandboxFsBridge, SandboxFsStat, SandboxResolvedPath } from "./sandbox/fs-bridge.js"; +import type { SandboxFsBridge, SandboxResolvedPath } from "./sandbox/fs-bridge.js"; import { createOpenClawCodingTools } from "./pi-tools.js"; +import { createSandboxFsBridgeFromResolver } from "./test-helpers/host-sandbox-fs-bridge.js"; vi.mock("../infra/shell-env.js", async (importOriginal) => { const mod = await importOriginal(); @@ -54,54 +55,7 @@ function createUnsafeMountedBridge(params: { return { hostPath, relativePath, containerPath }; }; - return { - resolvePath: ({ filePath, cwd }) => resolvePath(filePath, cwd), - readFile: async ({ filePath, cwd }) => { - const target = resolvePath(filePath, cwd); - return fs.readFile(target.hostPath); - }, - writeFile: async ({ filePath, cwd, data, mkdir = true }) => { - const target = resolvePath(filePath, cwd); - if (mkdir) { - await fs.mkdir(path.dirname(target.hostPath), { recursive: true }); - } - const buffer = Buffer.isBuffer(data) ? data : Buffer.from(data); - await fs.writeFile(target.hostPath, buffer); - }, - mkdirp: async ({ filePath, cwd }) => { - const target = resolvePath(filePath, cwd); - await fs.mkdir(target.hostPath, { recursive: true }); - }, - remove: async ({ filePath, cwd, recursive, force }) => { - const target = resolvePath(filePath, cwd); - await fs.rm(target.hostPath, { - recursive: recursive ?? false, - force: force ?? false, - }); - }, - rename: async ({ from, to, cwd }) => { - const source = resolvePath(from, cwd); - const target = resolvePath(to, cwd); - await fs.mkdir(path.dirname(target.hostPath), { recursive: true }); - await fs.rename(source.hostPath, target.hostPath); - }, - stat: async ({ filePath, cwd }) => { - try { - const target = resolvePath(filePath, cwd); - const stats = await fs.stat(target.hostPath); - return { - type: stats.isDirectory() ? "directory" : stats.isFile() ? "file" : "other", - size: stats.size, - mtimeMs: stats.mtimeMs, - } satisfies SandboxFsStat; - } catch (error) { - if ((error as NodeJS.ErrnoException).code === "ENOENT") { - return null; - } - throw error; - } - }, - }; + return createSandboxFsBridgeFromResolver(resolvePath); } function createSandbox(params: { diff --git a/src/agents/test-helpers/host-sandbox-fs-bridge.ts b/src/agents/test-helpers/host-sandbox-fs-bridge.ts index 4f3dc6bd8cd..85b22745fce 100644 --- a/src/agents/test-helpers/host-sandbox-fs-bridge.ts +++ b/src/agents/test-helpers/host-sandbox-fs-bridge.ts @@ -3,26 +3,9 @@ import path from "node:path"; import type { SandboxFsBridge, SandboxFsStat, SandboxResolvedPath } from "../sandbox/fs-bridge.js"; import { resolveSandboxPath } from "../sandbox-paths.js"; -export function createHostSandboxFsBridge(rootDir: string): SandboxFsBridge { - const root = path.resolve(rootDir); - - const resolvePath = (filePath: string, cwd?: string): SandboxResolvedPath => { - const resolved = resolveSandboxPath({ - filePath, - cwd: cwd ?? root, - root, - }); - const relativePath = resolved.relative - ? resolved.relative.split(path.sep).filter(Boolean).join(path.posix.sep) - : ""; - const containerPath = relativePath ? path.posix.join("/workspace", relativePath) : "/workspace"; - return { - hostPath: resolved.resolved, - relativePath, - containerPath, - }; - }; - +export function createSandboxFsBridgeFromResolver( + resolvePath: (filePath: string, cwd?: string) => SandboxResolvedPath, +): SandboxFsBridge { return { resolvePath: ({ filePath, cwd }) => resolvePath(filePath, cwd), readFile: async ({ filePath, cwd }) => { @@ -72,3 +55,26 @@ export function createHostSandboxFsBridge(rootDir: string): SandboxFsBridge { }, }; } + +export function createHostSandboxFsBridge(rootDir: string): SandboxFsBridge { + const root = path.resolve(rootDir); + + const resolvePath = (filePath: string, cwd?: string): SandboxResolvedPath => { + const resolved = resolveSandboxPath({ + filePath, + cwd: cwd ?? root, + root, + }); + const relativePath = resolved.relative + ? resolved.relative.split(path.sep).filter(Boolean).join(path.posix.sep) + : ""; + const containerPath = relativePath ? path.posix.join("/workspace", relativePath) : "/workspace"; + return { + hostPath: resolved.resolved, + relativePath, + containerPath, + }; + }; + + return createSandboxFsBridgeFromResolver(resolvePath); +}