/** * Persistent allow/deny patterns. No Bare imports. * * A rule is { tool, pattern, decision: 'allow'|'deny' }. * Shell patterns match the leading tokens of the command (e.g. "git status"). * Path patterns match args.path / args.file, prefix or exact. */ function patternFromArgs(tool, args) { args = args || {}; if (tool === 'run_terminal_cmd') { return String(args.command || '') .trim() .split(/\s+/) .slice(0, 2) .join(' '); } if (args.path) return String(args.path); if (args.file) return String(args.file); if (args.url) return String(args.url); if (args.name) return String(args.name); return '*'; } function globish(value, pattern) { const v = String(value || ''); const p = String(pattern || ''); if (!p || p === '*') return true; if (v === p) return true; if (v.indexOf(p) === 0) return true; if (p.endsWith('*') && v.indexOf(p.slice(0, -1)) === 0) return true; return false; } function matchRule(rule, tool, args) { if (!rule || rule.tool !== tool) return false; const pat = patternFromArgs(tool, args); return globish(pat, rule.pattern); } function resolve(rules, tool, args) { const list = Array.isArray(rules) ? rules : []; for (let i = list.length - 1; i >= 0; i--) { if (matchRule(list[i], tool, args)) return list[i].decision === 'deny' ? 'deny' : 'allow'; } return null; } function addRule(rules, tool, args, decision) { const next = Array.isArray(rules) ? rules.slice() : []; const pattern = patternFromArgs(tool, args); const rec = { tool: String(tool), pattern: pattern || '*', decision: decision === 'deny' ? 'deny' : 'allow' }; const idx = next.findIndex((r) => r.tool === rec.tool && r.pattern === rec.pattern); if (idx >= 0) next[idx] = rec; else next.push(rec); return next; } module.exports = { patternFromArgs, globish, matchRule, resolve, addRule };