@dollhousemcp/mcp-server
Version:
DollhouseMCP - A Model Context Protocol (MCP) server that enables dynamic AI persona management from markdown files, allowing Claude and other compatible AI assistants to activate and switch between different behavioral personas.
669 lines • 86 kB
JavaScript
/**
* Tool Classification for CLI-Level Permission Prompts
*
* Provides static classification of Claude Code CLI tool calls and
* evaluation against active element gatekeeper policies.
*
* Used by the permission_prompt operation (Issue #625) to evaluate
* --permission-prompt-tool requests without requiring LLM evaluation.
*
* @module
*/
import { matchesPattern } from '../../../utils/patternMatcher.js';
import { logger } from '../../../utils/logger.js';
// ── Gatekeeper-Essential Operations ──────────────────────────────────
/**
* MCP-AQL operations that must NEVER be blocked by permission_prompt,
* even if element denyPatterns would match the MCP tool name.
*
* These are essential for the Gatekeeper flow itself. Blocking them
* would prevent the human-in-the-loop approval path from functioning
* (e.g., a denyPattern of 'mcp__DollhouseMCP*' would block confirm_operation).
*/
const GATEKEEPER_ESSENTIAL_OPERATIONS = new Set([
'confirm_operation',
'verify_challenge',
'release_deadlock',
'permission_prompt',
'introspect',
'get_active_elements',
'get_execution_state',
'get_gathered_data',
'approve_cli_permission', // Issue #625 Phase 3
'get_pending_cli_approvals', // Issue #625 Phase 3
]);
/**
* MCP-AQL operations that are inherently read-only.
*
* These auto-allow in permission_prompt (no element policy evaluation).
* The Gatekeeper (Layer 2) still applies its own per-operation policies,
* so this doesn't bypass server-side access control — it just avoids
* unnecessary 'evaluate' round-trips for operations that can't modify state.
*/
const SAFE_MCP_OPERATIONS = new Set([
'list_elements',
'get_element',
'get_element_details',
'search_elements',
'query_elements',
'get_active_elements',
'validate_element',
'render',
'export_element',
'introspect',
'get_execution_state',
'get_gathered_data',
'browse_collection',
'search_collection',
'search_collection_enhanced',
'get_collection_content',
'get_collection_cache_health',
'portfolio_status',
'portfolio_config',
'search_portfolio',
'search_all',
'check_github_auth',
'oauth_helper_status',
'dollhouse_config',
'get_build_info',
'get_cache_budget_report',
'query_logs',
'query_metrics',
'find_similar_elements',
'get_element_relationships',
'search_by_verb',
'get_relationship_stats',
'get_effective_cli_policies',
'get_pending_cli_approvals',
]);
// ── Static Classification Lists ────────────────────────────────────
/**
* Tools that are always safe (read-only, no side effects).
*
* NOTE: "Safe" here means no destructive side effects — it does NOT mean
* unrestricted. Read-only tools can still pose information-leakage or
* scope-creep risks when used to access files outside the project working
* directory (e.g., ~/.ssh/*, /etc/passwd, credentials in home directories).
* Most LLM clients (Claude Code, Cursor, etc.) already enforce directory
* scoping at the client level. The `assessRisk()` function applies a small
* score bump for read operations targeting out-of-scope paths as an
* additional signal for approval policies.
*/
const SAFE_TOOLS = new Set([
'Read',
'Grep',
'Glob',
'WebFetch',
'WebSearch',
'TaskCreate',
'TaskUpdate',
'TaskGet',
'TaskList',
'TaskOutput',
'AskUserQuestion',
'EnterPlanMode',
'ExitPlanMode',
'TodoRead',
'TodoWrite',
]);
/** Bash command prefixes/patterns that are safe */
const SAFE_BASH_PATTERNS = [
'git status*',
'git log*',
'git diff*',
'git branch*',
'git show*',
'git remote*',
'git stash list*',
'ls*',
'pwd',
'cat *',
'head *',
'tail *',
'wc *',
'echo *',
'npm test*',
'npm run lint*',
'npm run build*',
'npm run test*',
'npm run check*',
'npm run typecheck*',
'npm run format*',
'npm ls*',
'npm info*',
'npm outdated*',
'npx jest*',
'npx tsc --noEmit*',
'node --version*',
'which *',
'type *',
'gh issue list*',
'gh issue view*',
'gh pr list*',
'gh pr view*',
'gh pr checks*',
];
/** Bash command patterns that are dangerous */
const DANGEROUS_BASH_PATTERNS = [
'rm -rf *',
'rm -fr *',
'git push --force*',
'git push -f *',
'git reset --hard*',
'git clean -f*',
'git checkout -- *',
'git branch -D *',
'chmod 777*',
'chmod -R 777*',
'chmod +s *',
'chown root *',
'sudo *',
'doas *',
'su -*',
'eval *',
// Inline interpreter execution (#1782) — arbitrary code via -c/-e flags
'python -c *',
'python3 -c *',
'node -e *',
'node --eval *',
'perl -e *',
'ruby -e *',
// Pipe-to-shell patterns (with and without spaces, multiple shells)
'*| sh',
'*| sh *',
'*|sh',
'*|sh *',
'*| bash',
'*| bash *',
'*|bash',
'*|bash *',
'*| zsh',
'*|zsh',
'curl * | *',
'wget * | *',
// Package manager installs (can execute arbitrary post-install scripts)
'npm install *',
'npm install',
'npm i *',
'npm i',
'yarn add *',
'yarn install*',
'pip install *',
'gem install *',
// Environment manipulation (path poisoning, library injection, variable destruction)
'export PATH=*',
'export LD_PRELOAD=*',
'export LD_LIBRARY_PATH=*',
'env -i *',
'unset *',
// Process control (can terminate agents or system processes)
'kill *',
'kill -*',
'pkill *',
'killall *',
// Network tools (exfiltration, reverse shells)
'nc *',
'nc -*',
'netcat *',
'ncat *',
'socat *',
// Archive operations (archive bombs, root directory exfiltration/ransomware)
'tar -xf *',
'tar xf *',
'zip -r * /',
// Command chaining with dangerous subcommands
'*; rm -rf *',
'*&& rm -rf *',
'*|| rm -rf *',
'*; sudo *',
'*&& sudo *',
'*|| sudo *',
'*; eval *',
'*&& eval *',
// Subprocess execution wrappers (bypass outer command classification)
'bash -c *',
'sh -c *',
'zsh -c *',
'/bin/bash -c *',
'/bin/sh -c *',
// Process substitution (can inject arbitrary command output)
'*<(*',
// Encoded payload execution (base64-decode piped to shell)
'*base64 -d*|*',
'*base64 --decode*|*',
'*base64 -D*|*',
];
/** Bash command patterns that are always blocked */
const BLOCKED_BASH_PATTERNS = [
'mkfs*',
'dd if=*',
':(){:|:&};:',
'format *',
'*(){ *',
];
// ── Static Classification ──────────────────────────────────────────
/**
* Classify a CLI tool call by risk level using static rules.
*
* Returns 'allow' for known-safe tools, 'deny' for known-dangerous patterns,
* and 'evaluate' for anything that needs further policy checking.
*/
export function classifyTool(toolName, toolInput) {
// Known-safe tools: auto-allow
if (SAFE_TOOLS.has(toolName)) {
return { riskLevel: 'safe', behavior: 'allow', reason: `${toolName} is a read-only tool` };
}
// Bash: sub-classify by command content
if (toolName === 'Bash') {
return classifyBashCommand(toolInput);
}
// MCP tool calls: auto-allow gatekeeper-essential and safe read-only operations, evaluate others
if (toolName.startsWith('mcp__')) {
const operation = typeof toolInput.operation === 'string' ? toolInput.operation : '';
if (operation && GATEKEEPER_ESSENTIAL_OPERATIONS.has(operation)) {
return {
riskLevel: 'safe',
behavior: 'allow',
reason: `Gatekeeper-essential operation '${operation}' — cannot be blocked by permission_prompt`,
};
}
if (operation && SAFE_MCP_OPERATIONS.has(operation)) {
return {
riskLevel: 'safe',
behavior: 'allow',
reason: `Read-only MCP operation '${operation}'`,
};
}
return { riskLevel: 'moderate', behavior: 'evaluate', reason: 'MCP tool call requires policy evaluation' };
}
// Edit, Write, Agent, NotebookEdit, etc.: moderate risk
if (['Edit', 'Write', 'Agent', 'NotebookEdit'].includes(toolName)) {
return { riskLevel: 'moderate', behavior: 'evaluate', reason: `${toolName} modifies state, requires policy evaluation` };
}
// Unknown tool: evaluate (permissive default for Phase 1)
return { riskLevel: 'moderate', behavior: 'evaluate', reason: `Unknown tool '${toolName}', requires policy evaluation` };
}
/**
* Sub-classify Bash commands by matching against known patterns.
*/
function classifyBashCommand(toolInput) {
const command = typeof toolInput.command === 'string' ? toolInput.command.trim() : '';
if (!command) {
return { riskLevel: 'moderate', behavior: 'evaluate', reason: 'Empty Bash command' };
}
// Check blocked patterns first (highest priority)
for (const pattern of BLOCKED_BASH_PATTERNS) {
if (matchesPattern(command, pattern)) {
return { riskLevel: 'blocked', behavior: 'deny', reason: `Blocked command pattern: ${pattern}` };
}
}
// Check dangerous patterns
for (const pattern of DANGEROUS_BASH_PATTERNS) {
if (matchesPattern(command, pattern)) {
return { riskLevel: 'dangerous', behavior: 'deny', reason: `Dangerous command pattern: ${pattern}` };
}
}
// Check safe patterns
for (const pattern of SAFE_BASH_PATTERNS) {
if (matchesPattern(command, pattern)) {
return { riskLevel: 'safe', behavior: 'allow', reason: `Safe command pattern: ${pattern}` };
}
}
// Unclassified: evaluate against element policies
return { riskLevel: 'moderate', behavior: 'evaluate', reason: 'Bash command not statically classified' };
}
// ── Risk Assessment ───────────────────────────────────────────────
/**
* Base risk scores by classification level (0-100 scale).
*
* Score ranges:
* - 0: safe — read-only tools, no side effects
* - 1-39: low — minor side effects, easily reversible
* - 40-59: moderate — file writes, package installs, unclassified commands
* - 60-79: elevated — moderate + aggravating factors (network, file creation)
* - 80-99: dangerous — destructive commands, privilege escalation
* - 100: blocked — always denied (e.g., reverse shells, disk wipe)
*
* Adjustments applied on top of base: irreversible pattern (+10),
* network operation (+10), out-of-scope read (+10), file creation (+5).
* Score is capped at 100.
*/
const RISK_SCORES = {
safe: 0,
moderate: 40,
dangerous: 80,
blocked: 100,
};
/** Read-only tools that may reference file paths */
const SAFE_READ_TOOLS = new Set(['Read', 'Grep', 'Glob']);
/** Sensitive path prefixes that indicate out-of-scope reads */
const SENSITIVE_PATH_PREFIXES = [
'~/.ssh/', '~/.gnupg/', '~/.aws/', '~/.config/',
'~/.env', '~/.netrc', '~/.npmrc',
'/etc/shadow', '/etc/passwd', '/etc/sudoers',
'/proc/', '/sys/',
];
/**
* Heuristic: does a path look like it targets files outside the project scope?
* Checks for home-directory sensitive paths, system paths, and parent traversals.
*/
function isOutOfScopePath(targetPath) {
const normalized = targetPath.replace(/\\/g, '/');
// Explicit sensitive paths
for (const prefix of SENSITIVE_PATH_PREFIXES) {
if (normalized.startsWith(prefix) || normalized.includes(`/${prefix}`)) {
return true;
}
}
// Home directory references (~/...) that aren't relative to the project
if (normalized.startsWith('~/') || normalized.startsWith('/Users/') || normalized.startsWith('/home/')) {
// Heuristic: reading sensitive dotfiles/dirs outside a project.
// Targets known credential/config stores — avoids false positives for
// common project dotfiles like .github/, .vscode/, .eslintrc, etc.
if (/\/\.(ssh|gnupg|aws|azure|gcloud|kube|docker|npmrc|netrc|env|bash_history|zsh_history|credentials|password|secret)/i.test(normalized))
return true;
}
return false;
}
/** Bash command patterns that are irreversible */
const IRREVERSIBLE_PATTERNS = [
'rm -rf *',
'rm -fr *',
'git push --force*',
'git push -f *',
'git reset --hard*',
'git clean -f*',
'mkfs*',
'dd if=*',
'drop *',
'truncate *',
];
/**
* Assess the risk of a CLI tool call.
*
* Returns a numeric score (0-100) and irreversibility indicator based on
* the static classification and tool-specific heuristics.
*
* @param toolName - The tool being called
* @param toolInput - The tool input parameters
* @param classification - The result from classifyTool()
* @returns Risk assessment with score, irreversibility, and contributing factors
*/
export function assessRisk(toolName, toolInput, classification) {
let score = RISK_SCORES[classification.riskLevel] ?? 40;
const factors = [`Base: ${classification.riskLevel} (${RISK_SCORES[classification.riskLevel] ?? 40})`];
let irreversible = false;
// Check for irreversible patterns in Bash commands
if (toolName === 'Bash' && typeof toolInput.command === 'string') {
const command = toolInput.command.trim();
for (const pattern of IRREVERSIBLE_PATTERNS) {
if (matchesPattern(command, pattern)) {
irreversible = true;
score = Math.min(100, score + 10);
factors.push(`Irreversible pattern: ${pattern} (+10)`);
break;
}
}
// Network operations increase risk
if (/\b(curl|wget|fetch|nc|netcat|ncat|socat)\b/.test(command)) {
score = Math.min(100, score + 10);
factors.push('Network operation (+10)');
}
}
// Write/Edit operations: file creation increases risk slightly
if (toolName === 'Write') {
score = Math.min(100, score + 5);
factors.push('File creation (+5)');
}
// Read-only tools targeting paths outside the working directory.
// Most clients already enforce directory scoping, but this provides an
// additional signal for approval policies to act on.
if (SAFE_READ_TOOLS.has(toolName)) {
const targetPath = (toolInput.file_path ?? toolInput.path ?? '');
if (targetPath && isOutOfScopePath(targetPath)) {
score = Math.min(100, score + 10);
factors.push('Out-of-scope read path (+10)');
}
}
return { score, irreversible, factors };
}
// ── Static Policy Data Export ─────────────────────────────────────
/**
* Return all static classification data for bridge policy export.
*
* Used by PolicyExportService to write the bridge-compatible policy file.
* All data is returned as plain arrays/objects (no Sets).
*/
export function getStaticPolicyData() {
return {
safe_tools: [...SAFE_TOOLS],
safe_bash_patterns: [...SAFE_BASH_PATTERNS],
dangerous_bash_patterns: [...DANGEROUS_BASH_PATTERNS],
blocked_bash_patterns: [...BLOCKED_BASH_PATTERNS],
irreversible_patterns: [...IRREVERSIBLE_PATTERNS],
sensitive_path_prefixes: [...SENSITIVE_PATH_PREFIXES],
gatekeeper_essential_operations: [...GATEKEEPER_ESSENTIAL_OPERATIONS],
safe_mcp_operations: [...SAFE_MCP_OPERATIONS],
risk_scores: { ...RISK_SCORES },
};
}
// ── Element Policy Evaluation ──────────────────────────────────────
/**
* Evaluate a CLI tool call against active element gatekeeper policies.
*
* Four-step evaluation per element (Issue #625 Phase 2, Issue #1660):
* 1. denyPatterns (highest priority) — first match = immediate deny
* 1.5. confirmPatterns — first match = immediate confirm (requires approval)
* 2. allowPatterns — if element defines them, record whether tool matched
* 3. After all elements: if any had allowPatterns but tool wasn't allowed by any = deny
*
* Union semantics: tool must match at least ONE element's allowPatterns (not all).
* Elements without allowPatterns don't restrict.
*
* @example
* // Tool matches allowPatterns in element A but not B → ALLOWED (union semantics)
* // Tool matches denyPatterns in any element → DENIED (deny always wins)
* // Tool matches no allowPatterns but some exist → DENIED ("not in any allowlist")
* // No allowPatterns defined anywhere → Phase 1 behavior (fall through to default)
*
* @returns 'deny' if blocked, 'evaluate' if permitted to fall through to default
*/
export function evaluateCliToolPolicy(toolName, toolInput, activeElements) {
const evaluatedElements = [];
const decisionChain = [];
const startTime = performance.now();
if (!activeElements.length) {
decisionChain.push('No active elements — fall through to default');
logger.debug(`[CliPolicy] ${toolName}: no active elements, fall through to default`);
return {
behavior: 'evaluate',
policyContext: { evaluatedElements, decisionChain },
};
}
// Build the strings to match against patterns
const matchTargets = buildMatchTargets(toolName, toolInput);
const elementTypeSummary = summarizeElementTypes(activeElements);
logger.debug(`[CliPolicy] Evaluating ${toolName} against ${activeElements.length} elements (${elementTypeSummary}), matchTargets: [${matchTargets.join(', ')}]`);
let anyElementHasAllowPatterns = false;
let toolAllowedByAnyElement = false;
const elementsWithAllowPatterns = [];
for (const element of activeElements) {
const restrictions = element.metadata?.gatekeeper?.externalRestrictions;
const denyPatterns = restrictions?.denyPatterns;
const confirmPatterns = restrictions?.confirmPatterns;
const allowPatterns = restrictions?.allowPatterns;
const hasRestrictions = (Array.isArray(denyPatterns) && denyPatterns.length > 0)
|| (Array.isArray(confirmPatterns) && confirmPatterns.length > 0)
|| (Array.isArray(allowPatterns) && allowPatterns.length > 0);
if (!hasRestrictions) {
evaluatedElements.push({ type: element.type, name: element.name });
decisionChain.push(`${element.type} '${element.name}': no externalRestrictions`);
logger.debug(`[CliPolicy] ${element.type} '${element.name}': no externalRestrictions, skipping`);
continue;
}
logger.debug(`[CliPolicy] ${element.type} '${element.name}': evaluating (deny: ${Array.isArray(denyPatterns) ? denyPatterns.length : 0}, confirm: ${Array.isArray(confirmPatterns) ? confirmPatterns.length : 0}, allow: ${Array.isArray(allowPatterns) ? allowPatterns.length : 0} patterns)`);
// Step 1: Check denyPatterns (highest priority)
if (Array.isArray(denyPatterns)) {
for (const pattern of denyPatterns) {
if (typeof pattern !== 'string')
continue;
for (const target of matchTargets) {
if (matchesPattern(target, pattern)) {
evaluatedElements.push({
type: element.type,
name: element.name,
matched: 'denyPatterns',
matchedPattern: pattern,
matchedTarget: target,
});
decisionChain.push(`DENY: ${element.type} '${element.name}' denyPattern '${pattern}' matches '${target}'`);
logger.debug(`[CliPolicy] DENY: ${element.type} '${element.name}' denyPattern '${pattern}' matched '${target}' (${elapsed(startTime)})`);
return {
behavior: 'deny',
message: `Denied by ${element.type} '${element.name}' policy: pattern '${pattern}' matches '${target}'`,
policyContext: { evaluatedElements, decisionChain },
};
}
}
}
}
// Step 1.5: Check confirmPatterns (requires approval — Issue #1660)
if (Array.isArray(confirmPatterns) && confirmPatterns.length > 0) {
for (const pattern of confirmPatterns) {
if (typeof pattern !== 'string')
continue;
for (const target of matchTargets) {
if (matchesPattern(target, pattern)) {
evaluatedElements.push({
type: element.type,
name: element.name,
matched: 'confirmPatterns',
matchedPattern: pattern,
matchedTarget: target,
});
decisionChain.push(`CONFIRM: ${element.type} '${element.name}' confirmPattern '${pattern}' matches '${target}'`);
logger.debug(`[CliPolicy] CONFIRM: ${element.type} '${element.name}' confirmPattern '${pattern}' matched '${target}' (${elapsed(startTime)})`);
return {
behavior: 'confirm',
message: `Requires approval: ${element.type} '${element.name}' policy requires confirmation for pattern '${pattern}'`,
confirmSource: `${element.type}:${element.name}`,
policyContext: { evaluatedElements, decisionChain },
};
}
}
}
}
// Step 2: Check allowPatterns
if (Array.isArray(allowPatterns) && allowPatterns.length > 0) {
anyElementHasAllowPatterns = true;
elementsWithAllowPatterns.push(`${element.type} '${element.name}'`);
let matchedAllow = false;
for (const pattern of allowPatterns) {
if (typeof pattern !== 'string')
continue;
for (const target of matchTargets) {
if (matchesPattern(target, pattern)) {
evaluatedElements.push({
type: element.type,
name: element.name,
matched: 'allowPatterns',
matchedPattern: pattern,
matchedTarget: target,
});
decisionChain.push(`${element.type} '${element.name}': allowPattern '${pattern}' matches '${target}'`);
logger.debug(`[CliPolicy] ALLOW: ${element.type} '${element.name}' allowPattern '${pattern}' matched '${target}'`);
toolAllowedByAnyElement = true;
matchedAllow = true;
break;
}
}
if (matchedAllow)
break;
}
if (!matchedAllow) {
evaluatedElements.push({ type: element.type, name: element.name });
decisionChain.push(`${element.type} '${element.name}': allowPatterns defined but no match`);
}
}
else {
evaluatedElements.push({ type: element.type, name: element.name });
decisionChain.push(`${element.type} '${element.name}': denyPatterns checked, no match`);
}
}
// Step 3: If any element had allowPatterns, tool must have matched at least one
if (anyElementHasAllowPatterns && !toolAllowedByAnyElement) {
const restrictors = elementsWithAllowPatterns.join(', ');
decisionChain.push(`DENY: tool not in any element allowlist (restricted by: ${restrictors})`);
logger.debug(`[CliPolicy] DENY: ${toolName} not in any allowlist (restricted by: ${restrictors}) (${elapsed(startTime)})`);
return {
behavior: 'deny',
message: `Tool '${toolName}' not permitted by allowlists defined in: ${restrictors}. Either deactivate these elements or add allowPatterns to match this tool.`,
policyContext: { evaluatedElements, decisionChain },
};
}
if (anyElementHasAllowPatterns) {
decisionChain.push('Tool matched allowlist — fall through to default');
logger.debug(`[CliPolicy] ${toolName}: matched allowlist, fall through to default (${elapsed(startTime)})`);
}
else {
decisionChain.push('No allowPatterns defined — fall through to default (Phase 1 behavior)');
logger.debug(`[CliPolicy] ${toolName}: no allowPatterns defined, fall through to default (${elapsed(startTime)})`);
}
return {
behavior: 'evaluate',
policyContext: { evaluatedElements, decisionChain },
};
}
/** Format elapsed time since startTime in milliseconds. */
function elapsed(startTime) {
return `${(performance.now() - startTime).toFixed(2)}ms`;
}
/** Summarize active element types for the entry log (e.g., "3 personas, 2 skills, 1 ensemble"). */
function summarizeElementTypes(elements) {
const counts = new Map();
for (const el of elements) {
counts.set(el.type, (counts.get(el.type) ?? 0) + 1);
}
return [...counts.entries()].map(([type, count]) => `${count} ${type}${count > 1 ? 's' : ''}`).join(', ');
}
/**
* Maximum input length for pattern matching targets.
* Truncates long commands/paths to prevent DoS via pathological glob matching.
*/
const MAX_MATCH_INPUT_LENGTH = 1000;
/**
* Strip null bytes, control characters, and normalize Unicode for match input.
* Preserves tab (\x09), newline (\x0A), carriage return (\x0D).
* Prevents pattern bypass via injected control characters or Unicode
* normalization attacks (e.g., combining characters that look like ASCII).
*/
function sanitizeMatchInput(input) {
// Normalize Unicode to NFC (canonical decomposition then composition).
// This prevents bypass via combining characters or alternative representations.
const normalized = input.normalize('NFC');
// eslint-disable-next-line no-control-regex
return normalized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g, '');
}
/**
* Build match target strings for a tool call.
*
* For Bash: matches against the tool name and "Bash:<command>"
* For Edit/Write: matches against the tool name and "Edit:<file_path>"
* For MCP tools: matches against the full tool name
*
* Inputs are truncated to MAX_MATCH_INPUT_LENGTH and sanitized to prevent
* DoS via pathological glob matching and pattern bypass via control chars.
*/
function buildMatchTargets(toolName, toolInput) {
const targets = [toolName];
if (toolName === 'Bash' && typeof toolInput.command === 'string') {
const sanitized = sanitizeMatchInput(toolInput.command.slice(0, MAX_MATCH_INPUT_LENGTH));
targets.push(`Bash:${sanitized}`);
}
else if ((toolName === 'Edit' || toolName === 'Write') && typeof toolInput.file_path === 'string') {
const sanitized = sanitizeMatchInput(toolInput.file_path.slice(0, MAX_MATCH_INPUT_LENGTH));
targets.push(`${toolName}:${sanitized}`);
}
return targets;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiVG9vbENsYXNzaWZpY2F0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2hhbmRsZXJzL21jcC1hcWwvcG9saWNpZXMvVG9vbENsYXNzaWZpY2F0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7O0dBVUc7QUFFSCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sa0NBQWtDLENBQUM7QUFDbEUsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBaUNsRCx3RUFBd0U7QUFFeEU7Ozs7Ozs7R0FPRztBQUNILE1BQU0sK0JBQStCLEdBQUcsSUFBSSxHQUFHLENBQUM7SUFDOUMsbUJBQW1CO0lBQ25CLGtCQUFrQjtJQUNsQixrQkFBa0I7SUFDbEIsbUJBQW1CO0lBQ25CLFlBQVk7SUFDWixxQkFBcUI7SUFDckIscUJBQXFCO0lBQ3JCLG1CQUFtQjtJQUNuQix3QkFBd0IsRUFBUSxxQkFBcUI7SUFDckQsMkJBQTJCLEVBQUsscUJBQXFCO0NBQ3RELENBQUMsQ0FBQztBQUVIOzs7Ozs7O0dBT0c7QUFDSCxNQUFNLG1CQUFtQixHQUFHLElBQUksR0FBRyxDQUFDO0lBQ2xDLGVBQWU7SUFDZixhQUFhO0lBQ2IscUJBQXFCO0lBQ3JCLGlCQUFpQjtJQUNqQixnQkFBZ0I7SUFDaEIscUJBQXFCO0lBQ3JCLGtCQUFrQjtJQUNsQixRQUFRO0lBQ1IsZ0JBQWdCO0lBQ2hCLFlBQVk7SUFDWixxQkFBcUI7SUFDckIsbUJBQW1CO0lBQ25CLG1CQUFtQjtJQUNuQixtQkFBbUI7SUFDbkIsNEJBQTRCO0lBQzVCLHdCQUF3QjtJQUN4Qiw2QkFBNkI7SUFDN0Isa0JBQWtCO0lBQ2xCLGtCQUFrQjtJQUNsQixrQkFBa0I7SUFDbEIsWUFBWTtJQUNaLG1CQUFtQjtJQUNuQixxQkFBcUI7SUFDckIsa0JBQWtCO0lBQ2xCLGdCQUFnQjtJQUNoQix5QkFBeUI7SUFDekIsWUFBWTtJQUNaLGVBQWU7SUFD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LFFBQVEsRUFBRSxDQUFDO1FBQ3BHLE1BQU0sU0FBUyxHQUFHLGtCQUFrQixDQUFDLFNBQVMsQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxzQkFBc0IsQ0FBQyxDQUFDLENBQUM7UUFDM0YsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLFFBQVEsSUFBSSxTQUFTLEVBQUUsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRCxPQUFPLE9BQU8sQ0FBQztBQUNqQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBUb29sIENsYXNzaWZpY2F0aW9uIGZvciBDTEktTGV2ZWwgUGVybWlzc2lvbiBQcm9tcHRzXG4gKlxuICogUHJvdmlkZXMgc3RhdGljIGNsYXNzaWZpY2F0aW9uIG9mIENsYXVkZSBDb2RlIENMSSB0b29sIGNhbGxzIGFuZFxuICogZXZhbHVhdGlvbiBhZ2FpbnN0IGFjdGl2ZSBlbGVtZW50IGdhdGVrZWVwZXIgcG9saWNpZXMuXG4gKlxuICogVXNlZCBieSB0aGUgcGVybWlzc2lvbl9wcm9tcHQgb3BlcmF0aW9uIChJc3N1ZSAjNjI1KSB0byBldmFsdWF0ZVxuICogLS1wZXJtaXNzaW9uLXByb21wdC10b29sIHJlcXVlc3RzIHdpdGhvdXQgcmVxdWlyaW5nIExMTSBldmFsdWF0aW9uLlxuICpcbiAqIEBtb2R1bGVcbiAqL1xuXG5pbXBvcnQgeyBtYXRjaGVzUGF0dGVybiB9IGZyb20gJy4uLy4uLy4uL3V0aWxzL3BhdHRlcm5NYXRjaGVyLmpzJztcbmltcG9ydCB7IGxvZ2dlciB9IGZyb20gJy4uLy4uLy4uL3V0aWxzL2xvZ2dlci5qcyc7XG5pbXBvcnQgdHlwZSB7IEFjdGl2ZUVsZW1lbnQgfSBmcm9tICcuL0VsZW1lbnRQb2xpY2llcy5qcyc7XG5pbXBvcnQgdHlwZSB7IFJpc2tBc3Nlc3NtZW50IH0gZnJvbSAnLi4vR2F0ZWtlZXBlclR5cGVzLmpzJztcblxuLy8g4pSA4pSAIFR5cGVzIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG5leHBvcnQgdHlwZSBUb29sUmlza0xldmVsID0gJ3NhZmUnIHwgJ21vZGVyYXRlJyB8ICdkYW5nZXJvdXMnIHwgJ2Jsb2NrZWQnO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRvb2xDbGFzc2lmaWNhdGlvblJlc3VsdCB7XG4gIHJpc2tMZXZlbDogVG9vbFJpc2tMZXZlbDtcbiAgLyoqICdhbGxvdycgPSBhdXRvLWFwcHJvdmUsICdkZW55JyA9IGF1dG8tcmVqZWN0LCAnZXZhbHVhdGUnID0gY2hlY2sgZWxlbWVudCBwb2xpY2llcyAqL1xuICBiZWhhdmlvcjogJ2FsbG93JyB8ICdkZW55JyB8ICdldmFsdWF0ZSc7XG4gIHJlYXNvbjogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFBvbGljeUV2YWx1YXRpb25Db250ZXh0IHtcbiAgZXZhbHVhdGVkRWxlbWVudHM6IEFycmF5PHtcbiAgICB0eXBlOiBzdHJpbmc7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIG1hdGNoZWQ/OiAnYWxsb3dQYXR0ZXJucycgfCAnY29uZmlybVBhdHRlcm5zJyB8ICdkZW55UGF0dGVybnMnO1xuICAgIG1hdGNoZWRQYXR0ZXJuPzogc3RyaW5nO1xuICAgIG1hdGNoZWRUYXJnZXQ/OiBzdHJpbmc7XG4gIH0+O1xuICBkZWNpc2lvbkNoYWluOiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDbGlUb29sUG9saWN5UmVzdWx0IHtcbiAgYmVoYXZpb3I6ICdhbGxvdycgfCAnZGVueScgfCAnZXZhbHVhdGUnIHwgJ2NvbmZpcm0nO1xuICBtZXNzYWdlPzogc3RyaW5nO1xuICBjb25maXJtU291cmNlPzogc3RyaW5nO1xuICBwb2xpY3lDb250ZXh0PzogUG9saWN5RXZhbHVhd