@sema-agent/core
Version:
Stateless, task-oriented AI agent core
80 lines (79 loc) • 3.79 kB
JavaScript
import { isAbsoluteForFamily, joinForFamily, pathFamilyOf, pathIdentityOf, win32NamespaceScreen } from "../tools/fs/safety.js";
import { pathTargetValue } from "./tool-registry.js";
export function pathTargetBaseOf(pt, bases) {
return (pt?.base ?? "cwd") === "root" ? bases.root : (bases.cwd ?? bases.root);
}
export function splitAbsoluteGlobPattern(pattern, family) {
const screened = win32NamespaceScreen(pattern, family);
if (!screened.ok)
return { refused: screened.refuse };
const spelled = screened.spelled;
if (!isAbsoluteForFamily(family, spelled))
return undefined;
const lastSep = (s) => (family === "win" ? Math.max(s.lastIndexOf("/"), s.lastIndexOf("\\")) : s.lastIndexOf("/"));
const m = /[*?[{]/.exec(spelled);
const cut = m ? lastSep(spelled.slice(0, m.index)) : lastSep(spelled);
if (cut <= 0 && (m === null || cut === -1))
return undefined;
let baseDir = spelled.slice(0, cut);
if (baseDir === "")
baseDir = "/";
if (/^[A-Za-z]:$/.test(baseDir))
baseDir = baseDir + spelled[cut];
return { baseDir, relativePattern: spelled.slice(cut + 1) };
}
export function effectivePathTargetOf(call, pt, bases) {
const spelling = effectivePathSpellingOf(call, pt, bases);
if (spelling === undefined)
return undefined;
if ("refused" in spelling)
return { kind: "refused", reason: spelling.refused };
if (spelling.spelled !== undefined)
return resolveSpelling(spelling.spelled, spelling.base, bases);
const declaredBase = spelling.base;
if (declaredBase === undefined)
return undefined;
const family = pathFamilyOf(bases);
return isAbsoluteForFamily(family, declaredBase) ? readingOf(pathIdentityOf(declaredBase, family, bases.root ?? bases.cwd)) : unreadableBase(declaredBase);
}
export function effectivePathSpellingOf(call, pt, bases) {
if (pt === undefined)
return undefined;
const declaredBase = pathTargetBaseOf(pt, bases);
const spelled = pathTargetValue(call.args, pt);
if (spelled !== undefined)
return { spelled, base: declaredBase };
if ((pt.absent ?? "none") === "none")
return undefined;
if (pt.patternParam !== undefined) {
const pattern = pathTargetValue(call.args, { param: pt.patternParam });
const split = pattern === undefined ? undefined : splitAbsoluteGlobPattern(pattern, pathFamilyOf(bases));
if (split !== undefined && "refused" in split)
return { refused: split.refused };
if (split !== undefined)
return { spelled: split.baseDir, base: declaredBase };
}
return { base: declaredBase };
}
function resolveSpelling(spelled, declaredBase, bases) {
const family = pathFamilyOf(bases);
const screened = win32NamespaceScreen(spelled, family);
if (!screened.ok)
return { kind: "refused", reason: screened.refuse };
const tree = bases.root ?? bases.cwd;
if (isAbsoluteForFamily(family, screened.spelled))
return readingOf(pathIdentityOf(screened.spelled, family, tree));
if (declaredBase === undefined || family === undefined)
return undefined;
if (!isAbsoluteForFamily(family, declaredBase))
return unreadableBase(declaredBase);
return readingOf(pathIdentityOf(joinForFamily(family, declaredBase, screened.spelled), family, tree));
}
function readingOf(r) {
if (r.ok)
return { kind: "path", identity: r.identity };
return r.reason === "relative" || r.reason === "unanchored" ? undefined : { kind: "refused", reason: r.reason };
}
function unreadableBase(base) {
return { kind: "unreadable", reason: `the base this call resolves against (${JSON.stringify(base)}) is not a fully-qualified path of this tree's family` };
}