UNPKG

@struktoai/mirage-core

Version:

A Unified Virtual Filesystem For AI Agents

134 lines • 5.39 kB
// ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ========= Copyright 2026 @ Strukto.AI All Rights Reserved. ========= import { fromUnits, units } from "./document.js"; import { MovableStream } from "./stream.js"; const CACHE_SIZE = 1024; const encoder = new TextEncoder(); const decoder = new TextDecoder(); function open(config) { return new MovableStream('policy', { ...config, dialect: 'ecmascript' }); } /** * A profile's rules and visibility, compiled once by mirage-rs's `policy` * stream and asked one request at a time. Mirrors Python's PolicyMatcher. */ export class PolicyMatcher { stream; constructor(config) { this.stream = open(config); } /** The answer to one request, decoded from its JSON; text travels as code points. */ ask(op, args = {}) { const stream = this.stream.live; stream.feed(encoder.encode(JSON.stringify({ op, ...args }))); return JSON.parse(decoder.decode(stream.finish())); } } /** One rule in the stream's wire shape. Mirrors Python's rule_wire. */ export function ruleWire(rule) { return { reason: units(rule.reason), commands: (rule.commands ?? []).map(units), paths: (rule.paths ?? []).map(units), mount: rule.mount === undefined ? null : units(rule.mount), }; } /** A rule set in the stream's wire shape. Mirrors Python's rules_wire. */ export function rulesWire(rules) { return { allow: rules.allow == null ? null : rules.allow.map(units), deny: (rules.deny ?? []).map(ruleWire), ask: (rules.ask ?? []).map(ruleWire), }; } /** A session's visibility in the stream's wire shape. Mirrors Python's visibility_wire. */ export function visibilityWire(vis) { return { hidden: vis.paths === null ? {} : { paths: (vis.paths.paths ?? []).map(units), patterns: (vis.paths.patterns ?? []).map(units), }, shown: (vis.shown?.entries ?? []).map((entry) => ({ path: units(entry.path), mode: entry.mode, })), vars: vis.vars === null ? {} : { names: (vis.vars.names ?? []).map(units), patterns: (vis.vars.patterns ?? []).map(units), }, }; } /** A compiled visibility from the stream's wire shape. Mirrors Python's visibility_from. */ export function visibilityFrom(value, processes = 'session') { const { hidden, shown, vars } = value; return { paths: hidden.paths.length + hidden.patterns.length === 0 ? null : { paths: hidden.paths.map(fromUnits), patterns: hidden.patterns.map(fromUnits) }, shown: shown.length === 0 ? null : { entries: shown.map((entry) => ({ path: fromUnits(entry.path), mode: entry.mode })) }, vars: vars.names.length + vars.patterns.length === 0 ? null : { names: vars.names.map(fromUnits), patterns: vars.patterns.map(fromUnits) }, processes, }; } /** A symlink walk's steps in the stream's wire shape. Mirrors Python's link_trace_wire. */ export function linkTraceWire(trace) { return trace.map((step) => { switch (step.kind) { case 'follow': return { follow: units(step.path) }; case 'enter': return { enter: { path: units(step.path), next_is_parent: step.nextIsParent } }; case 'landing': return { landing: units(step.path) }; case 'hop_limit': return 'hop_limit'; } }); } const byValue = new Map(); // One matcher per configuration as its JSON reads now, however many // objects spell it, the least recently asked dropped first; the wire is // built only for a configuration not seen yet. function cached(text, config) { const matcher = byValue.get(text) ?? new PolicyMatcher(config()); byValue.delete(text); byValue.set(text, matcher); if (byValue.size > CACHE_SIZE) { const oldest = byValue.keys().next(); if (oldest.done !== true) byValue.delete(oldest.value); } return matcher; } /** * The compiled matcher for a rule set, shared by every caller asking the * same; null answers the requests no profile scopes. Mirrors Python's * admission_matcher. */ export function admissionMatcher(rules) { return cached(JSON.stringify({ rules }), () => rules === null ? {} : { rules: rulesWire(rules) }); } /** The compiled matcher for a visibility, shared by every caller asking the same. Mirrors Python's visibility_matcher. */ export function visibilityMatcher(vis) { return cached(JSON.stringify({ visibility: vis }), () => vis === null ? {} : { visibility: visibilityWire(vis) }); } //# sourceMappingURL=policy.js.map