@sema-agent/core
Version:
Stateless, task-oriented AI agent core
53 lines (52 loc) • 1.88 kB
JavaScript
function escapedAt(s, i) {
let backslashes = 0;
for (let j = i - 1; j >= 0 && s[j] === "\\"; j--)
backslashes++;
return backslashes % 2 === 1;
}
export function indexOfUnescaped(s, ch) {
for (let i = 0; i < s.length; i++)
if (s[i] === ch && !escapedAt(s, i))
return i;
return -1;
}
export function lastIndexOfUnescaped(s, ch) {
for (let i = s.length - 1; i >= 0; i--)
if (s[i] === ch && !escapedAt(s, i))
return i;
return -1;
}
function unescapeRuleContent(s) {
return s.replaceAll("\\(", "(").replaceAll("\\)", ")").replaceAll("\\\\", "\\");
}
export function parsePermissionRule(rule) {
const open = indexOfUnescaped(rule, "(");
if (open === -1)
return { toolName: rule.trim() };
const close = lastIndexOfUnescaped(rule, ")");
if (close === -1 || close <= open)
return { toolName: rule.trim() };
if (close !== rule.length - 1)
return { toolName: rule.trim() };
const name = rule.substring(0, open);
const content = rule.substring(open + 1, close);
if (!name)
return { toolName: rule.trim() };
if (content === "" || content === "*")
return { toolName: name.trim() };
return { toolName: name.trim(), ruleContent: unescapeRuleContent(content) };
}
const RULE_TOOL_NAME = /^(?:\*|[A-Za-z0-9_](?:[A-Za-z0-9_.:*-]*[A-Za-z0-9_*-])?)$/;
export function isNameableToolName(name) {
return typeof name === "string" && name !== "*" && RULE_TOOL_NAME.test(name);
}
export function ruleSpellingOf(rule) {
if (rule !== rule.trim())
return undefined;
const open = indexOfUnescaped(rule, "(");
const name = open < 0 ? rule : rule.slice(0, open);
if (!RULE_TOOL_NAME.test(name))
return undefined;
const parsed = parsePermissionRule(rule);
return parsed.toolName === name ? parsed : undefined;
}