UNPKG

@sema-agent/core

Version:

Stateless, task-oriented AI agent core

60 lines (59 loc) • 2.89 kB
import { canonicalPathIsAuthoritative } from "../../core/remote-env.js"; const OBSERVED = Symbol("observedFilesystem"); const CONCLUSIVE = new Set(["not_found", "not_directory", "not_supported"]); export function canonicalRootsOnce(env, readRoots, known) { let once = known ? Promise.resolve({ roots: readRoots, incomplete: [] }) : undefined; return (signal) => (once ??= (async () => { const seen = observeEnvironment(env); const roots = []; for (const r of readRoots) { const c = await seen.fs.canonicalPath(r, signal); roots.push(c.ok ? c.value : r); } const result = { roots, incomplete: seen.incomplete() }; if (result.incomplete.length > 0) once = undefined; return result; })()); } export function observeEnvironment(env) { const authoritative = canonicalPathIsAuthoritative(env); const records = []; const note = (op, path, what, code) => void records.push({ op, detail: `"${path}" ${what} (${code})` }); const watch = (op, path, what, ask) => new Promise((resolve) => resolve(ask())).then((r) => { if (!r.ok && !CONCLUSIVE.has(r.error.code)) note(op, path, what, r.error.code); return r; }, (e) => { note(op, path, what, e instanceof Error ? e.name : "threw"); throw e; }); const look = (op, what, member) => member === undefined ? {} : { [op]: (path, signal) => watch(op, path, what, () => member.call(env, path, signal)) }; const overlay = { ...look("canonicalPath", "cannot be resolved", env.canonicalPath), ...look("listDir", "cannot be enumerated", env.listDir), ...look("fileInfo", "cannot be inspected", env.fileInfo), ...look("readLink", "cannot be read as a link", env.readLink), ...look("exists", "cannot be checked", env.exists), ...look("absolutePath", "cannot be made absolute", env.absolutePath), ...look("canonicalChain", "its link chain cannot be read", env.canonicalChain), ...look("fileIdentity", "cannot be identified", env.fileIdentity), [OBSERVED]: true, }; const fs = new Proxy(env, { get: (target, prop) => { if (Object.prototype.hasOwnProperty.call(overlay, prop)) return overlay[prop]; const value = Reflect.get(target, prop, target); return typeof value === "function" ? value.bind(target) : value; }, has: (target, prop) => Object.prototype.hasOwnProperty.call(overlay, prop) || Reflect.has(target, prop), }); return { fs, authoritative, incomplete: () => records.map(({ op, detail }) => ({ op, detail })), bound: (detail) => void records.push({ op: "bound", detail }), adopt: (adopted) => void records.push(...adopted.map(({ op, detail }) => ({ op, detail }))), }; }