#!/usr/bin/env node /** * Glob F8 post-execution filter (router-gate v4 Stream C, spec ยง5.2 F8 closure). * * Pure: the consumer hook expands the glob (glob.sync) and passes the already- * matched path array here. We strip paths that live under a /restricted/ segment * (e.g. subagent-block files the controller must not read) or whose inode is in * the protectedInodes Set (injected). No `glob` npm dependency in this module. */ const RUNTIME_RE = /[~/\\]\.claude[/\\]runtime[/\\]/; const DOUBLE_STAR_RE = /\*\*/; /** * True when an incoming Glob pattern targets ~/.claude/runtime with a ** wildcard * and therefore must be post-filtered. * @param {string} pattern */ export function globNeedsFilter(pattern) { if (typeof pattern !== 'string') return false; return RUNTIME_RE.test(pattern) && DOUBLE_STAR_RE.test(pattern); } /** * Filter an already-expanded glob match list. * @param {string[]} matches * @param {{isProtectedInode?: (path: string) => boolean}} [deps] * @returns {string[]} */ export function filterRestrictedMatches(matches, deps = {}) { if (!Array.isArray(matches)) return []; const isProtectedInode = typeof deps.isProtectedInode === 'function' ? deps.isProtectedInode : () => false; return matches.filter((m) => { if (typeof m !== 'string') return false; const norm = m.replace(/\\/g, '/'); if (norm.includes('/restricted/')) return false; if (isProtectedInode(m)) return false; return true; }); }