UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

80 lines (79 loc) • 3.79 kB
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` }; }