mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-26 20:35:39 -06:00
341551937e
* fix(agents): preserve empty CLI subagent completions * chore(qa): remove retired Matrix coverage leaf * refactor: consolidate shared runtime ownership * fix(scripts): keep runtime build coercion dependency-light * chore: remove release-owned changelog entry
85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
import { lstatSync, realpathSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { isPathInside } from "openclaw/plugin-sdk/file-access-runtime";
|
|
|
|
export type MxcWorkspaceAccess = "none" | "ro" | "rw";
|
|
|
|
export type MxcReadOnlySkillMount = {
|
|
hostPath: string;
|
|
containerPath: string;
|
|
};
|
|
|
|
const MATERIALIZED_SANDBOX_SKILLS_WORKSPACE_PARTS = [".openclaw", "sandbox-skills"] as const;
|
|
|
|
function containerJoin(root: string, ...parts: string[]): string {
|
|
const normalizedRoot = root.endsWith("/") && root !== "/" ? root.slice(0, -1) : root;
|
|
const suffix = parts
|
|
.map((part) => part.replace(/^\/+|\/+$/g, ""))
|
|
.filter(Boolean)
|
|
.join("/");
|
|
return suffix ? `${normalizedRoot}/${suffix}` : normalizedRoot;
|
|
}
|
|
|
|
function resolveMaterializedSandboxSkillsWorkspaceDir(rootDir: string): string {
|
|
return path.join(rootDir, ...MATERIALIZED_SANDBOX_SKILLS_WORKSPACE_PARTS);
|
|
}
|
|
|
|
function isExistingMxcSkillMountSource(params: { rootDir: string; hostPath: string }): boolean {
|
|
try {
|
|
if (!lstatSync(params.hostPath).isDirectory()) {
|
|
return false;
|
|
}
|
|
return isPathInside(
|
|
realpathSync(path.resolve(params.rootDir)),
|
|
realpathSync(path.resolve(params.hostPath)),
|
|
);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function resolveMxcReadOnlySkillMounts(params: {
|
|
agentWorkspaceDir: string;
|
|
skillsWorkspaceDir?: string;
|
|
workdir: string;
|
|
workspaceAccess: MxcWorkspaceAccess;
|
|
}): readonly MxcReadOnlySkillMount[] {
|
|
if (params.workspaceAccess !== "rw") {
|
|
return [];
|
|
}
|
|
|
|
const materializedSkillsWorkspaceDir =
|
|
params.skillsWorkspaceDir ??
|
|
resolveMaterializedSandboxSkillsWorkspaceDir(params.agentWorkspaceDir);
|
|
const mounts = [
|
|
{
|
|
hostPath: path.join(params.agentWorkspaceDir, "skills"),
|
|
containerPath: containerJoin(params.workdir, "skills"),
|
|
rootDir: params.agentWorkspaceDir,
|
|
},
|
|
{
|
|
hostPath: path.join(params.agentWorkspaceDir, ".agents", "skills"),
|
|
containerPath: containerJoin(params.workdir, ".agents", "skills"),
|
|
rootDir: params.agentWorkspaceDir,
|
|
},
|
|
{
|
|
hostPath: path.join(materializedSkillsWorkspaceDir, "skills"),
|
|
containerPath: containerJoin(
|
|
params.workdir,
|
|
...MATERIALIZED_SANDBOX_SKILLS_WORKSPACE_PARTS,
|
|
"skills",
|
|
),
|
|
rootDir: materializedSkillsWorkspaceDir,
|
|
},
|
|
];
|
|
|
|
return mounts
|
|
.filter((mount) =>
|
|
isExistingMxcSkillMountSource({
|
|
rootDir: mount.rootDir,
|
|
hostPath: mount.hostPath,
|
|
}),
|
|
)
|
|
.map(({ hostPath, containerPath }) => ({ hostPath, containerPath }));
|
|
}
|