@agent-wall/core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +17 -0
- package/.turbo/turbo-test.log +30 -0
- package/LICENSE +21 -0
- package/README.md +80 -0
- package/dist/index.d.ts +1297 -0
- package/dist/index.js +3067 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/src/audit-logger-security.test.ts +225 -0
- package/src/audit-logger.test.ts +93 -0
- package/src/audit-logger.ts +458 -0
- package/src/chain-detector.test.ts +100 -0
- package/src/chain-detector.ts +269 -0
- package/src/dashboard-server.test.ts +362 -0
- package/src/dashboard-server.ts +454 -0
- package/src/egress-control.test.ts +177 -0
- package/src/egress-control.ts +274 -0
- package/src/index.ts +137 -0
- package/src/injection-detector.test.ts +207 -0
- package/src/injection-detector.ts +397 -0
- package/src/kill-switch.test.ts +119 -0
- package/src/kill-switch.ts +198 -0
- package/src/policy-engine-security.test.ts +227 -0
- package/src/policy-engine.test.ts +453 -0
- package/src/policy-engine.ts +414 -0
- package/src/policy-loader.test.ts +202 -0
- package/src/policy-loader.ts +485 -0
- package/src/proxy.ts +786 -0
- package/src/read-buffer-security.test.ts +59 -0
- package/src/read-buffer.test.ts +135 -0
- package/src/read-buffer.ts +126 -0
- package/src/response-scanner.test.ts +464 -0
- package/src/response-scanner.ts +587 -0
- package/src/types.test.ts +152 -0
- package/src/types.ts +146 -0
- package/tsconfig.json +8 -0
- package/tsup.config.ts +9 -0
- package/vitest.config.ts +12 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/read-buffer.ts","../src/policy-engine.ts","../src/policy-loader.ts","../src/response-scanner.ts","../src/audit-logger.ts","../src/proxy.ts","../src/injection-detector.ts","../src/egress-control.ts","../src/kill-switch.ts","../src/chain-detector.ts","../src/dashboard-server.ts"],"sourcesContent":["/**\n * Agent Wall JSON-RPC Types\n *\n * Mirrors the MCP protocol's JSON-RPC 2.0 message format.\n * We define our own types instead of depending on the MCP SDK\n * so Agent Wall has zero coupling to any specific MCP version.\n */\n\nimport { z } from \"zod\";\n\n// ── JSON-RPC 2.0 Base ──────────────────────────────────────────────\n\nexport const JsonRpcRequestSchema = z.object({\n jsonrpc: z.literal(\"2.0\"),\n id: z.union([z.string(), z.number()]),\n method: z.string(),\n params: z.record(z.unknown()).optional(),\n});\n\nexport const JsonRpcNotificationSchema = z.object({\n jsonrpc: z.literal(\"2.0\"),\n method: z.string(),\n params: z.record(z.unknown()).optional(),\n});\n\nexport const JsonRpcResponseSchema = z.object({\n jsonrpc: z.literal(\"2.0\"),\n id: z.union([z.string(), z.number()]),\n result: z.unknown().optional(),\n error: z\n .object({\n code: z.number(),\n message: z.string(),\n data: z.unknown().optional(),\n })\n .optional(),\n});\n\nexport const JsonRpcMessageSchema = z.union([\n JsonRpcRequestSchema,\n JsonRpcNotificationSchema,\n JsonRpcResponseSchema,\n]);\n\nexport type JsonRpcRequest = z.infer<typeof JsonRpcRequestSchema>;\nexport type JsonRpcNotification = z.infer<typeof JsonRpcNotificationSchema>;\nexport type JsonRpcResponse = z.infer<typeof JsonRpcResponseSchema>;\nexport type JsonRpcMessage = z.infer<typeof JsonRpcMessageSchema>;\n\n// ── MCP-specific message types ──────────────────────────────────────\n\n/** MCP tools/call request params */\nexport interface ToolCallParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\n/** MCP tools/list result */\nexport interface ToolListResult {\n tools: Array<{\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n annotations?: Record<string, unknown>;\n }>;\n nextCursor?: string;\n}\n\n/** MCP response content block (text, image, resource) */\nexport interface McpContentBlock {\n type: string;\n text?: string;\n data?: string;\n mimeType?: string;\n [key: string]: unknown;\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────\n\nexport function isRequest(msg: JsonRpcMessage): msg is JsonRpcRequest {\n return \"id\" in msg && \"method\" in msg;\n}\n\nexport function isNotification(\n msg: JsonRpcMessage\n): msg is JsonRpcNotification {\n return !(\"id\" in msg) && \"method\" in msg;\n}\n\nexport function isResponse(msg: JsonRpcMessage): msg is JsonRpcResponse {\n return \"id\" in msg && !(\"method\" in msg);\n}\n\nexport function isToolCall(msg: JsonRpcMessage): boolean {\n return isRequest(msg) && msg.method === \"tools/call\";\n}\n\nexport function isToolList(msg: JsonRpcMessage): boolean {\n return isRequest(msg) && msg.method === \"tools/list\";\n}\n\nexport function getToolCallParams(\n msg: JsonRpcRequest\n): ToolCallParams | null {\n if (msg.method !== \"tools/call\" || !msg.params) return null;\n const params = msg.params as Record<string, unknown>;\n if (typeof params.name !== \"string\") return null;\n return {\n name: params.name,\n arguments: (params.arguments as Record<string, unknown>) ?? {},\n };\n}\n\n/**\n * Create a JSON-RPC error response for a denied tool call.\n */\nexport function createDenyResponse(\n id: string | number,\n message: string\n): JsonRpcResponse {\n return {\n jsonrpc: \"2.0\",\n id,\n error: {\n code: -32001, // Custom: policy denied\n message: `Agent Wall: ${message}`,\n },\n };\n}\n\n/**\n * Create a JSON-RPC error response for a tool call requiring approval.\n */\nexport function createPromptResponse(\n id: string | number,\n message: string\n): JsonRpcResponse {\n return {\n jsonrpc: \"2.0\",\n id,\n error: {\n code: -32002, // Custom: awaiting approval\n message: `Agent Wall: Awaiting approval — ${message}`,\n },\n };\n}\n","/**\n * Agent Wall Read Buffer\n *\n * Accumulates raw bytes from a stream and extracts\n * newline-delimited JSON-RPC messages one at a time.\n *\n * Directly mirrors the MCP SDK's ReadBuffer pattern:\n * - Append raw chunks\n * - Scan for '\\n' delimiter\n * - Extract line, strip '\\r', JSON.parse, validate\n *\n * Security: Enforces maximum buffer size to prevent DOS\n * via unbounded memory growth from a single large message.\n */\n\nimport { JsonRpcMessage, JsonRpcMessageSchema } from \"./types.js\";\n\n/** Default max buffer size: 10MB */\nconst DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;\n\nexport class ReadBuffer {\n private buffer: Buffer | null = null;\n private maxBufferSize: number;\n\n constructor(maxBufferSize: number = DEFAULT_MAX_BUFFER_SIZE) {\n this.maxBufferSize = maxBufferSize;\n }\n\n /**\n * Append raw bytes from a stream chunk.\n * Throws if the buffer exceeds the configured maximum size.\n */\n append(chunk: Buffer): void {\n this.buffer = this.buffer ? Buffer.concat([this.buffer, chunk]) : chunk;\n if (this.buffer.length > this.maxBufferSize) {\n const size = this.buffer.length;\n this.buffer = null;\n throw new BufferOverflowError(\n `Buffer size ${size} exceeds maximum ${this.maxBufferSize} bytes — possible DOS attack`\n );\n }\n }\n\n /**\n * Try to extract the next complete JSON-RPC message.\n * Returns null if no complete message is available yet.\n * Automatically skips empty lines.\n */\n readMessage(): JsonRpcMessage | null {\n while (this.buffer) {\n const index = this.buffer.indexOf(\"\\n\");\n if (index === -1) return null;\n\n // Extract the line (strip trailing \\r for Windows compatibility)\n const line = this.buffer.toString(\"utf8\", 0, index).replace(/\\r$/, \"\");\n this.buffer = this.buffer.subarray(index + 1);\n\n // Normalize: discard buffer reference if empty\n if (this.buffer.length === 0) this.buffer = null;\n\n // Skip empty lines\n if (line.length === 0) continue;\n\n return deserializeMessage(line);\n }\n return null;\n }\n\n /**\n * Extract ALL available messages from the buffer.\n */\n readAllMessages(): JsonRpcMessage[] {\n const messages: JsonRpcMessage[] = [];\n let msg: JsonRpcMessage | null;\n while ((msg = this.readMessage()) !== null) {\n messages.push(msg);\n }\n return messages;\n }\n\n /**\n * Clear the buffer.\n */\n clear(): void {\n this.buffer = null;\n }\n\n /**\n * Check if there's any pending data in the buffer.\n */\n get hasPendingData(): boolean {\n return this.buffer !== null && this.buffer.length > 0;\n }\n\n /**\n * Get current buffer size in bytes.\n */\n get currentSize(): number {\n return this.buffer?.length ?? 0;\n }\n}\n\n/**\n * Error thrown when buffer exceeds maximum size.\n */\nexport class BufferOverflowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"BufferOverflowError\";\n }\n}\n\n/**\n * Parse a single line of text into a validated JSON-RPC message.\n */\nexport function deserializeMessage(line: string): JsonRpcMessage {\n const parsed = JSON.parse(line);\n return JsonRpcMessageSchema.parse(parsed);\n}\n\n/**\n * Serialize a JSON-RPC message to a newline-delimited string.\n */\nexport function serializeMessage(message: JsonRpcMessage): string {\n return JSON.stringify(message) + \"\\n\";\n}\n","/**\n * Agent Wall Policy Engine\n *\n * Evaluates tool calls against YAML-defined rules.\n * Rules are matched in order — first match wins.\n * If no rule matches, the default action applies.\n *\n * Security hardening:\n * - Path normalization (resolves ../ before matching)\n * - Unicode NFC normalization (prevents homoglyph bypass)\n * - Zero-trust \"strict\" mode (default deny, only explicit allows pass)\n * - Safe regex construction (prevents ReDoS in argument matching)\n * - Deep argument scanning across all string values\n */\n\nimport * as path from \"node:path\";\nimport { minimatch } from \"minimatch\";\nimport type { ToolCallParams } from \"./types.js\";\nimport type { InjectionDetectorConfig } from \"./injection-detector.js\";\nimport type { EgressControlConfig } from \"./egress-control.js\";\nimport type { KillSwitchConfig } from \"./kill-switch.js\";\nimport type { ChainDetectorConfig } from \"./chain-detector.js\";\n\n// ── Rule Types ──────────────────────────────────────────────────────\n\nexport type RuleAction = \"allow\" | \"deny\" | \"prompt\";\n\n/** Policy mode: \"standard\" (backward-compatible) or \"strict\" (zero-trust) */\nexport type PolicyMode = \"standard\" | \"strict\";\n\nexport interface RuleMatch {\n /** Glob patterns matched against string values in arguments */\n arguments?: Record<string, string>;\n}\n\nexport interface RateLimitConfig {\n maxCalls: number;\n windowSeconds: number;\n}\n\nexport interface PolicyRule {\n name: string;\n /** Glob pattern for tool name(s). Use \"|\" to separate multiple patterns. */\n tool: string;\n /** Optional argument matching */\n match?: RuleMatch;\n /** What to do when this rule matches */\n action: RuleAction;\n /** Human-readable message shown when rule triggers */\n message?: string;\n /** Rate limiting for this rule's scope */\n rateLimit?: RateLimitConfig;\n}\n\n/** Security modules configuration. */\nexport interface SecurityConfig {\n /** Prompt injection detection */\n injectionDetection?: InjectionDetectorConfig;\n /** URL/SSRF egress control */\n egressControl?: EgressControlConfig;\n /** Emergency kill switch */\n killSwitch?: KillSwitchConfig;\n /** Tool call chain/sequence detection */\n chainDetection?: ChainDetectorConfig;\n /** Enable HMAC-SHA256 audit log signing */\n signing?: boolean;\n /** Signing key (auto-generated per session if not provided) */\n signingKey?: string;\n}\n\nexport interface PolicyConfig {\n version: number;\n /** Policy mode: \"standard\" (default) or \"strict\" (zero-trust deny-by-default) */\n mode?: PolicyMode;\n /** Default action when no rule matches (overridden to \"deny\" in strict mode) */\n defaultAction?: RuleAction;\n /** Global rate limit across all tools */\n globalRateLimit?: RateLimitConfig;\n /** Response scanning configuration */\n responseScanning?: ResponseScannerPolicyConfig;\n /** Security modules (injection detection, egress control, kill switch, chain detection) */\n security?: SecurityConfig;\n /** Ordered list of rules — first match wins */\n rules: PolicyRule[];\n}\n\n/** Response scanning section in the YAML policy. */\nexport interface ResponseScannerPolicyConfig {\n enabled?: boolean;\n maxResponseSize?: number;\n oversizeAction?: \"block\" | \"redact\";\n detectSecrets?: boolean;\n detectPII?: boolean;\n /** Action for base64 blob detection: \"pass\" (default), \"redact\", or \"block\" */\n base64Action?: \"pass\" | \"redact\" | \"block\";\n /** Maximum number of custom patterns allowed (default: 100) */\n maxPatterns?: number;\n patterns?: Array<{\n name: string;\n pattern: string;\n flags?: string;\n action: \"pass\" | \"redact\" | \"block\";\n message?: string;\n category?: string;\n }>;\n}\n\n// ── Policy Evaluation Result ────────────────────────────────────────\n\nexport interface PolicyVerdict {\n action: RuleAction;\n rule: string | null; // Name of the matched rule, or null for default\n message: string;\n}\n\n// ── Rate Limiter ────────────────────────────────────────────────────\n\ninterface RateLimitBucket {\n timestamps: number[];\n}\n\nclass RateLimiter {\n private buckets = new Map<string, RateLimitBucket>();\n\n check(key: string, config: RateLimitConfig): boolean {\n const now = Date.now();\n const windowMs = config.windowSeconds * 1000;\n const bucket = this.buckets.get(key) ?? { timestamps: [] };\n\n // Prune old entries outside the window\n bucket.timestamps = bucket.timestamps.filter((t) => now - t < windowMs);\n\n if (bucket.timestamps.length >= config.maxCalls) {\n return false; // Rate limit exceeded\n }\n\n bucket.timestamps.push(now);\n this.buckets.set(key, bucket);\n return true;\n }\n\n reset(): void {\n this.buckets.clear();\n }\n}\n\n// ── Normalization Utilities ─────────────────────────────────────────\n\n/**\n * Normalize a string value for secure matching:\n * 1. Unicode NFC normalization (prevents homoglyph/decomposition bypass)\n * 2. Path normalization for path-like values (resolves ../ traversal)\n */\nfunction normalizeValue(value: string): string {\n // Unicode NFC normalization\n let normalized = value.normalize(\"NFC\");\n\n // Path normalization: if it looks like a file path, resolve traversals\n if (looksLikePath(normalized)) {\n normalized = normalizePath(normalized);\n }\n\n return normalized;\n}\n\n/**\n * Heuristic: does this string look like a file path?\n */\nfunction looksLikePath(value: string): boolean {\n return (\n value.includes(\"/\") ||\n value.includes(\"\\\\\") ||\n value.startsWith(\".\") ||\n value.startsWith(\"~\")\n );\n}\n\n/**\n * Normalize a file path: resolve ../ and ./ components, normalize separators.\n * Does NOT resolve to absolute path (preserves relative paths).\n */\nfunction normalizePath(p: string): string {\n // Normalize separators to forward slash\n let normalized = p.replace(/\\\\/g, \"/\");\n\n // Use path.posix.normalize to resolve ../ and ./\n normalized = path.posix.normalize(normalized);\n\n return normalized;\n}\n\n/**\n * Safe glob-to-regex conversion with ReDoS protection.\n * Limits the resulting regex complexity.\n */\nfunction safeGlobToRegex(pattern: string): RegExp | null {\n // Reject patterns that are too long (ReDoS vector)\n if (pattern.length > 500) return null;\n\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\");\n\n try {\n return new RegExp(`^${escaped}$`, \"i\");\n } catch {\n return null;\n }\n}\n\n// ── Common argument key aliases ─────────────────────────────────────\n\n/**\n * Map of common argument key aliases for path-like values.\n * If a rule specifies \"path\", it also matches \"file\", \"filepath\", etc.\n */\nconst PATH_KEY_ALIASES: Record<string, string[]> = {\n path: [\"file\", \"filepath\", \"file_path\", \"filename\", \"file_name\", \"target\", \"source\", \"destination\", \"dest\", \"src\", \"uri\", \"url\"],\n command: [\"cmd\", \"shell\", \"exec\", \"script\", \"run\"],\n content: [\"text\", \"body\", \"data\", \"input\", \"message\"],\n};\n\n/**\n * Get all alias keys for a given argument key.\n */\nfunction getKeyAliases(key: string): string[] {\n const lowerKey = key.toLowerCase();\n // Direct aliases\n const aliases = PATH_KEY_ALIASES[lowerKey];\n if (aliases) return [lowerKey, ...aliases];\n\n // Reverse lookup: if key is an alias, find its canonical form\n for (const [canonical, aliasList] of Object.entries(PATH_KEY_ALIASES)) {\n if (aliasList.includes(lowerKey)) {\n return [canonical, ...aliasList];\n }\n }\n\n return [lowerKey];\n}\n\n// ── Policy Engine ───────────────────────────────────────────────────\n\nexport class PolicyEngine {\n private config: PolicyConfig;\n private rateLimiter = new RateLimiter();\n\n constructor(config: PolicyConfig) {\n this.config = config;\n }\n\n /**\n * Update the policy configuration (e.g., after file reload).\n */\n updateConfig(config: PolicyConfig): void {\n this.config = config;\n this.rateLimiter.reset();\n }\n\n /**\n * Evaluate a tool call against the policy rules.\n * Returns the verdict: allow, deny, or prompt.\n */\n evaluate(toolCall: ToolCallParams): PolicyVerdict {\n // 1. Check global rate limit\n if (this.config.globalRateLimit) {\n if (!this.rateLimiter.check(\"__global__\", this.config.globalRateLimit)) {\n return {\n action: \"deny\",\n rule: \"__global_rate_limit__\",\n message: `Global rate limit exceeded (${this.config.globalRateLimit.maxCalls} calls per ${this.config.globalRateLimit.windowSeconds}s)`,\n };\n }\n }\n\n // 2. Evaluate rules in order — first match wins\n for (const rule of this.config.rules) {\n if (this.matchesRule(rule, toolCall)) {\n // Check per-rule rate limit\n if (rule.rateLimit) {\n if (!this.rateLimiter.check(`rule:${rule.name}`, rule.rateLimit)) {\n return {\n action: \"deny\",\n rule: rule.name,\n message:\n rule.message ??\n `Rate limit exceeded for rule \"${rule.name}\" (${rule.rateLimit.maxCalls} per ${rule.rateLimit.windowSeconds}s)`,\n };\n }\n }\n\n return {\n action: rule.action,\n rule: rule.name,\n message:\n rule.message ??\n `${rule.action === \"deny\" ? \"Blocked\" : rule.action === \"prompt\" ? \"Approval required\" : \"Allowed\"} by rule \"${rule.name}\"`,\n };\n }\n }\n\n // 3. No rule matched — use default action\n // In strict (zero-trust) mode, default is always \"deny\"\n const isStrict = this.config.mode === \"strict\";\n const defaultAction = isStrict ? \"deny\" : (this.config.defaultAction ?? \"prompt\");\n return {\n action: defaultAction,\n rule: null,\n message: isStrict\n ? `Zero-trust mode: no matching allow rule. Denied by default.`\n : `No matching rule. Default action: ${defaultAction}`,\n };\n }\n\n /**\n * Check if a rule matches a tool call.\n */\n private matchesRule(rule: PolicyRule, toolCall: ToolCallParams): boolean {\n // Match tool name — normalize with NFC\n const normalizedToolName = toolCall.name.normalize(\"NFC\");\n if (!this.matchToolName(rule.tool, normalizedToolName)) {\n return false;\n }\n\n // Match arguments if specified\n if (rule.match?.arguments) {\n if (!this.matchArguments(rule.match.arguments, toolCall.arguments ?? {})) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Match a tool name against a pattern.\n * Pattern can contain \"|\" for multiple alternatives.\n */\n private matchToolName(pattern: string, toolName: string): boolean {\n const patterns = pattern.split(\"|\").map((p) => p.trim());\n return patterns.some((p) => minimatch(toolName, p));\n }\n\n /**\n * Match rule argument patterns against actual tool arguments.\n * Each key in ruleArgs is an argument name, value is a glob pattern.\n * ALL specified argument patterns must match for the rule to match.\n *\n * Security: normalizes paths and unicode before matching.\n * Security: checks key aliases (path → file, filepath, etc.)\n */\n private matchArguments(\n ruleArgs: Record<string, string>,\n actualArgs: Record<string, unknown>\n ): boolean {\n for (const [key, pattern] of Object.entries(ruleArgs)) {\n // Get the actual value — try the key directly and all aliases\n const aliases = getKeyAliases(key);\n let rawValue: unknown;\n for (const alias of aliases) {\n // Case-insensitive key lookup\n const found = Object.entries(actualArgs).find(\n ([k]) => k.toLowerCase() === alias\n );\n if (found !== undefined && found[1] !== undefined) {\n rawValue = found[1];\n break;\n }\n }\n\n if (rawValue === undefined) return false;\n\n // Normalize the value (Unicode NFC + path traversal resolution)\n const strValue = normalizeValue(String(rawValue));\n const patterns = pattern.split(\"|\").map((p) => p.trim());\n\n // At least one pattern must match\n const matched = patterns.some((p) => {\n // Try glob match with dot:true so patterns match dotfiles\n if (minimatch(strValue, p, { dot: true })) return true;\n\n // Fallback: safe glob-to-regex for non-path strings\n if (p.includes(\"*\") || p.includes(\"?\")) {\n const regex = safeGlobToRegex(p);\n if (regex && regex.test(strValue)) return true;\n }\n\n // Also try case-insensitive substring for simple patterns\n if (!p.includes(\"*\") && !p.includes(\"?\")) {\n return strValue.toLowerCase().includes(p.toLowerCase());\n }\n return false;\n });\n\n if (!matched) return false;\n }\n return true;\n }\n\n /**\n * Get the current policy config.\n */\n getConfig(): PolicyConfig {\n return this.config;\n }\n\n /**\n * Get all rule names.\n */\n getRuleNames(): string[] {\n return this.config.rules.map((r) => r.name);\n }\n}\n","/**\n * Agent Wall Policy Loader\n *\n * Loads and validates policy configuration from YAML files.\n * Supports loading from a specific path or auto-discovering\n * agent-wall.yaml in the current directory or parent directories.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as yaml from \"js-yaml\";\nimport { z } from \"zod\";\nimport type { PolicyConfig, PolicyRule, RuleAction, SecurityConfig } from \"./policy-engine.js\";\n\n// ── YAML Schema Validation ──────────────────────────────────────────\n\nconst RateLimitSchema = z.object({\n maxCalls: z.number().int().positive(),\n windowSeconds: z.number().positive(),\n});\n\nconst RuleMatchSchema = z.object({\n arguments: z.record(z.string()).optional(),\n});\n\nconst PolicyRuleSchema = z.object({\n name: z.string().min(1),\n tool: z.string().min(1),\n match: RuleMatchSchema.optional(),\n action: z.enum([\"allow\", \"deny\", \"prompt\"]),\n message: z.string().optional(),\n rateLimit: RateLimitSchema.optional(),\n});\n\nconst ResponsePatternSchema = z.object({\n name: z.string().min(1),\n pattern: z.string().min(1),\n flags: z.string().optional(),\n action: z.enum([\"pass\", \"redact\", \"block\"]),\n message: z.string().optional(),\n category: z.string().optional(),\n});\n\nconst ResponseScanningSchema = z.object({\n enabled: z.boolean().optional(),\n maxResponseSize: z.number().int().nonnegative().optional(),\n oversizeAction: z.enum([\"block\", \"redact\"]).optional(),\n detectSecrets: z.boolean().optional(),\n detectPII: z.boolean().optional(),\n base64Action: z.enum([\"pass\", \"redact\", \"block\"]).optional(),\n maxPatterns: z.number().int().positive().optional(),\n patterns: z.array(ResponsePatternSchema).optional(),\n});\n\n// ── Security Config Schemas ──────────────────────────────────────────\n\nconst InjectionDetectionSchema = z.object({\n enabled: z.boolean().optional(),\n sensitivity: z.enum([\"low\", \"medium\", \"high\"]).optional(),\n customPatterns: z.array(z.string()).optional(),\n excludeTools: z.array(z.string()).optional(),\n});\n\nconst EgressControlSchema = z.object({\n enabled: z.boolean().optional(),\n allowedDomains: z.array(z.string()).optional(),\n blockedDomains: z.array(z.string()).optional(),\n blockPrivateIPs: z.boolean().optional(),\n blockMetadataEndpoints: z.boolean().optional(),\n excludeTools: z.array(z.string()).optional(),\n});\n\nconst KillSwitchSchema = z.object({\n enabled: z.boolean().optional(),\n checkFile: z.boolean().optional(),\n killFileNames: z.array(z.string()).optional(),\n pollIntervalMs: z.number().int().positive().optional(),\n});\n\nconst ChainDetectionSchema = z.object({\n enabled: z.boolean().optional(),\n windowSize: z.number().int().positive().optional(),\n windowMs: z.number().int().positive().optional(),\n});\n\nconst SecuritySchema = z.object({\n injectionDetection: InjectionDetectionSchema.optional(),\n egressControl: EgressControlSchema.optional(),\n killSwitch: KillSwitchSchema.optional(),\n chainDetection: ChainDetectionSchema.optional(),\n signing: z.boolean().optional(),\n signingKey: z.string().optional(),\n});\n\nconst PolicyConfigSchema = z.object({\n version: z.number().int().min(1),\n mode: z.enum([\"standard\", \"strict\"]).optional(),\n defaultAction: z.enum([\"allow\", \"deny\", \"prompt\"]).optional(),\n globalRateLimit: RateLimitSchema.optional(),\n responseScanning: ResponseScanningSchema.optional(),\n security: SecuritySchema.optional(),\n rules: z.array(PolicyRuleSchema),\n});\n\n// ── Config File Names ───────────────────────────────────────────────\n\nconst CONFIG_FILENAMES = [\n \"agent-wall.yaml\",\n \"agent-wall.yml\",\n \".agent-wall.yaml\",\n \".agent-wall.yml\",\n // Legacy support\n\n];\n\n// ── Loader Functions ────────────────────────────────────────────────\n\n/**\n * Load a policy config from a specific file path.\n */\nexport function loadPolicyFile(filePath: string): PolicyConfig {\n if (!fs.existsSync(filePath)) {\n throw new Error(`Policy file not found: ${filePath}`);\n }\n\n const content = fs.readFileSync(filePath, \"utf-8\");\n return parsePolicyYaml(content);\n}\n\n/**\n * Parse a YAML string into a validated PolicyConfig.\n */\nexport function parsePolicyYaml(yamlContent: string): PolicyConfig {\n const raw = yaml.load(yamlContent, { schema: yaml.JSON_SCHEMA });\n const validated = PolicyConfigSchema.parse(raw);\n return validated as PolicyConfig;\n}\n\n/**\n * Auto-discover the nearest agent-wall.yaml by walking up\n * from the given directory (defaults to cwd).\n * Returns the file path if found, null otherwise.\n */\nexport function discoverPolicyFile(\n startDir: string = process.cwd()\n): string | null {\n let dir = path.resolve(startDir);\n\n while (true) {\n for (const filename of CONFIG_FILENAMES) {\n const candidate = path.join(dir, filename);\n if (fs.existsSync(candidate)) {\n return candidate;\n }\n }\n\n const parent = path.dirname(dir);\n if (parent === dir) break; // Reached filesystem root\n dir = parent;\n }\n\n return null;\n}\n\n/**\n * Load the policy config by auto-discovering the config file.\n * Falls back to default policy if no config file found.\n */\nexport function loadPolicy(configPath?: string): {\n config: PolicyConfig;\n filePath: string | null;\n} {\n if (configPath) {\n return {\n config: loadPolicyFile(configPath),\n filePath: configPath,\n };\n }\n\n const discovered = discoverPolicyFile();\n if (discovered) {\n return {\n config: loadPolicyFile(discovered),\n filePath: discovered,\n };\n }\n\n // No config found — return sensible defaults\n return {\n config: getDefaultPolicy(),\n filePath: null,\n };\n}\n\n/**\n * Get the default policy config.\n * Ships with Agent Wall — provides reasonable security out of the box.\n */\nexport function getDefaultPolicy(): PolicyConfig {\n return {\n version: 1,\n defaultAction: \"prompt\",\n globalRateLimit: {\n maxCalls: 200,\n windowSeconds: 60,\n },\n responseScanning: {\n enabled: true,\n maxResponseSize: 5 * 1024 * 1024, // 5MB\n oversizeAction: \"redact\",\n detectSecrets: true,\n detectPII: false,\n },\n security: {\n injectionDetection: { enabled: true, sensitivity: \"medium\" },\n egressControl: { enabled: true, blockPrivateIPs: true, blockMetadataEndpoints: true },\n killSwitch: { enabled: true, checkFile: true },\n chainDetection: { enabled: true },\n signing: false,\n },\n rules: [\n // ── Always block: credential access ──\n {\n name: \"block-ssh-keys\",\n tool: \"*\",\n match: { arguments: { path: \"**/.ssh/**|**/.ssh\" } },\n action: \"deny\" as RuleAction,\n message: \"Access to SSH keys is blocked by default policy\",\n },\n {\n name: \"block-env-files\",\n tool: \"*\",\n match: { arguments: { path: \"**/.env*\" } },\n action: \"deny\" as RuleAction,\n message: \"Access to .env files is blocked by default policy\",\n },\n {\n name: \"block-credential-files\",\n tool: \"*\",\n match: {\n arguments: { path: \"*credentials*|**/*.pem|**/*.key|**/*.pfx|**/*.p12\" },\n },\n action: \"deny\" as RuleAction,\n message: \"Access to credential files is blocked by default policy\",\n },\n // ── Always block: exfiltration patterns ──\n {\n name: \"block-curl-exfil\",\n tool: \"shell_exec|run_command|execute_command\",\n match: { arguments: { command: \"*curl *\" } },\n action: \"deny\" as RuleAction,\n message:\n \"Shell commands with curl are blocked — potential data exfiltration\",\n },\n {\n name: \"block-wget-exfil\",\n tool: \"shell_exec|run_command|execute_command\",\n match: { arguments: { command: \"*wget *\" } },\n action: \"deny\" as RuleAction,\n message:\n \"Shell commands with wget are blocked — potential data exfiltration\",\n },\n {\n name: \"block-netcat-exfil\",\n tool: \"shell_exec|run_command|execute_command\",\n match: { arguments: { command: \"*nc *|*ncat *|*netcat *\" } },\n action: \"deny\" as RuleAction,\n message:\n \"Shell commands with netcat are blocked — potential data exfiltration\",\n },\n {\n name: \"block-powershell-exfil\",\n tool: \"shell_exec|run_command|execute_command|bash\",\n match: { arguments: { command: \"*powershell*|*pwsh*|*Invoke-WebRequest*|*Invoke-RestMethod*|*DownloadString*|*DownloadFile*|*Start-BitsTransfer*\" } },\n action: \"deny\" as RuleAction,\n message:\n \"PowerShell command blocked — potential data exfiltration\",\n },\n {\n name: \"block-dns-exfil\",\n tool: \"shell_exec|run_command|execute_command|bash\",\n match: { arguments: { command: \"*nslookup *|*dig *|*host *\" } },\n action: \"deny\" as RuleAction,\n message:\n \"DNS lookup command blocked — potential DNS exfiltration vector\",\n },\n // ── Require approval: scripting language one-liners ──\n {\n name: \"approve-script-exec\",\n tool: \"shell_exec|run_command|execute_command|bash\",\n match: { arguments: { command: \"*python* -c *|*python3* -c *|*ruby* -e *|*perl* -e *|*node* -e *|*node* --eval*\" } },\n action: \"prompt\" as RuleAction,\n message:\n \"Inline script execution requires approval — may be used for exfiltration\",\n },\n // ── Require approval: destructive operations ──\n {\n name: \"approve-file-delete\",\n tool: \"*delete*|*remove*|*unlink*\",\n action: \"prompt\" as RuleAction,\n message: \"File deletion requires approval\",\n },\n {\n name: \"approve-shell-exec\",\n tool: \"shell_exec|run_command|execute_command|bash\",\n action: \"prompt\" as RuleAction,\n message: \"Shell command execution requires approval\",\n },\n // ── Allow: safe read operations ──\n {\n name: \"allow-read-file\",\n tool: \"read_file|get_file_contents|view_file\",\n action: \"allow\" as RuleAction,\n },\n {\n name: \"allow-list-dir\",\n tool: \"list_directory|list_dir|ls\",\n action: \"allow\" as RuleAction,\n },\n {\n name: \"allow-search\",\n tool: \"search_files|grep|find_files|ripgrep\",\n action: \"allow\" as RuleAction,\n },\n ],\n };\n}\n\n/**\n * Generate the default agent-wall.yaml content for `agent-wall init`.\n */\nexport function generateDefaultConfigYaml(): string {\n return `# Agent Wall Policy Configuration\n# Docs: https://github.com/agent-wall/agent-wall\n#\n# Rules are evaluated in order — first match wins.\n# Actions: allow, deny, prompt (ask human for approval)\n\nversion: 1\n\n# Default action when no rule matches\ndefaultAction: prompt\n\n# Global rate limit across all tools\nglobalRateLimit:\n maxCalls: 200\n windowSeconds: 60\n\n# Response scanning — inspect what the MCP server returns\n# before it reaches the AI agent\nresponseScanning:\n enabled: true\n maxResponseSize: 5242880 # 5MB\n oversizeAction: redact # \"block\" or \"redact\" (truncate)\n detectSecrets: true # API keys, tokens, private keys\n detectPII: false # Email, phone, SSN, credit cards (opt-in)\n # Custom patterns (optional):\n # patterns:\n # - name: internal-urls\n # pattern: \"https?://internal\\\\.[a-z]+\\\\.corp\"\n # action: redact\n # message: \"Internal URL detected\"\n # category: custom\n\n# Security modules\nsecurity:\n injectionDetection:\n enabled: true\n sensitivity: medium # low, medium, high\n egressControl:\n enabled: true\n blockPrivateIPs: true # Block RFC1918, loopback, link-local IPs\n blockMetadataEndpoints: true # Block cloud metadata (169.254.169.254)\n killSwitch:\n enabled: true\n checkFile: true # Watch for .agent-wall-kill file\n chainDetection:\n enabled: true # Detect exfiltration chains (read→curl, etc.)\n signing: false # HMAC-SHA256 audit log signing\n\nrules:\n # ── Block: Credential Access ────────────────────────────\n - name: block-ssh-keys\n tool: \"*\"\n match:\n arguments:\n path: \"**/.ssh/**|**/.ssh\"\n action: deny\n message: \"Access to SSH keys is blocked\"\n\n - name: block-env-files\n tool: \"*\"\n match:\n arguments:\n path: \"**/.env*\"\n action: deny\n message: \"Access to .env files is blocked\"\n\n - name: block-credential-files\n tool: \"*\"\n match:\n arguments:\n path: \"*credentials*|**/*.pem|**/*.key|**/*.pfx|**/*.p12\"\n action: deny\n message: \"Access to credential files is blocked\"\n\n # ── Block: Exfiltration Patterns ────────────────────────\n - name: block-curl-exfil\n tool: \"shell_exec|run_command|execute_command\"\n match:\n arguments:\n command: \"*curl *\"\n action: deny\n message: \"Shell commands with curl are blocked (potential exfiltration)\"\n\n - name: block-wget-exfil\n tool: \"shell_exec|run_command|execute_command\"\n match:\n arguments:\n command: \"*wget *\"\n action: deny\n message: \"Shell commands with wget are blocked (potential exfiltration)\"\n\n - name: block-netcat-exfil\n tool: \"shell_exec|run_command|execute_command\"\n match:\n arguments:\n command: \"*nc *|*ncat *|*netcat *\"\n action: deny\n message: \"Shell commands with netcat are blocked (potential exfiltration)\"\n\n - name: block-powershell-exfil\n tool: \"shell_exec|run_command|execute_command|bash\"\n match:\n arguments:\n command: \"*powershell*|*pwsh*|*Invoke-WebRequest*|*Invoke-RestMethod*|*DownloadString*|*DownloadFile*|*Start-BitsTransfer*\"\n action: deny\n message: \"PowerShell command blocked (potential exfiltration)\"\n\n - name: block-dns-exfil\n tool: \"shell_exec|run_command|execute_command|bash\"\n match:\n arguments:\n command: \"*nslookup *|*dig *|*host *\"\n action: deny\n message: \"DNS lookup blocked (potential DNS exfiltration)\"\n\n # ── Prompt: Scripting One-Liners ────────────────────\n - name: approve-script-exec\n tool: \"shell_exec|run_command|execute_command|bash\"\n match:\n arguments:\n command: \"*python* -c *|*python3* -c *|*ruby* -e *|*perl* -e *|*node* -e *|*node* --eval*\"\n action: prompt\n message: \"Inline script execution requires approval\"\n\n # ── Prompt: Destructive Operations ──────────────────────\n - name: approve-file-delete\n tool: \"*delete*|*remove*|*unlink*\"\n action: prompt\n message: \"File deletion requires approval\"\n\n - name: approve-shell-exec\n tool: \"shell_exec|run_command|execute_command|bash\"\n action: prompt\n message: \"Shell command execution requires approval\"\n\n # ── Allow: Safe Read Operations ─────────────────────────\n - name: allow-read-file\n tool: \"read_file|get_file_contents|view_file\"\n action: allow\n\n - name: allow-list-dir\n tool: \"list_directory|list_dir|ls\"\n action: allow\n\n - name: allow-search\n tool: \"search_files|grep|find_files|ripgrep\"\n action: allow\n\n # ────────────────────────────────────────────────────────\n # Add your own rules below. Remember: first match wins!\n # ────────────────────────────────────────────────────────\n`;\n}\n","/**\n * Agent Wall Response Scanner\n *\n * Inspects MCP server responses BEFORE they reach the AI agent.\n * This is the second half of the firewall:\n * - Policy Engine controls what goes IN (tool calls)\n * - Response Scanner controls what comes OUT (tool results)\n *\n * Detects:\n * 1. Secret leaks (API keys, tokens, passwords in response text)\n * 2. Data exfiltration markers (base64 blobs, large hex dumps)\n * 3. Sensitive file content (private keys, certificates, AWS creds)\n * 4. Oversized responses (context window stuffing)\n * 5. Custom patterns (user-defined via YAML config)\n *\n * Security:\n * - ReDoS-safe pattern validation (rejects dangerous regex)\n * - Max pattern count enforcement\n * - Configurable base64 blob action\n * - Generic redaction markers (no pattern name leak)\n */\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport type ResponseAction = \"pass\" | \"redact\" | \"block\";\n\n/** A single pattern to match against response content. */\nexport interface ResponsePattern {\n /** Unique name for this pattern */\n name: string;\n /** Regex pattern to match against response text */\n pattern: string;\n /** Flags for the regex (default: \"gi\") */\n flags?: string;\n /** What to do when the pattern matches */\n action: ResponseAction;\n /** Human-readable description */\n message?: string;\n /** Category for grouping in audit logs */\n category?: string;\n}\n\n/** Configuration for response scanning. */\nexport interface ResponseScannerConfig {\n /** Enable/disable the response scanner (default: true) */\n enabled?: boolean;\n /** Maximum response size in bytes before blocking (0 = no limit) */\n maxResponseSize?: number;\n /** Action when response exceeds maxResponseSize: \"block\" or \"redact\" (truncate) */\n oversizeAction?: \"block\" | \"redact\";\n /** Built-in secret detection (default: true) */\n detectSecrets?: boolean;\n /** Built-in PII detection (default: false — opt-in) */\n detectPII?: boolean;\n /** Action for base64 blob detection: \"pass\" (default), \"redact\", or \"block\" */\n base64Action?: ResponseAction;\n /** Maximum number of custom patterns allowed (default: 100) */\n maxPatterns?: number;\n /** Custom patterns to match against response content */\n patterns?: ResponsePattern[];\n}\n\n/** Result of scanning a response. */\nexport interface ScanResult {\n /** Whether the response is clean */\n clean: boolean;\n /** The final action to take */\n action: ResponseAction;\n /** All findings */\n findings: ScanFinding[];\n /** If action is \"redact\", the redacted response text */\n redactedText?: string;\n /** Original size in bytes */\n originalSize: number;\n}\n\n/** A single finding from the scanner. */\nexport interface ScanFinding {\n /** Name of the pattern that matched */\n pattern: string;\n /** Category */\n category: string;\n /** The action this pattern requests */\n action: ResponseAction;\n /** Human-readable message */\n message: string;\n /** Number of matches found */\n matchCount: number;\n /** Preview of matched content (redacted) */\n preview?: string;\n}\n\n// ── ReDoS Protection ────────────────────────────────────────────────\n\n/**\n * Dangerous regex patterns that indicate potential ReDoS:\n * - Nested quantifiers: (a+)+ , (a*)*\n * - Overlapping alternations with quantifiers\n */\nconst REDOS_DANGEROUS_PATTERNS = [\n /\\([^)]*[+*][^)]*\\)[+*]/, // (x+)+ or (x*)* nested quantifiers\n /\\([^)]*\\|[^)]*\\)[+*]{/, // (a|a)+ overlapping alternation with quantifier\n /(.+)\\1[+*]/, // backreference with quantifier\n];\n\n/** Maximum allowed regex pattern length */\nconst MAX_PATTERN_LENGTH = 1000;\n\n/** Default max number of custom patterns */\nconst DEFAULT_MAX_PATTERNS = 100;\n\n/**\n * Validate a regex pattern is safe from ReDoS attacks.\n * Returns true if the pattern is safe, false if potentially dangerous.\n */\nexport function isRegexSafe(pattern: string): boolean {\n // Length check\n if (pattern.length > MAX_PATTERN_LENGTH) return false;\n\n // Check for dangerous nested quantifier patterns\n for (const dangerous of REDOS_DANGEROUS_PATTERNS) {\n if (dangerous.test(pattern)) return false;\n }\n\n // Verify it's valid regex\n try {\n new RegExp(pattern);\n return true;\n } catch {\n return false;\n }\n}\n\n// ── Built-in Secret Patterns ────────────────────────────────────────\n\nconst SECRET_PATTERNS: ResponsePattern[] = [\n // ── API Keys & Tokens ──\n {\n name: \"aws-access-key\",\n pattern: \"(?:^|[^A-Za-z0-9])AKIA[0-9A-Z]{16}(?:[^A-Za-z0-9]|$)\",\n action: \"redact\",\n message: \"AWS Access Key ID detected in response\",\n category: \"secrets\",\n },\n {\n name: \"aws-secret-key\",\n pattern: \"(?:aws_secret_access_key|aws_secret_key|secret_access_key)\\\\s*[=:]\\\\s*[A-Za-z0-9/+=]{40}\",\n flags: \"gi\",\n action: \"redact\",\n message: \"AWS Secret Access Key detected in response\",\n category: \"secrets\",\n },\n {\n name: \"github-token\",\n pattern: \"(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9_]{36,255}\",\n action: \"redact\",\n message: \"GitHub token detected in response\",\n category: \"secrets\",\n },\n {\n name: \"openai-api-key\",\n pattern: \"sk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20}\",\n action: \"redact\",\n message: \"OpenAI API key detected in response\",\n category: \"secrets\",\n },\n {\n name: \"generic-api-key\",\n pattern: \"(?:api[_-]?key|apikey|api[_-]?secret)\\\\s*[=:]+\\\\s*[\\\"']?[A-Za-z0-9_\\\\-]{20,}\",\n flags: \"gi\",\n action: \"redact\",\n message: \"Generic API key detected in response\",\n category: \"secrets\",\n },\n {\n name: \"bearer-token\",\n pattern: \"Bearer\\\\s+[A-Za-z0-9\\\\-._~+/]+=*\",\n flags: \"gi\",\n action: \"redact\",\n message: \"Bearer token detected in response\",\n category: \"secrets\",\n },\n {\n name: \"jwt-token\",\n pattern: \"eyJ[A-Za-z0-9_-]{10,}\\\\.eyJ[A-Za-z0-9_-]{10,}\\\\.[A-Za-z0-9_\\\\-]{10,}\",\n action: \"redact\",\n message: \"JWT token detected in response\",\n category: \"secrets\",\n },\n // ── Private Keys & Certificates ──\n {\n name: \"private-key\",\n pattern: \"-----BEGIN (?:RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----\",\n action: \"block\",\n message: \"Private key detected in response — blocking entirely\",\n category: \"secrets\",\n },\n {\n name: \"certificate\",\n pattern: \"-----BEGIN CERTIFICATE-----\",\n action: \"redact\",\n message: \"Certificate detected in response\",\n category: \"secrets\",\n },\n // ── Connection Strings ──\n {\n name: \"database-url\",\n pattern: \"(?:postgres|mysql|mongodb|redis|amqp)://[^\\\\s\\\"']+:[^\\\\s\\\"']+@[^\\\\s\\\"']+\",\n flags: \"gi\",\n action: \"redact\",\n message: \"Database connection string with credentials detected\",\n category: \"secrets\",\n },\n // ── Password Patterns ──\n {\n name: \"password-assignment\",\n pattern: \"(?:password|passwd|pwd)\\\\s*[=:]\\\\s*[\\\"']?[^\\\\s\\\"']{8,}\",\n flags: \"gi\",\n action: \"redact\",\n message: \"Password assignment detected in response\",\n category: \"secrets\",\n },\n];\n\n/**\n * Exfiltration marker patterns. Base64 action is configurable.\n */\nfunction getExfiltrationPatterns(base64Action: ResponseAction): ResponsePattern[] {\n return [\n {\n name: \"large-base64-blob\",\n pattern: \"(?:[A-Za-z0-9+/]{100,}={0,2})\",\n action: base64Action,\n message: \"Large base64-encoded blob detected\",\n category: \"exfiltration\",\n },\n {\n name: \"hex-dump\",\n pattern: \"(?:[0-9a-f]{2}[:\\\\s]){32,}\",\n flags: \"gi\",\n action: \"pass\",\n message: \"Large hex dump detected (informational)\",\n category: \"exfiltration\",\n },\n ];\n}\n\nconst PII_PATTERNS: ResponsePattern[] = [\n {\n name: \"email-address\",\n pattern: \"[a-zA-Z0-9._%+\\\\-]+@[a-zA-Z0-9.\\\\-]+\\\\.[a-zA-Z]{2,}\",\n action: \"redact\",\n message: \"Email address detected in response\",\n category: \"pii\",\n },\n {\n name: \"phone-number\",\n pattern: \"(?:\\\\+?1[\\\\s.-]?)?\\\\(?[0-9]{3}\\\\)?[\\\\s.-]?[0-9]{3}[\\\\s.-]?[0-9]{4}\",\n action: \"redact\",\n message: \"Phone number detected in response\",\n category: \"pii\",\n },\n {\n name: \"ssn\",\n pattern: \"\\\\b\\\\d{3}-\\\\d{2}-\\\\d{4}\\\\b\",\n action: \"block\",\n message: \"Social Security Number detected — blocking response\",\n category: \"pii\",\n },\n {\n name: \"credit-card\",\n pattern: \"\\\\b(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})\\\\b\",\n action: \"block\",\n message: \"Credit card number detected — blocking response\",\n category: \"pii\",\n },\n {\n name: \"ip-address\",\n pattern: \"\\\\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\\\b\",\n action: \"pass\",\n message: \"IP address detected (informational)\",\n category: \"pii\",\n },\n];\n\n// ── Response Scanner Engine ─────────────────────────────────────────\n\nexport class ResponseScanner {\n private config: Required<Pick<ResponseScannerConfig, \"enabled\" | \"maxResponseSize\" | \"oversizeAction\" | \"detectSecrets\" | \"detectPII\" | \"base64Action\" | \"maxPatterns\">> & { patterns: ResponsePattern[] };\n private compiledPatterns: Array<{\n pattern: ResponsePattern;\n regex: RegExp;\n }> = [];\n private rejectedPatterns: string[] = [];\n\n constructor(config: ResponseScannerConfig = {}) {\n this.config = {\n enabled: config.enabled ?? true,\n maxResponseSize: config.maxResponseSize ?? 0,\n oversizeAction: config.oversizeAction ?? \"redact\",\n detectSecrets: config.detectSecrets ?? true,\n detectPII: config.detectPII ?? false,\n base64Action: config.base64Action ?? \"pass\",\n maxPatterns: config.maxPatterns ?? DEFAULT_MAX_PATTERNS,\n patterns: config.patterns ?? [],\n };\n\n this.compilePatterns();\n }\n\n /**\n * Compile all regex patterns upfront for performance.\n * Validates each pattern for ReDoS safety before compilation.\n */\n private compilePatterns(): void {\n this.compiledPatterns = [];\n this.rejectedPatterns = [];\n\n // Built-in secret patterns (pre-validated, always safe)\n if (this.config.detectSecrets) {\n for (const p of SECRET_PATTERNS) {\n this.safeCompile(p, true);\n }\n }\n\n // Exfiltration patterns with configurable base64 action\n if (this.config.detectSecrets) {\n for (const p of getExfiltrationPatterns(this.config.base64Action)) {\n this.safeCompile(p, true);\n }\n }\n\n // Built-in PII patterns (pre-validated, always safe)\n if (this.config.detectPII) {\n for (const p of PII_PATTERNS) {\n this.safeCompile(p, true);\n }\n }\n\n // User-defined patterns — enforce max count and ReDoS validation\n const userPatterns = this.config.patterns ?? [];\n const maxAllowed = this.config.maxPatterns;\n const limited = userPatterns.slice(0, maxAllowed);\n\n if (userPatterns.length > maxAllowed) {\n this.rejectedPatterns.push(\n `${userPatterns.length - maxAllowed} patterns exceeded max limit of ${maxAllowed}`\n );\n }\n\n for (const p of limited) {\n this.safeCompile(p, false);\n }\n }\n\n /**\n * Safely compile a pattern. For user patterns, validate ReDoS safety first.\n */\n private safeCompile(pattern: ResponsePattern, trusted: boolean): void {\n // ReDoS validation for untrusted (user) patterns\n if (!trusted) {\n if (!isRegexSafe(pattern.pattern)) {\n this.rejectedPatterns.push(\n `Pattern \"${pattern.name}\" rejected: potentially unsafe regex (ReDoS risk)`\n );\n return;\n }\n }\n\n try {\n const regex = new RegExp(pattern.pattern, pattern.flags ?? \"gi\");\n this.compiledPatterns.push({ pattern, regex });\n } catch {\n this.rejectedPatterns.push(\n `Pattern \"${pattern.name}\" rejected: invalid regex`\n );\n }\n }\n\n /**\n * Scan a response text for sensitive content.\n */\n scan(text: string): ScanResult {\n if (!this.config.enabled) {\n return {\n clean: true,\n action: \"pass\",\n findings: [],\n originalSize: Buffer.byteLength(text, \"utf-8\"),\n };\n }\n\n const originalSize = Buffer.byteLength(text, \"utf-8\");\n const findings: ScanFinding[] = [];\n\n // 1. Check response size\n if (this.config.maxResponseSize && this.config.maxResponseSize > 0) {\n if (originalSize > this.config.maxResponseSize) {\n findings.push({\n pattern: \"__oversize__\",\n category: \"size\",\n action: this.config.oversizeAction ?? \"redact\",\n message: `Response size (${originalSize} bytes) exceeds limit (${this.config.maxResponseSize} bytes)`,\n matchCount: 1,\n });\n }\n }\n\n // 2. Run all compiled patterns against the text\n for (const { pattern, regex } of this.compiledPatterns) {\n // Reset lastIndex for stateful regexes\n regex.lastIndex = 0;\n const matches = text.match(regex);\n\n if (matches && matches.length > 0) {\n findings.push({\n pattern: pattern.name,\n category: pattern.category ?? \"custom\",\n action: pattern.action,\n message: pattern.message ?? `Pattern \"${pattern.name}\" matched`,\n matchCount: matches.length,\n preview: this.createPreview(matches[0]),\n });\n }\n }\n\n if (findings.length === 0) {\n return { clean: true, action: \"pass\", findings: [], originalSize };\n }\n\n // 3. Determine overall action (highest severity wins)\n const overallAction = this.resolveAction(findings);\n\n // 4. Build result\n const result: ScanResult = {\n clean: false,\n action: overallAction,\n findings,\n originalSize,\n };\n\n // 5. Produce redacted text if action is \"redact\"\n if (overallAction === \"redact\") {\n result.redactedText = this.redactText(text, findings);\n }\n\n return result;\n }\n\n /**\n * Scan the content array from an MCP tools/call response.\n * MCP responses have the shape: { content: [{ type: \"text\", text: \"...\" }, ...] }\n */\n scanMcpResponse(result: unknown): ScanResult {\n const text = this.extractText(result);\n return this.scan(text);\n }\n\n /**\n * Extract all text content from an MCP response result.\n */\n private extractText(result: unknown): string {\n if (typeof result === \"string\") return result;\n if (!result || typeof result !== \"object\") return \"\";\n\n const obj = result as Record<string, unknown>;\n\n // MCP standard: { content: [{ type: \"text\", text: \"...\" }] }\n if (Array.isArray(obj.content)) {\n return obj.content\n .filter((c: any) => c?.type === \"text\" && typeof c?.text === \"string\")\n .map((c: any) => c.text)\n .join(\"\\n\");\n }\n\n // Fallback: stringify the result\n try {\n return JSON.stringify(result);\n } catch {\n return \"\";\n }\n }\n\n /**\n * Resolve the highest-severity action from all findings.\n * Priority: block > redact > pass\n */\n private resolveAction(findings: ScanFinding[]): ResponseAction {\n let highest: ResponseAction = \"pass\";\n for (const f of findings) {\n if (f.action === \"block\") return \"block\";\n if (f.action === \"redact\") highest = \"redact\";\n }\n return highest;\n }\n\n /**\n * Redact matched patterns from the text.\n * Uses generic [REDACTED] marker — never leaks pattern names.\n */\n private redactText(text: string, findings: ScanFinding[]): string {\n let redacted = text;\n\n // Handle oversize: truncate\n if (this.config.maxResponseSize && this.config.maxResponseSize > 0) {\n const sizeExceeded = findings.some((f) => f.pattern === \"__oversize__\");\n if (sizeExceeded) {\n const limit = this.config.maxResponseSize;\n redacted = redacted.slice(0, limit) + \"\\n\\n[Agent Wall: Response truncated — exceeded size limit]\";\n }\n }\n\n // Redact each finding's pattern matches\n for (const { pattern, regex } of this.compiledPatterns) {\n const finding = findings.find((f) => f.pattern === pattern.name);\n if (!finding || finding.action !== \"redact\") continue;\n\n regex.lastIndex = 0;\n redacted = redacted.replace(regex, `[REDACTED]`);\n }\n\n return redacted;\n }\n\n /**\n * Create a safe preview of matched content (first 4 chars + last 4).\n */\n private createPreview(match: string): string {\n if (match.length <= 8) return \"***\";\n const start = match.slice(0, 4);\n const end = match.slice(-4);\n return `${start}...${end}`;\n }\n\n /**\n * Get the current configuration.\n */\n getConfig(): ResponseScannerConfig {\n return { ...this.config };\n }\n\n /**\n * Get the number of compiled patterns.\n */\n getPatternCount(): number {\n return this.compiledPatterns.length;\n }\n\n /**\n * Get list of patterns that were rejected during compilation.\n */\n getRejectedPatterns(): string[] {\n return [...this.rejectedPatterns];\n }\n\n /**\n * Update configuration (e.g., after policy file reload).\n */\n updateConfig(config: ResponseScannerConfig): void {\n this.config = {\n enabled: config.enabled ?? true,\n maxResponseSize: config.maxResponseSize ?? 0,\n oversizeAction: config.oversizeAction ?? \"redact\",\n detectSecrets: config.detectSecrets ?? true,\n detectPII: config.detectPII ?? false,\n base64Action: config.base64Action ?? \"pass\",\n maxPatterns: config.maxPatterns ?? DEFAULT_MAX_PATTERNS,\n patterns: config.patterns ?? [],\n };\n this.compilePatterns();\n }\n}\n\n// ── Convenience: Default scanner ────────────────────────────────────\n\n/**\n * Create a scanner with sensible defaults (secrets ON, PII OFF).\n */\nexport function createDefaultScanner(): ResponseScanner {\n return new ResponseScanner({\n enabled: true,\n maxResponseSize: 5 * 1024 * 1024, // 5MB\n oversizeAction: \"redact\",\n detectSecrets: true,\n detectPII: false,\n });\n}\n","/**\n * Agent Wall Audit Logger\n *\n * Structured logging of every tool call and its policy verdict.\n * Logs to stderr (JSON) and optionally to a file.\n * This is the audit trail — proof of what the agent did and what was blocked.\n *\n * Security:\n * - HMAC-SHA256 chain signing (tamper-evident log entries)\n * - Log rotation (max file size with automatic rotation)\n * - File permission checks on policy files\n */\n\nimport * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { RuleAction } from \"./policy-engine.js\";\n\n// ── Log Entry Types ─────────────────────────────────────────────────\n\nexport interface AuditEntry {\n timestamp: string;\n sessionId: string;\n direction: \"request\" | \"response\";\n method: string;\n tool?: string;\n arguments?: Record<string, unknown>;\n verdict?: {\n action: RuleAction;\n rule: string | null;\n message: string;\n };\n responsePreview?: string;\n latencyMs?: number;\n error?: string;\n}\n\n/** Signed audit entry — includes HMAC chain for tamper evidence. */\nexport interface SignedAuditEntry extends AuditEntry {\n /** HMAC-SHA256 of this entry + previous hash (chain) */\n _sig?: string;\n /** Sequence number in the chain */\n _seq?: number;\n}\n\n// ── Logger Options ──────────────────────────────────────────────────\n\nexport interface AuditLoggerOptions {\n /** Log to stdout as JSON lines (default: true) */\n stdout?: boolean;\n /** Log to a file (JSON lines) */\n filePath?: string;\n /** Redact sensitive values in arguments (default: true) */\n redact?: boolean;\n /** Maximum argument value length before truncation */\n maxArgLength?: number;\n /** Silent mode — no output */\n silent?: boolean;\n /** Enable HMAC-SHA256 chain signing */\n signing?: boolean;\n /** HMAC signing key (auto-generated per session if not provided) */\n signingKey?: string;\n /** Max log file size in bytes before rotation (default: 50MB, 0 = no limit) */\n maxFileSize?: number;\n /** Number of rotated log files to keep (default: 5) */\n maxFiles?: number;\n /** Callback fired after every log entry (for dashboard streaming) */\n onEntry?: (entry: AuditEntry) => void;\n}\n\n// ── Sensitive Patterns ──────────────────────────────────────────────\n\nconst SENSITIVE_PATTERNS = [\n /password/i,\n /secret/i,\n /token/i,\n /api[_-]?key/i,\n /auth/i,\n /credential/i,\n /private[_-]?key/i,\n /access[_-]?key/i,\n];\n\n// ── Constants ───────────────────────────────────────────────────────\n\nconst DEFAULT_MAX_FILE_SIZE = 50 * 1024 * 1024; // 50MB\nconst DEFAULT_MAX_FILES = 5;\n\n// ── Logger Implementation ───────────────────────────────────────────\n\nexport class AuditLogger {\n private options: {\n stdout: boolean;\n filePath: string;\n redact: boolean;\n maxArgLength: number;\n silent: boolean;\n signing: boolean;\n signingKey: string;\n maxFileSize: number;\n maxFiles: number;\n onEntry?: (entry: AuditEntry) => void;\n };\n private fileFd: number | null = null;\n private entries: AuditEntry[] = [];\n private prevHash: string = \"genesis\";\n private seqCounter: number = 0;\n private currentFileSize: number = 0;\n\n constructor(options: AuditLoggerOptions = {}) {\n this.options = {\n stdout: options.stdout ?? true,\n filePath: options.filePath ?? \"\",\n redact: options.redact ?? true,\n maxArgLength: options.maxArgLength ?? 200,\n silent: options.silent ?? false,\n signing: options.signing ?? false,\n signingKey: options.signingKey ?? crypto.randomBytes(32).toString(\"hex\"),\n maxFileSize: options.maxFileSize ?? DEFAULT_MAX_FILE_SIZE,\n maxFiles: options.maxFiles ?? DEFAULT_MAX_FILES,\n onEntry: options.onEntry,\n };\n\n if (this.options.filePath) {\n this.openLogFile();\n }\n }\n\n /**\n * Open or reopen the log file using synchronous fd (reliable on Windows).\n */\n private openLogFile(): void {\n const dir = path.dirname(this.options.filePath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n // Get current file size for rotation tracking\n try {\n const stat = fs.statSync(this.options.filePath);\n this.currentFileSize = stat.size;\n } catch {\n this.currentFileSize = 0;\n }\n\n this.fileFd = fs.openSync(this.options.filePath, \"a\");\n }\n\n /**\n * Log a tool call with its policy verdict.\n */\n log(entry: AuditEntry): void {\n const processed = this.options.redact\n ? this.redactEntry(entry)\n : entry;\n\n this.entries.push(processed);\n\n // Add HMAC chain signature if signing is enabled\n let outputEntry: SignedAuditEntry = { ...processed };\n if (this.options.signing) {\n this.seqCounter++;\n const sig = this.computeHmac(processed);\n outputEntry._seq = this.seqCounter;\n outputEntry._sig = sig;\n this.prevHash = sig;\n }\n\n const line = JSON.stringify(outputEntry);\n\n if (this.options.stdout && !this.options.silent) {\n process.stderr.write(`[agent-wall] ${line}\\n`);\n }\n\n if (this.fileFd !== null) {\n const data = line + \"\\n\";\n const bytes = Buffer.byteLength(data, \"utf-8\");\n fs.writeSync(this.fileFd, data);\n this.currentFileSize += bytes;\n\n // Check if rotation is needed\n if (this.options.maxFileSize > 0 && this.currentFileSize >= this.options.maxFileSize) {\n this.rotateLogFile();\n }\n }\n\n this.options.onEntry?.(processed);\n }\n\n /**\n * Compute HMAC-SHA256 for a log entry in the chain.\n * Chain: HMAC(entry_json + prev_hash)\n */\n private computeHmac(entry: AuditEntry): string {\n const payload = JSON.stringify(entry) + \"|\" + this.prevHash;\n return crypto\n .createHmac(\"sha256\", this.options.signingKey)\n .update(payload)\n .digest(\"hex\");\n }\n\n /**\n * Rotate log files: current → .1, .1 → .2, etc.\n * Oldest file beyond maxFiles is deleted.\n */\n private rotateLogFile(): void {\n // Close current file descriptor synchronously (critical on Windows)\n if (this.fileFd !== null) {\n fs.closeSync(this.fileFd);\n this.fileFd = null;\n }\n\n const basePath = this.options.filePath;\n\n // Delete oldest if at max\n const oldest = `${basePath}.${this.options.maxFiles}`;\n try { fs.unlinkSync(oldest); } catch { /* doesn't exist */ }\n\n // Shift existing rotated files: .4 → .5, .3 → .4, etc.\n for (let i = this.options.maxFiles - 1; i >= 1; i--) {\n const src = `${basePath}.${i}`;\n const dst = `${basePath}.${i + 1}`;\n try { fs.renameSync(src, dst); } catch { /* doesn't exist */ }\n }\n\n // Move current → .1\n try { fs.renameSync(basePath, `${basePath}.1`); } catch { /* ignore */ }\n\n // Reopen fresh log file\n this.currentFileSize = 0;\n this.openLogFile();\n }\n\n /**\n * Log a denied tool call (convenience method).\n */\n logDeny(\n sessionId: string,\n tool: string,\n args: Record<string, unknown>,\n ruleName: string | null,\n message: string\n ): void {\n this.log({\n timestamp: new Date().toISOString(),\n sessionId,\n direction: \"request\",\n method: \"tools/call\",\n tool,\n arguments: args,\n verdict: {\n action: \"deny\",\n rule: ruleName,\n message,\n },\n });\n }\n\n /**\n * Log an allowed tool call (convenience method).\n */\n logAllow(\n sessionId: string,\n tool: string,\n args: Record<string, unknown>,\n ruleName: string | null,\n message: string\n ): void {\n this.log({\n timestamp: new Date().toISOString(),\n sessionId,\n direction: \"request\",\n method: \"tools/call\",\n tool,\n arguments: args,\n verdict: {\n action: \"allow\",\n rule: ruleName,\n message,\n },\n });\n }\n\n /**\n * Get all logged entries (for the audit command).\n */\n getEntries(): AuditEntry[] {\n return this.entries;\n }\n\n /**\n * Get summary statistics.\n */\n getStats(): {\n total: number;\n allowed: number;\n denied: number;\n prompted: number;\n } {\n let allowed = 0;\n let denied = 0;\n let prompted = 0;\n for (const entry of this.entries) {\n switch (entry.verdict?.action) {\n case \"allow\":\n allowed++;\n break;\n case \"deny\":\n denied++;\n break;\n case \"prompt\":\n prompted++;\n break;\n }\n }\n return {\n total: this.entries.length,\n allowed,\n denied,\n prompted,\n };\n }\n\n /**\n * Redact sensitive argument values.\n */\n private redactEntry(entry: AuditEntry): AuditEntry {\n if (!entry.arguments) return entry;\n\n const redacted: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(entry.arguments)) {\n if (SENSITIVE_PATTERNS.some((p) => p.test(key))) {\n redacted[key] = \"[REDACTED]\";\n } else if (typeof value === \"string\" && value.length > this.options.maxArgLength) {\n redacted[key] = value.slice(0, this.options.maxArgLength) + \"...[truncated]\";\n } else {\n redacted[key] = value;\n }\n }\n\n return { ...entry, arguments: redacted };\n }\n\n /**\n * Verify the HMAC chain integrity of a log file.\n * Returns { valid: boolean, entries: number, firstBroken: number | null }\n */\n static verifyChain(\n logFilePath: string,\n signingKey: string\n ): { valid: boolean; entries: number; firstBroken: number | null } {\n const content = fs.readFileSync(logFilePath, \"utf-8\");\n const lines = content.trim().split(\"\\n\").filter(Boolean);\n\n let prevHash = \"genesis\";\n let firstBroken: number | null = null;\n\n for (let i = 0; i < lines.length; i++) {\n const parsed = JSON.parse(lines[i]) as SignedAuditEntry;\n const { _sig, _seq, ...entry } = parsed;\n\n if (!_sig) {\n // Unsigned entry — skip or flag\n continue;\n }\n\n const payload = JSON.stringify(entry) + \"|\" + prevHash;\n const expected = crypto\n .createHmac(\"sha256\", signingKey)\n .update(payload)\n .digest(\"hex\");\n\n if (_sig !== expected) {\n if (firstBroken === null) firstBroken = i;\n }\n\n prevHash = _sig;\n }\n\n return {\n valid: firstBroken === null,\n entries: lines.length,\n firstBroken,\n };\n }\n\n /**\n * Set or replace the onEntry callback (for dashboard streaming).\n */\n setOnEntry(callback: ((entry: AuditEntry) => void) | undefined): void {\n this.options.onEntry = callback;\n }\n\n /**\n * Close the logger (flush file stream).\n */\n close(): void {\n if (this.fileFd !== null) {\n fs.closeSync(this.fileFd);\n this.fileFd = null;\n }\n }\n}\n\n// ── File Permission Checking ────────────────────────────────────────\n\nexport interface FilePermissionCheckResult {\n safe: boolean;\n warnings: string[];\n}\n\n/**\n * Check if a policy file has safe permissions.\n * Warns if world-writable, group-writable, or owned by different user.\n * On Windows this is best-effort (no Unix permission model).\n */\nexport function checkFilePermissions(filePath: string): FilePermissionCheckResult {\n const warnings: string[] = [];\n\n try {\n const stat = fs.statSync(filePath);\n\n // Unix permission checks (mode is a bitmask)\n const mode = stat.mode;\n if (mode !== undefined) {\n // Check world-writable (o+w = 0o002)\n if (mode & 0o002) {\n warnings.push(\n `Policy file is world-writable (mode ${(mode & 0o777).toString(8)}). ` +\n `Run: chmod 644 ${filePath}`\n );\n }\n\n // Check group-writable (g+w = 0o020)\n if (mode & 0o020) {\n warnings.push(\n `Policy file is group-writable (mode ${(mode & 0o777).toString(8)}). ` +\n `Consider: chmod 644 ${filePath}`\n );\n }\n }\n\n // Check if the file is a symlink (could be pointing to attacker-controlled path)\n const lstat = fs.lstatSync(filePath);\n if (lstat.isSymbolicLink()) {\n warnings.push(\n `Policy file is a symbolic link. Ensure it points to a trusted location.`\n );\n }\n } catch (err) {\n warnings.push(`Cannot check permissions for ${filePath}: ${err}`);\n }\n\n return {\n safe: warnings.length === 0,\n warnings,\n };\n}\n","/**\n * Agent Wall Stdio Proxy\n *\n * The core of Agent Wall. Sits between an MCP client and server,\n * intercepting every JSON-RPC message over stdio (stdin/stdout).\n *\n * Architecture:\n * MCP Client (e.g. Claude Code)\n * ↕ stdin/stdout\n * Agent Wall Proxy (this file)\n * ↕ stdin/stdout (child process)\n * MCP Server (e.g. filesystem server)\n *\n * The proxy:\n * 1. Spawns the real MCP server as a child process\n * 2. Reads JSON-RPC from its own stdin (from the MCP client)\n * 3. For tools/call requests: evaluates against the policy engine\n * 4. If allowed: forwards to child's stdin\n * 5. If denied: returns a JSON-RPC error without forwarding\n * 6. Pipes child's stdout back to its own stdout (to the MCP client)\n */\n\nimport { type ChildProcess } from \"node:child_process\";\nimport spawn from \"cross-spawn\";\nimport * as crypto from \"node:crypto\";\nimport * as fs from \"node:fs\";\nimport * as readline from \"node:readline\";\nimport { EventEmitter } from \"node:events\";\nimport { ReadBuffer, BufferOverflowError, serializeMessage } from \"./read-buffer.js\";\nimport {\n type JsonRpcMessage,\n type JsonRpcRequest,\n type JsonRpcResponse,\n type McpContentBlock,\n isRequest,\n isResponse,\n isToolCall,\n getToolCallParams,\n createDenyResponse,\n} from \"./types.js\";\nimport { PolicyEngine, type PolicyVerdict } from \"./policy-engine.js\";\nimport { AuditLogger, type AuditEntry } from \"./audit-logger.js\";\nimport { ResponseScanner, type ScanResult } from \"./response-scanner.js\";\nimport { InjectionDetector } from \"./injection-detector.js\";\nimport { EgressControl } from \"./egress-control.js\";\nimport { KillSwitch } from \"./kill-switch.js\";\nimport { ChainDetector } from \"./chain-detector.js\";\n\n// ── Proxy Options ───────────────────────────────────────────────────\n\nexport interface ProxyOptions {\n /** The command to spawn (e.g. \"npx\") */\n command: string;\n /** Arguments for the command (e.g. [\"@modelcontextprotocol/server-filesystem\", \"/path\"]) */\n args?: string[];\n /** Environment variables for the child process */\n env?: Record<string, string>;\n /** Working directory for the child process */\n cwd?: string;\n /** The policy engine instance */\n policyEngine: PolicyEngine;\n /** The response scanner instance (optional — if not provided, responses pass through) */\n responseScanner?: ResponseScanner;\n /** The audit logger instance */\n logger: AuditLogger;\n /** Session ID for audit logging */\n sessionId?: string;\n /** Callback for prompt actions — return true to allow, false to deny */\n onPrompt?: (\n tool: string,\n args: Record<string, unknown>,\n message: string\n ) => Promise<boolean>;\n /** Called when the proxy is ready (child process spawned) */\n onReady?: () => void;\n /** Called when the proxy exits */\n onExit?: (code: number | null) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n /** Maximum buffer size in bytes (default: 10MB) */\n maxBufferSize?: number;\n /** TTL for pending tool calls in ms (default: 30000) — prevents memory leaks */\n pendingCallTtlMs?: number;\n /** Prompt injection detector (optional) */\n injectionDetector?: InjectionDetector;\n /** Egress/SSRF control (optional) */\n egressControl?: EgressControl;\n /** Emergency kill switch (optional) */\n killSwitch?: KillSwitch;\n /** Tool call chain detector (optional) */\n chainDetector?: ChainDetector;\n}\n\n// ── Proxy Events ────────────────────────────────────────────────────\n\nexport interface ProxyEvents {\n ready: [];\n exit: [code: number | null];\n error: [error: Error];\n denied: [tool: string, message: string];\n allowed: [tool: string];\n prompted: [tool: string, message: string];\n responseBlocked: [tool: string, findings: string];\n responseRedacted: [tool: string, findings: string];\n injectionDetected: [tool: string, summary: string];\n egressBlocked: [tool: string, summary: string];\n killSwitchActive: [tool: string];\n chainDetected: [tool: string, summary: string];\n}\n\n// ── Stdio Proxy ─────────────────────────────────────────────────────\n\n/** Default TTL for pending tool calls: 30 seconds */\nconst DEFAULT_PENDING_CALL_TTL_MS = 30_000;\n/** Cleanup interval for expired pending calls: 10 seconds */\nconst PENDING_CALL_CLEANUP_INTERVAL_MS = 10_000;\n\nexport class StdioProxy extends EventEmitter {\n private child: ChildProcess | null = null;\n private clientBuffer: ReadBuffer;\n private serverBuffer: ReadBuffer;\n private options: ProxyOptions;\n private sessionId: string;\n private running = false;\n private stats = { forwarded: 0, denied: 0, prompted: 0, total: 0, scanned: 0, responseBlocked: 0, responseRedacted: 0 };\n /** Track pending tools/call requests by JSON-RPC id, so we can correlate responses */\n private pendingToolCalls = new Map<string | number, { tool: string; args: Record<string, unknown>; timestamp: number }>();\n /** Cleanup timer for expired pending calls */\n private pendingCleanupTimer: ReturnType<typeof setInterval> | null = null;\n private pendingCallTtlMs: number;\n\n constructor(options: ProxyOptions) {\n super();\n this.options = options;\n const maxBuf = options.maxBufferSize;\n this.clientBuffer = new ReadBuffer(maxBuf);\n this.serverBuffer = new ReadBuffer(maxBuf);\n this.sessionId =\n options.sessionId ?? `ag-${crypto.randomUUID()}`;\n this.pendingCallTtlMs = options.pendingCallTtlMs ?? DEFAULT_PENDING_CALL_TTL_MS;\n\n // Prevent unhandled 'error' event crash — route to onError callback if set\n this.on(\"error\", (err: Error) => {\n this.options.onError?.(err);\n });\n }\n\n /**\n * Start the proxy — spawn the child MCP server and begin intercepting.\n */\n async start(): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n try {\n this.child = spawn(this.options.command, this.options.args ?? [], {\n stdio: [\"pipe\", \"pipe\", \"inherit\"],\n env: {\n ...process.env,\n ...this.options.env,\n },\n cwd: this.options.cwd,\n shell: false,\n windowsHide: true,\n });\n\n this.child.on(\"error\", (err) => {\n this.options.onError?.(err);\n this.emit(\"error\", err);\n reject(err);\n });\n\n this.child.on(\"spawn\", () => {\n this.running = true;\n this.setupPipelines();\n this.startPendingCallCleanup();\n this.options.onReady?.();\n this.emit(\"ready\");\n resolve();\n });\n\n this.child.on(\"close\", (code) => {\n this.running = false;\n this.options.onExit?.(code);\n this.emit(\"exit\", code);\n });\n } catch (err) {\n reject(err);\n }\n });\n }\n\n /**\n * Stop the proxy — gracefully shut down the child process.\n * Follows the MCP SDK pattern: stdin.end() → SIGTERM → SIGKILL\n */\n async stop(): Promise<void> {\n if (!this.child) return;\n\n const child = this.child;\n this.child = null;\n this.running = false;\n\n const closePromise = new Promise<void>((resolve) => {\n child.once(\"close\", () => resolve());\n });\n\n // 1. End stdin gracefully\n try {\n child.stdin?.end();\n } catch {\n /* ignore */\n }\n\n // 2. Wait up to 2s for process to exit\n const timeout = (ms: number) =>\n new Promise<void>((resolve) => {\n const t = setTimeout(resolve, ms);\n t.unref();\n });\n\n await Promise.race([closePromise, timeout(2000)]);\n\n // 3. SIGTERM if still alive\n if (child.exitCode === null) {\n try {\n child.kill(\"SIGTERM\");\n } catch {\n /* ignore */\n }\n await Promise.race([closePromise, timeout(2000)]);\n }\n\n // 4. SIGKILL as last resort\n if (child.exitCode === null) {\n try {\n child.kill(\"SIGKILL\");\n } catch {\n /* ignore */\n }\n }\n\n this.stopPendingCallCleanup();\n this.pendingToolCalls.clear();\n this.clientBuffer.clear();\n this.serverBuffer.clear();\n this.options.killSwitch?.dispose();\n this.options.chainDetector?.reset();\n this.options.logger.close();\n }\n\n /**\n * Get proxy statistics.\n */\n getStats() {\n return { ...this.stats };\n }\n\n /**\n * Wire up the stdin/stdout pipelines with interception.\n */\n private setupPipelines(): void {\n // ── Client → Proxy → Server ──\n process.stdin.on(\"data\", (chunk: Buffer) => {\n try {\n this.clientBuffer.append(chunk);\n this.processClientMessages();\n } catch (err) {\n if (err instanceof BufferOverflowError) {\n this.emit(\"error\", err);\n this.clientBuffer.clear();\n } else {\n this.emit(\"error\", new Error(`Client buffer error: ${err}`));\n }\n }\n });\n\n process.stdin.on(\"end\", () => {\n this.stop();\n });\n\n // ── Server → Proxy → Client ──\n this.child?.stdout?.on(\"data\", (chunk: Buffer) => {\n try {\n this.serverBuffer.append(chunk);\n this.processServerMessages();\n } catch (err) {\n if (err instanceof BufferOverflowError) {\n this.emit(\"error\", err);\n this.serverBuffer.clear();\n } else {\n this.emit(\"error\", new Error(`Server buffer error: ${err}`));\n }\n }\n });\n }\n\n /**\n * Start periodic cleanup of expired pending tool calls.\n */\n private startPendingCallCleanup(): void {\n this.pendingCleanupTimer = setInterval(() => {\n const now = Date.now();\n for (const [id, entry] of this.pendingToolCalls) {\n if (now - entry.timestamp > this.pendingCallTtlMs) {\n this.pendingToolCalls.delete(id);\n }\n }\n }, PENDING_CALL_CLEANUP_INTERVAL_MS);\n this.pendingCleanupTimer.unref();\n }\n\n /**\n * Stop the pending call cleanup timer.\n */\n private stopPendingCallCleanup(): void {\n if (this.pendingCleanupTimer) {\n clearInterval(this.pendingCleanupTimer);\n this.pendingCleanupTimer = null;\n }\n }\n\n /**\n * Process buffered messages from the MCP client.\n * This is where policy enforcement happens.\n */\n private processClientMessages(): void {\n try {\n const messages = this.clientBuffer.readAllMessages();\n for (const msg of messages) {\n this.handleClientMessage(msg);\n }\n } catch (err) {\n // Malformed JSON from client — log and continue\n this.emit(\"error\", new Error(`Invalid JSON from client: ${err}`));\n }\n }\n\n /**\n * Process buffered messages from the MCP server.\n * Applies response scanning before forwarding to the client.\n */\n private processServerMessages(): void {\n try {\n const messages = this.serverBuffer.readAllMessages();\n for (const msg of messages) {\n this.handleServerMessage(msg);\n }\n } catch (err) {\n // Malformed JSON from server — log and continue\n this.emit(\"error\", new Error(`Invalid JSON from server: ${err}`));\n }\n }\n\n /**\n * Handle a single message from the MCP server.\n * If it's a response to a tools/call we tracked, scan it.\n */\n private handleServerMessage(msg: JsonRpcMessage): void {\n // Only scan responses (not requests/notifications from server)\n if (!isResponse(msg)) {\n this.writeToClient(msg);\n return;\n }\n\n const response = msg as JsonRpcResponse;\n const pending = this.pendingToolCalls.get(response.id);\n\n // If we don't have a pending tool call for this id, or no scanner, pass through\n if (!pending || !this.options.responseScanner) {\n if (pending) this.pendingToolCalls.delete(response.id);\n this.writeToClient(msg);\n return;\n }\n\n // We have a tracked tool call response — scan it\n this.pendingToolCalls.delete(response.id);\n this.stats.scanned++;\n\n // Scan both successful responses AND error responses (secrets can leak in error.message/error.data)\n const scanResult = response.error\n ? this.options.responseScanner.scan(this.extractErrorText(response))\n : response.result !== undefined\n ? this.options.responseScanner.scanMcpResponse(response.result)\n : null;\n\n if (!scanResult || scanResult.clean) {\n this.writeToClient(msg);\n return;\n }\n\n const findingSummary = scanResult.findings\n .map((f) => `${f.pattern}: ${f.message}`)\n .join(\"; \");\n\n switch (scanResult.action) {\n case \"block\": {\n this.stats.responseBlocked++;\n this.options.logger.log({\n timestamp: new Date().toISOString(),\n sessionId: this.sessionId,\n direction: \"response\",\n method: \"tools/call\",\n tool: pending.tool,\n arguments: pending.args,\n verdict: { action: \"deny\", rule: \"__response_scanner__\", message: `Response blocked: ${findingSummary}` },\n });\n this.emit(\"responseBlocked\", pending.tool, findingSummary);\n // Send error back to client instead of the response\n const errorResponse = createDenyResponse(\n response.id,\n `Response blocked by Agent Wall scanner: ${findingSummary}`\n );\n this.writeToClient(errorResponse);\n break;\n }\n case \"redact\": {\n this.stats.responseRedacted++;\n this.options.logger.log({\n timestamp: new Date().toISOString(),\n sessionId: this.sessionId,\n direction: \"response\",\n method: \"tools/call\",\n tool: pending.tool,\n arguments: pending.args,\n verdict: { action: \"allow\", rule: \"__response_scanner__\", message: `Response redacted: ${findingSummary}` },\n });\n this.emit(\"responseRedacted\", pending.tool, findingSummary);\n // Replace the result content with redacted text\n const redacted = this.buildRedactedResponse(response, scanResult);\n this.writeToClient(redacted);\n break;\n }\n default:\n // \"pass\" findings — forward as-is (informational only)\n this.writeToClient(msg);\n break;\n }\n }\n\n /**\n * Build a redacted MCP response by replacing text content.\n */\n private buildRedactedResponse(original: JsonRpcResponse, scanResult: ScanResult): JsonRpcResponse {\n if (!scanResult.redactedText || !original.result) {\n return original;\n }\n\n const result = original.result as Record<string, unknown>;\n\n // MCP standard: result.content is an array of content blocks\n if (Array.isArray(result.content)) {\n const redactedContent = result.content.map((block: McpContentBlock) => {\n if (block.type === \"text\" && typeof block.text === \"string\") {\n return { ...block, text: scanResult.redactedText };\n }\n return block;\n });\n return {\n ...original,\n result: { ...result, content: redactedContent },\n };\n }\n\n // Fallback: replace the whole result\n return {\n ...original,\n result: { content: [{ type: \"text\", text: scanResult.redactedText }] },\n };\n }\n\n /**\n * Handle a single message from the MCP client.\n *\n * Security check order (defense in depth):\n * 1. Kill switch — if active, deny ALL calls immediately\n * 2. Injection detection — scan arguments for prompt injection\n * 3. Egress control — check for blocked URLs/IPs\n * 4. Policy engine — evaluate rules (existing behavior)\n * 5. Chain detection — record call and check for suspicious sequences\n */\n private handleClientMessage(msg: JsonRpcMessage): void {\n this.stats.total++;\n\n // Only intercept tools/call requests\n if (!isToolCall(msg)) {\n // Pass through all other messages (initialize, tools/list, notifications, etc.)\n this.writeToServer(msg);\n return;\n }\n\n // It's a tools/call — run security pipeline\n const request = msg as JsonRpcRequest;\n const toolCall = getToolCallParams(request);\n\n if (!toolCall) {\n // Malformed tools/call — forward anyway (let the server handle it)\n this.writeToServer(msg);\n return;\n }\n\n const args = toolCall.arguments ?? {};\n\n // ── 1. Kill switch check ──\n if (this.options.killSwitch?.isActive()) {\n const reason = this.options.killSwitch.getStatus().reason;\n this.emit(\"killSwitchActive\", toolCall.name);\n this.handleDeny(request, toolCall.name, args, {\n action: \"deny\",\n rule: \"__kill_switch__\",\n message: `Kill switch active: ${reason}. All tool calls denied.`,\n });\n return;\n }\n\n // ── 2. Injection detection ──\n if (this.options.injectionDetector) {\n const injection = this.options.injectionDetector.scan(toolCall);\n if (injection.detected && injection.confidence !== \"low\") {\n this.emit(\"injectionDetected\", toolCall.name, injection.summary);\n this.handleDeny(request, toolCall.name, args, {\n action: \"deny\",\n rule: \"__injection_detector__\",\n message: `Prompt injection blocked: ${injection.summary}`,\n });\n return;\n }\n }\n\n // ── 3. Egress control ──\n if (this.options.egressControl) {\n const egress = this.options.egressControl.check(toolCall);\n if (!egress.allowed) {\n this.emit(\"egressBlocked\", toolCall.name, egress.summary);\n this.handleDeny(request, toolCall.name, args, {\n action: \"deny\",\n rule: \"__egress_control__\",\n message: `Egress blocked: ${egress.summary}`,\n });\n return;\n }\n }\n\n // ── 4. Policy engine — rule evaluation ──\n const verdict = this.options.policyEngine.evaluate(toolCall);\n\n // ── 5. Chain detection — record this call and check patterns ──\n if (this.options.chainDetector && verdict.action !== \"deny\") {\n const chain = this.options.chainDetector.record(toolCall);\n if (chain.detected) {\n const critical = chain.matches.some((m) => m.severity === \"critical\");\n const summary = chain.matches.map((m) => `${m.chain}(${m.severity})`).join(\", \");\n this.emit(\"chainDetected\", toolCall.name, summary);\n // Critical chains are blocked, others are logged as warnings\n if (critical) {\n this.handleDeny(request, toolCall.name, args, {\n action: \"deny\",\n rule: \"__chain_detector__\",\n message: `Critical tool chain blocked: ${summary}`,\n });\n return;\n }\n // Non-critical chains: log the warning but let the call proceed\n this.options.logger.log({\n timestamp: new Date().toISOString(),\n sessionId: this.sessionId,\n direction: \"request\",\n method: \"tools/call\",\n tool: toolCall.name,\n arguments: args,\n verdict: {\n action: \"allow\",\n rule: \"__chain_detector__\",\n message: `Suspicious tool chain (warning): ${summary}`,\n },\n });\n }\n }\n\n switch (verdict.action) {\n case \"allow\":\n this.handleAllow(request, toolCall.name, args, verdict);\n break;\n case \"deny\":\n this.handleDeny(request, toolCall.name, args, verdict);\n break;\n case \"prompt\":\n this.handlePrompt(request, toolCall.name, args, verdict);\n break;\n }\n }\n\n /**\n * Handle an allowed tool call — forward to server.\n */\n private handleAllow(\n request: JsonRpcRequest,\n tool: string,\n args: Record<string, unknown>,\n verdict: PolicyVerdict\n ): void {\n this.stats.forwarded++;\n\n // Track this request so we can scan the response when it comes back\n if (this.options.responseScanner) {\n this.pendingToolCalls.set(request.id, { tool, args, timestamp: Date.now() });\n }\n\n this.options.logger.logAllow(\n this.sessionId,\n tool,\n args,\n verdict.rule,\n verdict.message\n );\n this.emit(\"allowed\", tool);\n this.writeToServer(request);\n }\n\n /**\n * Handle a denied tool call — return error to client, never forward.\n */\n private handleDeny(\n request: JsonRpcRequest,\n tool: string,\n args: Record<string, unknown>,\n verdict: PolicyVerdict\n ): void {\n this.stats.denied++;\n this.options.logger.logDeny(\n this.sessionId,\n tool,\n args,\n verdict.rule,\n verdict.message\n );\n this.emit(\"denied\", tool, verdict.message);\n\n // Send error back to client\n const errorResponse = createDenyResponse(request.id, verdict.message);\n this.writeToClient(errorResponse);\n }\n\n /**\n * Handle a prompt tool call — ask for human approval.\n */\n private async handlePrompt(\n request: JsonRpcRequest,\n tool: string,\n args: Record<string, unknown>,\n verdict: PolicyVerdict\n ): Promise<void> {\n this.emit(\"prompted\", tool, verdict.message);\n\n if (!this.options.onPrompt) {\n // No prompt handler — deny by default (fail-secure)\n this.handleDeny(request, tool, args, {\n ...verdict,\n action: \"deny\",\n message: `${verdict.message} (auto-denied: no prompt handler)`,\n });\n return;\n }\n\n try {\n const approved = await this.options.onPrompt(\n tool,\n args,\n verdict.message\n );\n\n if (approved) {\n this.handleAllow(request, tool, args, {\n ...verdict,\n action: \"allow\",\n message: `${verdict.message} (manually approved)`,\n });\n } else {\n this.handleDeny(request, tool, args, {\n ...verdict,\n action: \"deny\",\n message: `${verdict.message} (manually denied)`,\n });\n }\n } catch (err) {\n // Prompt failed — deny (fail-secure)\n this.handleDeny(request, tool, args, {\n ...verdict,\n action: \"deny\",\n message: `${verdict.message} (prompt error: ${err})`,\n });\n }\n }\n\n /**\n * Extract scannable text from a JSON-RPC error response.\n */\n private extractErrorText(response: JsonRpcResponse): string {\n const parts: string[] = [];\n if (response.error?.message) parts.push(response.error.message);\n if (response.error?.data !== undefined) {\n parts.push(typeof response.error.data === \"string\"\n ? response.error.data\n : JSON.stringify(response.error.data));\n }\n return parts.join(\"\\n\");\n }\n\n /**\n * Write a JSON-RPC message to the MCP server (child's stdin).\n */\n private writeToServer(msg: JsonRpcMessage): void {\n if (!this.child?.stdin?.writable) return;\n const data = serializeMessage(msg);\n this.child.stdin.write(data);\n }\n\n /**\n * Write a JSON-RPC message to the MCP client (our stdout).\n */\n private writeToClient(msg: JsonRpcMessage): void {\n const data = serializeMessage(msg);\n process.stdout.write(data);\n }\n}\n\n/**\n * Create a terminal-based prompt handler.\n *\n * IMPORTANT: stdin/stdout are reserved for MCP JSON-RPC protocol.\n * We open /dev/tty (Unix) or CON (Windows) directly to read from\n * the controlling terminal. This prevents conflicts with the\n * MCP message stream on stdin.\n *\n * Output goes to stderr (safe — MCP only uses stdout).\n */\nexport function createTerminalPromptHandler(): (\n tool: string,\n args: Record<string, unknown>,\n message: string\n) => Promise<boolean> {\n return async (tool, args, message) => {\n // Open the controlling terminal directly.\n // stdin is the MCP protocol pipe — we MUST NOT read from it.\n let ttyFd: number;\n try {\n // Works on Unix, macOS, and MINGW/Git Bash on Windows\n ttyFd = fs.openSync(\"/dev/tty\", \"r\");\n } catch {\n try {\n // Fallback for native Windows (cmd.exe, PowerShell)\n ttyFd = fs.openSync(\"CON\", \"r\");\n } catch {\n // No controlling terminal (headless, CI, non-interactive MCP client)\n process.stderr.write(\n \"\\n[agent-wall] No terminal available for prompt — auto-denying (fail-secure)\\n\"\n );\n return false;\n }\n }\n\n const ttyInput = fs.createReadStream(\"\", { fd: ttyFd, autoClose: false });\n\n const rl = readline.createInterface({\n input: ttyInput,\n output: process.stderr,\n });\n\n // Show the tool call details on stderr\n process.stderr.write(\"\\n\");\n process.stderr.write(\"╔══════════════════════════════════════════════════╗\\n\");\n process.stderr.write(\"║ Agent Wall: Approval Required ║\\n\");\n process.stderr.write(\"╠══════════════════════════════════════════════════╣\\n\");\n process.stderr.write(`║ Tool: ${tool}\\n`);\n process.stderr.write(`║ Rule: ${message}\\n`);\n process.stderr.write(`║ Args: ${JSON.stringify(args, null, 0).slice(0, 120)}\\n`);\n process.stderr.write(\"╚══════════════════════════════════════════════════╝\\n\");\n\n return new Promise<boolean>((resolve) => {\n rl.question(\" Allow this call? [y/N]: \", (answer) => {\n rl.close();\n ttyInput.destroy();\n try { fs.closeSync(ttyFd); } catch { /* ignore */ }\n resolve(answer.trim().toLowerCase() === \"y\");\n });\n });\n };\n}\n","/**\n * Agent Wall Prompt Injection Detector\n *\n * Detects prompt injection attacks in tool call arguments.\n * This is the #1 attack vector for AI agents — an attacker embeds\n * instructions in data (emails, documents, web pages) that trick\n * the AI into executing malicious actions.\n *\n * Detection layers:\n * 1. Known injection phrases (e.g., \"ignore previous instructions\")\n * 2. Role/system prompt markers (e.g., \"<|im_start|>system\")\n * 3. Instruction override patterns (e.g., \"IMPORTANT: new instructions\")\n * 4. Encoded injection (base64-encoded injection strings)\n * 5. Unicode obfuscation (homoglyphs, zero-width chars)\n */\n\nimport type { ToolCallParams } from \"./types.js\";\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport interface InjectionDetectorConfig {\n /** Enable injection detection (default: true) */\n enabled?: boolean;\n /** Sensitivity: \"low\" (fewer false positives), \"medium\", \"high\" (catches more) */\n sensitivity?: \"low\" | \"medium\" | \"high\";\n /** Custom patterns to add (regex strings) */\n customPatterns?: string[];\n /** Tool names to exclude from injection scanning */\n excludeTools?: string[];\n}\n\nexport interface InjectionScanResult {\n /** Whether injection was detected */\n detected: boolean;\n /** Confidence: \"low\", \"medium\", \"high\" */\n confidence: \"low\" | \"medium\" | \"high\";\n /** All matches found */\n matches: InjectionMatch[];\n /** Human-readable summary */\n summary: string;\n}\n\nexport interface InjectionMatch {\n /** Which pattern category matched */\n category: string;\n /** The matched text (truncated for safety) */\n matched: string;\n /** Which argument key contained the match */\n argumentKey: string;\n /** Confidence level for this specific match */\n confidence: \"low\" | \"medium\" | \"high\";\n}\n\n// ── Injection Patterns ──────────────────────────────────────────────\n\ninterface InjectionPattern {\n category: string;\n pattern: RegExp;\n confidence: \"low\" | \"medium\" | \"high\";\n sensitivity: \"low\" | \"medium\" | \"high\";\n}\n\n/**\n * Core injection patterns organized by attack type.\n * Each pattern has a minimum sensitivity level at which it activates.\n */\nconst INJECTION_PATTERNS: InjectionPattern[] = [\n // ── Direct instruction override (HIGH confidence) ──\n {\n category: \"instruction-override\",\n pattern: /ignore\\s+(all\\s+)?previous\\s+(instructions?|context|rules?|prompts?)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"instruction-override\",\n pattern: /disregard\\s+(all\\s+)?(previous|above|prior|earlier)\\s+(instructions?|context|rules?)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"instruction-override\",\n pattern: /forget\\s+(all\\s+)?(your|previous|prior)\\s+(instructions?|rules?|context|training)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"instruction-override\",\n pattern: /override\\s+(all\\s+)?(previous|system|safety)\\s+(instructions?|rules?|restrictions?|filters?)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"instruction-override\",\n pattern: /new\\s+instructions?:\\s/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"instruction-override\",\n pattern: /you\\s+are\\s+now\\s+(a|an|in)\\s/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"instruction-override\",\n pattern: /from\\s+now\\s+on,?\\s+(you|ignore|disregard|forget)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n\n // ── System/Role prompt markers (HIGH confidence) ──\n {\n category: \"prompt-marker\",\n pattern: /<\\|im_start\\|>system/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"prompt-marker\",\n pattern: /<\\|system\\|>/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"prompt-marker\",\n pattern: /\\[SYSTEM\\]\\s*:/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"prompt-marker\",\n pattern: /\\[INST\\]/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"prompt-marker\",\n pattern: /<<SYS>>/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"prompt-marker\",\n pattern: /###\\s*(System|Instruction|Human|Assistant)\\s*:/i,\n confidence: \"medium\",\n sensitivity: \"medium\",\n },\n\n // ── Authority claims (MEDIUM confidence) ──\n {\n category: \"authority-claim\",\n pattern: /admin(istrator)?\\s+(override|mode|access|command)/i,\n confidence: \"medium\",\n sensitivity: \"low\",\n },\n {\n category: \"authority-claim\",\n pattern: /IMPORTANT:\\s*(override|ignore|disregard|new\\s+instruction)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"authority-claim\",\n pattern: /URGENT:\\s*(you\\s+must|override|ignore)/i,\n confidence: \"medium\",\n sensitivity: \"low\",\n },\n {\n category: \"authority-claim\",\n pattern: /developer\\s+mode\\s+(enabled|activated|on)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"authority-claim\",\n pattern: /jailbreak/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"authority-claim\",\n pattern: /DAN\\s+(mode|prompt)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n\n // ── Data exfiltration instructions (HIGH confidence) ──\n {\n category: \"exfil-instruction\",\n pattern: /send\\s+(all\\s+)?(the\\s+|this\\s+|my\\s+)?(data|information|content|file|secret|key|token|password|credential)\\s+(to|via|through|using)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"exfil-instruction\",\n pattern: /exfiltrate|steal\\s+(the\\s+)?(data|secret|key|credential|token)/i,\n confidence: \"high\",\n sensitivity: \"low\",\n },\n {\n category: \"exfil-instruction\",\n pattern: /upload\\s+(all\\s+)?(the\\s+|this\\s+|my\\s+|every\\s+)?(files?|data|content|secrets?)/i,\n confidence: \"medium\",\n sensitivity: \"medium\",\n },\n\n // ── Output manipulation (MEDIUM confidence) ──\n {\n category: \"output-manipulation\",\n pattern: /respond\\s+with\\s+(only|just|exactly)\\s/i,\n confidence: \"low\",\n sensitivity: \"high\",\n },\n {\n category: \"output-manipulation\",\n pattern: /do\\s+not\\s+(mention|reveal|tell|show|display|output)\\s/i,\n confidence: \"low\",\n sensitivity: \"high\",\n },\n {\n category: \"output-manipulation\",\n pattern: /pretend\\s+(you|that|to\\s+be)/i,\n confidence: \"medium\",\n sensitivity: \"medium\",\n },\n\n // ── Unicode obfuscation markers (HIGH confidence) ──\n {\n category: \"unicode-obfuscation\",\n pattern: /[\\u200B-\\u200F\\u2028-\\u202F\\uFEFF]/, // Zero-width chars\n confidence: \"medium\",\n sensitivity: \"medium\",\n },\n {\n category: \"unicode-obfuscation\",\n pattern: /[\\u2060-\\u2064]/, // Invisible formatting chars\n confidence: \"medium\",\n sensitivity: \"medium\",\n },\n {\n category: \"unicode-obfuscation\",\n pattern: /[\\uE000-\\uF8FF]/, // Private Use Area (sometimes used to hide text)\n confidence: \"low\",\n sensitivity: \"high\",\n },\n\n // ── Encoded injection (base64 \"ignore\" etc.) ──\n {\n category: \"encoded-injection\",\n pattern: /aWdub3Jl/, // base64 of \"ignore\"\n confidence: \"medium\",\n sensitivity: \"medium\",\n },\n {\n category: \"encoded-injection\",\n pattern: /c3lzdGVt/, // base64 of \"system\"\n confidence: \"low\",\n sensitivity: \"high\",\n },\n\n // ── Delimiter injection (trying to break out of a tool argument) ──\n {\n category: \"delimiter-injection\",\n pattern: /\\}\\s*\\]\\s*\\}\\s*\\{/, // Trying to close JSON and start new object\n confidence: \"medium\",\n sensitivity: \"medium\",\n },\n {\n category: \"delimiter-injection\",\n pattern: /```\\s*(system|instruction|prompt)/i, // Code block with system marker\n confidence: \"medium\",\n sensitivity: \"medium\",\n },\n];\n\n// ── Sensitivity levels (numeric for comparison) ──\n\nconst SENSITIVITY_LEVELS: Record<string, number> = {\n low: 1,\n medium: 2,\n high: 3,\n};\n\n// ── Injection Detector ──────────────────────────────────────────────\n\nexport class InjectionDetector {\n private config: Required<InjectionDetectorConfig>;\n private customRegexes: RegExp[] = [];\n\n constructor(config: InjectionDetectorConfig = {}) {\n this.config = {\n enabled: config.enabled ?? true,\n sensitivity: config.sensitivity ?? \"medium\",\n customPatterns: config.customPatterns ?? [],\n excludeTools: config.excludeTools ?? [],\n };\n\n // Compile custom patterns\n for (const p of this.config.customPatterns) {\n try {\n this.customRegexes.push(new RegExp(p, \"i\"));\n } catch {\n // Log and skip invalid regex so users know which pattern failed\n process.stderr.write(`[agent-wall] Warning: invalid custom injection pattern: \"${p}\"\\n`);\n }\n }\n }\n\n /**\n * Scan a tool call's arguments for prompt injection.\n */\n scan(toolCall: ToolCallParams): InjectionScanResult {\n if (!this.config.enabled) {\n return { detected: false, confidence: \"low\", matches: [], summary: \"Injection detection disabled\" };\n }\n\n // Skip excluded tools\n if (this.config.excludeTools.includes(toolCall.name)) {\n return { detected: false, confidence: \"low\", matches: [], summary: \"Tool excluded from injection scanning\" };\n }\n\n const matches: InjectionMatch[] = [];\n const args = toolCall.arguments ?? {};\n const sensitivityLevel = SENSITIVITY_LEVELS[this.config.sensitivity] ?? 2;\n\n // Scan each argument value\n for (const [key, value] of Object.entries(args)) {\n const strValue = this.extractString(value);\n if (!strValue || strValue.length < 5) continue;\n\n // Run built-in patterns\n for (const injPattern of INJECTION_PATTERNS) {\n const patternSensitivity = SENSITIVITY_LEVELS[injPattern.sensitivity] ?? 2;\n if (patternSensitivity > sensitivityLevel) continue;\n\n if (injPattern.pattern.test(strValue)) {\n const match = strValue.match(injPattern.pattern);\n matches.push({\n category: injPattern.category,\n matched: match ? match[0].slice(0, 80) : \"***\",\n argumentKey: key,\n confidence: injPattern.confidence,\n });\n }\n }\n\n // Run custom patterns\n for (const regex of this.customRegexes) {\n regex.lastIndex = 0;\n if (regex.test(strValue)) {\n matches.push({\n category: \"custom\",\n matched: \"custom pattern match\",\n argumentKey: key,\n confidence: \"medium\",\n });\n }\n }\n }\n\n if (matches.length === 0) {\n return { detected: false, confidence: \"low\", matches: [], summary: \"No injection detected\" };\n }\n\n // Overall confidence = highest match confidence\n const highestConfidence = matches.reduce((best, m) => {\n const mLevel = SENSITIVITY_LEVELS[m.confidence] ?? 0;\n const bLevel = SENSITIVITY_LEVELS[best] ?? 0;\n return mLevel > bLevel ? m.confidence : best;\n }, \"low\" as \"low\" | \"medium\" | \"high\");\n\n const categories = [...new Set(matches.map((m) => m.category))];\n const summary = `Prompt injection detected (${highestConfidence} confidence): ${categories.join(\", \")}. ${matches.length} pattern(s) matched.`;\n\n return {\n detected: true,\n confidence: highestConfidence,\n matches,\n summary,\n };\n }\n\n /**\n * Extract a string from an argument value (handles nested objects).\n */\n private extractString(value: unknown): string {\n if (typeof value === \"string\") return value;\n if (typeof value === \"number\" || typeof value === \"boolean\") return String(value);\n if (value === null || value === undefined) return \"\";\n try {\n return JSON.stringify(value);\n } catch {\n return \"\";\n }\n }\n}\n","/**\n * Agent Wall Egress Control (URL/SSRF Protection)\n *\n * Inspects tool call arguments for URLs and blocks requests to:\n * - Private/internal IPs (RFC1918: 10.x, 172.16-31.x, 192.168.x)\n * - Loopback addresses (127.x, ::1, localhost)\n * - Link-local addresses (169.254.x — AWS/cloud metadata endpoint)\n * - Cloud metadata endpoints (169.254.169.254)\n * - Blocked domains (configurable)\n *\n * Supports allowlist mode: only explicitly allowed domains pass.\n */\n\nimport type { ToolCallParams } from \"./types.js\";\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport interface EgressControlConfig {\n /** Enable egress control (default: true when configured) */\n enabled?: boolean;\n /** Allowed domains (if set, ONLY these domains pass — allowlist mode) */\n allowedDomains?: string[];\n /** Blocked domains (blocklist mode, used when allowedDomains is not set) */\n blockedDomains?: string[];\n /** Block private/internal IPs (default: true) */\n blockPrivateIPs?: boolean;\n /** Block cloud metadata endpoints (default: true) */\n blockMetadataEndpoints?: boolean;\n /** Tool names to exclude from egress scanning */\n excludeTools?: string[];\n}\n\nexport interface EgressCheckResult {\n /** Whether the call is safe to proceed */\n allowed: boolean;\n /** URLs found in arguments */\n urlsFound: EgressUrlInfo[];\n /** URLs that were blocked */\n blocked: EgressUrlInfo[];\n /** Human-readable summary */\n summary: string;\n}\n\nexport interface EgressUrlInfo {\n /** The original URL string */\n url: string;\n /** Parsed hostname */\n hostname: string;\n /** Why it was blocked (if blocked) */\n reason?: string;\n /** Which argument key contained this URL */\n argumentKey: string;\n}\n\n// ── Private IP Ranges ───────────────────────────────────────────────\n\n/**\n * Check if an IP address is in a private/internal range.\n */\nfunction isPrivateIP(ip: string): boolean {\n // IPv4 private ranges\n const parts = ip.split(\".\").map(Number);\n if (parts.length === 4 && parts.every((p) => p >= 0 && p <= 255)) {\n // 10.0.0.0/8\n if (parts[0] === 10) return true;\n // 172.16.0.0/12\n if (parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31) return true;\n // 192.168.0.0/16\n if (parts[0] === 192 && parts[1] === 168) return true;\n // 127.0.0.0/8 (loopback)\n if (parts[0] === 127) return true;\n // 169.254.0.0/16 (link-local, includes cloud metadata)\n if (parts[0] === 169 && parts[1] === 254) return true;\n // 0.0.0.0\n if (parts.every((p) => p === 0)) return true;\n }\n\n // IPv6 loopback\n if (ip === \"::1\" || ip === \"[::1]\") return true;\n // IPv6 link-local\n if (ip.toLowerCase().startsWith(\"fe80:\")) return true;\n // IPv6 private (fc00::/7)\n if (ip.toLowerCase().startsWith(\"fc\") || ip.toLowerCase().startsWith(\"fd\")) return true;\n\n return false;\n}\n\n/**\n * Known cloud metadata endpoints.\n */\nconst METADATA_ENDPOINTS = [\n \"169.254.169.254\", // AWS, GCP, Azure\n \"metadata.google.internal\",\n \"metadata.goog\",\n \"100.100.100.200\", // Alibaba Cloud\n \"169.254.170.2\", // AWS ECS task metadata\n];\n\n// ── URL Extraction ──────────────────────────────────────────────────\n\n/**\n * Extract URLs from a string value.\n * Finds http://, https://, and bare domain patterns.\n */\nconst URL_REGEX = /https?:\\/\\/[^\\s\"'<>\\])}]+/gi;\n\nfunction extractUrls(value: string): string[] {\n const matches = value.match(URL_REGEX);\n return matches ? [...new Set(matches)] : [];\n}\n\n/**\n * Parse hostname from a URL string, handling edge cases.\n * Note: URL parser normalizes hex IPs (0x7f000001 → 127.0.0.1).\n */\nfunction parseHostname(urlStr: string): string | null {\n try {\n const url = new URL(urlStr);\n return url.hostname;\n } catch {\n // Try to extract hostname manually for malformed URLs\n const match = urlStr.match(/https?:\\/\\/([^/:?\\s#]+)/i);\n return match ? match[1] : null;\n }\n}\n\n/**\n * Extract raw hostname from URL before URL parser normalizes it.\n * This preserves hex/decimal IP encodings for obfuscation detection.\n */\nfunction extractRawHostname(urlStr: string): string | null {\n const match = urlStr.match(/https?:\\/\\/([^/:?\\s#]+)/i);\n return match ? match[1] : null;\n}\n\n// ── Egress Control ──────────────────────────────────────────────────\n\nexport class EgressControl {\n private config: Required<EgressControlConfig>;\n\n constructor(config: EgressControlConfig = {}) {\n this.config = {\n enabled: config.enabled ?? true,\n allowedDomains: config.allowedDomains ?? [],\n blockedDomains: config.blockedDomains ?? [],\n blockPrivateIPs: config.blockPrivateIPs ?? true,\n blockMetadataEndpoints: config.blockMetadataEndpoints ?? true,\n excludeTools: config.excludeTools ?? [],\n };\n }\n\n /**\n * Check a tool call's arguments for blocked URLs.\n */\n check(toolCall: ToolCallParams): EgressCheckResult {\n if (!this.config.enabled) {\n return { allowed: true, urlsFound: [], blocked: [], summary: \"Egress control disabled\" };\n }\n\n if (this.config.excludeTools.includes(toolCall.name)) {\n return { allowed: true, urlsFound: [], blocked: [], summary: \"Tool excluded from egress control\" };\n }\n\n const urlsFound: EgressUrlInfo[] = [];\n const blocked: EgressUrlInfo[] = [];\n const args = toolCall.arguments ?? {};\n\n // Extract URLs from all string arguments\n for (const [key, value] of Object.entries(args)) {\n const strValue = typeof value === \"string\" ? value : JSON.stringify(value ?? \"\");\n const urls = extractUrls(strValue);\n\n for (const url of urls) {\n // Extract raw hostname (before URL parser normalizes it)\n const rawHostname = extractRawHostname(url);\n const hostname = parseHostname(url);\n if (!hostname) continue;\n\n const info: EgressUrlInfo = { url, hostname, argumentKey: key };\n urlsFound.push(info);\n\n // Check if blocked (pass raw hostname for obfuscation detection)\n const blockReason = this.checkUrl(hostname, url, rawHostname);\n if (blockReason) {\n blocked.push({ ...info, reason: blockReason });\n }\n }\n }\n\n if (blocked.length === 0) {\n return {\n allowed: true,\n urlsFound,\n blocked: [],\n summary: urlsFound.length > 0\n ? `${urlsFound.length} URL(s) found, all allowed`\n : \"No URLs found in arguments\",\n };\n }\n\n const reasons = [...new Set(blocked.map((b) => b.reason))];\n return {\n allowed: false,\n urlsFound,\n blocked,\n summary: `Blocked ${blocked.length} URL(s): ${reasons.join(\"; \")}`,\n };\n }\n\n /**\n * Check a single hostname/URL against all rules.\n * Returns the block reason, or null if allowed.\n *\n * Check order matters: more specific checks (obfuscated, metadata) run\n * before generic private IP, so the reason message is precise.\n */\n private checkUrl(hostname: string, fullUrl: string, rawHostname?: string | null): string | null {\n const lowerHost = hostname.toLowerCase();\n const rawHost = rawHostname ?? hostname;\n\n // 1. Allowlist mode — if configured, ONLY listed domains pass\n if (this.config.allowedDomains.length > 0) {\n const allowed = this.config.allowedDomains.some((d) =>\n lowerHost === d.toLowerCase() || lowerHost.endsWith(\".\" + d.toLowerCase())\n );\n if (!allowed) {\n return `Domain \"${hostname}\" is not in the allowed domains list`;\n }\n // If allowed, still check private IPs (defense in depth)\n }\n\n // 2. Blocklist mode\n if (this.config.blockedDomains.length > 0) {\n const isBlocked = this.config.blockedDomains.some((d) =>\n lowerHost === d.toLowerCase() || lowerHost.endsWith(\".\" + d.toLowerCase())\n );\n if (isBlocked) {\n return `Domain \"${hostname}\" is in the blocked domains list`;\n }\n }\n\n // 3. Obfuscated IP check (BEFORE private IP — uses raw hostname before URL normalization)\n if (this.config.blockPrivateIPs) {\n if (/^0x[0-9a-f]+$/i.test(rawHost) || /^\\d{8,}$/.test(rawHost)) {\n return `Obfuscated IP address \"${rawHost}\" is blocked (potential SSRF bypass)`;\n }\n }\n\n // 4. Cloud metadata endpoint check (BEFORE generic private IP for precise messaging)\n if (this.config.blockMetadataEndpoints) {\n if (METADATA_ENDPOINTS.some((ep) => lowerHost === ep.toLowerCase())) {\n return `Cloud metadata endpoint \"${hostname}\" is blocked`;\n }\n\n if (fullUrl.includes(\"/latest/meta-data\") || fullUrl.includes(\"/metadata/instance\")) {\n return `Cloud metadata access is blocked`;\n }\n }\n\n // 5. Private IP check\n if (this.config.blockPrivateIPs) {\n if (isPrivateIP(hostname)) {\n return `Private/internal IP address \"${hostname}\" is blocked (SSRF protection)`;\n }\n\n // Also check for localhost aliases\n if (lowerHost === \"localhost\" || lowerHost === \"ip6-localhost\") {\n return `Localhost address is blocked (SSRF protection)`;\n }\n }\n\n return null;\n }\n}\n","/**\n * Agent Wall Kill Switch\n *\n * Emergency \"deny all\" mechanism for instantly shutting down\n * all tool call forwarding. Three activation methods:\n *\n * 1. File-based: touch .agent-wall-kill in cwd or home dir\n * 2. Programmatic: killSwitch.activate() / killSwitch.deactivate()\n * 3. Signal-based: SIGUSR2 toggles the kill switch (Unix only)\n *\n * When active, ALL tool calls are denied immediately with a clear message.\n * The kill switch is checked FIRST in the proxy pipeline — before policy\n * engine, injection detection, or any other check.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport * as os from \"node:os\";\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport interface KillSwitchConfig {\n /** Enable kill switch checking (default: true) */\n enabled?: boolean;\n /** Check for kill file on filesystem (default: true) */\n checkFile?: boolean;\n /** File names to check (default: [\".agent-wall-kill\"]) */\n killFileNames?: string[];\n /** Directories to check for kill files (default: [cwd, home]) */\n checkDirs?: string[];\n /** How often to check the kill file in ms (default: 1000) */\n pollIntervalMs?: number;\n /** Register SIGUSR2 signal handler to toggle (default: true on Unix) */\n registerSignal?: boolean;\n}\n\nexport interface KillSwitchStatus {\n /** Whether the kill switch is currently active */\n active: boolean;\n /** How it was activated */\n reason: string;\n /** When it was activated */\n activatedAt: string | null;\n}\n\n// ── Constants ───────────────────────────────────────────────────────\n\nconst DEFAULT_KILL_FILES = [\".agent-wall-kill\"];\nconst DEFAULT_POLL_INTERVAL = 1000;\n\n// ── Kill Switch ─────────────────────────────────────────────────────\n\nexport class KillSwitch {\n private config: Required<KillSwitchConfig>;\n private manuallyActive = false;\n private fileActive = false;\n private activeReason = \"\";\n private activatedAt: string | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(config: KillSwitchConfig = {}) {\n const isUnix = process.platform !== \"win32\";\n\n this.config = {\n enabled: config.enabled ?? true,\n checkFile: config.checkFile ?? true,\n killFileNames: config.killFileNames ?? DEFAULT_KILL_FILES,\n checkDirs: config.checkDirs ?? [process.cwd(), os.homedir()],\n pollIntervalMs: config.pollIntervalMs ?? DEFAULT_POLL_INTERVAL,\n registerSignal: config.registerSignal ?? isUnix,\n };\n\n if (this.config.enabled) {\n this.startPolling();\n this.registerSignalHandler();\n }\n }\n\n /**\n * Check if the kill switch is currently active.\n * This should be called at the TOP of the proxy pipeline.\n */\n isActive(): boolean {\n if (!this.config.enabled) return false;\n return this.manuallyActive || this.fileActive;\n }\n\n /**\n * Get the current kill switch status.\n */\n getStatus(): KillSwitchStatus {\n return {\n active: this.isActive(),\n reason: this.isActive() ? this.activeReason : \"inactive\",\n activatedAt: this.isActive() ? this.activatedAt : null,\n };\n }\n\n /**\n * Programmatically activate the kill switch.\n */\n activate(reason: string = \"Manually activated\"): void {\n this.manuallyActive = true;\n this.activeReason = reason;\n this.activatedAt = new Date().toISOString();\n }\n\n /**\n * Programmatically deactivate the kill switch.\n * Note: file-based kill switch must be deactivated by removing the file.\n */\n deactivate(): void {\n this.manuallyActive = false;\n if (!this.fileActive) {\n this.activeReason = \"\";\n this.activatedAt = null;\n }\n }\n\n /**\n * Start polling for kill files.\n */\n private startPolling(): void {\n if (!this.config.checkFile) return;\n\n // Check immediately\n this.checkKillFiles();\n\n // Then poll periodically\n this.pollTimer = setInterval(() => {\n this.checkKillFiles();\n }, this.config.pollIntervalMs);\n this.pollTimer.unref();\n }\n\n /**\n * Check if any kill file exists.\n */\n private checkKillFiles(): void {\n for (const dir of this.config.checkDirs) {\n for (const fileName of this.config.killFileNames) {\n const filePath = path.join(dir, fileName);\n try {\n if (fs.existsSync(filePath)) {\n if (!this.fileActive) {\n this.fileActive = true;\n this.activeReason = `Kill file detected: ${filePath}`;\n this.activatedAt = new Date().toISOString();\n }\n return;\n }\n } catch {\n // Ignore filesystem errors during polling\n }\n }\n }\n // No kill file found — deactivate file-based kill switch\n if (this.fileActive) {\n this.fileActive = false;\n if (!this.manuallyActive) {\n this.activeReason = \"\";\n this.activatedAt = null;\n }\n }\n }\n\n /**\n * Register SIGUSR2 signal handler to toggle kill switch.\n * SIGUSR2 is used (not SIGUSR1) because some tools use SIGUSR1.\n */\n private registerSignalHandler(): void {\n if (!this.config.registerSignal) return;\n\n try {\n process.on(\"SIGUSR2\", () => {\n if (this.manuallyActive) {\n this.deactivate();\n process.stderr.write(\"[agent-wall] Kill switch DEACTIVATED via SIGUSR2\\n\");\n } else {\n this.activate(\"Activated via SIGUSR2 signal\");\n process.stderr.write(\"[agent-wall] Kill switch ACTIVATED via SIGUSR2\\n\");\n }\n });\n } catch {\n // SIGUSR2 not available on this platform (Windows)\n }\n }\n\n /**\n * Stop the kill switch (cleanup timers and signal handlers).\n */\n dispose(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n}\n","/**\n * Agent Wall Tool Call Chain Detector\n *\n * Detects suspicious sequences of tool calls that indicate\n * multi-step attacks. Individual calls may look innocent,\n * but the CHAIN reveals the attack:\n *\n * read_file(.env) → write_file(tmp.txt) → bash(curl) = EXFILTRATION\n * list_directory(/) → read_file(passwd) → read_file(shadow) = RECON\n * write_file(script.sh) → bash(chmod +x) → bash(./script.sh) = DROPPER\n *\n * The detector maintains a sliding window of recent tool calls\n * and matches against known attack chain patterns.\n */\n\nimport type { ToolCallParams } from \"./types.js\";\n\n// ── Types ───────────────────────────────────────────────────────────\n\nexport interface ChainDetectorConfig {\n /** Enable chain detection (default: true) */\n enabled?: boolean;\n /** Sliding window size (number of recent calls to track) */\n windowSize?: number;\n /** Time window in ms (calls older than this are dropped) */\n windowMs?: number;\n /** Custom chain patterns to add */\n customChains?: ChainPattern[];\n}\n\nexport interface ChainPattern {\n /** Unique name for this chain pattern */\n name: string;\n /** Ordered sequence of tool name glob patterns */\n sequence: string[];\n /** Severity: \"low\", \"medium\", \"high\", \"critical\" */\n severity: \"low\" | \"medium\" | \"high\" | \"critical\";\n /** Human-readable description */\n message: string;\n /** Whether argument values must match across steps (e.g., same file read then sent) */\n trackArguments?: boolean;\n}\n\nexport interface ChainDetectionResult {\n /** Whether a suspicious chain was detected */\n detected: boolean;\n /** Matched chain patterns */\n matches: ChainMatchInfo[];\n /** Human-readable summary */\n summary: string;\n}\n\nexport interface ChainMatchInfo {\n /** Name of the matched chain pattern */\n chain: string;\n /** Severity level */\n severity: \"low\" | \"medium\" | \"high\" | \"critical\";\n /** The tool calls that formed the chain */\n calls: string[];\n /** Description */\n message: string;\n}\n\n// ── Built-in Chain Patterns ─────────────────────────────────────────\n\nconst BUILTIN_CHAINS: ChainPattern[] = [\n // ── Exfiltration chains ──\n {\n name: \"read-then-network\",\n sequence: [\"read_*|get_*|view_*\", \"shell_*|run_*|execute_*|bash\"],\n severity: \"high\",\n message: \"Potential data exfiltration: file read followed by shell command\",\n },\n {\n name: \"read-write-send\",\n sequence: [\"read_*|get_*\", \"write_*|create_*\", \"shell_*|run_*|bash\"],\n severity: \"critical\",\n message: \"Exfiltration chain: read → write → shell (staged exfiltration)\",\n },\n {\n name: \"env-then-network\",\n sequence: [\"read_*|get_*\", \"shell_*|run_*|bash\"],\n severity: \"critical\",\n message: \"Potential secret exfiltration: file read followed by network command\",\n trackArguments: true,\n },\n\n // ── Reconnaissance chains ──\n {\n name: \"directory-scan\",\n sequence: [\"list_*|ls\", \"list_*|ls\", \"list_*|ls\", \"read_*|get_*\"],\n severity: \"medium\",\n message: \"Directory scanning pattern: multiple listings followed by file read\",\n },\n\n // ── Dropper/persistence chains ──\n {\n name: \"write-execute\",\n sequence: [\"write_*|create_*\", \"shell_*|run_*|bash\"],\n severity: \"high\",\n message: \"Potential dropper: file write followed by shell execution\",\n },\n {\n name: \"write-chmod-execute\",\n sequence: [\"write_*|create_*\", \"shell_*|run_*|bash\", \"shell_*|run_*|bash\"],\n severity: \"critical\",\n message: \"Dropper chain: write → chmod → execute\",\n },\n\n // ── Privilege escalation ──\n {\n name: \"read-sensitive-then-write\",\n sequence: [\"read_*|get_*\", \"write_*|create_*|edit_*\"],\n severity: \"medium\",\n message: \"Sensitive file read followed by file modification\",\n trackArguments: true,\n },\n\n // ── Rapid shell commands ──\n {\n name: \"shell-burst\",\n sequence: [\"shell_*|run_*|bash\", \"shell_*|run_*|bash\", \"shell_*|run_*|bash\", \"shell_*|run_*|bash\"],\n severity: \"high\",\n message: \"Rapid burst of shell commands — potential automated attack\",\n },\n];\n\n// ── Internal tracked call ───────────────────────────────────────────\n\ninterface TrackedCall {\n tool: string;\n args: Record<string, unknown>;\n timestamp: number;\n}\n\n// ── Chain Detector ──────────────────────────────────────────────────\n\nexport class ChainDetector {\n private config: Required<ChainDetectorConfig>;\n private history: TrackedCall[] = [];\n private allChains: ChainPattern[];\n\n constructor(config: ChainDetectorConfig = {}) {\n this.config = {\n enabled: config.enabled ?? true,\n windowSize: config.windowSize ?? 20,\n windowMs: config.windowMs ?? 60_000, // 1 minute\n customChains: config.customChains ?? [],\n };\n this.allChains = [...BUILTIN_CHAINS, ...this.config.customChains];\n }\n\n /**\n * Record a tool call and check for suspicious chains.\n * Call this AFTER the policy engine allows the call.\n */\n record(toolCall: ToolCallParams): ChainDetectionResult {\n if (!this.config.enabled) {\n return { detected: false, matches: [], summary: \"Chain detection disabled\" };\n }\n\n const now = Date.now();\n\n // Add to history\n this.history.push({\n tool: toolCall.name,\n args: toolCall.arguments ?? {},\n timestamp: now,\n });\n\n // Prune old entries\n this.pruneHistory(now);\n\n // Check all chain patterns against current history\n const matches: ChainMatchInfo[] = [];\n\n for (const chain of this.allChains) {\n if (this.matchesChain(chain)) {\n matches.push({\n chain: chain.name,\n severity: chain.severity,\n calls: this.history.slice(-chain.sequence.length).map((c) => c.tool),\n message: chain.message,\n });\n }\n }\n\n if (matches.length === 0) {\n return { detected: false, matches: [], summary: \"No suspicious chains detected\" };\n }\n\n const highestSeverity = matches.reduce((best, m) => {\n const levels = { low: 0, medium: 1, high: 2, critical: 3 };\n return levels[m.severity] > levels[best] ? m.severity : best;\n }, \"low\" as \"low\" | \"medium\" | \"high\" | \"critical\");\n\n return {\n detected: true,\n matches,\n summary: `Suspicious tool call chain detected (${highestSeverity}): ${matches.map((m) => m.chain).join(\", \")}`,\n };\n }\n\n /**\n * Check if the current history matches a chain pattern.\n * Looks for the sequence appearing in order (not necessarily consecutive).\n */\n private matchesChain(chain: ChainPattern): boolean {\n if (this.history.length < chain.sequence.length) return false;\n\n // Check the most recent N calls match the sequence in order\n const recentCalls = this.history.slice(-chain.sequence.length);\n\n for (let i = 0; i < chain.sequence.length; i++) {\n const pattern = chain.sequence[i];\n const call = recentCalls[i];\n if (!this.matchesToolPattern(pattern, call.tool)) {\n return false;\n }\n }\n\n return true;\n }\n\n /**\n * Match a tool name against a pipe-separated glob-like pattern.\n */\n private matchesToolPattern(pattern: string, toolName: string): boolean {\n const alternatives = pattern.split(\"|\").map((p) => p.trim());\n return alternatives.some((p) => {\n if (p === \"*\") return true;\n if (p.endsWith(\"*\")) {\n return toolName.startsWith(p.slice(0, -1));\n }\n if (p.startsWith(\"*\")) {\n return toolName.endsWith(p.slice(1));\n }\n return toolName === p;\n });\n }\n\n /**\n * Remove entries outside the time window or exceeding window size.\n */\n private pruneHistory(now: number): void {\n // Remove by time\n const cutoff = now - this.config.windowMs;\n this.history = this.history.filter((c) => c.timestamp >= cutoff);\n\n // Remove by size (keep most recent)\n if (this.history.length > this.config.windowSize) {\n this.history = this.history.slice(-this.config.windowSize);\n }\n }\n\n /**\n * Clear the call history (e.g., on session reset).\n */\n reset(): void {\n this.history = [];\n }\n\n /**\n * Get the current call history length.\n */\n getHistoryLength(): number {\n return this.history.length;\n }\n}\n","/**\n * Agent Wall Dashboard Server\n *\n * HTTP + WebSocket server that bridges proxy events to a browser-based\n * security dashboard. Serves the built React SPA and streams real-time\n * events over WebSocket.\n *\n * Usage:\n * const dashboard = new DashboardServer({ port: 61100, proxy, killSwitch });\n * await dashboard.start();\n */\n\nimport * as http from \"node:http\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { WebSocketServer, type WebSocket } from \"ws\";\nimport type { StdioProxy } from \"./proxy.js\";\nimport type { KillSwitch } from \"./kill-switch.js\";\nimport type { PolicyEngine } from \"./policy-engine.js\";\nimport type { AuditLogger, AuditEntry } from \"./audit-logger.js\";\n\n// ── WebSocket Message Types ────────────────────────────────────────\n\nexport type WsMessageType =\n | \"event\"\n | \"stats\"\n | \"audit\"\n | \"killSwitch\"\n | \"ruleHits\"\n | \"config\"\n | \"welcome\";\n\nexport interface WsMessage<T = unknown> {\n type: WsMessageType;\n ts: string;\n payload: T;\n}\n\nexport interface ProxyEventPayload {\n event: string;\n tool: string;\n detail: string;\n severity: \"info\" | \"warn\" | \"critical\";\n}\n\nexport interface StatsPayload {\n forwarded: number;\n denied: number;\n prompted: number;\n total: number;\n scanned: number;\n responseBlocked: number;\n responseRedacted: number;\n uptime: number;\n killSwitchActive: boolean;\n}\n\nexport interface RuleHitsPayload {\n rules: Array<{\n name: string;\n action: string;\n hits: number;\n }>;\n}\n\nexport interface ConfigPayload {\n defaultAction: string;\n ruleCount: number;\n mode: string;\n security: {\n injection: boolean;\n egress: boolean;\n killSwitch: boolean;\n chain: boolean;\n signing: boolean;\n };\n}\n\n// ── Client → Server Messages ───────────────────────────────────────\n\nexport type ClientWsMessage =\n | { type: \"toggleKillSwitch\" }\n | { type: \"getStats\" }\n | { type: \"getConfig\" }\n | { type: \"getAuditLog\"; limit?: number; filter?: string };\n\n// ── MIME Types ──────────────────────────────────────────────────────\n\nconst MIME_TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"application/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n};\n\n// ── Dashboard Server ───────────────────────────────────────────────\n\nexport interface DashboardServerOptions {\n /** Port to listen on */\n port: number;\n /** The proxy instance to observe */\n proxy: StdioProxy;\n /** Kill switch instance (for toggle control) */\n killSwitch?: KillSwitch;\n /** Policy engine (for config summary) */\n policyEngine?: PolicyEngine;\n /** Audit logger (for log queries) */\n logger?: AuditLogger;\n /** Directory containing the built React SPA */\n staticDir?: string;\n /** Stats broadcast interval in ms (default: 2000) */\n statsIntervalMs?: number;\n}\n\nexport class DashboardServer {\n private httpServer: http.Server | null = null;\n private wss: WebSocketServer | null = null;\n private statsTimer: ReturnType<typeof setInterval> | null = null;\n private ruleHitCounts = new Map<string, { action: string; hits: number }>();\n private startTime = Date.now();\n private options: DashboardServerOptions;\n\n constructor(options: DashboardServerOptions) {\n this.options = options;\n }\n\n async start(): Promise<void> {\n const { port, staticDir, statsIntervalMs = 2000 } = this.options;\n\n // Create HTTP server for static files\n this.httpServer = http.createServer((req, res) => {\n this.handleHttpRequest(req, res, staticDir);\n });\n\n // Create WebSocket server on the same port\n this.wss = new WebSocketServer({ server: this.httpServer });\n this.wss.on(\"error\", () => {\n // Handled by httpServer error in start() promise\n });\n\n this.wss.on(\"connection\", (ws) => {\n // Send welcome message with current state\n this.sendTo(ws, {\n type: \"welcome\",\n ts: new Date().toISOString(),\n payload: { message: \"Agent Wall Dashboard connected\" },\n });\n\n // Send current stats immediately\n this.sendStats(ws);\n\n // Send current config\n this.sendConfig(ws);\n\n // Send current rule hits\n this.sendRuleHits(ws);\n\n // Handle incoming messages from dashboard\n ws.on(\"message\", (data) => {\n try {\n const msg: ClientWsMessage = JSON.parse(data.toString());\n this.handleClientMessage(ws, msg);\n } catch {\n // Ignore malformed messages\n }\n });\n });\n\n // Wire proxy events\n this.wireProxyEvents();\n\n // Broadcast stats on interval\n this.statsTimer = setInterval(() => {\n this.broadcastStats();\n }, statsIntervalMs);\n\n // Start listening\n return new Promise<void>((resolve, reject) => {\n this.httpServer!.on(\"error\", reject);\n this.httpServer!.listen(port, () => resolve());\n });\n }\n\n async stop(): Promise<void> {\n if (this.statsTimer) {\n clearInterval(this.statsTimer);\n this.statsTimer = null;\n }\n\n // Close all WebSocket connections\n if (this.wss) {\n for (const ws of this.wss.clients) {\n ws.close();\n }\n this.wss.close();\n this.wss = null;\n }\n\n // Close HTTP server\n if (this.httpServer) {\n return new Promise<void>((resolve) => {\n this.httpServer!.close(() => resolve());\n this.httpServer = null;\n });\n }\n }\n\n /** Get the actual port (useful when port 0 is used for testing) */\n getPort(): number {\n const addr = this.httpServer?.address();\n if (addr && typeof addr === \"object\") return addr.port;\n return this.options.port;\n }\n\n // ── Event Wiring ──────────────────────────────────────────────────\n\n private wireProxyEvents(): void {\n const { proxy } = this.options;\n\n const eventMap: Array<{\n event: string;\n severity: \"info\" | \"warn\" | \"critical\";\n getArgs: (tool: string, detail?: string) => { tool: string; detail: string };\n }> = [\n { event: \"allowed\", severity: \"info\", getArgs: (tool) => ({ tool, detail: \"\" }) },\n { event: \"denied\", severity: \"warn\", getArgs: (tool, msg = \"\") => ({ tool, detail: msg }) },\n { event: \"prompted\", severity: \"info\", getArgs: (tool, msg = \"\") => ({ tool, detail: msg }) },\n { event: \"responseBlocked\", severity: \"warn\", getArgs: (tool, findings = \"\") => ({ tool, detail: findings }) },\n { event: \"responseRedacted\", severity: \"info\", getArgs: (tool, findings = \"\") => ({ tool, detail: findings }) },\n { event: \"injectionDetected\", severity: \"critical\", getArgs: (tool, summary = \"\") => ({ tool, detail: summary }) },\n { event: \"egressBlocked\", severity: \"critical\", getArgs: (tool, summary = \"\") => ({ tool, detail: summary }) },\n { event: \"killSwitchActive\", severity: \"critical\", getArgs: (tool) => ({ tool, detail: \"Kill switch is active — all calls denied\" }) },\n { event: \"chainDetected\", severity: \"warn\", getArgs: (tool, summary = \"\") => ({ tool, detail: summary }) },\n ];\n\n for (const { event, severity, getArgs } of eventMap) {\n proxy.on(event, (tool: string, detail?: string) => {\n const parsed = getArgs(tool, detail);\n this.broadcast({\n type: \"event\",\n ts: new Date().toISOString(),\n payload: { event, tool: parsed.tool, detail: parsed.detail, severity } as ProxyEventPayload,\n });\n });\n }\n }\n\n /** Called by the audit logger's onEntry callback */\n handleAuditEntry(entry: AuditEntry): void {\n // Track rule hits\n if (entry.verdict?.rule) {\n const key = entry.verdict.rule;\n const existing = this.ruleHitCounts.get(key);\n if (existing) {\n existing.hits++;\n } else {\n this.ruleHitCounts.set(key, {\n action: entry.verdict.action,\n hits: 1,\n });\n }\n }\n\n // Broadcast audit entry to all clients\n this.broadcast({\n type: \"audit\",\n ts: new Date().toISOString(),\n payload: entry,\n });\n\n // Broadcast updated rule hits after each change\n if (entry.verdict?.rule) {\n const rules = Array.from(this.ruleHitCounts.entries()).map(\n ([name, { action, hits }]) => ({ name, action, hits })\n );\n this.broadcast({\n type: \"ruleHits\",\n ts: new Date().toISOString(),\n payload: { rules },\n });\n }\n }\n\n // ── Client Message Handling ────────────────────────────────────────\n\n private handleClientMessage(ws: WebSocket, msg: ClientWsMessage): void {\n switch (msg.type) {\n case \"toggleKillSwitch\":\n if (this.options.killSwitch) {\n if (this.options.killSwitch.isActive()) {\n this.options.killSwitch.deactivate();\n } else {\n this.options.killSwitch.activate();\n }\n // Broadcast new status\n this.broadcast({\n type: \"killSwitch\",\n ts: new Date().toISOString(),\n payload: { active: this.options.killSwitch.isActive() },\n });\n }\n break;\n\n case \"getStats\":\n this.sendStats(ws);\n break;\n\n case \"getConfig\":\n this.sendConfig(ws);\n break;\n\n case \"getAuditLog\": {\n const entries = this.options.logger?.getEntries() ?? [];\n let filtered = entries;\n if (msg.filter && msg.filter !== \"all\") {\n filtered = entries.filter((e) => e.verdict?.action === msg.filter);\n }\n const limited = msg.limit ? filtered.slice(-msg.limit) : filtered.slice(-100);\n this.sendTo(ws, {\n type: \"audit\",\n ts: new Date().toISOString(),\n payload: limited,\n });\n break;\n }\n }\n }\n\n // ── Broadcasting ──────────────────────────────────────────────────\n\n private broadcast(msg: WsMessage): void {\n if (!this.wss) return;\n const data = JSON.stringify(msg);\n for (const ws of this.wss.clients) {\n if (ws.readyState === 1 /* OPEN */) {\n ws.send(data);\n }\n }\n }\n\n private sendTo(ws: WebSocket, msg: WsMessage): void {\n if (ws.readyState === 1) {\n ws.send(JSON.stringify(msg));\n }\n }\n\n private broadcastStats(): void {\n if (!this.wss || this.wss.clients.size === 0) return;\n const stats = this.buildStats();\n this.broadcast({\n type: \"stats\",\n ts: new Date().toISOString(),\n payload: stats,\n });\n }\n\n private sendStats(ws: WebSocket): void {\n this.sendTo(ws, {\n type: \"stats\",\n ts: new Date().toISOString(),\n payload: this.buildStats(),\n });\n }\n\n private buildStats(): StatsPayload {\n const proxyStats = this.options.proxy.getStats();\n return {\n ...proxyStats,\n uptime: Math.floor((Date.now() - this.startTime) / 1000),\n killSwitchActive: this.options.killSwitch?.isActive() ?? false,\n };\n }\n\n private sendConfig(ws: WebSocket): void {\n const pe = this.options.policyEngine;\n const policyConfig = pe?.getConfig();\n const config: ConfigPayload = {\n defaultAction: policyConfig?.defaultAction ?? \"prompt\",\n ruleCount: policyConfig?.rules?.length ?? 0,\n mode: policyConfig?.mode ?? \"standard\",\n security: {\n injection: policyConfig?.security?.injectionDetection?.enabled ?? false,\n egress: policyConfig?.security?.egressControl?.enabled ?? false,\n killSwitch: !!this.options.killSwitch,\n chain: policyConfig?.security?.chainDetection?.enabled ?? false,\n signing: policyConfig?.security?.signing ?? false,\n },\n };\n this.sendTo(ws, {\n type: \"config\",\n ts: new Date().toISOString(),\n payload: config,\n });\n }\n\n private sendRuleHits(ws: WebSocket): void {\n const rules = Array.from(this.ruleHitCounts.entries()).map(\n ([name, { action, hits }]) => ({ name, action, hits })\n );\n this.sendTo(ws, {\n type: \"ruleHits\",\n ts: new Date().toISOString(),\n payload: { rules } as RuleHitsPayload,\n });\n }\n\n // ── Static File Serving ───────────────────────────────────────────\n\n private handleHttpRequest(\n req: http.IncomingMessage,\n res: http.ServerResponse,\n staticDir?: string\n ): void {\n if (!staticDir) {\n res.writeHead(200, { \"Content-Type\": \"text/html; charset=utf-8\" });\n res.end(\"<html><body><h1>Agent Wall Dashboard</h1><p>No static assets found. Build the dashboard package first.</p></body></html>\");\n return;\n }\n\n const url = req.url?.split(\"?\")[0] ?? \"/\";\n let filePath = path.join(staticDir, url === \"/\" ? \"index.html\" : url);\n\n // Security: prevent path traversal\n const resolved = path.resolve(filePath);\n if (!resolved.startsWith(path.resolve(staticDir))) {\n res.writeHead(403);\n res.end(\"Forbidden\");\n return;\n }\n\n // Try to serve the file\n try {\n if (!fs.existsSync(resolved) || fs.statSync(resolved).isDirectory()) {\n // SPA fallback: serve index.html for unknown routes\n filePath = path.join(staticDir, \"index.html\");\n }\n\n const content = fs.readFileSync(filePath);\n const ext = path.extname(filePath).toLowerCase();\n const contentType = MIME_TYPES[ext] ?? \"application/octet-stream\";\n\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(content);\n } catch {\n res.writeHead(404);\n res.end(\"Not Found\");\n }\n }\n}\n"],"mappings":"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","names":["path","z","fs","path","crypto","fs","resolve","fs","path","fs","path","resolve"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agent-wall/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core proxy engine and policy evaluator for Agent Wall",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Yalelet Dessalegn",
|
|
7
|
+
"homepage": "https://agent-wall.github.io/agent-wall/",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/agent-wall/agent-wall/issues"
|
|
10
|
+
},
|
|
11
|
+
"repository": {
|
|
12
|
+
"type": "git",
|
|
13
|
+
"url": "https://github.com/agent-wall/agent-wall"
|
|
14
|
+
},
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"types": "./dist/index.d.ts"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"cross-spawn": "^7.0.6",
|
|
26
|
+
"js-yaml": "^4.1.0",
|
|
27
|
+
"minimatch": "^10.0.1",
|
|
28
|
+
"ws": "^8.19.0",
|
|
29
|
+
"zod": "^3.25.67"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/cross-spawn": "^6.0.6",
|
|
33
|
+
"@types/js-yaml": "^4.0.9",
|
|
34
|
+
"@types/node": "^22.16.4",
|
|
35
|
+
"@types/ws": "^8.18.1",
|
|
36
|
+
"tsup": "^8.5.1",
|
|
37
|
+
"typescript": "^5.9.3",
|
|
38
|
+
"vitest": "^3.2.4"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup",
|
|
42
|
+
"dev": "tsup --watch",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"test:watch": "vitest",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"clean": "rm -rf dist"
|
|
47
|
+
}
|
|
48
|
+
}
|