openclaw/src/agents/sandbox/fs-bridge-command-plans.ts
2026-03-08 01:01:40 +00:00

121 lines
3.3 KiB
TypeScript

import { PATH_ALIAS_POLICIES } from "../../infra/path-alias-guards.js";
import type { AnchoredSandboxEntry, PathSafetyCheck } from "./fs-bridge-path-safety.js";
import type { SandboxResolvedFsPath } from "./fs-paths.js";
export type SandboxFsCommandPlan = {
checks: PathSafetyCheck[];
script: string;
args?: string[];
recheckBeforeCommand?: boolean;
allowFailure?: boolean;
};
export function buildReadFilePlan(target: SandboxResolvedFsPath): SandboxFsCommandPlan {
return {
checks: [{ target, options: { action: "read files" } }],
script: 'set -eu; cat -- "$1"',
args: [target.containerPath],
};
}
export function buildWriteCommitPlan(
target: SandboxResolvedFsPath,
tempPath: string,
): SandboxFsCommandPlan {
return {
checks: [{ target, options: { action: "write files", requireWritable: true } }],
recheckBeforeCommand: true,
script: 'set -eu; mv -f -- "$1" "$2"',
args: [tempPath, target.containerPath],
};
}
export function buildMkdirpPlan(
target: SandboxResolvedFsPath,
anchoredTarget: AnchoredSandboxEntry,
): SandboxFsCommandPlan {
return {
checks: [
{
target,
options: {
action: "create directories",
requireWritable: true,
allowedType: "directory",
},
},
],
script: 'set -eu\ncd -- "$1"\nmkdir -p -- "$2"',
args: [anchoredTarget.canonicalParentPath, anchoredTarget.basename],
};
}
export function buildRemovePlan(params: {
target: SandboxResolvedFsPath;
anchoredTarget: AnchoredSandboxEntry;
recursive?: boolean;
force?: boolean;
}): SandboxFsCommandPlan {
const flags = [params.force === false ? "" : "-f", params.recursive ? "-r" : ""].filter(Boolean);
const rmCommand = flags.length > 0 ? `rm ${flags.join(" ")}` : "rm";
return {
checks: [
{
target: params.target,
options: {
action: "remove files",
requireWritable: true,
aliasPolicy: PATH_ALIAS_POLICIES.unlinkTarget,
},
},
],
recheckBeforeCommand: true,
script: `set -eu\ncd -- "$1"\n${rmCommand} -- "$2"`,
args: [params.anchoredTarget.canonicalParentPath, params.anchoredTarget.basename],
};
}
export function buildRenamePlan(params: {
from: SandboxResolvedFsPath;
to: SandboxResolvedFsPath;
anchoredFrom: AnchoredSandboxEntry;
anchoredTo: AnchoredSandboxEntry;
}): SandboxFsCommandPlan {
return {
checks: [
{
target: params.from,
options: {
action: "rename files",
requireWritable: true,
aliasPolicy: PATH_ALIAS_POLICIES.unlinkTarget,
},
},
{
target: params.to,
options: {
action: "rename files",
requireWritable: true,
},
},
],
recheckBeforeCommand: true,
script: ["set -eu", 'mkdir -p -- "$2"', 'cd -- "$1"', 'mv -- "$3" "$2/$4"'].join("\n"),
args: [
params.anchoredFrom.canonicalParentPath,
params.anchoredTo.canonicalParentPath,
params.anchoredFrom.basename,
params.anchoredTo.basename,
],
};
}
export function buildStatPlan(target: SandboxResolvedFsPath): SandboxFsCommandPlan {
return {
checks: [{ target, options: { action: "stat files" } }],
script: 'set -eu; stat -c "%F|%s|%Y" -- "$1"',
args: [target.containerPath],
allowFailure: true,
};
}